simplicity_sys/c_jets/
c_env.rs

1// SPDX-License-Identifier: CC0-1.0
2
3use hashes::{sha256, Hash};
4
5use crate::ffi::sha256::CSha256Midstate;
6use crate::ffi::{c_size_t, c_uchar, c_uint, c_uint_fast32_t};
7
8/// Documentation of RawInputData/RawOutputData/RawTapData/Raw.
9///
10/// Data structure for holding data that CTransaction points to.
11///
12/// Why do we this special data structure?
13///     1. We need to keep the data in memory until the CTransaction is dropped.
14///     2. The memory is Transaction is not saved in the same format as required by FFI.
15/// We use more ergonomics in rust to allow better UX which interfere with the FFI. For example,
16/// the Value is stored as Tagged Union, but we require it to be a slice of bytes in elements format.
17///     3. Allocating inside FFI functions does not work because the memory is freed after the function returns.
18///     4. We only create allocations for data fields that are stored differently from the
19/// consensus serialization format.
20#[derive(Debug)]
21pub struct RawOutputData {
22    pub asset: Vec<c_uchar>,
23    pub value: Vec<c_uchar>,
24    pub nonce: Vec<c_uchar>,
25    pub surjection_proof: Vec<c_uchar>,
26    pub range_proof: Vec<c_uchar>,
27}
28
29#[derive(Debug)]
30#[repr(C)]
31pub struct CElementsRawBuffer {
32    pub ptr: *const c_uchar,
33    pub len: u32,
34}
35
36/// Similar to [`RawOutputData`], for inputs.
37#[derive(Debug)]
38pub struct RawInputData {
39    pub annex: Option<Vec<c_uchar>>,
40    // issuance
41    pub issuance_amount: Vec<c_uchar>,
42    pub issuance_inflation_keys: Vec<c_uchar>,
43    pub amount_range_proof: Vec<c_uchar>,
44    pub inflation_keys_range_proof: Vec<c_uchar>,
45    // spent txo
46    pub asset: Vec<c_uchar>,
47    pub value: Vec<c_uchar>,
48}
49
50/// Similar to [`RawOutputData`], but for transaction
51#[derive(Debug)]
52pub struct RawTransactionData {
53    pub inputs: Vec<RawInputData>,
54    pub outputs: Vec<RawOutputData>,
55}
56
57#[derive(Debug)]
58#[repr(C)]
59pub struct CElementsRawOutput {
60    asset: *const c_uchar,
61    value: *const c_uchar,
62    nonce: *const c_uchar,
63    script_pubkey: CElementsRawBuffer,
64    surjection_proof: CElementsRawBuffer,
65    range_proof: CElementsRawBuffer,
66}
67
68#[derive(Debug)]
69#[repr(C)]
70pub struct CElementsRawInput {
71    annex: *const CElementsRawBuffer,
72    prev_txid: *const c_uchar,
73    pegin: *const c_uchar,
74    // issuance
75    blinding_nonce: *const c_uchar,
76    asset_entropy: *const c_uchar,
77    amount: *const c_uchar,
78    inflation_keys: *const c_uchar,
79    amount_range_proof: CElementsRawBuffer,
80    inflation_keys_range_proof: CElementsRawBuffer,
81    // spent txo
82    asset: *const c_uchar,
83    value: *const c_uchar,
84    script_pubkey: CElementsRawBuffer,
85    // inputs
86    script_sig: CElementsRawBuffer,
87    prev_txout_index: u32,
88    sequence: u32,
89}
90
91#[derive(Debug)]
92#[repr(C)]
93pub struct CElementsRawTransaction {
94    txid: *const c_uchar,
95    inputs: *const CElementsRawInput,
96    outputs: *const CElementsRawOutput,
97    version: u32,
98    locktime: u32,
99    n_inputs: u32,
100    n_outputs: u32,
101}
102
103#[derive(Debug)]
104#[repr(C)]
105pub struct CElementsRawTapEnv {
106    control_block: *const c_uchar,
107    script_cmr: *const c_uchar,
108    branch_len: u8,
109}
110
111#[derive(Debug)]
112pub enum CTransaction {}
113
114#[derive(Debug)]
115#[repr(C)]
116pub struct CElementsTxEnv {
117    tx: *const CTransaction,
118    taproot: *const CTapEnv,
119    genesis_hash: CSha256Midstate,
120    sighash_all: CSha256Midstate,
121    ix: c_uint_fast32_t,
122}
123
124#[derive(Debug)]
125pub enum CTapEnv {}
126
127extern "C" {
128    #[link_name = "rustsimplicity_0_5_c_sizeof_rawElementsBuffer"]
129    pub static c_sizeof_rawElementsBuffer: c_size_t;
130    #[link_name = "rustsimplicity_0_5_c_sizeof_rawElementsOutput"]
131    pub static c_sizeof_rawElementsOutput: c_size_t;
132    #[link_name = "rustsimplicity_0_5_c_sizeof_rawElementsInput"]
133    pub static c_sizeof_rawElementsInput: c_size_t;
134    #[link_name = "rustsimplicity_0_5_c_sizeof_rawElementsTransaction"]
135    pub static c_sizeof_rawElementsTransaction: c_size_t;
136    #[link_name = "rustsimplicity_0_5_c_sizeof_rawElementsTapEnv"]
137    pub static c_sizeof_rawElementsTapEnv: c_size_t;
138    #[link_name = "rustsimplicity_0_5_c_sizeof_txEnv"]
139    pub static c_sizeof_txEnv: c_size_t;
140
141    #[link_name = "rustsimplicity_0_5_c_alignof_rawElementsBuffer"]
142    pub static c_alignof_rawElementsBuffer: c_size_t;
143    #[link_name = "rustsimplicity_0_5_c_alignof_rawElementsOutput"]
144    pub static c_alignof_rawElementsOutput: c_size_t;
145    #[link_name = "rustsimplicity_0_5_c_alignof_rawElementsInput"]
146    pub static c_alignof_rawElementsInput: c_size_t;
147    #[link_name = "rustsimplicity_0_5_c_alignof_rawElementsTransaction"]
148    pub static c_alignof_rawElementsTransaction: c_size_t;
149    #[link_name = "rustsimplicity_0_5_c_alignof_rawElementsTapEnv"]
150    pub static c_alignof_rawElementsTapEnv: c_size_t;
151    #[link_name = "rustsimplicity_0_5_c_alignof_txEnv"]
152    pub static c_alignof_txEnv: c_size_t;
153
154    #[link_name = "rustsimplicity_0_5_c_set_rawElementsBuffer"]
155    pub fn c_set_rawElementsBuffer(res: *mut CElementsRawBuffer, buf: *const c_uchar, len: c_uint);
156    #[link_name = "rustsimplicity_0_5_c_set_rawElementsOutput"]
157    pub fn c_set_rawElementsOutput(
158        res: *mut CElementsRawOutput,
159        asset: *const c_uchar,
160        value: *const c_uchar,
161        nonce: *const c_uchar,
162        scriptPubKey: *const CElementsRawBuffer,
163        surjectionProof: *const CElementsRawBuffer,
164        rangeProof: *const CElementsRawBuffer,
165    );
166    #[link_name = "rustsimplicity_0_5_c_set_rawElementsInput"]
167    pub fn c_set_rawElementsInput(
168        result: *mut CElementsRawInput,
169        annex: *const CElementsRawBuffer,
170        pegin: *const c_uchar,
171        scriptSig: *const CElementsRawBuffer,
172        prevTxid: *const c_uchar,
173        prevIx: c_uint,
174        asset: *const c_uchar,
175        value: *const c_uchar,
176        scriptPubKey: *const CElementsRawBuffer,
177        sequence: c_uint,
178        blindingNonce: *const c_uchar,
179        assetEntropy: *const c_uchar,
180        amount: *const c_uchar,
181        inflationKeys: *const c_uchar,
182        amountRangePrf: *const CElementsRawBuffer,
183        inflationKeysRangePrf: *const CElementsRawBuffer,
184    );
185
186    #[link_name = "rustsimplicity_0_5_c_set_rawElementsTransaction"]
187    pub fn c_set_rawElementsTransaction(
188        result: *mut CElementsRawTransaction,
189        version: c_uint,
190        txid: *const c_uchar,
191        input: *const CElementsRawInput,
192        numInputs: c_uint,
193        output: *const CElementsRawOutput,
194        numOutputs: c_uint,
195        lockTime: c_uint,
196    );
197    #[link_name = "rustsimplicity_0_5_c_set_rawElementsTapEnv"]
198    pub fn c_set_rawElementsTapEnv(
199        result: *mut CElementsRawTapEnv,
200        controlBlock: *const c_uchar,
201        pathLen: c_uchar,
202        scriptCMR: *const c_uchar,
203    );
204    #[link_name = "rustsimplicity_0_5_c_set_txEnv"]
205    pub fn c_set_txEnv(
206        result: *mut CElementsTxEnv,
207        tx: *const CTransaction,
208        taproot: *const CTapEnv,
209        genesisHash: *const c_uchar,
210        ix: c_uint,
211    );
212    #[link_name = "rustsimplicity_0_5_elements_mallocTapEnv"]
213    pub fn simplicity_elements_mallocTapEnv(rawEnv: *const CElementsRawTapEnv) -> *mut CTapEnv;
214    #[link_name = "rustsimplicity_0_5_elements_mallocTransaction"]
215    pub fn simplicity_elements_mallocTransaction(
216        rawTx: *const CElementsRawTransaction,
217    ) -> *mut CTransaction;
218    #[link_name = "rustsimplicity_0_5_c_free_transaction"]
219    pub fn c_free_transaction(tx: *mut CTransaction);
220    #[link_name = "rustsimplicity_0_5_c_free_tapEnv"]
221    pub fn c_free_tapEnv(env: *mut CTapEnv);
222}
223impl CElementsTxEnv {
224    pub fn sighash_all(&self) -> sha256::Hash {
225        let midstate: sha256::Midstate = self.sighash_all.into();
226        sha256::Hash::from_byte_array(midstate.to_byte_array())
227    }
228}
229
230// Pointer must be manually free after dropping
231impl Drop for CElementsTxEnv {
232    fn drop(&mut self) {
233        unsafe {
234            crate::alloc::rust_0_5_free(self.tx as *mut u8);
235            crate::alloc::rust_0_5_free(self.taproot as *mut u8);
236        }
237    }
238}
239
240impl CElementsRawBuffer {
241    pub fn new(buf: &[c_uchar]) -> Self {
242        unsafe {
243            let mut raw_buffer = std::mem::MaybeUninit::<Self>::uninit();
244            c_set_rawElementsBuffer(raw_buffer.as_mut_ptr(), buf.as_ptr(), buf.len() as c_uint);
245            raw_buffer.assume_init()
246        }
247    }
248}
249
250#[cfg(test)]
251mod tests {
252    use std::mem::{align_of, size_of};
253
254    use crate::c_jets::{c_env::*, frame_ffi::*};
255
256    #[test]
257    fn test_sizes() {
258        unsafe {
259            assert_eq!(size_of::<CFrameItem>(), c_sizeof_frameItem);
260            assert_eq!(size_of::<CElementsRawBuffer>(), c_sizeof_rawElementsBuffer);
261            assert_eq!(size_of::<CElementsRawInput>(), c_sizeof_rawElementsInput);
262            assert_eq!(size_of::<CElementsRawOutput>(), c_sizeof_rawElementsOutput);
263            assert_eq!(
264                size_of::<CElementsRawTransaction>(),
265                c_sizeof_rawElementsTransaction
266            );
267            assert_eq!(size_of::<CElementsRawTapEnv>(), c_sizeof_rawElementsTapEnv);
268            assert_eq!(size_of::<CElementsTxEnv>(), c_sizeof_txEnv);
269        }
270    }
271
272    #[test]
273    fn test_aligns() {
274        unsafe {
275            assert_eq!(align_of::<CFrameItem>(), c_alignof_frameItem);
276            assert_eq!(
277                align_of::<CElementsRawBuffer>(),
278                c_alignof_rawElementsBuffer
279            );
280            assert_eq!(align_of::<CElementsRawInput>(), c_alignof_rawElementsInput);
281            assert_eq!(
282                align_of::<CElementsRawOutput>(),
283                c_alignof_rawElementsOutput
284            );
285            assert_eq!(
286                align_of::<CElementsRawTransaction>(),
287                c_alignof_rawElementsTransaction
288            );
289            assert_eq!(
290                align_of::<CElementsRawTapEnv>(),
291                c_alignof_rawElementsTapEnv
292            );
293            assert_eq!(align_of::<CElementsTxEnv>(), c_alignof_txEnv);
294        }
295    }
296}