1#![allow(missing_docs)]
7
8use std::collections::HashMap;
9use std::ffi::CString;
10use std::os::raw::{c_char, c_int, c_uchar};
11use std::ptr;
12use std::slice;
13
14use crate::{Algorithm, EncParameters, KemParameters, PqcBinaryFormat, PqcMetadata};
15
16#[repr(C)]
18pub struct PqcFormatHandle {
19 _private: [u8; 0],
20}
21
22#[repr(C)]
24pub struct ByteBuffer {
25 pub data: *mut c_uchar,
26 pub len: usize,
27 pub capacity: usize,
28}
29
30impl ByteBuffer {
31 fn from_vec(vec: Vec<u8>) -> Self {
32 let mut vec = vec;
33 let data = vec.as_mut_ptr();
34 let len = vec.len();
35 let capacity = vec.capacity();
36 std::mem::forget(vec);
37 Self {
38 data,
39 len,
40 capacity,
41 }
42 }
43
44 #[allow(dead_code)]
45 unsafe fn to_vec(&self) -> Vec<u8> {
46 unsafe {
47 if self.data.is_null() {
48 return Vec::new();
49 }
50 slice::from_raw_parts(self.data, self.len).to_vec()
51 }
52 }
53}
54
55#[unsafe(no_mangle)]
60pub unsafe extern "C" fn pqc_free_buffer(buffer: ByteBuffer) {
61 unsafe {
62 if !buffer.data.is_null() {
63 drop(Vec::from_raw_parts(
64 buffer.data,
65 buffer.len,
66 buffer.capacity,
67 ));
68 }
69 }
70}
71
72#[unsafe(no_mangle)]
77pub unsafe extern "C" fn pqc_free_string(s: *mut c_char) {
78 unsafe {
79 if !s.is_null() {
80 drop(CString::from_raw(s));
81 }
82 }
83}
84
85#[unsafe(no_mangle)]
102pub unsafe extern "C" fn pqc_format_new(
103 algorithm_id: u16,
104 iv: *const c_uchar,
105 iv_len: usize,
106 tag: *const c_uchar,
107 tag_len: usize,
108 data: *const c_uchar,
109 data_len: usize,
110) -> *mut PqcFormatHandle {
111 unsafe {
112 if iv.is_null() || tag.is_null() || data.is_null() {
114 return ptr::null_mut();
115 }
116
117 let algorithm = match Algorithm::from_id(algorithm_id) {
119 Some(a) => a,
120 None => return ptr::null_mut(),
121 };
122
123 let iv_vec = slice::from_raw_parts(iv, iv_len).to_vec();
125 let tag_vec = slice::from_raw_parts(tag, tag_len).to_vec();
126 let data_vec = slice::from_raw_parts(data, data_len).to_vec();
127
128 let metadata = PqcMetadata {
130 enc_params: EncParameters {
131 iv: iv_vec,
132 tag: tag_vec,
133 params: HashMap::new(),
134 },
135 kem_params: None,
136 sig_params: None,
137 compression_params: None,
138 custom: HashMap::new(),
139 };
140
141 let format = PqcBinaryFormat::new(algorithm, metadata, data_vec);
143
144 Box::into_raw(Box::new(format)) as *mut PqcFormatHandle
145 }
146}
147
148#[unsafe(no_mangle)]
153pub unsafe extern "C" fn pqc_format_new_with_kem(
154 algorithm_id: u16,
155 iv: *const c_uchar,
156 iv_len: usize,
157 tag: *const c_uchar,
158 tag_len: usize,
159 kem_public_key: *const c_uchar,
160 kem_public_key_len: usize,
161 kem_ciphertext: *const c_uchar,
162 kem_ciphertext_len: usize,
163 data: *const c_uchar,
164 data_len: usize,
165) -> *mut PqcFormatHandle {
166 unsafe {
167 if iv.is_null()
168 || tag.is_null()
169 || kem_public_key.is_null()
170 || kem_ciphertext.is_null()
171 || data.is_null()
172 {
173 return ptr::null_mut();
174 }
175
176 let algorithm = match Algorithm::from_id(algorithm_id) {
177 Some(a) => a,
178 None => return ptr::null_mut(),
179 };
180
181 let metadata = PqcMetadata {
182 enc_params: EncParameters {
183 iv: slice::from_raw_parts(iv, iv_len).to_vec(),
184 tag: slice::from_raw_parts(tag, tag_len).to_vec(),
185 params: HashMap::new(),
186 },
187 kem_params: Some(KemParameters {
188 public_key: slice::from_raw_parts(kem_public_key, kem_public_key_len).to_vec(),
189 ciphertext: slice::from_raw_parts(kem_ciphertext, kem_ciphertext_len).to_vec(),
190 params: HashMap::new(),
191 }),
192 sig_params: None,
193 compression_params: None,
194 custom: HashMap::new(),
195 };
196
197 let data_vec = slice::from_raw_parts(data, data_len).to_vec();
198 let format = PqcBinaryFormat::new(algorithm, metadata, data_vec);
199
200 Box::into_raw(Box::new(format)) as *mut PqcFormatHandle
201 }
202}
203
204#[unsafe(no_mangle)]
215pub unsafe extern "C" fn pqc_format_to_bytes(handle: *const PqcFormatHandle) -> ByteBuffer {
216 unsafe {
217 if handle.is_null() {
218 return ByteBuffer {
219 data: ptr::null_mut(),
220 len: 0,
221 capacity: 0,
222 };
223 }
224
225 let format = &*(handle as *const PqcBinaryFormat);
226
227 match format.to_bytes() {
228 Ok(bytes) => ByteBuffer::from_vec(bytes),
229 Err(_) => ByteBuffer {
230 data: ptr::null_mut(),
231 len: 0,
232 capacity: 0,
233 },
234 }
235 }
236}
237
238#[unsafe(no_mangle)]
250pub unsafe extern "C" fn pqc_format_from_bytes(
251 data: *const c_uchar,
252 len: usize,
253) -> *mut PqcFormatHandle {
254 unsafe {
255 if data.is_null() {
256 return ptr::null_mut();
257 }
258
259 let bytes = slice::from_raw_parts(data, len);
260
261 match PqcBinaryFormat::from_bytes(bytes) {
262 Ok(format) => Box::into_raw(Box::new(format)) as *mut PqcFormatHandle,
263 Err(_) => ptr::null_mut(),
264 }
265 }
266}
267
268#[unsafe(no_mangle)]
273pub unsafe extern "C" fn pqc_format_get_algorithm_id(handle: *const PqcFormatHandle) -> u16 {
274 unsafe {
275 if handle.is_null() {
276 return 0;
277 }
278
279 let format = &*(handle as *const PqcBinaryFormat);
280 format.algorithm().as_id()
281 }
282}
283
284#[unsafe(no_mangle)]
292pub unsafe extern "C" fn pqc_format_get_algorithm_name(
293 handle: *const PqcFormatHandle,
294) -> *mut c_char {
295 unsafe {
296 if handle.is_null() {
297 return ptr::null_mut();
298 }
299
300 let format = &*(handle as *const PqcBinaryFormat);
301 let name = format.algorithm().name();
302
303 match CString::new(name) {
304 Ok(cstr) => cstr.into_raw(),
305 Err(_) => ptr::null_mut(),
306 }
307 }
308}
309
310#[unsafe(no_mangle)]
318pub unsafe extern "C" fn pqc_format_get_data(handle: *const PqcFormatHandle) -> ByteBuffer {
319 unsafe {
320 if handle.is_null() {
321 return ByteBuffer {
322 data: ptr::null_mut(),
323 len: 0,
324 capacity: 0,
325 };
326 }
327
328 let format = &*(handle as *const PqcBinaryFormat);
329 ByteBuffer::from_vec(format.data().to_vec())
330 }
331}
332
333#[unsafe(no_mangle)]
341pub unsafe extern "C" fn pqc_format_validate(handle: *const PqcFormatHandle) -> c_int {
342 unsafe {
343 if handle.is_null() {
344 return -1;
345 }
346
347 let format = &*(handle as *const PqcBinaryFormat);
348
349 match format.validate() {
350 Ok(()) => 0,
351 Err(_) => -1,
352 }
353 }
354}
355
356#[unsafe(no_mangle)]
361pub unsafe extern "C" fn pqc_format_get_total_size(handle: *const PqcFormatHandle) -> usize {
362 unsafe {
363 if handle.is_null() {
364 return 0;
365 }
366
367 let format = &*(handle as *const PqcBinaryFormat);
368 format.total_size()
369 }
370}
371
372#[unsafe(no_mangle)]
377pub unsafe extern "C" fn pqc_format_free(handle: *mut PqcFormatHandle) {
378 unsafe {
379 if !handle.is_null() {
380 drop(Box::from_raw(handle as *mut PqcBinaryFormat));
381 }
382 }
383}
384
385#[unsafe(no_mangle)]
390pub extern "C" fn pqc_get_version() -> *mut c_char {
391 match CString::new(crate::VERSION) {
392 Ok(cstr) => cstr.into_raw(),
393 Err(_) => ptr::null_mut(),
394 }
395}
396
397#[unsafe(no_mangle)]
399pub extern "C" fn pqc_get_binary_version() -> u8 {
400 crate::PQC_BINARY_VERSION
401}
402
403pub use crate::algorithm::c_constants::*;