Skip to content

Commit 0819459

Browse files
Merge commit 'a60e1366a63bd05f0fa1199d6f15b21acc32f90e' as 'src/simplicity'
2 parents eb83661 + a60e136 commit 0819459

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+35454
-0
lines changed

src/simplicity/Makefile

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
OBJS := bitstream.o dag.o deserialize.o eval.o frame.o jets.o jets-secp256k1.o rsort.o sha256.o type.o typeInference.o primitive/elements/env.o primitive/elements/exec.o primitive/elements/ops.o primitive/elements/jets.o primitive/elements/primitive.o
2+
TEST_OBJS := test.o hashBlock.o schnorr0.o schnorr6.o primitive/elements/checkSigHashAllTx1.o
3+
4+
# From https://fastcompression.blogspot.com/2019/01/compiler-warnings.html
5+
CWARN := -Werror -Wall -Wextra -Wcast-qual -Wcast-align -Wstrict-aliasing -Wpointer-arith -Winit-self -Wshadow -Wswitch-enum -Wstrict-prototypes -Wmissing-prototypes -Wredundant-decls -Wfloat-equal -Wundef -Wconversion
6+
7+
ifneq ($(doCheck), 1)
8+
CPPFLAGS := $(CPPFLAGS) -DNDEBUG
9+
endif
10+
11+
CFLAGS := -I include
12+
13+
# libsecp256k1 is full of conversion warnings, so we compile jets-secp256k1.c separately.
14+
jets-secp256k1.o: jets-secp256k1.c
15+
$(CC) -c $(CFLAGS) $(CWARN) -Wno-conversion $(CPPFLAGS) -o $@ $<
16+
17+
primitive/elements/jets.o: primitive/elements/jets.c
18+
$(CC) -c $(CFLAGS) $(CWARN) -Wno-switch-enum -Wswitch $(CPPFLAGS) -o $@ $<
19+
20+
%.o: %.c
21+
$(CC) -c $(CFLAGS) $(CWARN) $(CPPFLAGS) -o $@ $<
22+
23+
libElementsSimplicity.a: $(OBJS)
24+
ar rcs $@ $^
25+
26+
test: $(TEST_OBJS) libElementsSimplicity.a
27+
$(CC) $^ -o $@ $(LDFLAGS)
28+
29+
install: libElementsSimplicity.a
30+
mkdir -p $(out)/lib
31+
cp $^ $(out)/lib/
32+
cp -R include $(out)/include
33+
34+
check: test
35+
./test
36+
37+
clean:
38+
-rm -f test libElementsSimplicity.a $(TEST_OBJS) $(OBJS)
39+
40+
.PHONY: install check clean

src/simplicity/bitstream.c

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
#include "bitstream.h"
2+
3+
#include <assert.h>
4+
#include <limits.h>
5+
#include <stdlib.h>
6+
7+
/* Closes a bitstream by consuming all remaining bits.
8+
* Returns false if CHAR_BIT or more bits remain in the stream or if any remaining bits are non-zero.
9+
*
10+
* Precondition: NULL != stream
11+
*/
12+
bool closeBitstream(bitstream* stream) {
13+
if (1 < stream->len) return false; /* If there is more than one byte remaining. */
14+
if (1 == stream->len && /* If there is one byte remaining */
15+
(0 == stream->offset || /* and either no bits have been consumed */
16+
0 != (*stream->arr & (UCHAR_MAX >> stream->offset)) /* or any of the unconsumed bits are non-zero */
17+
)) return false;
18+
/* Otherwise there are either 0 bits remaining or there are between 1 and CHAR_BITS-1 bits remaining and they are all zero. */
19+
*stream = (bitstream){0};
20+
return true;
21+
}
22+
23+
/* Fetches up to 31 bits from 'stream' as the 'n' least significant bits of return value.
24+
* The 'n' bits are set from the MSB to the LSB.
25+
* Returns 'SIMPLICITY_ERR_BITSTREAM_EOF' if not enough bits are available.
26+
*
27+
* Precondition: 0 <= n < 32
28+
* NULL != stream
29+
*/
30+
int32_t readNBits(int n, bitstream* stream) {
31+
assert(0 <= n && n < 32);
32+
33+
uint32_t result = 0;
34+
while (CHAR_BIT <= stream->offset + n) {
35+
if (!stream->len) return SIMPLICITY_ERR_BITSTREAM_EOF;
36+
n -= CHAR_BIT - stream->offset;
37+
result |= (uint32_t)(*stream->arr & (UCHAR_MAX >> stream->offset)) << n;
38+
stream->arr++; stream->len--; stream->offset = 0;
39+
}
40+
/* stream->offset + n < CHAR_BIT */
41+
if (n) {
42+
if (!stream->len) return SIMPLICITY_ERR_BITSTREAM_EOF;
43+
stream->offset += (unsigned char)n;
44+
result |= (*stream->arr >> (CHAR_BIT - stream->offset)) & ((UCHAR_MAX >> (CHAR_BIT - n)));
45+
}
46+
return (int32_t)result;
47+
}
48+
/* Decode an encoded bitstring up to length 1.
49+
* If successful returns the length of the bitstring and 'result' contains the decoded bits.
50+
* The decoded bitstring is stored in the LSBs of 'result', with the LSB being the last bit decoded.
51+
* Any remaining bits in 'result' are reset to 0.
52+
* If the decoded bitstring would be too long 'SIMPLICITY_ERR_DATA_OUT_OF_RANGE' is returned ('result' may be modified).
53+
* If more bits are needed than available in the 'stream', 'SIMPLICITY_ERR_BITSTRING_EOF' is returned ('result' may be modified).
54+
* If an I/O error occurs when reading from the 'stream', 'SIMPLICITY_ERR_BISTRING_ERROR' is returned ('result' may be modified).
55+
*
56+
* Precondition: NULL != result
57+
* NULL != stream
58+
*/
59+
static int32_t decodeUpto1Bit(int32_t* result, bitstream* stream) {
60+
*result = read1Bit(stream);
61+
if (*result <= 0) return *result;
62+
63+
*result = read1Bit(stream);
64+
if (*result < 0) return *result;
65+
if (0 != *result) return SIMPLICITY_ERR_DATA_OUT_OF_RANGE;
66+
67+
*result = read1Bit(stream);
68+
if (*result < 0) return *result;
69+
return 1;
70+
}
71+
72+
/* Decode an encoded number between 1 and 3 inclusive.
73+
* When successful returns the decoded result.
74+
* If the decoded value would be too large, 'SIMPLICITY_ERR_DATA_OUT_OF_RANGE' is returned.
75+
* If more bits are needed than available in the 'stream', 'SIMPLICITY_ERR_BITSTRING_EOF' is returned.
76+
* If an I/O error occurs when reading from the 'stream', 'SIMPLICITY_ERR_BISTRING_ERROR' is returned.
77+
*
78+
* Precondition: NULL != stream
79+
*/
80+
static int32_t decodeUpto3(bitstream* stream) {
81+
int32_t result;
82+
int32_t len = decodeUpto1Bit(&result, stream);
83+
if (len < 0) return len;
84+
result |= 1 << len;
85+
return result;
86+
}
87+
88+
/* Decode an encoded bitstring up to length 3.
89+
* If successful returns the length of the bitstring and 'result' contains the decoded bits.
90+
* The decoded bitstring is stored in the LSBs of 'result', with the LSB being the last bit decoded.
91+
* Any remaining bits in 'result' are reset to 0.
92+
* If the decoded bitstring would be too long 'SIMPLICITY_ERR_DATA_OUT_OF_RANGE' is returned ('result' may be modified).
93+
* If more bits are needed than available in the 'stream', 'SIMPLICITY_ERR_BITSTRING_EOF' is returned ('result' may be modified).
94+
* If an I/O error occurs when reading from the 'stream', 'SIMPLICITY_ERR_BISTRING_ERROR' is returned ('result' may be modified).
95+
*
96+
* Precondition: NULL != result
97+
* NULL != stream
98+
*/
99+
static int32_t decodeUpto3Bits(int32_t* result, bitstream* stream) {
100+
int32_t bit = read1Bit(stream);
101+
if (bit < 0) return bit;
102+
103+
*result = 0;
104+
if (0 == bit) {
105+
return 0;
106+
} else {
107+
int32_t n = decodeUpto3(stream);
108+
if (0 <= n) {
109+
*result = readNBits(n, stream);
110+
if (*result < 0) return *result;
111+
}
112+
return n;
113+
}
114+
}
115+
116+
/* Decode an encoded number between 1 and 15 inclusive.
117+
* When successful returns the decoded result.
118+
* If the decoded value would be too large, 'SIMPLICITY_ERR_DATA_OUT_OF_RANGE' is returned.
119+
* If more bits are needed than available in the 'stream', 'SIMPLICITY_ERR_BITSTRING_EOF' is returned.
120+
* If an I/O error occurs when reading from the 'stream', 'SIMPLICITY_ERR_BISTRING_ERROR' is returned.
121+
*
122+
* Precondition: NULL != stream
123+
*/
124+
static int32_t decodeUpto15(bitstream* stream) {
125+
int32_t result;
126+
int32_t len = decodeUpto3Bits(&result, stream);
127+
if (len < 0) return len;
128+
result |= 1 << len;
129+
return result;
130+
}
131+
132+
/* Decode an encoded bitstring up to length 15.
133+
* If successful returns the length of the bitstring and 'result' contains the decoded bits.
134+
* The decoded bitstring is stored in the LSBs of 'result', with the LSB being the last bit decoded.
135+
* Any remaining bits in 'result' are reset to 0.
136+
* If the decoded bitstring would be too long 'SIMPLICITY_ERR_DATA_OUT_OF_RANGE' is returned ('result' may be modified).
137+
* If more bits are needed than available in the 'stream', 'SIMPLICITY_ERR_BITSTRING_EOF' is returned ('result' may be modified).
138+
* If an I/O error occurs when reading from the 'stream', 'SIMPLICITY_ERR_BISTRING_ERROR' is returned ('result' may be modified).
139+
*
140+
* Precondition: NULL != result
141+
* NULL != stream
142+
*/
143+
static int32_t decodeUpto15Bits(int32_t* result, bitstream* stream) {
144+
int32_t bit = read1Bit(stream);
145+
if (bit < 0) return bit;
146+
147+
*result = 0;
148+
if (0 == bit) {
149+
return 0;
150+
} else {
151+
int32_t n = decodeUpto15(stream);
152+
if (0 <= n) {
153+
*result = readNBits(n, stream);
154+
if (*result < 0) return *result;
155+
}
156+
return n;
157+
}
158+
}
159+
160+
/* Decode an encoded number between 1 and 65535 inclusive.
161+
* When successful returns the decoded result.
162+
* If the decoded value would be too large, 'SIMPLICITY_ERR_DATA_OUT_OF_RANGE' is returned.
163+
* If more bits are needed than available in the 'stream', 'SIMPLICITY_ERR_BITSTRING_EOF' is returned.
164+
* If an I/O error occurs when reading from the 'stream', 'SIMPLICITY_ERR_BISTRING_ERROR' is returned.
165+
*
166+
* Precondition: NULL != stream
167+
*/
168+
static int32_t decodeUpto65535(bitstream* stream) {
169+
int32_t result;
170+
int32_t len = decodeUpto15Bits(&result, stream);
171+
if (len < 0) return len;
172+
result |= 1 << len;
173+
return result;
174+
}
175+
176+
/* Decode an encoded number between 1 and 2^31 - 1 inclusive.
177+
* When successful returns the decoded result.
178+
* If the decoded value would be too large, 'SIMPLICITY_ERR_DATA_OUT_OF_RANGE' is returned.
179+
* If more bits are needed than available in the 'stream', 'SIMPLICITY_ERR_BITSTRING_EOF' is returned.
180+
* If an I/O error occurs when reading from the 'stream', 'SIMPLICITY_ERR_BISTRING_ERROR' is returned.
181+
*
182+
* Precondition: NULL != stream
183+
*/
184+
int32_t decodeUptoMaxInt(bitstream* stream) {
185+
int32_t bit = read1Bit(stream);
186+
if (bit < 0) return bit;
187+
if (0 == bit) {
188+
return 1;
189+
} else {
190+
int32_t n = decodeUpto65535(stream);
191+
if (n < 0) return n;
192+
if (30 < n) return SIMPLICITY_ERR_DATA_OUT_OF_RANGE;
193+
{
194+
int32_t result = readNBits(n, stream);
195+
if (result < 0) return result;
196+
return ((1 << n) | result);
197+
}
198+
}
199+
}
200+
201+
/* Fills a 'bitstring' containing 'n' bits from 'stream'.
202+
* Returns 'SIMPLICITY_ERR_BITSTREAM_EOF' if not enough bits are available.
203+
* If successful, '*result' is set to a bitstring with 'n' bits read from 'stream' and 0 is returned.
204+
*
205+
* If an error is returned '*result' might be modified.
206+
*
207+
* Precondition: NULL != result
208+
* n <= 2^31
209+
* NULL != stream
210+
*/
211+
int32_t readBitstring(bitstring* result, size_t n, bitstream* stream) {
212+
static_assert(0x8000u + 2*(CHAR_BIT - 1) <= SIZE_MAX, "size_t needs to be at least 32-bits");
213+
assert(n <= 0x8000u);
214+
size_t total_offset = n + stream->offset;
215+
/* |= stream->len * CHAR_BIT < total_offset iff stream->len < (total_offset + (CHAR_BIT - 1)) / CHAR_BIT */
216+
if (stream->len < (total_offset + (CHAR_BIT - 1)) / CHAR_BIT) return SIMPLICITY_ERR_BITSTREAM_EOF;
217+
/* total_offset <= stream->len * CHAR_BIT */
218+
*result = (bitstring)
219+
{ .arr = stream->arr
220+
, .offset = stream->offset
221+
, .len = n
222+
};
223+
{
224+
size_t delta = total_offset / CHAR_BIT;
225+
stream->arr += delta; stream->len -= delta;
226+
stream->offset = total_offset % CHAR_BIT;
227+
/* Note that if 0 == stream->len then 0 == stream->offset. */
228+
}
229+
return 0;
230+
}

src/simplicity/bitstream.h

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/* This module provides functions for initializing and reading from a stream of bits from a 'FILE'. */
2+
#ifndef SIMPLICITY_BITSTREAM_H
3+
#define SIMPLICITY_BITSTREAM_H
4+
5+
#include <stdio.h>
6+
#include <stdint.h>
7+
#include <stdbool.h>
8+
#include "bitstring.h"
9+
#include "errorCodes.h"
10+
11+
/* :TODO: consider adding an 'invalid' state that can be set when parsing has failed and should not be resumed. */
12+
/* Datatype representing a bit stream.
13+
* Bits are streamed from MSB to LSB.
14+
*
15+
* Invariant: unsigned char arr[len]
16+
* 0 <= offset < CHAR_BIT
17+
* 0 == len implies 0 == offset
18+
*/
19+
typedef struct bitstream {
20+
const unsigned char *arr; /* Underlying byte array */
21+
size_t len; /* Length of arr (in bytes) */
22+
unsigned char offset; /* Number of bits parsed from the beginning of arr */
23+
} bitstream;
24+
25+
/* Initialize a bit stream, 'stream', from a given byte array.
26+
* Precondition: unsigned char arr[len];
27+
*/
28+
static inline bitstream initializeBitstream(const unsigned char* arr, size_t len) {
29+
return (bitstream){ .arr = arr, .len = len };
30+
}
31+
32+
/* Closes a bitstream by consuming all remaining bits.
33+
* Returns false if CHAR_BIT or more bits remain in the stream or if any remaining bits are non-zero.
34+
*
35+
* Precondition: NULL != stream
36+
*/
37+
bool closeBitstream(bitstream* stream);
38+
39+
/* Fetches up to 31 bits from 'stream' as the 'n' least significant bits of return value.
40+
* The 'n' bits are set from the MSB to the LSB.
41+
* Returns 'SIMPLICITY_ERR_BITSTREAM_EOF' if not enough bits are available.
42+
*
43+
* Precondition: 0 <= n < 32
44+
* NULL != stream
45+
*/
46+
int32_t readNBits(int n, bitstream* stream);
47+
48+
/* Returns one bit from 'stream', 0 or 1.
49+
* Returns 'SIMPLICITY_ERR_BITSTREAM_EOF' if no bits are available.
50+
*
51+
* Precondition: NULL != stream
52+
*/
53+
static inline int32_t read1Bit(bitstream* stream) {
54+
return readNBits(1, stream);
55+
}
56+
57+
/* Decode an encoded number between 1 and 2^31 - 1 inclusive.
58+
* When successful returns the decoded result.
59+
* If the decoded value would be too large, 'SIMPLICITY_ERR_DATA_OUT_OF_RANGE' is returned.
60+
* If more bits are needed than available in the 'stream', 'SIMPLICITY_ERR_BITSTRING_EOF' is returned.
61+
* If an I/O error occurs when reading from the 'stream', 'SIMPLICITY_ERR_BISTRING_ERROR' is returned.
62+
*
63+
* Precondition: NULL != stream
64+
*/
65+
int32_t decodeUptoMaxInt(bitstream* stream);
66+
67+
/* Fills a 'bitstring' containing 'n' bits from 'stream'.
68+
* Returns 'SIMPLICITY_ERR_BITSTREAM_EOF' if not enough bits are available.
69+
* If successful, '*result' is set to a bitstring with 'n' bits read from 'stream' and 0 is returned.
70+
*
71+
* If an error is returned '*result' might be modified.
72+
*
73+
* Precondition: NULL != result
74+
* n <= 2^31
75+
* NULL != stream
76+
*/
77+
int32_t readBitstring(bitstring* result, size_t n, bitstream* stream);
78+
#endif

