sodot_mpc/ffi/
conversions.rs1use crate::{
2 ExtendedPrivateKey, ExtendedPublicKey, KeygenId, KeygenPrivateKey, PublicKey, RoomUUID, SecretShare,
3 bip340::Bip340Tweak,
4 ecdsa::{EcdsaSignature, MessageHash},
5 ffi::{AsRawFFI, ConstSlice, ConstStr, FromFFI, Room, ToFFI, bindings},
6};
7use std::{borrow::Cow, marker::PhantomData};
8
9const FFI_EXPECT: &str = "internal FFI error";
10
11impl<const N: usize> AsRawFFI for const_hex::Buffer<N, false> {
12 type FFI = bindings::ConstStr;
13
14 unsafe fn raw_ffi(&self) -> Self::FFI {
15 unsafe { ConstStr::from_str(self.as_str()).raw_ffi() }
16 }
17}
18
19impl AsRawFFI for ConstStr<'_> {
20 type FFI = bindings::ConstStr;
21 unsafe fn raw_ffi(&self) -> Self::FFI {
22 self.ffi
23 }
24}
25
26impl AsRawFFI for ConstSlice<'_, ConstStr<'_>> {
27 type FFI = bindings::ConstSlice_ConstStr;
28 unsafe fn raw_ffi(&self) -> Self::FFI {
29 bindings::ConstSlice_ConstStr { ptr: self.ptr.cast::<bindings::ConstStr>(), len: self.len }
31 }
32}
33
34impl AsRawFFI for ConstSlice<'_, u32> {
35 type FFI = bindings::ConstSlice_u32;
36 unsafe fn raw_ffi(&self) -> Self::FFI {
37 bindings::ConstSlice_u32 { ptr: self.ptr, len: self.len }
38 }
39}
40
41impl AsRawFFI for str {
42 type FFI = bindings::ConstStr;
43 unsafe fn raw_ffi(&self) -> Self::FFI {
44 unsafe { ConstStr::from_str(self).raw_ffi() }
45 }
46}
47
48impl AsRawFFI for String {
49 type FFI = bindings::ConstStr;
50 unsafe fn raw_ffi(&self) -> Self::FFI {
51 unsafe { ConstStr::from_str(self).raw_ffi() }
52 }
53}
54
55impl<S: AsRawFFI<FFI = bindings::ConstStr>> AsRawFFI for Option<S> {
56 type FFI = bindings::ConstStr;
57 unsafe fn raw_ffi(&self) -> Self::FFI {
58 match self {
59 Some(s) => unsafe { s.raw_ffi() },
60 None => unsafe { ConstStr::NULL.raw_ffi() },
61 }
62 }
63}
64
65impl<S: AsRawFFI + ?Sized> AsRawFFI for &'_ S {
66 type FFI = S::FFI;
67 unsafe fn raw_ffi(&self) -> Self::FFI {
68 unsafe { (*self).raw_ffi() }
69 }
70}
71
72impl<T> AsRawFFI for SecretShare<T> {
73 type FFI = bindings::ConstStr;
74 unsafe fn raw_ffi(&self) -> Self::FFI {
75 unsafe { self.as_str().raw_ffi() }
76 }
77}
78
79impl AsRawFFI for Room<'_> {
80 type FFI = bindings::Room;
81 unsafe fn raw_ffi(&self) -> Self::FFI {
82 unsafe { bindings::Room { host_url: self.host_url.raw_ffi(), uuid: self.uuid.raw_ffi() } }
83 }
84}
85
86impl<T: FromFFI> FromFFI for Option<T> {
87 fn parse_ffi<'a>(s: impl Into<Cow<'a, str>>) -> Self {
88 let s = s.into();
89 if s.is_empty() { None } else { Some(T::parse_ffi(s)) }
90 }
91}
92
93impl<T: ToFFI> ToFFI for Option<&T>
94where
95 for<'a> Option<T::Str<'a>>: AsRawFFI<FFI = bindings::ConstStr>,
96{
97 type Str<'a>
98 = Option<T::Str<'a>>
99 where
100 Self: 'a;
101 fn ffi<'a>(&'a self) -> Self::Str<'a> {
102 self.as_ref().map(|s| s.ffi())
103 }
104}
105
106impl FromFFI for KeygenId {
107 fn parse_ffi<'a>(s: impl Into<Cow<'a, str>>) -> Self {
108 let s = s.into();
109 KeygenId::new(s.into_owned())
110 }
111}
112
113impl ToFFI for KeygenId {
114 type Str<'a> = &'a str;
115
116 fn ffi<'a>(&'a self) -> Self::Str<'a> {
117 self.as_str()
118 }
119}
120
121impl ToFFI for [u8] {
122 type Str<'a> = String;
123
124 fn ffi<'a>(&'a self) -> Self::Str<'a> {
125 const_hex::encode(self)
126 }
127}
128
129impl FromFFI for KeygenPrivateKey {
130 fn parse_ffi<'a>(s: impl Into<Cow<'a, str>>) -> Self {
131 Self(FromFFI::parse_ffi(s))
132 }
133}
134
135impl ToFFI for KeygenPrivateKey {
136 type Str<'a> = const_hex::Buffer<32, false>;
137
138 fn ffi<'a>(&'a self) -> Self::Str<'a> {
139 self.0.ffi()
140 }
141}
142
143impl FromFFI for RoomUUID {
144 fn parse_ffi<'a>(s: impl Into<Cow<'a, str>>) -> Self {
145 let s = s.into();
146 RoomUUID::new(s.into_owned())
147 }
148}
149
150impl ToFFI for RoomUUID {
151 type Str<'a> = &'a str;
152
153 fn ffi<'a>(&'a self) -> Self::Str<'a> {
154 self.0.as_str()
155 }
156}
157
158impl<T> FromFFI for ExtendedPublicKey<T> {
159 fn parse_ffi<'a>(s: impl Into<Cow<'a, str>>) -> Self {
160 Self(s.into().into_owned(), PhantomData)
161 }
162}
163
164impl<T: 'static> ToFFI for ExtendedPublicKey<T> {
165 type Str<'a> = &'a str;
166
167 fn ffi<'a>(&'a self) -> Self::Str<'a> {
168 self.0.as_str()
169 }
170}
171
172impl<T> FromFFI for ExtendedPrivateKey<T> {
173 fn parse_ffi<'a>(s: impl Into<Cow<'a, str>>) -> Self {
174 Self(s.into().into_owned(), PhantomData)
175 }
176}
177
178impl<T: 'static> ToFFI for ExtendedPrivateKey<T> {
179 type Str<'a> = &'a str;
180
181 fn ffi<'a>(&'a self) -> Self::Str<'a> {
182 self.0.as_str()
183 }
184}
185
186impl<T> FromFFI for SecretShare<T> {
187 fn parse_ffi<'a>(s: impl Into<Cow<'a, str>>) -> Self {
188 Self(s.into().into_owned(), PhantomData)
189 }
190}
191
192impl<T: 'static> ToFFI for SecretShare<T> {
193 type Str<'a> = &'a str;
194
195 fn ffi<'a>(&'a self) -> Self::Str<'a> {
196 self.0.as_str()
197 }
198}
199
200impl<T, const N: usize> FromFFI for PublicKey<T, N> {
201 fn parse_ffi<'a>(s: impl Into<Cow<'a, str>>) -> Self {
202 let arr = const_hex::decode_to_array(&*s.into()).expect(FFI_EXPECT);
203 Self(arr, PhantomData)
204 }
205}
206
207impl FromFFI for [u8; 32] {
208 fn parse_ffi<'a>(s: impl Into<Cow<'a, str>>) -> Self {
209 const_hex::decode_to_array(&*s.into()).expect(FFI_EXPECT)
210 }
211}
212
213impl ToFFI for [u8; 32] {
214 type Str<'a> = const_hex::Buffer<32, false>;
215
216 fn ffi<'a>(&'a self) -> Self::Str<'a> {
217 let mut buf = const_hex::Buffer::new();
218 buf.format(self);
219 buf
220 }
221}
222
223impl FromFFI for [u8; 64] {
224 fn parse_ffi<'a>(s: impl Into<Cow<'a, str>>) -> Self {
225 const_hex::decode_to_array(&*s.into()).expect(FFI_EXPECT)
226 }
227}
228
229impl ToFFI for [u8; 64] {
230 type Str<'a> = const_hex::Buffer<64, false>;
231
232 fn ffi<'a>(&'a self) -> Self::Str<'a> {
233 let mut buf = const_hex::Buffer::new();
234 buf.format(self);
235 buf
236 }
237}
238
239impl FromFFI for EcdsaSignature {
240 fn parse_ffi<'a>(s: impl Into<Cow<'a, str>>) -> Self {
241 let s = s.into();
242 let decoded = const_hex::decode(s.as_ref()).expect(FFI_EXPECT);
243 assert!(
244 decoded.len() >= Self::MIN_SIZE && decoded.len() <= Self::MAX_SIZE,
245 "Invalid signature length, expected between {}..{} bytes, found: {}",
246 Self::MIN_SIZE,
247 Self::MAX_SIZE,
248 decoded.len()
249 );
250 Self { expanded_sig: decoded }
251 }
252}
253
254impl ToFFI for MessageHash {
255 type Str<'a> = const_hex::Buffer<32, false>;
256
257 fn ffi<'a>(&'a self) -> Self::Str<'a> {
258 self.0.ffi()
259 }
260}
261
262impl ToFFI for Bip340Tweak {
263 type Str<'a> = const_hex::Buffer<32, false>;
264 fn ffi(&self) -> Self::Str<'_> {
265 self.0.ffi()
266 }
267}