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 CRawBuffer {
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 CRawOutput {
60    asset: *const c_uchar,
61    value: *const c_uchar,
62    nonce: *const c_uchar,
63    script_pubkey: CRawBuffer,
64    surjection_proof: CRawBuffer,
65    range_proof: CRawBuffer,
66}
67
68#[derive(Debug)]
69#[repr(C)]
70pub struct CRawInput {
71    annex: *const CRawBuffer,
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: CRawBuffer,
80    inflation_keys_range_proof: CRawBuffer,
81    // spent txo
82    asset: *const c_uchar,
83    value: *const c_uchar,
84    script_pubkey: CRawBuffer,
85    // inputs
86    script_sig: CRawBuffer,
87    prev_txout_index: u32,
88    sequence: u32,
89}
90
91#[derive(Debug)]
92#[repr(C)]
93pub struct CRawTransaction {
94    txid: *const c_uchar,
95    inputs: *const CRawInput,
96    outputs: *const CRawOutput,
97    version: u32,
98    locktime: u32,
99    n_inputs: u32,
100    n_outputs: u32,
101}
102
103#[derive(Debug)]
104#[repr(C)]
105pub struct CRawTapEnv {
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
129    pub static c_sizeof_rawBuffer: c_size_t;
130    pub static c_sizeof_rawOutput: c_size_t;
131    pub static c_sizeof_rawInput: c_size_t;
132    pub static c_sizeof_rawTransaction: c_size_t;
133    pub static c_sizeof_rawTapEnv: c_size_t;
134    pub static c_sizeof_txEnv: c_size_t;
135
136    pub static c_alignof_rawBuffer: c_size_t;
137    pub static c_alignof_rawOutput: c_size_t;
138    pub static c_alignof_rawInput: c_size_t;
139    pub static c_alignof_rawTransaction: c_size_t;
140    pub static c_alignof_rawTapEnv: c_size_t;
141    pub static c_alignof_txEnv: c_size_t;
142
143    pub fn c_set_rawBuffer(res: *mut CRawBuffer, buf: *const c_uchar, len: c_uint);
144    pub fn c_set_rawOutput(
145        res: *mut CRawOutput,
146        asset: *const c_uchar,
147        value: *const c_uchar,
148        nonce: *const c_uchar,
149        scriptPubKey: *const CRawBuffer,
150        surjectionProof: *const CRawBuffer,
151        rangeProof: *const CRawBuffer,
152    );
153    pub fn c_set_rawInput(
154        result: *mut CRawInput,
155        annex: *const CRawBuffer,
156        pegin: *const c_uchar,
157        scriptSig: *const CRawBuffer,
158        prevTxid: *const c_uchar,
159        prevIx: c_uint,
160        asset: *const c_uchar,
161        value: *const c_uchar,
162        scriptPubKey: *const CRawBuffer,
163        sequence: c_uint,
164        blindingNonce: *const c_uchar,
165        assetEntropy: *const c_uchar,
166        amount: *const c_uchar,
167        inflationKeys: *const c_uchar,
168        amountRangePrf: *const CRawBuffer,
169        inflationKeysRangePrf: *const CRawBuffer,
170    );
171
172    pub fn c_set_rawTransaction(
173        result: *mut CRawTransaction,
174        version: c_uint,
175        txid: *const c_uchar,
176        input: *const CRawInput,
177        numInputs: c_uint,
178        output: *const CRawOutput,
179        numOutputs: c_uint,
180        lockTime: c_uint,
181    );
182    pub fn c_set_rawTapEnv(
183        result: *mut CRawTapEnv,
184        controlBlock: *const c_uchar,
185        pathLen: c_uchar,
186        scriptCMR: *const c_uchar,
187    );
188    pub fn c_set_txEnv(
189        result: *mut CElementsTxEnv,
190        tx: *const CTransaction,
191        taproot: *const CTapEnv,
192        genesisHash: *const c_uchar,
193        ix: c_uint,
194    );
195    pub fn simplicity_elements_mallocTapEnv(rawEnv: *const CRawTapEnv) -> *mut CTapEnv;
196    pub fn simplicity_elements_mallocTransaction(
197        rawTx: *const CRawTransaction,
198    ) -> *mut CTransaction;
199    pub fn c_free_transaction(tx: *mut CTransaction);
200    pub fn c_free_tapEnv(env: *mut CTapEnv);
201}
202impl CElementsTxEnv {
203    pub fn sighash_all(&self) -> sha256::Hash {
204        let midstate: sha256::Midstate = self.sighash_all.into();
205        sha256::Hash::from_byte_array(midstate.to_byte_array())
206    }
207}
208
209// Pointer must be manually free after dropping
210impl Drop for CElementsTxEnv {
211    fn drop(&mut self) {
212        unsafe {
213            crate::alloc::rust_0_4_free(self.tx as *mut u8);
214            crate::alloc::rust_0_4_free(self.taproot as *mut u8);
215        }
216    }
217}
218
219impl CRawBuffer {
220    pub fn new(buf: &[c_uchar]) -> Self {
221        unsafe {
222            let mut raw_buffer = std::mem::MaybeUninit::<CRawBuffer>::uninit();
223            c_set_rawBuffer(raw_buffer.as_mut_ptr(), buf.as_ptr(), buf.len() as c_uint);
224            raw_buffer.assume_init()
225        }
226    }
227}
228
229#[cfg(test)]
230mod tests {
231    use std::mem::{align_of, size_of};
232
233    use crate::c_jets::{c_env::*, frame_ffi::*};
234
235    #[test]
236    fn test_sizes() {
237        unsafe {
238            assert_eq!(size_of::<CFrameItem>(), c_sizeof_frameItem);
239            assert_eq!(size_of::<CRawBuffer>(), c_sizeof_rawBuffer);
240            assert_eq!(size_of::<CRawInput>(), c_sizeof_rawInput);
241            assert_eq!(size_of::<CRawOutput>(), c_sizeof_rawOutput);
242            assert_eq!(size_of::<CRawTransaction>(), c_sizeof_rawTransaction);
243            assert_eq!(size_of::<CRawTapEnv>(), c_sizeof_rawTapEnv);
244            assert_eq!(size_of::<CElementsTxEnv>(), c_sizeof_txEnv);
245        }
246    }
247
248    #[test]
249    fn test_aligns() {
250        unsafe {
251            assert_eq!(align_of::<CFrameItem>(), c_alignof_frameItem);
252            assert_eq!(align_of::<CRawBuffer>(), c_alignof_rawBuffer);
253            assert_eq!(align_of::<CRawInput>(), c_alignof_rawInput);
254            assert_eq!(align_of::<CRawOutput>(), c_alignof_rawOutput);
255            assert_eq!(align_of::<CRawTransaction>(), c_alignof_rawTransaction);
256            assert_eq!(align_of::<CRawTapEnv>(), c_alignof_rawTapEnv);
257            assert_eq!(align_of::<CElementsTxEnv>(), c_alignof_txEnv);
258        }
259    }
260}