src/simplicity/bitstring.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/* This modules defines a structure representing bit strings. */
2+
#ifndef SIMPLICITY_BITSTRING_H
3+
#define SIMPLICITY_BITSTRING_H
4+
5+
#include <assert.h>
6+
#include <limits.h>
7+
#include <stdbool.h>
8+
9+
/* Represents a bitstring of length 'len' bits using an array of unsigned char.
10+
* The bit at index 'n', where 0 <= 'n' < 'len', is located at bit '1 << (CHAR_BIT - 1 - (offset + n) % CHAR_BIT)' of
11+
* array element 'arr[(offset + n) / CHAR_BIT]'.
12+
* Other bits in the array may be any value.
13+
*
14+
* Invariant: len <= 2^31
15+
* offset + length <= SIZE_MAX
16+
* 0 < len implies unsigned char arr[(offset + len - 1) / CHAR_BIT + 1];
17+
*/
18+
typedef struct bitstring {
19+
const unsigned char* arr;
20+
size_t len;
21+
size_t offset;
22+
} bitstring;
23+
24+
/* Return the nth bit from a bitstring.
25+
*
26+
* Precondition: NULL != s
27+
* n < s->len;
28+
*/
29+
static inline bool getBit(const bitstring *s, size_t n) {
30+
size_t total_offset = s->offset + n;
31+
assert(n < s->len);
32+
return 1 & (s->arr[total_offset / CHAR_BIT] >> (CHAR_BIT - 1 - (total_offset % CHAR_BIT)));
33+
}
34+
35+
#endif

0 commit comments

Comments
 (0)