diff --git a/channel/channel.go b/channel/channel.go index fd0e7c6..f362af6 100644 --- a/channel/channel.go +++ b/channel/channel.go @@ -163,44 +163,87 @@ func NewTripleRatchet( func DoubleRatchetEncrypt( ratchetStateAndMessage generated.DoubleRatchetStateAndMessage, ) generated.DoubleRatchetStateAndEnvelope { - return generated.DoubleRatchetEncrypt(ratchetStateAndMessage) + result, err := generated.DoubleRatchetEncrypt(ratchetStateAndMessage) + if err != nil { + return generated.DoubleRatchetStateAndEnvelope{} + } + return result } func DoubleRatchetDecrypt( ratchetStateAndEnvelope generated.DoubleRatchetStateAndEnvelope, ) generated.DoubleRatchetStateAndMessage { - return generated.DoubleRatchetDecrypt(ratchetStateAndEnvelope) + result, err := generated.DoubleRatchetDecrypt(ratchetStateAndEnvelope) + if err != nil { + return generated.DoubleRatchetStateAndMessage{} + } + return result } func TripleRatchetInitRound1( ratchetStateAndMetadata generated.TripleRatchetStateAndMetadata, ) generated.TripleRatchetStateAndMetadata { - return generated.TripleRatchetInitRound1(ratchetStateAndMetadata) + result, err := generated.TripleRatchetInitRound1(ratchetStateAndMetadata) + if err != nil { + return generated.TripleRatchetStateAndMetadata{ + Metadata: map[string]string{"error": err.Error()}, + } + } + return result } + func TripleRatchetInitRound2( ratchetStateAndMetadata generated.TripleRatchetStateAndMetadata, ) generated.TripleRatchetStateAndMetadata { - return generated.TripleRatchetInitRound2(ratchetStateAndMetadata) + result, err := generated.TripleRatchetInitRound2(ratchetStateAndMetadata) + if err != nil { + return generated.TripleRatchetStateAndMetadata{ + Metadata: map[string]string{"error": err.Error()}, + } + } + return result } + func TripleRatchetInitRound3( ratchetStateAndMetadata generated.TripleRatchetStateAndMetadata, ) generated.TripleRatchetStateAndMetadata { - return generated.TripleRatchetInitRound3(ratchetStateAndMetadata) + result, err := generated.TripleRatchetInitRound3(ratchetStateAndMetadata) + if err != nil { + return generated.TripleRatchetStateAndMetadata{ + Metadata: map[string]string{"error": err.Error()}, + } + } + return result } + func TripleRatchetInitRound4( ratchetStateAndMetadata generated.TripleRatchetStateAndMetadata, ) generated.TripleRatchetStateAndMetadata { - return generated.TripleRatchetInitRound4(ratchetStateAndMetadata) + result, err := generated.TripleRatchetInitRound4(ratchetStateAndMetadata) + if err != nil { + return generated.TripleRatchetStateAndMetadata{ + Metadata: map[string]string{"error": err.Error()}, + } + } + return result } func TripleRatchetEncrypt( ratchetStateAndMessage generated.TripleRatchetStateAndMessage, ) generated.TripleRatchetStateAndEnvelope { - return generated.TripleRatchetEncrypt(ratchetStateAndMessage) + result, err := generated.TripleRatchetEncrypt(ratchetStateAndMessage) + if err != nil { + return generated.TripleRatchetStateAndEnvelope{} + } + return result } func TripleRatchetDecrypt( ratchetStateAndEnvelope generated.TripleRatchetStateAndEnvelope, ) generated.TripleRatchetStateAndMessage { - return generated.TripleRatchetDecrypt(ratchetStateAndEnvelope) + result, err := generated.TripleRatchetDecrypt(ratchetStateAndEnvelope) + if err != nil { + return generated.TripleRatchetStateAndMessage{} + } + return result } diff --git a/crates/channel/Cargo.toml b/crates/channel/Cargo.toml index 2f5492a..7432ebc 100644 --- a/crates/channel/Cargo.toml +++ b/crates/channel/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [lib] -crate-type = ["lib", "staticlib"] +crate-type = ["lib", "staticlib", "cdylib"] name = "channel" [[bin]] diff --git a/crates/channel/bindings/kotlin/uniffi/channel/channel.kt b/crates/channel/bindings/kotlin/uniffi/channel/channel.kt index 2c4ab39..91f545f 100644 --- a/crates/channel/bindings/kotlin/uniffi/channel/channel.kt +++ b/crates/channel/bindings/kotlin/uniffi/channel/channel.kt @@ -748,6 +748,8 @@ internal interface UniffiForeignFutureCompleteVoid : com.sun.jna.Callback { + + @@ -804,6 +806,8 @@ internal interface UniffiLib : Library { ): RustBuffer.ByValue fun uniffi_channel_fn_func_triple_ratchet_init_round_4(`ratchetStateAndMetadata`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): RustBuffer.ByValue + fun uniffi_channel_fn_func_triple_ratchet_resize(`ratchetState`: RustBuffer.ByValue,`other`: RustBuffer.ByValue,`id`: Long,`total`: Long,uniffi_out_err: UniffiRustCallStatus, + ): RustBuffer.ByValue fun uniffi_channel_fn_func_verify_ed448(`publicKey`: RustBuffer.ByValue,`message`: RustBuffer.ByValue,`signature`: RustBuffer.ByValue,uniffi_out_err: UniffiRustCallStatus, ): RustBuffer.ByValue fun ffi_channel_rustbuffer_alloc(`size`: Long,uniffi_out_err: UniffiRustCallStatus, @@ -956,6 +960,8 @@ internal interface UniffiLib : Library { ): Short fun uniffi_channel_checksum_func_triple_ratchet_init_round_4( ): Short + fun uniffi_channel_checksum_func_triple_ratchet_resize( + ): Short fun uniffi_channel_checksum_func_verify_ed448( ): Short fun ffi_channel_uniffi_contract_version( @@ -978,10 +984,10 @@ private fun uniffiCheckApiChecksums(lib: UniffiLib) { if (lib.uniffi_channel_checksum_func_decrypt_inbox_message() != 59344.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_channel_checksum_func_double_ratchet_decrypt() != 13335.toShort()) { + if (lib.uniffi_channel_checksum_func_double_ratchet_decrypt() != 59687.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_channel_checksum_func_double_ratchet_encrypt() != 59209.toShort()) { + if (lib.uniffi_channel_checksum_func_double_ratchet_encrypt() != 57909.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } if (lib.uniffi_channel_checksum_func_encrypt_inbox_message() != 48273.toShort()) { @@ -1014,22 +1020,25 @@ private fun uniffiCheckApiChecksums(lib: UniffiLib) { if (lib.uniffi_channel_checksum_func_sign_ed448() != 28573.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_channel_checksum_func_triple_ratchet_decrypt() != 42324.toShort()) { + if (lib.uniffi_channel_checksum_func_triple_ratchet_decrypt() != 15842.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_channel_checksum_func_triple_ratchet_encrypt() != 61617.toShort()) { + if (lib.uniffi_channel_checksum_func_triple_ratchet_encrypt() != 23451.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_channel_checksum_func_triple_ratchet_init_round_1() != 42612.toShort()) { + if (lib.uniffi_channel_checksum_func_triple_ratchet_init_round_1() != 63112.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_channel_checksum_func_triple_ratchet_init_round_2() != 11875.toShort()) { + if (lib.uniffi_channel_checksum_func_triple_ratchet_init_round_2() != 34197.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_channel_checksum_func_triple_ratchet_init_round_3() != 50331.toShort()) { + if (lib.uniffi_channel_checksum_func_triple_ratchet_init_round_3() != 39476.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_channel_checksum_func_triple_ratchet_init_round_4() != 14779.toShort()) { + if (lib.uniffi_channel_checksum_func_triple_ratchet_init_round_4() != 19263.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } + if (lib.uniffi_channel_checksum_func_triple_ratchet_resize() != 57124.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } if (lib.uniffi_channel_checksum_func_verify_ed448() != 57200.toShort()) { @@ -1371,6 +1380,83 @@ public object FfiConverterTypeTripleRatchetStateAndMetadata: FfiConverterRustBuf + +sealed class CryptoException(message: String): kotlin.Exception(message) { + + class InvalidState(message: String) : CryptoException(message) + + class InvalidEnvelope(message: String) : CryptoException(message) + + class DecryptionFailed(message: String) : CryptoException(message) + + class EncryptionFailed(message: String) : CryptoException(message) + + class SerializationFailed(message: String) : CryptoException(message) + + class InvalidInput(message: String) : CryptoException(message) + + + companion object ErrorHandler : UniffiRustCallStatusErrorHandler { + override fun lift(error_buf: RustBuffer.ByValue): CryptoException = FfiConverterTypeCryptoError.lift(error_buf) + } +} + +/** + * @suppress + */ +public object FfiConverterTypeCryptoError : FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): CryptoException { + + return when(buf.getInt()) { + 1 -> CryptoException.InvalidState(FfiConverterString.read(buf)) + 2 -> CryptoException.InvalidEnvelope(FfiConverterString.read(buf)) + 3 -> CryptoException.DecryptionFailed(FfiConverterString.read(buf)) + 4 -> CryptoException.EncryptionFailed(FfiConverterString.read(buf)) + 5 -> CryptoException.SerializationFailed(FfiConverterString.read(buf)) + 6 -> CryptoException.InvalidInput(FfiConverterString.read(buf)) + else -> throw RuntimeException("invalid error enum value, something is very wrong!!") + } + + } + + override fun allocationSize(value: CryptoException): ULong { + return 4UL + } + + override fun write(value: CryptoException, buf: ByteBuffer) { + when(value) { + is CryptoException.InvalidState -> { + buf.putInt(1) + Unit + } + is CryptoException.InvalidEnvelope -> { + buf.putInt(2) + Unit + } + is CryptoException.DecryptionFailed -> { + buf.putInt(3) + Unit + } + is CryptoException.EncryptionFailed -> { + buf.putInt(4) + Unit + } + is CryptoException.SerializationFailed -> { + buf.putInt(5) + Unit + } + is CryptoException.InvalidInput -> { + buf.putInt(6) + Unit + } + }.let { /* this makes the `when` an expression, which ensures it is exhaustive */ } + } + +} + + + + /** * @suppress */ @@ -1470,18 +1556,20 @@ public object FfiConverterMapStringString: FfiConverterRustBuffer + uniffiRustCallWithError(CryptoException) { _status -> UniffiLib.INSTANCE.uniffi_channel_fn_func_double_ratchet_decrypt( FfiConverterTypeDoubleRatchetStateAndEnvelope.lower(`ratchetStateAndEnvelope`),_status) } ) } - fun `doubleRatchetEncrypt`(`ratchetStateAndMessage`: DoubleRatchetStateAndMessage): DoubleRatchetStateAndEnvelope { + + @Throws(CryptoException::class) fun `doubleRatchetEncrypt`(`ratchetStateAndMessage`: DoubleRatchetStateAndMessage): DoubleRatchetStateAndEnvelope { return FfiConverterTypeDoubleRatchetStateAndEnvelope.lift( - uniffiRustCall() { _status -> + uniffiRustCallWithError(CryptoException) { _status -> UniffiLib.INSTANCE.uniffi_channel_fn_func_double_ratchet_encrypt( FfiConverterTypeDoubleRatchetStateAndMessage.lower(`ratchetStateAndMessage`),_status) } @@ -1578,60 +1666,75 @@ public object FfiConverterMapStringString: FfiConverterRustBuffer + uniffiRustCallWithError(CryptoException) { _status -> UniffiLib.INSTANCE.uniffi_channel_fn_func_triple_ratchet_decrypt( FfiConverterTypeTripleRatchetStateAndEnvelope.lower(`ratchetStateAndEnvelope`),_status) } ) } - fun `tripleRatchetEncrypt`(`ratchetStateAndMessage`: TripleRatchetStateAndMessage): TripleRatchetStateAndEnvelope { + + @Throws(CryptoException::class) fun `tripleRatchetEncrypt`(`ratchetStateAndMessage`: TripleRatchetStateAndMessage): TripleRatchetStateAndEnvelope { return FfiConverterTypeTripleRatchetStateAndEnvelope.lift( - uniffiRustCall() { _status -> + uniffiRustCallWithError(CryptoException) { _status -> UniffiLib.INSTANCE.uniffi_channel_fn_func_triple_ratchet_encrypt( FfiConverterTypeTripleRatchetStateAndMessage.lower(`ratchetStateAndMessage`),_status) } ) } - fun `tripleRatchetInitRound1`(`ratchetStateAndMetadata`: TripleRatchetStateAndMetadata): TripleRatchetStateAndMetadata { + + @Throws(CryptoException::class) fun `tripleRatchetInitRound1`(`ratchetStateAndMetadata`: TripleRatchetStateAndMetadata): TripleRatchetStateAndMetadata { return FfiConverterTypeTripleRatchetStateAndMetadata.lift( - uniffiRustCall() { _status -> + uniffiRustCallWithError(CryptoException) { _status -> UniffiLib.INSTANCE.uniffi_channel_fn_func_triple_ratchet_init_round_1( FfiConverterTypeTripleRatchetStateAndMetadata.lower(`ratchetStateAndMetadata`),_status) } ) } - fun `tripleRatchetInitRound2`(`ratchetStateAndMetadata`: TripleRatchetStateAndMetadata): TripleRatchetStateAndMetadata { + + @Throws(CryptoException::class) fun `tripleRatchetInitRound2`(`ratchetStateAndMetadata`: TripleRatchetStateAndMetadata): TripleRatchetStateAndMetadata { return FfiConverterTypeTripleRatchetStateAndMetadata.lift( - uniffiRustCall() { _status -> + uniffiRustCallWithError(CryptoException) { _status -> UniffiLib.INSTANCE.uniffi_channel_fn_func_triple_ratchet_init_round_2( FfiConverterTypeTripleRatchetStateAndMetadata.lower(`ratchetStateAndMetadata`),_status) } ) } - fun `tripleRatchetInitRound3`(`ratchetStateAndMetadata`: TripleRatchetStateAndMetadata): TripleRatchetStateAndMetadata { + + @Throws(CryptoException::class) fun `tripleRatchetInitRound3`(`ratchetStateAndMetadata`: TripleRatchetStateAndMetadata): TripleRatchetStateAndMetadata { return FfiConverterTypeTripleRatchetStateAndMetadata.lift( - uniffiRustCall() { _status -> + uniffiRustCallWithError(CryptoException) { _status -> UniffiLib.INSTANCE.uniffi_channel_fn_func_triple_ratchet_init_round_3( FfiConverterTypeTripleRatchetStateAndMetadata.lower(`ratchetStateAndMetadata`),_status) } ) } - fun `tripleRatchetInitRound4`(`ratchetStateAndMetadata`: TripleRatchetStateAndMetadata): TripleRatchetStateAndMetadata { + + @Throws(CryptoException::class) fun `tripleRatchetInitRound4`(`ratchetStateAndMetadata`: TripleRatchetStateAndMetadata): TripleRatchetStateAndMetadata { return FfiConverterTypeTripleRatchetStateAndMetadata.lift( - uniffiRustCall() { _status -> + uniffiRustCallWithError(CryptoException) { _status -> UniffiLib.INSTANCE.uniffi_channel_fn_func_triple_ratchet_init_round_4( FfiConverterTypeTripleRatchetStateAndMetadata.lower(`ratchetStateAndMetadata`),_status) } ) } + fun `tripleRatchetResize`(`ratchetState`: kotlin.String, `other`: kotlin.String, `id`: kotlin.ULong, `total`: kotlin.ULong): List> { + return FfiConverterSequenceSequenceUByte.lift( + uniffiRustCall() { _status -> + UniffiLib.INSTANCE.uniffi_channel_fn_func_triple_ratchet_resize( + FfiConverterString.lower(`ratchetState`),FfiConverterString.lower(`other`),FfiConverterULong.lower(`id`),FfiConverterULong.lower(`total`),_status) +} + ) + } + fun `verifyEd448`(`publicKey`: kotlin.String, `message`: kotlin.String, `signature`: kotlin.String): kotlin.String { return FfiConverterString.lift( uniffiRustCall() { _status -> diff --git a/crates/channel/bindings/swift/channel.swift b/crates/channel/bindings/swift/channel.swift index c0aae17..2b5917f 100644 --- a/crates/channel/bindings/swift/channel.swift +++ b/crates/channel/bindings/swift/channel.swift @@ -823,6 +823,101 @@ public func FfiConverterTypeTripleRatchetStateAndMetadata_lower(_ value: TripleR return FfiConverterTypeTripleRatchetStateAndMetadata.lower(value) } + +public enum CryptoError { + + + + case InvalidState(message: String) + + case InvalidEnvelope(message: String) + + case DecryptionFailed(message: String) + + case EncryptionFailed(message: String) + + case SerializationFailed(message: String) + + case InvalidInput(message: String) + +} + + +#if swift(>=5.8) +@_documentation(visibility: private) +#endif +public struct FfiConverterTypeCryptoError: FfiConverterRustBuffer { + typealias SwiftType = CryptoError + + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> CryptoError { + let variant: Int32 = try readInt(&buf) + switch variant { + + + + + case 1: return .InvalidState( + message: try FfiConverterString.read(from: &buf) + ) + + case 2: return .InvalidEnvelope( + message: try FfiConverterString.read(from: &buf) + ) + + case 3: return .DecryptionFailed( + message: try FfiConverterString.read(from: &buf) + ) + + case 4: return .EncryptionFailed( + message: try FfiConverterString.read(from: &buf) + ) + + case 5: return .SerializationFailed( + message: try FfiConverterString.read(from: &buf) + ) + + case 6: return .InvalidInput( + message: try FfiConverterString.read(from: &buf) + ) + + + default: throw UniffiInternalError.unexpectedEnumCase + } + } + + public static func write(_ value: CryptoError, into buf: inout [UInt8]) { + switch value { + + + + + case .InvalidState(_ /* message is ignored*/): + writeInt(&buf, Int32(1)) + case .InvalidEnvelope(_ /* message is ignored*/): + writeInt(&buf, Int32(2)) + case .DecryptionFailed(_ /* message is ignored*/): + writeInt(&buf, Int32(3)) + case .EncryptionFailed(_ /* message is ignored*/): + writeInt(&buf, Int32(4)) + case .SerializationFailed(_ /* message is ignored*/): + writeInt(&buf, Int32(5)) + case .InvalidInput(_ /* message is ignored*/): + writeInt(&buf, Int32(6)) + + + } + } +} + + +extension CryptoError: Equatable, Hashable {} + +extension CryptoError: Foundation.LocalizedError { + public var errorDescription: String? { + String(reflecting: self) + } +} + #if swift(>=5.8) @_documentation(visibility: private) #endif @@ -905,15 +1000,15 @@ public func decryptInboxMessage(input: String) -> String { ) }) } -public func doubleRatchetDecrypt(ratchetStateAndEnvelope: DoubleRatchetStateAndEnvelope) -> DoubleRatchetStateAndMessage { - return try! FfiConverterTypeDoubleRatchetStateAndMessage.lift(try! rustCall() { +public func doubleRatchetDecrypt(ratchetStateAndEnvelope: DoubleRatchetStateAndEnvelope)throws -> DoubleRatchetStateAndMessage { + return try FfiConverterTypeDoubleRatchetStateAndMessage.lift(try rustCallWithError(FfiConverterTypeCryptoError.lift) { uniffi_channel_fn_func_double_ratchet_decrypt( FfiConverterTypeDoubleRatchetStateAndEnvelope.lower(ratchetStateAndEnvelope),$0 ) }) } -public func doubleRatchetEncrypt(ratchetStateAndMessage: DoubleRatchetStateAndMessage) -> DoubleRatchetStateAndEnvelope { - return try! FfiConverterTypeDoubleRatchetStateAndEnvelope.lift(try! rustCall() { +public func doubleRatchetEncrypt(ratchetStateAndMessage: DoubleRatchetStateAndMessage)throws -> DoubleRatchetStateAndEnvelope { + return try FfiConverterTypeDoubleRatchetStateAndEnvelope.lift(try rustCallWithError(FfiConverterTypeCryptoError.lift) { uniffi_channel_fn_func_double_ratchet_encrypt( FfiConverterTypeDoubleRatchetStateAndMessage.lower(ratchetStateAndMessage),$0 ) @@ -1006,48 +1101,58 @@ public func signEd448(key: String, message: String) -> String { ) }) } -public func tripleRatchetDecrypt(ratchetStateAndEnvelope: TripleRatchetStateAndEnvelope) -> TripleRatchetStateAndMessage { - return try! FfiConverterTypeTripleRatchetStateAndMessage.lift(try! rustCall() { +public func tripleRatchetDecrypt(ratchetStateAndEnvelope: TripleRatchetStateAndEnvelope)throws -> TripleRatchetStateAndMessage { + return try FfiConverterTypeTripleRatchetStateAndMessage.lift(try rustCallWithError(FfiConverterTypeCryptoError.lift) { uniffi_channel_fn_func_triple_ratchet_decrypt( FfiConverterTypeTripleRatchetStateAndEnvelope.lower(ratchetStateAndEnvelope),$0 ) }) } -public func tripleRatchetEncrypt(ratchetStateAndMessage: TripleRatchetStateAndMessage) -> TripleRatchetStateAndEnvelope { - return try! FfiConverterTypeTripleRatchetStateAndEnvelope.lift(try! rustCall() { +public func tripleRatchetEncrypt(ratchetStateAndMessage: TripleRatchetStateAndMessage)throws -> TripleRatchetStateAndEnvelope { + return try FfiConverterTypeTripleRatchetStateAndEnvelope.lift(try rustCallWithError(FfiConverterTypeCryptoError.lift) { uniffi_channel_fn_func_triple_ratchet_encrypt( FfiConverterTypeTripleRatchetStateAndMessage.lower(ratchetStateAndMessage),$0 ) }) } -public func tripleRatchetInitRound1(ratchetStateAndMetadata: TripleRatchetStateAndMetadata) -> TripleRatchetStateAndMetadata { - return try! FfiConverterTypeTripleRatchetStateAndMetadata.lift(try! rustCall() { +public func tripleRatchetInitRound1(ratchetStateAndMetadata: TripleRatchetStateAndMetadata)throws -> TripleRatchetStateAndMetadata { + return try FfiConverterTypeTripleRatchetStateAndMetadata.lift(try rustCallWithError(FfiConverterTypeCryptoError.lift) { uniffi_channel_fn_func_triple_ratchet_init_round_1( FfiConverterTypeTripleRatchetStateAndMetadata.lower(ratchetStateAndMetadata),$0 ) }) } -public func tripleRatchetInitRound2(ratchetStateAndMetadata: TripleRatchetStateAndMetadata) -> TripleRatchetStateAndMetadata { - return try! FfiConverterTypeTripleRatchetStateAndMetadata.lift(try! rustCall() { +public func tripleRatchetInitRound2(ratchetStateAndMetadata: TripleRatchetStateAndMetadata)throws -> TripleRatchetStateAndMetadata { + return try FfiConverterTypeTripleRatchetStateAndMetadata.lift(try rustCallWithError(FfiConverterTypeCryptoError.lift) { uniffi_channel_fn_func_triple_ratchet_init_round_2( FfiConverterTypeTripleRatchetStateAndMetadata.lower(ratchetStateAndMetadata),$0 ) }) } -public func tripleRatchetInitRound3(ratchetStateAndMetadata: TripleRatchetStateAndMetadata) -> TripleRatchetStateAndMetadata { - return try! FfiConverterTypeTripleRatchetStateAndMetadata.lift(try! rustCall() { +public func tripleRatchetInitRound3(ratchetStateAndMetadata: TripleRatchetStateAndMetadata)throws -> TripleRatchetStateAndMetadata { + return try FfiConverterTypeTripleRatchetStateAndMetadata.lift(try rustCallWithError(FfiConverterTypeCryptoError.lift) { uniffi_channel_fn_func_triple_ratchet_init_round_3( FfiConverterTypeTripleRatchetStateAndMetadata.lower(ratchetStateAndMetadata),$0 ) }) } -public func tripleRatchetInitRound4(ratchetStateAndMetadata: TripleRatchetStateAndMetadata) -> TripleRatchetStateAndMetadata { - return try! FfiConverterTypeTripleRatchetStateAndMetadata.lift(try! rustCall() { +public func tripleRatchetInitRound4(ratchetStateAndMetadata: TripleRatchetStateAndMetadata)throws -> TripleRatchetStateAndMetadata { + return try FfiConverterTypeTripleRatchetStateAndMetadata.lift(try rustCallWithError(FfiConverterTypeCryptoError.lift) { uniffi_channel_fn_func_triple_ratchet_init_round_4( FfiConverterTypeTripleRatchetStateAndMetadata.lower(ratchetStateAndMetadata),$0 ) }) } +public func tripleRatchetResize(ratchetState: String, other: String, id: UInt64, total: UInt64) -> [[UInt8]] { + return try! FfiConverterSequenceSequenceUInt8.lift(try! rustCall() { + uniffi_channel_fn_func_triple_ratchet_resize( + FfiConverterString.lower(ratchetState), + FfiConverterString.lower(other), + FfiConverterUInt64.lower(id), + FfiConverterUInt64.lower(total),$0 + ) +}) +} public func verifyEd448(publicKey: String, message: String, signature: String) -> String { return try! FfiConverterString.lift(try! rustCall() { uniffi_channel_fn_func_verify_ed448( @@ -1076,10 +1181,10 @@ private var initializationResult: InitializationResult = { if (uniffi_channel_checksum_func_decrypt_inbox_message() != 59344) { return InitializationResult.apiChecksumMismatch } - if (uniffi_channel_checksum_func_double_ratchet_decrypt() != 13335) { + if (uniffi_channel_checksum_func_double_ratchet_decrypt() != 59687) { return InitializationResult.apiChecksumMismatch } - if (uniffi_channel_checksum_func_double_ratchet_encrypt() != 59209) { + if (uniffi_channel_checksum_func_double_ratchet_encrypt() != 57909) { return InitializationResult.apiChecksumMismatch } if (uniffi_channel_checksum_func_encrypt_inbox_message() != 48273) { @@ -1112,22 +1217,25 @@ private var initializationResult: InitializationResult = { if (uniffi_channel_checksum_func_sign_ed448() != 28573) { return InitializationResult.apiChecksumMismatch } - if (uniffi_channel_checksum_func_triple_ratchet_decrypt() != 42324) { + if (uniffi_channel_checksum_func_triple_ratchet_decrypt() != 15842) { return InitializationResult.apiChecksumMismatch } - if (uniffi_channel_checksum_func_triple_ratchet_encrypt() != 61617) { + if (uniffi_channel_checksum_func_triple_ratchet_encrypt() != 23451) { return InitializationResult.apiChecksumMismatch } - if (uniffi_channel_checksum_func_triple_ratchet_init_round_1() != 42612) { + if (uniffi_channel_checksum_func_triple_ratchet_init_round_1() != 63112) { return InitializationResult.apiChecksumMismatch } - if (uniffi_channel_checksum_func_triple_ratchet_init_round_2() != 11875) { + if (uniffi_channel_checksum_func_triple_ratchet_init_round_2() != 34197) { return InitializationResult.apiChecksumMismatch } - if (uniffi_channel_checksum_func_triple_ratchet_init_round_3() != 50331) { + if (uniffi_channel_checksum_func_triple_ratchet_init_round_3() != 39476) { return InitializationResult.apiChecksumMismatch } - if (uniffi_channel_checksum_func_triple_ratchet_init_round_4() != 14779) { + if (uniffi_channel_checksum_func_triple_ratchet_init_round_4() != 19263) { + return InitializationResult.apiChecksumMismatch + } + if (uniffi_channel_checksum_func_triple_ratchet_resize() != 57124) { return InitializationResult.apiChecksumMismatch } if (uniffi_channel_checksum_func_verify_ed448() != 57200) { diff --git a/crates/channel/bindings/swift/channelFFI.h b/crates/channel/bindings/swift/channelFFI.h index 71e63c6..603cefc 100644 --- a/crates/channel/bindings/swift/channelFFI.h +++ b/crates/channel/bindings/swift/channelFFI.h @@ -348,6 +348,11 @@ RustBuffer uniffi_channel_fn_func_triple_ratchet_init_round_3(RustBuffer ratchet RustBuffer uniffi_channel_fn_func_triple_ratchet_init_round_4(RustBuffer ratchet_state_and_metadata, RustCallStatus *_Nonnull out_status ); #endif +#ifndef UNIFFI_FFIDEF_UNIFFI_CHANNEL_FN_FUNC_TRIPLE_RATCHET_RESIZE +#define UNIFFI_FFIDEF_UNIFFI_CHANNEL_FN_FUNC_TRIPLE_RATCHET_RESIZE +RustBuffer uniffi_channel_fn_func_triple_ratchet_resize(RustBuffer ratchet_state, RustBuffer other, uint64_t id, uint64_t total, RustCallStatus *_Nonnull out_status +); +#endif #ifndef UNIFFI_FFIDEF_UNIFFI_CHANNEL_FN_FUNC_VERIFY_ED448 #define UNIFFI_FFIDEF_UNIFFI_CHANNEL_FN_FUNC_VERIFY_ED448 RustBuffer uniffi_channel_fn_func_verify_ed448(RustBuffer public_key, RustBuffer message, RustBuffer signature, RustCallStatus *_Nonnull out_status @@ -745,6 +750,12 @@ uint16_t uniffi_channel_checksum_func_triple_ratchet_init_round_3(void #define UNIFFI_FFIDEF_UNIFFI_CHANNEL_CHECKSUM_FUNC_TRIPLE_RATCHET_INIT_ROUND_4 uint16_t uniffi_channel_checksum_func_triple_ratchet_init_round_4(void +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_CHANNEL_CHECKSUM_FUNC_TRIPLE_RATCHET_RESIZE +#define UNIFFI_FFIDEF_UNIFFI_CHANNEL_CHECKSUM_FUNC_TRIPLE_RATCHET_RESIZE +uint16_t uniffi_channel_checksum_func_triple_ratchet_resize(void + ); #endif #ifndef UNIFFI_FFIDEF_UNIFFI_CHANNEL_CHECKSUM_FUNC_VERIFY_ED448 diff --git a/crates/channel/src/lib.rs b/crates/channel/src/lib.rs index c901bb9..29e67b5 100644 --- a/crates/channel/src/lib.rs +++ b/crates/channel/src/lib.rs @@ -16,6 +16,22 @@ pub(crate) mod protocols; uniffi::include_scaffolding!("lib"); +#[derive(Debug, thiserror::Error)] +pub enum CryptoError { + #[error("Invalid state: {0}")] + InvalidState(String), + #[error("Invalid envelope: {0}")] + InvalidEnvelope(String), + #[error("Decryption failed: {0}")] + DecryptionFailed(String), + #[error("Encryption failed: {0}")] + EncryptionFailed(String), + #[error("Serialization failed: {0}")] + SerializationFailed(String), + #[error("Invalid input: {0}")] + InvalidInput(String), +} + #[derive(Clone, PartialEq, Serialize, Deserialize)] pub struct DoubleRatchetStateAndEnvelope { pub ratchet_state: String, @@ -467,84 +483,45 @@ pub fn new_double_ratchet(session_key: &Vec, sending_header_key: &Vec, n return json.unwrap(); } -pub fn double_ratchet_encrypt(ratchet_state_and_message: DoubleRatchetStateAndMessage) -> DoubleRatchetStateAndEnvelope { +pub fn double_ratchet_encrypt(ratchet_state_and_message: DoubleRatchetStateAndMessage) -> Result { let ratchet_state = ratchet_state_and_message.ratchet_state.clone(); - let participant = DoubleRatchetParticipant::from_json(ratchet_state.clone()); + let participant = DoubleRatchetParticipant::from_json(ratchet_state.clone()) + .map_err(|e| CryptoError::InvalidState(e.to_string()))?; - if participant.is_err() { - return DoubleRatchetStateAndEnvelope{ - ratchet_state: participant.unwrap_err().to_string(), - envelope: "".to_string(), - }; - } + let mut dr = participant; + let envelope = dr.ratchet_encrypt(&ratchet_state_and_message.message) + .map_err(|e| CryptoError::EncryptionFailed(e.to_string()))?; - let mut dr = participant.unwrap(); - let envelope = dr.ratchet_encrypt(&ratchet_state_and_message.message); + let participant_json = dr.to_json() + .map_err(|e| CryptoError::SerializationFailed(e.to_string()))?; - if envelope.is_err() { - return DoubleRatchetStateAndEnvelope{ - ratchet_state: ratchet_state, - envelope: envelope.unwrap_err().to_string(), - }; - } + let envelope_json = envelope.to_json() + .map_err(|e| CryptoError::SerializationFailed(e.to_string()))?; - - let participant_json = dr.to_json(); - if participant_json.is_err() { - return DoubleRatchetStateAndEnvelope{ - ratchet_state: participant_json.unwrap_err().to_string(), - envelope: "".to_string(), - }; - } - - let envelope_json = envelope.unwrap().to_json(); - if envelope_json.is_err() { - return DoubleRatchetStateAndEnvelope{ - ratchet_state: ratchet_state, - envelope: envelope_json.unwrap_err().to_string(), - }; - } - - return DoubleRatchetStateAndEnvelope{ - ratchet_state: participant_json.unwrap(), - envelope: envelope_json.unwrap(), - }; + Ok(DoubleRatchetStateAndEnvelope{ + ratchet_state: participant_json, + envelope: envelope_json, + }) } -pub fn double_ratchet_decrypt(ratchet_state_and_envelope: DoubleRatchetStateAndEnvelope) -> DoubleRatchetStateAndMessage { +pub fn double_ratchet_decrypt(ratchet_state_and_envelope: DoubleRatchetStateAndEnvelope) -> Result { let ratchet_state = ratchet_state_and_envelope.ratchet_state.clone(); - let participant = DoubleRatchetParticipant::from_json(ratchet_state.clone()); - let envelope = P2PChannelEnvelope::from_json(ratchet_state_and_envelope.envelope); + let participant = DoubleRatchetParticipant::from_json(ratchet_state.clone()) + .map_err(|e| CryptoError::InvalidState(e.to_string()))?; + let envelope = P2PChannelEnvelope::from_json(ratchet_state_and_envelope.envelope) + .map_err(|e| CryptoError::InvalidEnvelope(e.to_string()))?; - if participant.is_err() || envelope.is_err() { - return DoubleRatchetStateAndMessage{ - ratchet_state: ratchet_state, - message: vec![], - }; - } + let mut dr = participant; + let message = dr.ratchet_decrypt(&envelope) + .map_err(|e| CryptoError::DecryptionFailed(e.to_string()))?; - let mut dr = participant.unwrap(); - let message = dr.ratchet_decrypt(&envelope.unwrap()); + let participant_json = dr.to_json() + .map_err(|e| CryptoError::SerializationFailed(e.to_string()))?; - if message.is_err() { - return DoubleRatchetStateAndMessage{ - ratchet_state: ratchet_state, - message: message.unwrap_err().to_string().as_bytes().to_vec(), - }; - } - - let participant_json = dr.to_json(); - if participant_json.is_err() { - return DoubleRatchetStateAndMessage{ - ratchet_state: participant_json.unwrap_err().to_string(), - message: vec![], - }; - } - - return DoubleRatchetStateAndMessage{ - ratchet_state: participant_json.unwrap(), - message: message.unwrap(), - }; + Ok(DoubleRatchetStateAndMessage{ + ratchet_state: participant_json, + message: message, + }) } pub fn new_triple_ratchet(peers: &Vec>, peer_key: &Vec, identity_key: &Vec, signed_pre_key: &Vec, threshold: u64, async_dkg_ratchet: bool) -> TripleRatchetStateAndMetadata { @@ -688,287 +665,178 @@ fn json_to_metadata(ratchet_state_and_metadata: TripleRatchetStateAndMetadata, r Ok(metadata) } -pub fn triple_ratchet_init_round_1(ratchet_state_and_metadata: TripleRatchetStateAndMetadata) -> TripleRatchetStateAndMetadata { - let ratchet_state = ratchet_state_and_metadata.ratchet_state.clone(); - let tr = TripleRatchetParticipant::from_json(&ratchet_state); - if tr.is_err() { - return TripleRatchetStateAndMetadata{ - ratchet_state: tr.err().unwrap().to_string(), - metadata: HashMap::new(), - }; - } - - let metadata = match json_to_metadata(ratchet_state_and_metadata, &ratchet_state) { - Ok(value) => value, - Err(value) => return value, - }; - - let mut trp = tr.unwrap(); - let result = trp.initialize(&metadata); - if result.is_err() { - return TripleRatchetStateAndMetadata{ - ratchet_state: result.err().unwrap().to_string(), - metadata: HashMap::new(), - }; - } - - let metadata = result.unwrap(); - let metadata_json = match metadata_to_json(&ratchet_state, metadata) { - Ok(value) => value, - Err(value) => return value, - }; - - let json = trp.to_json(); - if json.is_err() { - return TripleRatchetStateAndMetadata{ - ratchet_state: json.err().unwrap().to_string(), - metadata: HashMap::new(), - }; - } - - return TripleRatchetStateAndMetadata{ - ratchet_state: json.unwrap(), - metadata: metadata_json, - }; +fn json_to_metadata_result(ratchet_state_and_metadata: TripleRatchetStateAndMetadata, _ratchet_state: &String) -> Result, P2PChannelEnvelope>, CryptoError> { + let mut metadata = HashMap::, P2PChannelEnvelope>::new(); + for (k,v) in ratchet_state_and_metadata.metadata { + let env = P2PChannelEnvelope::from_json(v) + .map_err(|e| CryptoError::InvalidEnvelope(e.to_string()))?; + let kb = BASE64_STANDARD.decode(k) + .map_err(|e| CryptoError::InvalidInput(e.to_string()))?; + metadata.insert(kb, env); + } + Ok(metadata) } -pub fn triple_ratchet_init_round_2(ratchet_state_and_metadata: TripleRatchetStateAndMetadata) -> TripleRatchetStateAndMetadata { - let ratchet_state = ratchet_state_and_metadata.ratchet_state.clone(); - let tr = TripleRatchetParticipant::from_json(&ratchet_state); - if tr.is_err() { - return TripleRatchetStateAndMetadata{ - ratchet_state: tr.err().unwrap().to_string(), - metadata: HashMap::new(), - }; +fn metadata_to_json_result(_ratchet_state: &String, metadata: HashMap, P2PChannelEnvelope>) -> Result, CryptoError> { + let mut metadata_json = HashMap::::new(); + for (k,v) in metadata { + let env = v.to_json() + .map_err(|e| CryptoError::SerializationFailed(e.to_string()))?; + metadata_json.insert(BASE64_STANDARD.encode(k), env); } + Ok(metadata_json) +} - let metadata = match json_to_metadata(ratchet_state_and_metadata, &ratchet_state) { - Ok(value) => value, - Err(value) => return value, - }; +pub fn triple_ratchet_init_round_1(ratchet_state_and_metadata: TripleRatchetStateAndMetadata) -> Result { + let ratchet_state = ratchet_state_and_metadata.ratchet_state.clone(); + let tr = TripleRatchetParticipant::from_json(&ratchet_state) + .map_err(|e| CryptoError::InvalidState(e.to_string()))?; - let mut trp = tr.unwrap(); + let metadata = json_to_metadata_result(ratchet_state_and_metadata, &ratchet_state)?; + + let mut trp = tr; + let result = trp.initialize(&metadata) + .map_err(|e| CryptoError::InvalidInput(e.to_string()))?; + + let metadata_json = metadata_to_json_result(&ratchet_state, result)?; + + let json = trp.to_json() + .map_err(|e| CryptoError::SerializationFailed(e.to_string()))?; + + Ok(TripleRatchetStateAndMetadata{ + ratchet_state: json, + metadata: metadata_json, + }) +} + +pub fn triple_ratchet_init_round_2(ratchet_state_and_metadata: TripleRatchetStateAndMetadata) -> Result { + let ratchet_state = ratchet_state_and_metadata.ratchet_state.clone(); + let tr = TripleRatchetParticipant::from_json(&ratchet_state) + .map_err(|e| CryptoError::InvalidState(e.to_string()))?; + + let metadata = json_to_metadata_result(ratchet_state_and_metadata, &ratchet_state)?; + + let mut trp = tr; let mut result = HashMap::, P2PChannelEnvelope>::new(); for (k, v) in metadata { - let r = trp.receive_poly_frag(&k, &v); - if r.is_err() { - return TripleRatchetStateAndMetadata{ - ratchet_state: r.err().unwrap().to_string(), - metadata: HashMap::new(), - }; - } + let r = trp.receive_poly_frag(&k, &v) + .map_err(|e| CryptoError::InvalidInput(e.to_string()))?; - let opt = r.unwrap(); - if opt.is_some() { - result = opt.unwrap(); + if let Some(out) = r { + result = out; } } - let metadata_json = match metadata_to_json(&ratchet_state, result) { - Ok(value) => value, - Err(value) => return value, - }; + let metadata_json = metadata_to_json_result(&ratchet_state, result)?; - let json = trp.to_json(); - if json.is_err() { - return TripleRatchetStateAndMetadata{ - ratchet_state: json.err().unwrap().to_string(), - metadata: HashMap::new(), - }; - } + let json = trp.to_json() + .map_err(|e| CryptoError::SerializationFailed(e.to_string()))?; - return TripleRatchetStateAndMetadata{ - ratchet_state: json.unwrap(), + Ok(TripleRatchetStateAndMetadata{ + ratchet_state: json, metadata: metadata_json, - }; + }) } -pub fn triple_ratchet_init_round_3(ratchet_state_and_metadata: TripleRatchetStateAndMetadata) -> TripleRatchetStateAndMetadata { +pub fn triple_ratchet_init_round_3(ratchet_state_and_metadata: TripleRatchetStateAndMetadata) -> Result { let ratchet_state = ratchet_state_and_metadata.ratchet_state.clone(); - let tr = TripleRatchetParticipant::from_json(&ratchet_state); - if tr.is_err() { - return TripleRatchetStateAndMetadata{ - ratchet_state: tr.err().unwrap().to_string(), - metadata: HashMap::new(), - }; - } + let tr = TripleRatchetParticipant::from_json(&ratchet_state) + .map_err(|e| CryptoError::InvalidState(e.to_string()))?; - let metadata = match json_to_metadata(ratchet_state_and_metadata, &ratchet_state) { - Ok(value) => value, - Err(value) => return value, - }; + let metadata = json_to_metadata_result(ratchet_state_and_metadata, &ratchet_state)?; - let mut trp = tr.unwrap(); + let mut trp = tr; let mut result = HashMap::, P2PChannelEnvelope>::new(); for (k, v) in metadata { - let r = trp.receive_commitment(&k, &v); - if r.is_err() { - return TripleRatchetStateAndMetadata{ - ratchet_state: r.err().unwrap().to_string(), - metadata: HashMap::new(), - }; - } + let r = trp.receive_commitment(&k, &v) + .map_err(|e| CryptoError::InvalidInput(e.to_string()))?; - let opt = r.unwrap(); - if opt.is_some() { - result = opt.unwrap(); + if let Some(out) = r { + result = out; } } - let metadata_json = match metadata_to_json(&ratchet_state, result) { - Ok(value) => value, - Err(value) => return value, - }; + let metadata_json = metadata_to_json_result(&ratchet_state, result)?; - let json = trp.to_json(); - if json.is_err() { - return TripleRatchetStateAndMetadata{ - ratchet_state: json.err().unwrap().to_string(), - metadata: HashMap::new(), - }; - } + let json = trp.to_json() + .map_err(|e| CryptoError::SerializationFailed(e.to_string()))?; - return TripleRatchetStateAndMetadata{ - ratchet_state: json.unwrap(), + Ok(TripleRatchetStateAndMetadata{ + ratchet_state: json, metadata: metadata_json, - }; + }) } -pub fn triple_ratchet_init_round_4(ratchet_state_and_metadata: TripleRatchetStateAndMetadata) -> TripleRatchetStateAndMetadata { +pub fn triple_ratchet_init_round_4(ratchet_state_and_metadata: TripleRatchetStateAndMetadata) -> Result { let ratchet_state = ratchet_state_and_metadata.ratchet_state.clone(); - let tr = TripleRatchetParticipant::from_json(&ratchet_state); - if tr.is_err() { - return TripleRatchetStateAndMetadata{ - ratchet_state: tr.err().unwrap().to_string(), - metadata: HashMap::new(), - }; - } + let tr = TripleRatchetParticipant::from_json(&ratchet_state) + .map_err(|e| CryptoError::InvalidState(e.to_string()))?; - let metadata = match json_to_metadata(ratchet_state_and_metadata, &ratchet_state) { - Ok(value) => value, - Err(value) => return value, - }; + let metadata = json_to_metadata_result(ratchet_state_and_metadata, &ratchet_state)?; - let mut trp = tr.unwrap(); - let mut result = HashMap::, P2PChannelEnvelope>::new(); + let mut trp = tr; + let result = HashMap::, P2PChannelEnvelope>::new(); for (k, v) in metadata { - let r = trp.recombine(&k, &v); - if r.is_err() { - return TripleRatchetStateAndMetadata{ - ratchet_state: r.err().unwrap().to_string(), - metadata: HashMap::new(), - }; - } + trp.recombine(&k, &v) + .map_err(|e| CryptoError::InvalidInput(e.to_string()))?; } - let metadata_json = match metadata_to_json(&ratchet_state, result) { - Ok(value) => value, - Err(value) => return value, - }; + let metadata_json = metadata_to_json_result(&ratchet_state, result)?; - let json = trp.to_json(); - if json.is_err() { - return TripleRatchetStateAndMetadata{ - ratchet_state: json.err().unwrap().to_string(), - metadata: HashMap::new(), - }; - } + let json = trp.to_json() + .map_err(|e| CryptoError::SerializationFailed(e.to_string()))?; - return TripleRatchetStateAndMetadata{ - ratchet_state: json.unwrap(), + Ok(TripleRatchetStateAndMetadata{ + ratchet_state: json, metadata: metadata_json, - }; + }) } -pub fn triple_ratchet_encrypt(ratchet_state_and_message: TripleRatchetStateAndMessage) -> TripleRatchetStateAndEnvelope { +pub fn triple_ratchet_encrypt(ratchet_state_and_message: TripleRatchetStateAndMessage) -> Result { let ratchet_state = ratchet_state_and_message.ratchet_state.clone(); - let tr = TripleRatchetParticipant::from_json(&ratchet_state); - if tr.is_err() { - return TripleRatchetStateAndEnvelope{ - ratchet_state: tr.err().unwrap().to_string(), - envelope: "".to_string(), - }; - } + let tr = TripleRatchetParticipant::from_json(&ratchet_state) + .map_err(|e| CryptoError::InvalidState(e.to_string()))?; - let mut trp = tr.unwrap(); - let result = trp.ratchet_encrypt(&ratchet_state_and_message.message); + let mut trp = tr; + let envelope = trp.ratchet_encrypt(&ratchet_state_and_message.message) + .map_err(|e| CryptoError::EncryptionFailed(e.to_string()))?; - if result.is_err() { - return TripleRatchetStateAndEnvelope{ - ratchet_state: result.err().unwrap().to_string(), - envelope: "".to_string(), - }; - } + let envelope_json = envelope.to_json() + .map_err(|e| CryptoError::SerializationFailed(e.to_string()))?; - let envelope = result.unwrap(); - let envelope_json = envelope.to_json(); + let json = trp.to_json() + .map_err(|e| CryptoError::SerializationFailed(e.to_string()))?; - if envelope_json.is_err() { - return TripleRatchetStateAndEnvelope{ - ratchet_state: envelope_json.err().unwrap().to_string(), - envelope: "".to_string(), - }; - } - - let json = trp.to_json(); - if json.is_err() { - return TripleRatchetStateAndEnvelope{ - ratchet_state: json.err().unwrap().to_string(), - envelope: "".to_string(), - }; - } - - return TripleRatchetStateAndEnvelope{ - ratchet_state: json.unwrap(), - envelope: envelope_json.unwrap(), - }; + Ok(TripleRatchetStateAndEnvelope{ + ratchet_state: json, + envelope: envelope_json, + }) } -pub fn triple_ratchet_decrypt(ratchet_state_and_envelope: TripleRatchetStateAndEnvelope) -> TripleRatchetStateAndMessage { +pub fn triple_ratchet_decrypt(ratchet_state_and_envelope: TripleRatchetStateAndEnvelope) -> Result { let ratchet_state = ratchet_state_and_envelope.ratchet_state.clone(); - let tr = TripleRatchetParticipant::from_json(&ratchet_state); - if tr.is_err() { - return TripleRatchetStateAndMessage{ - ratchet_state: tr.err().unwrap().to_string(), - message: vec![], - }; - } + let tr = TripleRatchetParticipant::from_json(&ratchet_state) + .map_err(|e| CryptoError::InvalidState(e.to_string()))?; - let mut trp = tr.unwrap(); - let env = P2PChannelEnvelope::from_json(ratchet_state_and_envelope.envelope); - if env.is_err() { - return TripleRatchetStateAndMessage{ - ratchet_state: env.err().unwrap().to_string(), - message: vec![], - }; - } + let mut trp = tr; + let env = P2PChannelEnvelope::from_json(ratchet_state_and_envelope.envelope) + .map_err(|e| CryptoError::InvalidEnvelope(e.to_string()))?; - let result = trp.ratchet_decrypt(&env.unwrap()); + let result = trp.ratchet_decrypt(&env) + .map_err(|e| CryptoError::DecryptionFailed(e.to_string()))?; - if result.is_err() { - return TripleRatchetStateAndMessage{ - ratchet_state: result.err().unwrap().to_string(), - message: vec![], - }; - } + let message = result.0; - let message = result.unwrap().0; + let json = trp.to_json() + .map_err(|e| CryptoError::SerializationFailed(e.to_string()))?; - let json = trp.to_json(); - if json.is_err() { - return TripleRatchetStateAndMessage{ - ratchet_state: json.err().unwrap().to_string(), - message: vec![], - }; - } - - return TripleRatchetStateAndMessage{ - ratchet_state: json.unwrap(), + Ok(TripleRatchetStateAndMessage{ + ratchet_state: json, message: message, - }; + }) } -pub fn triple_ratchet_resize(ratchet_state: String, other: String, id: usize, total: usize) -> Vec> { +pub fn triple_ratchet_resize(ratchet_state: String, other: String, id: u64, total: u64) -> Vec> { let tr = TripleRatchetParticipant::from_json(&ratchet_state); if tr.is_err() { return vec![vec![1]]; @@ -979,7 +847,7 @@ pub fn triple_ratchet_resize(ratchet_state: String, other: String, id: usize, to return vec![other_bytes.unwrap_err().to_string().as_bytes().to_vec()]; } - let result = tr.unwrap().ratchet_resize(other_bytes.unwrap(), id, total); + let result = tr.unwrap().ratchet_resize(other_bytes.unwrap(), id as usize, total as usize); if result.is_err() { return vec![result.unwrap_err().to_string().as_bytes().to_vec()]; } diff --git a/crates/channel/src/lib.udl b/crates/channel/src/lib.udl index fb4c5ef..386efc8 100644 --- a/crates/channel/src/lib.udl +++ b/crates/channel/src/lib.udl @@ -19,17 +19,38 @@ namespace channel { // Double Ratchet string new_double_ratchet([ByRef] sequence session_key, [ByRef] sequence sending_header_key, [ByRef] sequence next_receiving_header_key, boolean is_sender, [ByRef] sequence sending_ephemeral_private_key, [ByRef] sequence receiving_ephemeral_key); + [Throws=CryptoError] DoubleRatchetStateAndEnvelope double_ratchet_encrypt(DoubleRatchetStateAndMessage ratchet_state_and_message); + [Throws=CryptoError] DoubleRatchetStateAndMessage double_ratchet_decrypt(DoubleRatchetStateAndEnvelope ratchet_state_and_envelope); // Triple Ratchet TripleRatchetStateAndMetadata new_triple_ratchet([ByRef] sequence> peers, [ByRef] sequence peer_key, [ByRef] sequence identity_key, [ByRef] sequence signed_pre_key, u64 threshold, boolean async_dkg_ratchet); + [Throws=CryptoError] TripleRatchetStateAndMetadata triple_ratchet_init_round_1(TripleRatchetStateAndMetadata ratchet_state_and_metadata); + [Throws=CryptoError] TripleRatchetStateAndMetadata triple_ratchet_init_round_2(TripleRatchetStateAndMetadata ratchet_state_and_metadata); + [Throws=CryptoError] TripleRatchetStateAndMetadata triple_ratchet_init_round_3(TripleRatchetStateAndMetadata ratchet_state_and_metadata); + [Throws=CryptoError] TripleRatchetStateAndMetadata triple_ratchet_init_round_4(TripleRatchetStateAndMetadata ratchet_state_and_metadata); + [Throws=CryptoError] TripleRatchetStateAndEnvelope triple_ratchet_encrypt(TripleRatchetStateAndMessage ratchet_state_and_message); + [Throws=CryptoError] TripleRatchetStateAndMessage triple_ratchet_decrypt(TripleRatchetStateAndEnvelope ratchet_state_and_envelope); + + // Triple Ratchet Resize + sequence> triple_ratchet_resize(string ratchet_state, string other, u64 id, u64 total); +}; + +[Error] +enum CryptoError { + "InvalidState", + "InvalidEnvelope", + "DecryptionFailed", + "EncryptionFailed", + "SerializationFailed", + "InvalidInput", }; dictionary DoubleRatchetStateAndEnvelope { diff --git a/hypergraph/sync.go b/hypergraph/sync.go index 760a5db..31e50ae 100644 --- a/hypergraph/sync.go +++ b/hypergraph/sync.go @@ -1521,7 +1521,7 @@ func (s *streamManager) walk( // ) if len(lpref) > len(rpref) { // s.logger.Debug("local prefix longer, traversing remote to path", pathString) - traverse := lpref[len(rpref):] + traverse := lpref[len(rpref)-1:] rtrav := rnode traversePath := append([]int32{}, rpref...) for _, nibble := range traverse { @@ -1578,7 +1578,7 @@ func (s *streamManager) walk( ) } else { // s.logger.Debug("remote prefix longer, traversing local to path", pathString) - traverse := rpref[len(lpref):] + traverse := rpref[len(lpref)-1:] ltrav := lnode traversedPath := append([]int32{}, lnode.Path...) @@ -1626,9 +1626,12 @@ func (s *streamManager) walk( ); err != nil { return errors.Wrap(err, "walk") } + } else { + err := s.handleLeafData(incomingLeaves) + if err != nil { + return errors.Wrap(err, "walk") + } } - // Client has extra data that server doesn't have - // Skip - pruning happens after sync completes } } // If no child matched the nibble, the local tree doesn't extend @@ -1694,7 +1697,7 @@ func (s *streamManager) walk( if (lchild != nil && rchild == nil) || (lchild == nil && rchild != nil) { // s.logger.Info("branch divergence", pathString) - if lchild != nil && rchild == nil { + if lchild != nil { // Local has a child that remote doesn't have if isServer { nextPath := append( @@ -1712,22 +1715,12 @@ func (s *streamManager) walk( // Client has data server doesn't // Skip - pruning happens after sync completes } - if rchild != nil && lchild == nil { - // Remote has a child that local doesn't have - if isServer { - // Server doesn't have what client has - nothing to do - // Client will prune on their side - } else { - // Client doesn't have what server has - receive it - nextPath := append( - append([]int32{}, rpref...), - rchild.Index, - ) + if rchild != nil { + if !isServer { err := s.handleLeafData(incomingLeaves) if err != nil { return errors.Wrap(err, "walk") } - _ = nextPath // path used by server's sendLeafData } } } else { @@ -1741,10 +1734,21 @@ func (s *streamManager) walk( nextPath, ) if err != nil { - // s.logger.Debug("incomplete branch descension", zap.Error(err)) - // Don't try to merge/prune on error - the connection may have failed - // and we don't want to delete local data based on incomplete info - return errors.Wrap(err, "walk") + s.logger.Info("incomplete branch descension", zap.Error(err)) + if isServer { + if err := s.sendLeafData( + nextPath, + incomingLeaves, + ); err != nil { + return errors.Wrap(err, "walk") + } + } else { + err := s.handleLeafData(incomingLeaves) + if err != nil { + return errors.Wrap(err, "walk") + } + } + continue } if err = s.walk( diff --git a/node/consensus/global/coverage_events.go b/node/consensus/global/coverage_events.go index 5adb0c9..329f227 100644 --- a/node/consensus/global/coverage_events.go +++ b/node/consensus/global/coverage_events.go @@ -44,6 +44,27 @@ func (e *GlobalConsensusEngine) ensureCoverageThresholds() { haltGraceFrames = 360 } +// triggerCoverageCheckAsync starts a coverage check in a goroutine if one is +// not already in progress. This prevents blocking the event processing loop. +func (e *GlobalConsensusEngine) triggerCoverageCheckAsync(frameNumber uint64) { + // Skip if a coverage check is already in progress + if !e.coverageCheckInProgress.CompareAndSwap(false, true) { + e.logger.Debug( + "skipping coverage check, one already in progress", + zap.Uint64("frame_number", frameNumber), + ) + return + } + + go func() { + defer e.coverageCheckInProgress.Store(false) + + if err := e.checkShardCoverage(frameNumber); err != nil { + e.logger.Error("failed to check shard coverage", zap.Error(err)) + } + }() +} + // checkShardCoverage verifies coverage levels for all active shards func (e *GlobalConsensusEngine) checkShardCoverage(frameNumber uint64) error { e.ensureCoverageThresholds() diff --git a/node/consensus/global/event_distributor.go b/node/consensus/global/event_distributor.go index 3b49945..64e2470 100644 --- a/node/consensus/global/event_distributor.go +++ b/node/consensus/global/event_distributor.go @@ -81,12 +81,8 @@ func (e *GlobalConsensusEngine) eventDistributorLoop( e.flushDeferredGlobalMessages(data.Frame.GetRank() + 1) - // Check shard coverage - if err := e.checkShardCoverage( - data.Frame.Header.FrameNumber, - ); err != nil { - e.logger.Error("failed to check shard coverage", zap.Error(err)) - } + // Check shard coverage asynchronously to avoid blocking event processing + e.triggerCoverageCheckAsync(data.Frame.Header.FrameNumber) // Update global coordination metrics globalCoordinationTotal.Inc() diff --git a/node/consensus/global/global_consensus_engine.go b/node/consensus/global/global_consensus_engine.go index 2827c17..b892319 100644 --- a/node/consensus/global/global_consensus_engine.go +++ b/node/consensus/global/global_consensus_engine.go @@ -202,6 +202,7 @@ type GlobalConsensusEngine struct { appFrameStoreMu sync.RWMutex lowCoverageStreak map[string]*coverageStreak proverOnlyMode atomic.Bool + coverageCheckInProgress atomic.Bool peerInfoDigestCache map[string]struct{} peerInfoDigestCacheMu sync.Mutex keyRegistryDigestCache map[string]struct{} diff --git a/node/consensus/global/message_processors.go b/node/consensus/global/message_processors.go index f011f77..ea1a221 100644 --- a/node/consensus/global/message_processors.go +++ b/node/consensus/global/message_processors.go @@ -1708,10 +1708,8 @@ func (e *GlobalConsensusEngine) addCertifiedState( return } - if err := e.checkShardCoverage(parent.State.GetFrameNumber()); err != nil { - e.logger.Error("could not check shard coverage", zap.Error(err)) - return - } + // Trigger coverage check asynchronously to avoid blocking message processing + e.triggerCoverageCheckAsync(parent.State.GetFrameNumber()) } func (e *GlobalConsensusEngine) handleProposal(message *pb.Message) {