diff --git a/server/crates/arbiter-crypto/src/authn/v1.rs b/server/crates/arbiter-crypto/src/authn/v1.rs index f192e76..5f21169 100644 --- a/server/crates/arbiter-crypto/src/authn/v1.rs +++ b/server/crates/arbiter-crypto/src/authn/v1.rs @@ -43,6 +43,14 @@ impl AuthChallenge { buffer } } + + pub fn from_parts(nonce: &[u8], timestamp: i64) -> Result { + let random_nonce = nonce.as_array().ok_or(())?; + Ok(AuthChallenge { + nonce: *random_nonce, + timestamp: DateTime::from_timestamp_nanos(timestamp), + }) + } } pub type KeyParams = MlDsa87; diff --git a/useragent/lib/features/connection/auth.dart b/useragent/lib/features/connection/auth.dart index f7e50a8..84cb3d9 100644 --- a/useragent/lib/features/connection/auth.dart +++ b/useragent/lib/features/connection/auth.dart @@ -7,6 +7,7 @@ import 'package:arbiter/features/identity/pk_manager.dart'; import 'package:arbiter/proto/arbiter.pbgrpc.dart'; import 'package:arbiter/proto/user_agent/auth.pb.dart' as ua_auth; import 'package:arbiter/proto/user_agent.pb.dart'; +import 'package:arbiter/src/rust/api.dart'; import 'package:grpc/grpc.dart'; import 'package:mtcore/markettakers.dart'; @@ -92,7 +93,10 @@ Future connectAndAuthorize( ); } - final challenge = _formatChallenge(authResponse.challenge, pubkey); + final challenge = await formatChallenge( + random: authResponse.challenge.random, + timestamp: authResponse.challenge.timestampNanos.toInt(), + ); talker.info( 'Received auth challenge, signing with key ${base64Encode(pubkey)}', ); @@ -164,9 +168,3 @@ Future _connect(StoredServerInfo serverInfo) async { return Connection(channel: channel, tx: tx, rx: rx); } - -List _formatChallenge(ua_auth.AuthChallenge challenge, List pubkey) { - final encodedPubkey = base64Encode(pubkey); - final payload = "${challenge.nonce}:$encodedPubkey"; - return utf8.encode(payload); -} diff --git a/useragent/lib/proto/client/auth.pb.dart b/useragent/lib/proto/client/auth.pb.dart index 98eaab1..ae19314 100644 --- a/useragent/lib/proto/client/auth.pb.dart +++ b/useragent/lib/proto/client/auth.pb.dart @@ -12,6 +12,7 @@ import 'dart:core' as $core; +import 'package:fixnum/fixnum.dart' as $fixnum; import 'package:protobuf/protobuf.dart' as $pb; import '../shared/client.pb.dart' as $0; @@ -94,12 +95,12 @@ class AuthChallengeRequest extends $pb.GeneratedMessage { class AuthChallenge extends $pb.GeneratedMessage { factory AuthChallenge({ - $core.List<$core.int>? pubkey, - $core.int? nonce, + $fixnum.Int64? timestampNanos, + $core.List<$core.int>? random, }) { final result = create(); - if (pubkey != null) result.pubkey = pubkey; - if (nonce != null) result.nonce = nonce; + if (timestampNanos != null) result.timestampNanos = timestampNanos; + if (random != null) result.random = random; return result; } @@ -117,9 +118,11 @@ class AuthChallenge extends $pb.GeneratedMessage { package: const $pb.PackageName(_omitMessageNames ? '' : 'arbiter.client.auth'), createEmptyInstance: create) + ..a<$fixnum.Int64>( + 1, _omitFieldNames ? '' : 'timestampNanos', $pb.PbFieldType.OU6, + defaultOrMaker: $fixnum.Int64.ZERO) ..a<$core.List<$core.int>>( - 1, _omitFieldNames ? '' : 'pubkey', $pb.PbFieldType.OY) - ..aI(2, _omitFieldNames ? '' : 'nonce') + 2, _omitFieldNames ? '' : 'random', $pb.PbFieldType.OY) ..hasRequiredFields = false; @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') @@ -142,22 +145,22 @@ class AuthChallenge extends $pb.GeneratedMessage { static AuthChallenge? _defaultInstance; @$pb.TagNumber(1) - $core.List<$core.int> get pubkey => $_getN(0); + $fixnum.Int64 get timestampNanos => $_getI64(0); @$pb.TagNumber(1) - set pubkey($core.List<$core.int> value) => $_setBytes(0, value); + set timestampNanos($fixnum.Int64 value) => $_setInt64(0, value); @$pb.TagNumber(1) - $core.bool hasPubkey() => $_has(0); + $core.bool hasTimestampNanos() => $_has(0); @$pb.TagNumber(1) - void clearPubkey() => $_clearField(1); + void clearTimestampNanos() => $_clearField(1); @$pb.TagNumber(2) - $core.int get nonce => $_getIZ(1); + $core.List<$core.int> get random => $_getN(1); @$pb.TagNumber(2) - set nonce($core.int value) => $_setSignedInt32(1, value); + set random($core.List<$core.int> value) => $_setBytes(1, value); @$pb.TagNumber(2) - $core.bool hasNonce() => $_has(1); + $core.bool hasRandom() => $_has(1); @$pb.TagNumber(2) - void clearNonce() => $_clearField(2); + void clearRandom() => $_clearField(2); } class AuthChallengeSolution extends $pb.GeneratedMessage { diff --git a/useragent/lib/proto/client/auth.pbjson.dart b/useragent/lib/proto/client/auth.pbjson.dart index c9cf99e..c7b42b7 100644 --- a/useragent/lib/proto/client/auth.pbjson.dart +++ b/useragent/lib/proto/client/auth.pbjson.dart @@ -62,15 +62,15 @@ final $typed_data.Uint8List authChallengeRequestDescriptor = $convert.base64Deco const AuthChallenge$json = { '1': 'AuthChallenge', '2': [ - {'1': 'pubkey', '3': 1, '4': 1, '5': 12, '10': 'pubkey'}, - {'1': 'nonce', '3': 2, '4': 1, '5': 5, '10': 'nonce'}, + {'1': 'timestamp_nanos', '3': 1, '4': 1, '5': 4, '10': 'timestampNanos'}, + {'1': 'random', '3': 2, '4': 1, '5': 12, '10': 'random'}, ], }; /// Descriptor for `AuthChallenge`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List authChallengeDescriptor = $convert.base64Decode( - 'Cg1BdXRoQ2hhbGxlbmdlEhYKBnB1YmtleRgBIAEoDFIGcHVia2V5EhQKBW5vbmNlGAIgASgFUg' - 'Vub25jZQ=='); + 'Cg1BdXRoQ2hhbGxlbmdlEicKD3RpbWVzdGFtcF9uYW5vcxgBIAEoBFIOdGltZXN0YW1wTmFub3' + 'MSFgoGcmFuZG9tGAIgASgMUgZyYW5kb20='); @$core.Deprecated('Use authChallengeSolutionDescriptor instead') const AuthChallengeSolution$json = { diff --git a/useragent/lib/proto/user_agent/auth.pb.dart b/useragent/lib/proto/user_agent/auth.pb.dart index 1fa8bbd..c89b8c5 100644 --- a/useragent/lib/proto/user_agent/auth.pb.dart +++ b/useragent/lib/proto/user_agent/auth.pb.dart @@ -12,6 +12,7 @@ import 'dart:core' as $core; +import 'package:fixnum/fixnum.dart' as $fixnum; import 'package:protobuf/protobuf.dart' as $pb; import 'auth.pbenum.dart'; @@ -90,10 +91,12 @@ class AuthChallengeRequest extends $pb.GeneratedMessage { class AuthChallenge extends $pb.GeneratedMessage { factory AuthChallenge({ - $core.int? nonce, + $fixnum.Int64? timestampNanos, + $core.List<$core.int>? random, }) { final result = create(); - if (nonce != null) result.nonce = nonce; + if (timestampNanos != null) result.timestampNanos = timestampNanos; + if (random != null) result.random = random; return result; } @@ -111,7 +114,11 @@ class AuthChallenge extends $pb.GeneratedMessage { package: const $pb.PackageName( _omitMessageNames ? '' : 'arbiter.user_agent.auth'), createEmptyInstance: create) - ..aI(1, _omitFieldNames ? '' : 'nonce') + ..a<$fixnum.Int64>( + 1, _omitFieldNames ? '' : 'timestampNanos', $pb.PbFieldType.OU6, + defaultOrMaker: $fixnum.Int64.ZERO) + ..a<$core.List<$core.int>>( + 2, _omitFieldNames ? '' : 'random', $pb.PbFieldType.OY) ..hasRequiredFields = false; @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.') @@ -134,13 +141,22 @@ class AuthChallenge extends $pb.GeneratedMessage { static AuthChallenge? _defaultInstance; @$pb.TagNumber(1) - $core.int get nonce => $_getIZ(0); + $fixnum.Int64 get timestampNanos => $_getI64(0); @$pb.TagNumber(1) - set nonce($core.int value) => $_setSignedInt32(0, value); + set timestampNanos($fixnum.Int64 value) => $_setInt64(0, value); @$pb.TagNumber(1) - $core.bool hasNonce() => $_has(0); + $core.bool hasTimestampNanos() => $_has(0); @$pb.TagNumber(1) - void clearNonce() => $_clearField(1); + void clearTimestampNanos() => $_clearField(1); + + @$pb.TagNumber(2) + $core.List<$core.int> get random => $_getN(1); + @$pb.TagNumber(2) + set random($core.List<$core.int> value) => $_setBytes(1, value); + @$pb.TagNumber(2) + $core.bool hasRandom() => $_has(1); + @$pb.TagNumber(2) + void clearRandom() => $_clearField(2); } class AuthChallengeSolution extends $pb.GeneratedMessage { diff --git a/useragent/lib/proto/user_agent/auth.pbjson.dart b/useragent/lib/proto/user_agent/auth.pbjson.dart index 7f7fe15..87d0979 100644 --- a/useragent/lib/proto/user_agent/auth.pbjson.dart +++ b/useragent/lib/proto/user_agent/auth.pbjson.dart @@ -67,13 +67,15 @@ final $typed_data.Uint8List authChallengeRequestDescriptor = $convert.base64Deco const AuthChallenge$json = { '1': 'AuthChallenge', '2': [ - {'1': 'nonce', '3': 1, '4': 1, '5': 5, '10': 'nonce'}, + {'1': 'timestamp_nanos', '3': 1, '4': 1, '5': 4, '10': 'timestampNanos'}, + {'1': 'random', '3': 2, '4': 1, '5': 12, '10': 'random'}, ], }; /// Descriptor for `AuthChallenge`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List authChallengeDescriptor = $convert - .base64Decode('Cg1BdXRoQ2hhbGxlbmdlEhQKBW5vbmNlGAEgASgFUgVub25jZQ=='); +final $typed_data.Uint8List authChallengeDescriptor = $convert.base64Decode( + 'Cg1BdXRoQ2hhbGxlbmdlEicKD3RpbWVzdGFtcF9uYW5vcxgBIAEoBFIOdGltZXN0YW1wTmFub3' + 'MSFgoGcmFuZG9tGAIgASgMUgZyYW5kb20='); @$core.Deprecated('Use authChallengeSolutionDescriptor instead') const AuthChallengeSolution$json = { diff --git a/useragent/lib/src/rust/api.dart b/useragent/lib/src/rust/api.dart index 0c22fbf..8648c0e 100644 --- a/useragent/lib/src/rust/api.dart +++ b/useragent/lib/src/rust/api.dart @@ -6,6 +6,14 @@ import 'frb_generated.dart'; import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; +Future formatChallenge({ + required List random, + required PlatformInt64 timestamp, +}) => RustLib.instance.api.crateApiFormatChallenge( + random: random, + timestamp: timestamp, +); + // Rust type: RustOpaqueMoi> abstract class MldsaKey implements RustOpaqueInterface { static Future fromBytes({required List bytes}) => diff --git a/useragent/lib/src/rust/frb_generated.dart b/useragent/lib/src/rust/frb_generated.dart index d9206e5..fa57ada 100644 --- a/useragent/lib/src/rust/frb_generated.dart +++ b/useragent/lib/src/rust/frb_generated.dart @@ -64,7 +64,7 @@ class RustLib extends BaseEntrypoint { String get codegenVersion => '2.12.0'; @override - int get rustContentHash => -437661335; + int get rustContentHash => 1247923898; static const kDefaultExternalLibraryLoaderConfig = ExternalLibraryLoaderConfig( @@ -89,6 +89,11 @@ abstract class RustLibApi extends BaseApi { Future crateApiMldsaKeyToBytes({required MldsaKey that}); + Future crateApiFormatChallenge({ + required List random, + required PlatformInt64 timestamp, + }); + RustArcIncrementStrongCountFnType get rust_arc_increment_strong_count_MldsaKey; @@ -267,6 +272,40 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { TaskConstMeta get kCrateApiMldsaKeyToBytesConstMeta => const TaskConstMeta(debugName: "MldsaKey_to_bytes", argNames: ["that"]); + @override + Future crateApiFormatChallenge({ + required List random, + required PlatformInt64 timestamp, + }) { + return handler.executeNormal( + NormalTask( + callFfi: (port_) { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_list_prim_u_8_loose(random, serializer); + sse_encode_i_64(timestamp, serializer); + pdeCallFfi( + generalizedFrbRustBinding, + serializer, + funcId: 6, + port: port_, + ); + }, + codec: SseCodec( + decodeSuccessData: sse_decode_list_prim_u_8_strict, + decodeErrorData: sse_decode_String, + ), + constMeta: kCrateApiFormatChallengeConstMeta, + argValues: [random, timestamp], + apiImpl: this, + ), + ); + } + + TaskConstMeta get kCrateApiFormatChallengeConstMeta => const TaskConstMeta( + debugName: "format_challenge", + argNames: ["random", "timestamp"], + ); + RustArcIncrementStrongCountFnType get rust_arc_increment_strong_count_MldsaKey => wire .rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerMldsaKey; @@ -314,6 +353,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return raw as String; } + @protected + PlatformInt64 dco_decode_i_64(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return dcoDecodeI64(raw); + } + @protected List dco_decode_list_prim_u_8_loose(dynamic raw) { // Codec=Dco (DartCObject based), see doc to use other codecs @@ -394,6 +439,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return utf8.decoder.convert(inner); } + @protected + PlatformInt64 sse_decode_i_64(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + return deserializer.buffer.getPlatformInt64(); + } + @protected List sse_decode_list_prim_u_8_loose(SseDeserializer deserializer) { // Codec=Sse (Serialization based), see doc to use other codecs @@ -491,6 +542,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { sse_encode_list_prim_u_8_strict(utf8.encoder.convert(self), serializer); } + @protected + void sse_encode_i_64(PlatformInt64 self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + serializer.buffer.putPlatformInt64(self); + } + @protected void sse_encode_list_prim_u_8_loose( List self, diff --git a/useragent/lib/src/rust/frb_generated.io.dart b/useragent/lib/src/rust/frb_generated.io.dart index 942e9cd..3780c4e 100644 --- a/useragent/lib/src/rust/frb_generated.io.dart +++ b/useragent/lib/src/rust/frb_generated.io.dart @@ -46,6 +46,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected String dco_decode_String(dynamic raw); + @protected + PlatformInt64 dco_decode_i_64(dynamic raw); + @protected List dco_decode_list_prim_u_8_loose(dynamic raw); @@ -85,6 +88,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected String sse_decode_String(SseDeserializer deserializer); + @protected + PlatformInt64 sse_decode_i_64(SseDeserializer deserializer); + @protected List sse_decode_list_prim_u_8_loose(SseDeserializer deserializer); @@ -136,6 +142,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected void sse_encode_String(String self, SseSerializer serializer); + @protected + void sse_encode_i_64(PlatformInt64 self, SseSerializer serializer); + @protected void sse_encode_list_prim_u_8_loose(List self, SseSerializer serializer); diff --git a/useragent/lib/src/rust/frb_generated.web.dart b/useragent/lib/src/rust/frb_generated.web.dart index 640f1f8..e8a41cb 100644 --- a/useragent/lib/src/rust/frb_generated.web.dart +++ b/useragent/lib/src/rust/frb_generated.web.dart @@ -48,6 +48,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected String dco_decode_String(dynamic raw); + @protected + PlatformInt64 dco_decode_i_64(dynamic raw); + @protected List dco_decode_list_prim_u_8_loose(dynamic raw); @@ -87,6 +90,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected String sse_decode_String(SseDeserializer deserializer); + @protected + PlatformInt64 sse_decode_i_64(SseDeserializer deserializer); + @protected List sse_decode_list_prim_u_8_loose(SseDeserializer deserializer); @@ -138,6 +144,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected void sse_encode_String(String self, SseSerializer serializer); + @protected + void sse_encode_i_64(PlatformInt64 self, SseSerializer serializer); + @protected void sse_encode_list_prim_u_8_loose(List self, SseSerializer serializer); diff --git a/useragent/mise.toml b/useragent/mise.toml new file mode 100644 index 0000000..540e6c5 --- /dev/null +++ b/useragent/mise.toml @@ -0,0 +1,4 @@ +[tasks.codegen] +run = ''' + flutter_rust_bridge_codegen generate +''' diff --git a/useragent/rust/Cargo.lock b/useragent/rust/Cargo.lock index 9b8db0c..5442523 100644 --- a/useragent/rust/Cargo.lock +++ b/useragent/rust/Cargo.lock @@ -232,7 +232,7 @@ checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" name = "arbiter-crypto" version = "0.1.0" dependencies = [ - "base64", + "chrono", "memsafe", "ml-dsa", "rand", @@ -487,12 +487,6 @@ dependencies = [ "rustc-demangle", ] -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - [[package]] name = "base64ct" version = "1.8.3" @@ -718,6 +712,20 @@ dependencies = [ "rand_core", ] +[[package]] +name = "chrono" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-link", +] + [[package]] name = "clipboard-win" version = "5.4.1" @@ -1821,6 +1829,30 @@ dependencies = [ "zeroize", ] +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "icu_collections" version = "2.2.0" diff --git a/useragent/rust/src/api/mod.rs b/useragent/rust/src/api/mod.rs index baaab3c..0590ab0 100644 --- a/useragent/rust/src/api/mod.rs +++ b/useragent/rust/src/api/mod.rs @@ -1,13 +1,15 @@ use anyhow::anyhow; +use arbiter_crypto::authn::{self, AuthChallenge, USERAGENT_CONTEXT}; use flutter_rust_bridge::frb; -use arbiter_crypto::authn::{self, USERAGENT_CONTEXT}; #[frb(opaque)] pub struct MldsaKey(authn::SigningKey); impl MldsaKey { pub fn from_bytes(bytes: &[u8]) -> anyhow::Result { - let bytes: [u8; 32] = bytes.try_into().map_err(|_| anyhow!("Invalid key length"))?; + let bytes: [u8; 32] = bytes + .try_into() + .map_err(|_| anyhow!("Invalid key length"))?; Ok(Self(authn::SigningKey::from_seed(bytes))) } @@ -26,4 +28,11 @@ impl MldsaKey { pub fn get_public_key(&self) -> Vec { self.0.public_key().to_bytes().to_vec() } -} \ No newline at end of file +} + +pub fn format_challenge(random: Vec, timestamp: i64) -> Result, String> { + let challenge = AuthChallenge::from_parts(&random, timestamp) + .map_err(|_| "Invalid nonce length".to_string())?; + + Ok(challenge.format()) +} diff --git a/useragent/rust/src/frb_generated.rs b/useragent/rust/src/frb_generated.rs index 7489044..46647d0 100644 --- a/useragent/rust/src/frb_generated.rs +++ b/useragent/rust/src/frb_generated.rs @@ -39,7 +39,7 @@ flutter_rust_bridge::frb_generated_boilerplate!( default_rust_auto_opaque = RustAutoOpaqueMoi, ); pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_VERSION: &str = "2.12.0"; -pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = -437661335; +pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = 1247923898; // Section: executor @@ -267,6 +267,40 @@ fn wire__crate__api__MldsaKey_to_bytes_impl( }, ) } +fn wire__crate__api__format_challenge_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "format_challenge", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_random = >::sse_decode(&mut deserializer); + let api_timestamp = ::sse_decode(&mut deserializer); + deserializer.end(); + move |context| { + transform_result_sse::<_, String>((move || { + let output_ok = crate::api::format_challenge(api_random, api_timestamp)?; + Ok(output_ok) + })()) + } + }, + ) +} // Section: related_funcs @@ -312,6 +346,13 @@ impl SseDecode for String { } } +impl SseDecode for i64 { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + deserializer.cursor.read_i64::().unwrap() + } +} + impl SseDecode for Vec { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { @@ -371,6 +412,7 @@ fn pde_ffi_dispatcher_primary_impl( 3 => wire__crate__api__MldsaKey_get_public_key_impl(port, ptr, rust_vec_len, data_len), 4 => wire__crate__api__MldsaKey_sign_impl(port, ptr, rust_vec_len, data_len), 5 => wire__crate__api__MldsaKey_to_bytes_impl(port, ptr, rust_vec_len, data_len), + 6 => wire__crate__api__format_challenge_impl(port, ptr, rust_vec_len, data_len), _ => unreachable!(), } } @@ -436,6 +478,13 @@ impl SseEncode for String { } } +impl SseEncode for i64 { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + serializer.cursor.write_i64::(self).unwrap(); + } +} + impl SseEncode for Vec { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {