Skip to content

Commit 66135ce

Browse files
committed
Add bindings for DAGs and tests
1 parent 33994ea commit 66135ce

File tree

7 files changed

+374
-0
lines changed

7 files changed

+374
-0
lines changed

simplicity-sys/src/bitstream.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Simplicity Bindings
2+
// Written in 2022 by
3+
// Christian Lewe <[email protected]>
4+
//
5+
// To the extent possible under law, the author(s) have dedicated all
6+
// copyright and related and neighboring rights to this software to
7+
// the public domain worldwide. This software is distributed without
8+
// any warranty.
9+
//
10+
// You should have received a copy of the CC0 Public Domain Dedication
11+
// along with this software.
12+
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
13+
//
14+
15+
use libc::{c_char, c_int, c_uchar, c_void, FILE};
16+
use std::marker::PhantomData;
17+
18+
/// Stream of bits.
19+
#[repr(C)]
20+
pub struct Bitstream<'a> {
21+
file: *mut FILE,
22+
available: c_int,
23+
byte: c_uchar,
24+
_marker: PhantomData<&'a u8>,
25+
}
26+
27+
impl<'a> From<&'a [u8]> for Bitstream<'a> {
28+
fn from(bytes: &'a [u8]) -> Self {
29+
unsafe {
30+
let mode = "r";
31+
let file = libc::fmemopen(
32+
bytes.as_ptr() as *mut c_void,
33+
bytes.len(),
34+
mode.as_ptr() as *const c_char,
35+
);
36+
37+
Bitstream {
38+
file,
39+
available: 0,
40+
byte: c_uchar::default(),
41+
_marker: PhantomData,
42+
}
43+
}
44+
}
45+
}
46+
47+
impl<'a> Drop for Bitstream<'a> {
48+
fn drop(&mut self) {
49+
unsafe {
50+
libc::fclose(self.file);
51+
}
52+
}
53+
}

simplicity-sys/src/bitstring.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Simplicity Bindings
2+
// Written in 2022 by
3+
// Christian Lewe <[email protected]>
4+
//
5+
// To the extent possible under law, the author(s) have dedicated all
6+
// copyright and related and neighboring rights to this software to
7+
// the public domain worldwide. This software is distributed without
8+
// any warranty.
9+
//
10+
// You should have received a copy of the CC0 Public Domain Dedication
11+
// along with this software.
12+
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
13+
//
14+
15+
use libc::{c_uchar, size_t};
16+
17+
/// String of bits.
18+
#[repr(C)]
19+
#[derive(Copy, Clone)]
20+
pub(crate) struct Bitstring {
21+
arr: *const c_uchar,
22+
len: size_t,
23+
offset: size_t,
24+
}

simplicity-sys/src/dag.rs

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
// Simplicity Bindings
2+
// Written in 2022 by
3+
// Christian Lewe <[email protected]>
4+
//
5+
// To the extent possible under law, the author(s) have dedicated all
6+
// copyright and related and neighboring rights to this software to
7+
// the public domain worldwide. This software is distributed without
8+
// any warranty.
9+
//
10+
// You should have received a copy of the CC0 Public Domain Dedication
11+
// along with this software.
12+
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
13+
//
14+
15+
use crate::bitstream::Bitstream;
16+
use crate::bitstring::Bitstring;
17+
use crate::error::Error;
18+
use crate::util;
19+
use libc::{c_void, size_t};
20+
use std::fmt;
21+
22+
/// Kind of Simplicity node.
23+
#[repr(C)]
24+
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
25+
pub enum Tag {
26+
COMP,
27+
CASE,
28+
ASSERTL,
29+
ASSERTR,
30+
PAIR,
31+
DISCONNECT,
32+
INJL,
33+
INJR,
34+
TAKE,
35+
DROP,
36+
IDEN,
37+
UNIT,
38+
HIDDEN,
39+
WITNESS,
40+
JET,
41+
}
42+
43+
#[repr(C)]
44+
#[derive(Copy, Clone)]
45+
union AuxTypes {
46+
/// scratch space for verifyCanonicalOrder
47+
aux: size_t,
48+
/// source type, target type
49+
types: [size_t; 2],
50+
}
51+
52+
#[repr(C)]
53+
#[derive(Copy, Clone)]
54+
union IndicesChildrenWitness {
55+
/// source index, target index
56+
indices: [size_t; 2],
57+
/// first child, second child
58+
children: [size_t; 2],
59+
/// witness
60+
witness: Bitstring,
61+
}
62+
63+
#[repr(C)]
64+
struct PrivateDagNode {
65+
jet: *const c_void,
66+
cmr: [u32; 8],
67+
aux_types: AuxTypes,
68+
indices_children_witness: IndicesChildrenWitness,
69+
tag: Tag,
70+
}
71+
72+
extern "C" {
73+
fn decodeMallocDag(
74+
dag: *mut *mut PrivateDagNode,
75+
combinator_counters: *const c_void,
76+
stream: *mut Bitstream,
77+
) -> i32;
78+
}
79+
80+
/// Simplicity DAG (typed or untyped).
81+
/// Uses the Elements extension by default.
82+
pub struct Dag {
83+
first: *mut PrivateDagNode,
84+
len: usize,
85+
}
86+
87+
impl fmt::Debug for Dag {
88+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89+
f.debug_struct("Dag").field("cmr", &self.cmr()).finish()
90+
}
91+
}
92+
93+
impl Dag {
94+
/// Decode a Simplicity DAG from bytes.
95+
pub fn decode(bytes: &[u8]) -> Result<Self, Error> {
96+
let mut bitstream = Bitstream::from(bytes);
97+
let mut dag: *mut PrivateDagNode = std::ptr::null_mut();
98+
99+
unsafe {
100+
let len =
101+
Error::get_result(decodeMallocDag(&mut dag, std::ptr::null(), &mut bitstream))?;
102+
103+
if dag.is_null() {
104+
Err(Error::Malloc)
105+
} else {
106+
Ok(Dag {
107+
first: dag,
108+
len: len as usize,
109+
})
110+
}
111+
}
112+
}
113+
114+
/// Return the CMR of the DAG.
115+
pub fn cmr(&self) -> [u8; 32] {
116+
unsafe { util::into_u8_merkle_root(&(*self.root_node()).cmr) }
117+
}
118+
119+
/// Return the root node of the DAG.
120+
unsafe fn root_node(&self) -> *const PrivateDagNode {
121+
self.get(self.len - 1)
122+
}
123+
124+
// TODO: Add notion of `DagNode<'a>` that is spawned by &'a self
125+
// and that enables read-only access to node fields
126+
/// Return the node at the given `index` in the DAG.
127+
/// Panics if `index` is out of bounds.
128+
unsafe fn get(&self, index: usize) -> *const PrivateDagNode {
129+
self.first.add(index)
130+
}
131+
}
132+
133+
impl Drop for Dag {
134+
fn drop(&mut self) {
135+
unsafe {
136+
libc::free(self.first as *mut libc::c_void);
137+
}
138+
}
139+
}
140+
141+
#[cfg(test)]
142+
mod test {
143+
use super::*;
144+
use crate::test::SCHNORR0;
145+
146+
#[test]
147+
fn decode_cmr() {
148+
let bytes = SCHNORR0.bytes;
149+
let dag = Dag::decode(bytes).expect("decoding");
150+
assert_eq!(SCHNORR0.cmr(), dag.cmr());
151+
}
152+
}

simplicity-sys/src/error.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Simplicity Bindings
2+
// Written in 2022 by
3+
// Christian Lewe <[email protected]>
4+
//
5+
// To the extent possible under law, the author(s) have dedicated all
6+
// copyright and related and neighboring rights to this software to
7+
// the public domain worldwide. This software is distributed without
8+
// any warranty.
9+
//
10+
// You should have received a copy of the CC0 Public Domain Dedication
11+
// along with this software.
12+
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
13+
//
14+
15+
/// Simplicity error.
16+
#[derive(Debug)]
17+
pub enum Error {
18+
Malloc,
19+
BitstreamEOF,
20+
BitstreamError,
21+
DataOutOfRange,
22+
NotYetImplemented,
23+
DataOutOfOrder,
24+
FailCode,
25+
StopCode,
26+
Hidden,
27+
}
28+
29+
impl Error {
30+
pub(crate) fn get_result(ret: i32) -> Result<i32, Error> {
31+
match ret {
32+
i if i >= 0 => Ok(i),
33+
-1 => Err(Error::Malloc),
34+
-2 => Err(Error::BitstreamEOF),
35+
-3 => Err(Error::BitstreamError),
36+
-4 => Err(Error::DataOutOfRange),
37+
-5 => Err(Error::NotYetImplemented),
38+
-6 => Err(Error::DataOutOfOrder),
39+
-8 => Err(Error::FailCode),
40+
-10 => Err(Error::StopCode),
41+
-12 => Err(Error::Hidden),
42+
i => panic!("Unexpected error code: {}", i),
43+
}
44+
}
45+
}

simplicity-sys/src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,10 @@
1111
// along with this software.
1212
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
1313
//
14+
15+
mod bitstream;
16+
mod bitstring;
17+
pub mod dag;
18+
pub mod error;
19+
pub mod test;
20+
mod util;

simplicity-sys/src/test.rs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// Simplicity Bindings
2+
// Written in 2022 by
3+
// Christian Lewe <[email protected]>
4+
//
5+
// To the extent possible under law, the author(s) have dedicated all
6+
// copyright and related and neighboring rights to this software to
7+
// the public domain worldwide. This software is distributed without
8+
// any warranty.
9+
//
10+
// You should have received a copy of the CC0 Public Domain Dedication
11+
// along with this software.
12+
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
13+
//
14+
15+
use crate::util;
16+
17+
extern "C" {
18+
static schnorr0: [u8; 257];
19+
static schnorr0_cmr: [u32; 8];
20+
static schnorr0_imr: [u32; 8];
21+
22+
static schnorr6: [u8; 405];
23+
static schnorr6_cmr: [u32; 8];
24+
static schnorr6_imr: [u32; 8];
25+
26+
static hashBlock: [u8; 3259];
27+
static hashBlock_cmr: [u32; 8];
28+
static hashBlock_imr: [u32; 8];
29+
30+
static elementsCheckSigHashAllTx1: [u8; 1151];
31+
static elementsCheckSigHashAllTx1_cmr: [u32; 8];
32+
static elementsCheckSigHashAllTx1_imr: [u32; 8];
33+
}
34+
35+
/// Simplicity program with bytes, CMR and IMR for testing.
36+
pub struct TestProgram {
37+
pub bytes: &'static [u8],
38+
pub(crate) cmr: &'static [u32; 8],
39+
pub(crate) imr: &'static [u32; 8],
40+
}
41+
42+
impl TestProgram {
43+
/// Return the CMR of the given program.
44+
pub fn cmr(&self) -> [u8; 32] {
45+
util::into_u8_merkle_root(self.cmr)
46+
}
47+
48+
/// Return the IMR of the given program.
49+
pub fn imr(&self) -> [u8; 32] {
50+
util::into_u8_merkle_root(self.imr)
51+
}
52+
}
53+
54+
pub static SCHNORR0: TestProgram = unsafe {
55+
TestProgram {
56+
bytes: &schnorr0,
57+
cmr: &schnorr0_cmr,
58+
imr: &schnorr0_imr,
59+
}
60+
};
61+
62+
pub static SCHNORR6: TestProgram = unsafe {
63+
TestProgram {
64+
bytes: &schnorr6,
65+
cmr: &schnorr6_cmr,
66+
imr: &schnorr6_imr,
67+
}
68+
};
69+
70+
pub static HASHBLOCK: TestProgram = unsafe {
71+
TestProgram {
72+
bytes: &hashBlock,
73+
cmr: &hashBlock_cmr,
74+
imr: &hashBlock_imr,
75+
}
76+
};
77+
78+
pub static ELEMENTS_CHECK_SIGHASH_ALL_TX1: TestProgram = unsafe {
79+
TestProgram {
80+
bytes: &elementsCheckSigHashAllTx1,
81+
cmr: &elementsCheckSigHashAllTx1_cmr,
82+
imr: &elementsCheckSigHashAllTx1_imr,
83+
}
84+
};

simplicity-sys/src/util.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
pub(crate) fn into_u8_merkle_root(u32_merkle_root: &[u32; 8]) -> [u8; 32] {
2+
let mut u8_merkle_root = [0; 32];
3+
4+
for i in 0..8 {
5+
u8_merkle_root[i * 4..i * 4 + 4].copy_from_slice(&u32_merkle_root[i].to_be_bytes());
6+
}
7+
8+
u8_merkle_root
9+
}

0 commit comments

Comments
 (0)