iodine 0.4.19 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of iodine might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.travis.yml +1 -2
- data/CHANGELOG.md +22 -0
- data/LIMITS.md +19 -9
- data/README.md +92 -77
- data/SPEC-PubSub-Draft.md +113 -0
- data/SPEC-Websocket-Draft.md +127 -143
- data/bin/http-hello +0 -1
- data/bin/raw-rbhttp +1 -1
- data/bin/raw_broadcast +8 -10
- data/bin/updated api +2 -2
- data/bin/ws-broadcast +2 -4
- data/bin/ws-echo +2 -2
- data/examples/config.ru +13 -13
- data/examples/echo.ru +5 -6
- data/examples/hello.ru +2 -3
- data/examples/info.md +316 -0
- data/examples/pubsub_engine.ru +81 -0
- data/examples/redis.ru +9 -9
- data/examples/shootout.ru +45 -11
- data/ext/iodine/defer.c +194 -297
- data/ext/iodine/defer.h +61 -53
- data/ext/iodine/evio.c +0 -260
- data/ext/iodine/evio.h +50 -22
- data/ext/iodine/evio_callbacks.c +26 -0
- data/ext/iodine/evio_epoll.c +251 -0
- data/ext/iodine/evio_kqueue.c +193 -0
- data/ext/iodine/extconf.rb +1 -1
- data/ext/iodine/facil.c +1420 -542
- data/ext/iodine/facil.h +151 -64
- data/ext/iodine/fio_ary.h +418 -0
- data/ext/iodine/{base64.c → fio_base64.c} +33 -24
- data/ext/iodine/{base64.h → fio_base64.h} +6 -7
- data/ext/iodine/{fio_cli_helper.c → fio_cli.c} +77 -58
- data/ext/iodine/{fio_cli_helper.h → fio_cli.h} +9 -4
- data/ext/iodine/fio_hashmap.h +759 -0
- data/ext/iodine/fio_json_parser.h +651 -0
- data/ext/iodine/fio_llist.h +257 -0
- data/ext/iodine/fio_mem.c +672 -0
- data/ext/iodine/fio_mem.h +140 -0
- data/ext/iodine/fio_random.c +248 -0
- data/ext/iodine/{random.h → fio_random.h} +11 -14
- data/ext/iodine/{sha1.c → fio_sha1.c} +28 -24
- data/ext/iodine/{sha1.h → fio_sha1.h} +38 -16
- data/ext/iodine/{sha2.c → fio_sha2.c} +66 -49
- data/ext/iodine/{sha2.h → fio_sha2.h} +57 -26
- data/ext/iodine/{fiobj_internal.c → fio_siphash.c} +9 -90
- data/ext/iodine/fio_siphash.h +18 -0
- data/ext/iodine/fio_tmpfile.h +38 -0
- data/ext/iodine/fiobj.h +24 -7
- data/ext/iodine/fiobj4sock.h +23 -0
- data/ext/iodine/fiobj_ary.c +143 -226
- data/ext/iodine/fiobj_ary.h +17 -16
- data/ext/iodine/fiobj_data.c +1160 -0
- data/ext/iodine/fiobj_data.h +164 -0
- data/ext/iodine/fiobj_hash.c +298 -406
- data/ext/iodine/fiobj_hash.h +101 -54
- data/ext/iodine/fiobj_json.c +478 -601
- data/ext/iodine/fiobj_json.h +34 -9
- data/ext/iodine/fiobj_numbers.c +383 -51
- data/ext/iodine/fiobj_numbers.h +87 -11
- data/ext/iodine/fiobj_str.c +423 -184
- data/ext/iodine/fiobj_str.h +81 -32
- data/ext/iodine/fiobject.c +273 -522
- data/ext/iodine/fiobject.h +477 -112
- data/ext/iodine/http.c +2243 -83
- data/ext/iodine/http.h +842 -121
- data/ext/iodine/http1.c +810 -385
- data/ext/iodine/http1.h +16 -39
- data/ext/iodine/http1_parser.c +146 -74
- data/ext/iodine/http1_parser.h +15 -4
- data/ext/iodine/http_internal.c +1258 -0
- data/ext/iodine/http_internal.h +226 -0
- data/ext/iodine/http_mime_parser.h +341 -0
- data/ext/iodine/iodine.c +86 -68
- data/ext/iodine/iodine.h +26 -11
- data/ext/iodine/iodine_helpers.c +8 -7
- data/ext/iodine/iodine_http.c +487 -324
- data/ext/iodine/iodine_json.c +304 -0
- data/ext/iodine/iodine_json.h +6 -0
- data/ext/iodine/iodine_protocol.c +107 -45
- data/ext/iodine/iodine_pubsub.c +526 -225
- data/ext/iodine/iodine_pubsub.h +10 -0
- data/ext/iodine/iodine_websockets.c +268 -510
- data/ext/iodine/iodine_websockets.h +2 -4
- data/ext/iodine/pubsub.c +726 -432
- data/ext/iodine/pubsub.h +85 -103
- data/ext/iodine/rb-call.c +4 -4
- data/ext/iodine/rb-defer.c +46 -22
- data/ext/iodine/rb-fiobj2rb.h +117 -0
- data/ext/iodine/rb-rack-io.c +73 -238
- data/ext/iodine/rb-rack-io.h +2 -2
- data/ext/iodine/rb-registry.c +35 -93
- data/ext/iodine/rb-registry.h +1 -0
- data/ext/iodine/redis_engine.c +742 -304
- data/ext/iodine/redis_engine.h +42 -39
- data/ext/iodine/resp_parser.h +311 -0
- data/ext/iodine/sock.c +627 -490
- data/ext/iodine/sock.h +345 -297
- data/ext/iodine/spnlock.inc +15 -4
- data/ext/iodine/websocket_parser.h +16 -20
- data/ext/iodine/websockets.c +188 -257
- data/ext/iodine/websockets.h +24 -133
- data/lib/iodine.rb +52 -7
- data/lib/iodine/cli.rb +6 -24
- data/lib/iodine/json.rb +40 -0
- data/lib/iodine/version.rb +1 -1
- data/lib/iodine/websocket.rb +5 -3
- data/lib/rack/handler/iodine.rb +58 -13
- metadata +38 -48
- data/bin/ws-shootout +0 -107
- data/examples/broadcast.ru +0 -56
- data/ext/iodine/bscrypt-common.h +0 -116
- data/ext/iodine/bscrypt.h +0 -49
- data/ext/iodine/fio2resp.c +0 -60
- data/ext/iodine/fio2resp.h +0 -51
- data/ext/iodine/fio_dict.c +0 -446
- data/ext/iodine/fio_dict.h +0 -99
- data/ext/iodine/fio_hash_table.h +0 -370
- data/ext/iodine/fio_list.h +0 -111
- data/ext/iodine/fiobj_internal.h +0 -280
- data/ext/iodine/fiobj_primitives.c +0 -131
- data/ext/iodine/fiobj_primitives.h +0 -55
- data/ext/iodine/fiobj_sym.c +0 -135
- data/ext/iodine/fiobj_sym.h +0 -60
- data/ext/iodine/hex.c +0 -124
- data/ext/iodine/hex.h +0 -70
- data/ext/iodine/http1_request.c +0 -81
- data/ext/iodine/http1_request.h +0 -58
- data/ext/iodine/http1_response.c +0 -417
- data/ext/iodine/http1_response.h +0 -95
- data/ext/iodine/http_request.c +0 -111
- data/ext/iodine/http_request.h +0 -102
- data/ext/iodine/http_response.c +0 -1703
- data/ext/iodine/http_response.h +0 -250
- data/ext/iodine/misc.c +0 -182
- data/ext/iodine/misc.h +0 -74
- data/ext/iodine/random.c +0 -208
- data/ext/iodine/redis_connection.c +0 -278
- data/ext/iodine/redis_connection.h +0 -86
- data/ext/iodine/resp.c +0 -842
- data/ext/iodine/resp.h +0 -261
- data/ext/iodine/siphash.c +0 -154
- data/ext/iodine/siphash.h +0 -22
- data/ext/iodine/xor-crypt.c +0 -193
- data/ext/iodine/xor-crypt.h +0 -107
data/ext/iodine/resp.h
DELETED
@@ -1,261 +0,0 @@
|
|
1
|
-
/*
|
2
|
-
Copyright: Boaz segev, 2017
|
3
|
-
License: MIT except for any non-public-domain algorithms (none that I'm aware
|
4
|
-
of), which might be subject to their own licenses.
|
5
|
-
|
6
|
-
Feel free to copy, use and enjoy in accordance with to the license(s).
|
7
|
-
*/
|
8
|
-
#ifndef H_RESP_PARSER_H
|
9
|
-
/**
|
10
|
-
This is a neive implementation of the RESP protocol for Redis.
|
11
|
-
*/
|
12
|
-
#define H_RESP_PARSER_H
|
13
|
-
|
14
|
-
#include <stdint.h>
|
15
|
-
#include <stdlib.h>
|
16
|
-
|
17
|
-
/* support C++ */
|
18
|
-
#ifdef __cplusplus
|
19
|
-
extern "C" {
|
20
|
-
#endif
|
21
|
-
|
22
|
-
/** The RESP Parser Type */
|
23
|
-
typedef struct resp_parser_s *resp_parser_pt;
|
24
|
-
|
25
|
-
/* *****************************************************************************
|
26
|
-
RESP types and objects (Arrays, Strings & Integers)
|
27
|
-
***************************************************************************** */
|
28
|
-
|
29
|
-
enum resp_type_enum {
|
30
|
-
/** A simple flag object object (`resp_object_s`) for NULL. */
|
31
|
-
RESP_NULL = 0,
|
32
|
-
/** A simple flag object object (`resp_object_s`) for OK. */
|
33
|
-
RESP_OK = 1,
|
34
|
-
/** A String object (`resp_string_s`) that indicates an error. */
|
35
|
-
RESP_ERR = (2 + 8),
|
36
|
-
/** A Number object object (`resp_number_s`). */
|
37
|
-
RESP_NUMBER = 4,
|
38
|
-
/** A String object (`resp_string_s`). */
|
39
|
-
RESP_STRING = 8,
|
40
|
-
/** An Array object object (`resp_array_s`). */
|
41
|
-
RESP_ARRAY = 16,
|
42
|
-
/**
|
43
|
-
* A specific Array object object (`resp_array_s`) for Pub/Sub semantics.
|
44
|
-
*
|
45
|
-
* This is more of a hint than a decree, sometimes pubsub semantics are
|
46
|
-
* misleading.
|
47
|
-
*/
|
48
|
-
RESP_PUBSUB = (32 + 16),
|
49
|
-
};
|
50
|
-
|
51
|
-
/** a simple emtpy object type, used for RESP_NULL and RESP_OK */
|
52
|
-
typedef struct { enum resp_type_enum type; } resp_object_s;
|
53
|
-
|
54
|
-
/** The RESP_ARRAY and RESP_PUBSUB types */
|
55
|
-
typedef struct {
|
56
|
-
enum resp_type_enum type;
|
57
|
-
size_t len;
|
58
|
-
size_t pos; /** allows simple iteration. */
|
59
|
-
resp_object_s *array[];
|
60
|
-
} resp_array_s;
|
61
|
-
|
62
|
-
/** The RESP_STRING and RESP_ERR types */
|
63
|
-
typedef struct {
|
64
|
-
enum resp_type_enum type;
|
65
|
-
size_t len;
|
66
|
-
uint8_t string[];
|
67
|
-
} resp_string_s;
|
68
|
-
|
69
|
-
/** The RESP_NUMBER type */
|
70
|
-
typedef struct {
|
71
|
-
enum resp_type_enum type;
|
72
|
-
int64_t number;
|
73
|
-
} resp_number_s;
|
74
|
-
|
75
|
-
#define resp_obj2arr(obj) \
|
76
|
-
((resp_array_s *)((obj)->type == RESP_ARRAY || (obj)->type == RESP_PUBSUB \
|
77
|
-
? (obj) \
|
78
|
-
: NULL))
|
79
|
-
#define resp_obj2str(obj) \
|
80
|
-
((resp_string_s *)((obj)->type == RESP_STRING || (obj)->type == RESP_ERR \
|
81
|
-
? (obj) \
|
82
|
-
: NULL))
|
83
|
-
#define resp_obj2num(obj) \
|
84
|
-
((resp_number_s *)((obj)->type == RESP_NUMBER ? (obj) : NULL))
|
85
|
-
|
86
|
-
/** Allocates an RESP NULL objcet. Remeber to free when done. */
|
87
|
-
resp_object_s *resp_nil2obj(void);
|
88
|
-
|
89
|
-
/** Allocates an RESP OK objcet. Remeber to free when done. */
|
90
|
-
resp_object_s *resp_OK2obj(void);
|
91
|
-
|
92
|
-
/** Allocates an RESP Error objcet. Remeber to free when done. */
|
93
|
-
resp_object_s *resp_err2obj(const void *msg, size_t len);
|
94
|
-
|
95
|
-
/** Allocates an RESP Number objcet. Remeber to free when done. */
|
96
|
-
resp_object_s *resp_num2obj(uint64_t num);
|
97
|
-
|
98
|
-
/** Allocates an RESP String objcet. Remeber to free when done. */
|
99
|
-
resp_object_s *resp_str2obj(const void *str, size_t len);
|
100
|
-
|
101
|
-
/**
|
102
|
-
*Allocates an RESP Array objcet. Remeber to free when done (freeing an array
|
103
|
-
*frees it's children automatically).
|
104
|
-
*
|
105
|
-
* It's possible to pass NULL as the `argv`, in which case the array created
|
106
|
-
* will have the capacity `argc` and could me manually populated.
|
107
|
-
*
|
108
|
-
* The objects are MOVED into the array's possesion. If you wish to retain a
|
109
|
-
* copy of the objects, use the `resp_dup_object` to increase their reference
|
110
|
-
* count.
|
111
|
-
*/
|
112
|
-
resp_object_s *resp_arr2obj(int argc, resp_object_s *argv[]);
|
113
|
-
|
114
|
-
/** Duplicates an object by increasing it's reference count. */
|
115
|
-
resp_object_s *resp_dup_object(resp_object_s *obj);
|
116
|
-
|
117
|
-
/** frees an object by decreasing it's reference count and testing. */
|
118
|
-
void resp_free_object(resp_object_s *obj);
|
119
|
-
|
120
|
-
/**
|
121
|
-
* Formats a RESP object back into a string.
|
122
|
-
*
|
123
|
-
* Returns 0 on success and -1 on failur.
|
124
|
-
*
|
125
|
-
* Accepts a memory buffer `dest` to which the data will be written and a poiner
|
126
|
-
* to the size of the buffer.
|
127
|
-
*
|
128
|
-
* Once the function returns, `size` will be updated to include the number of
|
129
|
-
* bytes required for the string. If the function returned a failure, this value
|
130
|
-
* can be used to allocate enough memory to contain the string.
|
131
|
-
*
|
132
|
-
* The string is Binary safe and it ISN'T always NUL terminated.
|
133
|
-
*
|
134
|
-
* The optional `parser` argument allows experimental extensions to be used when
|
135
|
-
* formatting the object. It can be ignored when formatting without extensions.
|
136
|
-
*
|
137
|
-
* **If implementing a server**:
|
138
|
-
*
|
139
|
-
* When implementing a server, Pub/Sub should avoid multiple copies by using a
|
140
|
-
* dedicated buffer with a reference count. By decreasing the reference count
|
141
|
-
* every time the message was sent (see the `sock_write2` support for the
|
142
|
-
* dealloc callback), it's possible to avoid multiple copies of the message.
|
143
|
-
*/
|
144
|
-
int resp_format(resp_parser_pt p, uint8_t *dest, size_t *size,
|
145
|
-
resp_object_s *obj);
|
146
|
-
|
147
|
-
/**
|
148
|
-
* Performs a task on each object. Protects from loop-backs.
|
149
|
-
*
|
150
|
-
* To break loop in the middle, `task` can return -1.
|
151
|
-
*
|
152
|
-
* Returns count.
|
153
|
-
*/
|
154
|
-
size_t resp_obj_each(resp_parser_pt p, resp_object_s *obj,
|
155
|
-
int (*task)(resp_parser_pt p, resp_object_s *obj,
|
156
|
-
void *arg),
|
157
|
-
void *arg);
|
158
|
-
|
159
|
-
/* *****************************************************************************
|
160
|
-
The RESP Parser
|
161
|
-
***************************************************************************** */
|
162
|
-
|
163
|
-
/** create the parser */
|
164
|
-
resp_parser_pt resp_parser_new(void);
|
165
|
-
|
166
|
-
/** free the parser and it's resources. */
|
167
|
-
void resp_parser_destroy(resp_parser_pt);
|
168
|
-
|
169
|
-
/** Clears the parser state, as if starting a new session / connection. */
|
170
|
-
void resp_parser_clear(resp_parser_pt);
|
171
|
-
|
172
|
-
/**
|
173
|
-
* Feed the parser with data.
|
174
|
-
*
|
175
|
-
* Returns any fully parsed object / reply (often an array, but not always) or
|
176
|
-
* NULL (needs more data / error).
|
177
|
-
*
|
178
|
-
* If a RESP object was parsed, it is returned and `len` is updated to reflect
|
179
|
-
* the number of bytes actually read.
|
180
|
-
*
|
181
|
-
* If more data is needed, NULL is returned and `len` is left unchanged.
|
182
|
-
*
|
183
|
-
* An error is reported by by returning NULL and setting `len` to 0 at the same
|
184
|
-
* time.
|
185
|
-
*
|
186
|
-
* Partial consumption is possible when multiple replys were available in the
|
187
|
-
* buffer. Otherwise the parser will consume the whole of the buffer.
|
188
|
-
*
|
189
|
-
*/
|
190
|
-
resp_object_s *resp_parser_feed(resp_parser_pt, uint8_t *buffer, size_t *len);
|
191
|
-
|
192
|
-
/* *****************************************************************************
|
193
|
-
State - The Pub / Sub Multiplexer (Experimental)
|
194
|
-
***************************************************************************** */
|
195
|
-
|
196
|
-
/**
|
197
|
-
It seems to me that the main reason that pub/sub messages and normal RESP
|
198
|
-
connetcions cannot share the same socket is the risk of identity collisions.
|
199
|
-
|
200
|
-
For example, the command LRANGE might return the following array response
|
201
|
-
`["message", "users", "hello"]`... this looks exactly like a Pub/Sub
|
202
|
-
notification.
|
203
|
-
|
204
|
-
However, this situation is very uncomfortable. For example:
|
205
|
-
|
206
|
-
* The sender already knows the content of the message. There is no reason to
|
207
|
-
waste bandwidth to send the same message back to the sender using a different
|
208
|
-
socket.
|
209
|
-
|
210
|
-
* The cost isn't just Bandwidth, but also memory, since the sender will have two
|
211
|
-
copies of the same message (if not more), the one being sent and the other
|
212
|
-
being received (sometimes more then once, for different channel patterns).
|
213
|
-
|
214
|
-
|
215
|
-
* Instead of handling the message localy, the sender is forced to wait until the
|
216
|
-
message is received by the pub/sub Redis conection - otherwise tere will be
|
217
|
-
duplicate messages being published.
|
218
|
-
|
219
|
-
* This design doubles the client load (number of connections) for each Redis
|
220
|
-
server (and client).
|
221
|
-
|
222
|
-
But we can solve this.
|
223
|
-
|
224
|
-
For example, what if we use a "magic byte" to distinguish between the array
|
225
|
-
`["message", "users", "hello"]` and the pub/sub notification `["message",
|
226
|
-
"users", "hello"]`?
|
227
|
-
|
228
|
-
What if every time the first word in an array response satrts with an `"m"` or a
|
229
|
-
`"+"`, we will add the `"+"` byte infront of it?
|
230
|
-
|
231
|
-
Now the notification will look like this: `["message", "users", "hello"]`, and
|
232
|
-
the array response (i.e. to `LRANGE`) will be: `["+message", "users", "hello"]`
|
233
|
-
- a distinct difference allowing for pub/sub and regular conections to use the
|
234
|
-
same pipelining socket.
|
235
|
-
|
236
|
-
The big issue (and I may be wrong), is backwards compatibility - we can't change
|
237
|
-
the semantics of the protocol without breaking existing clients... or can we?
|
238
|
-
|
239
|
-
I believe this hurdle can be easily circumvented by adding a single command to
|
240
|
-
the existing pallet. Somthing along the lines of: `ENABLE <feature>`.
|
241
|
-
|
242
|
-
Such a flexible command allows clients to negotiate changes to the semantics
|
243
|
-
for the connection. It's meant to be a single non-reversible change for the
|
244
|
-
specific connection (similar to the `Upgrade` HTTP/Websocket concept).
|
245
|
-
|
246
|
-
Now, the little `"+"` "magic byte" can be easily handled.
|
247
|
-
|
248
|
-
The following function activates the "magic byte" assuming the `ENABLE` command
|
249
|
-
was negotiated for the connection.
|
250
|
-
*/
|
251
|
-
void resp_enable_duplex_pubsub(resp_parser_pt parser);
|
252
|
-
|
253
|
-
#ifdef DEBUG
|
254
|
-
void resp_test(void);
|
255
|
-
#endif
|
256
|
-
|
257
|
-
#ifdef __cplusplus
|
258
|
-
} /* extern "C" */
|
259
|
-
#endif
|
260
|
-
|
261
|
-
#endif
|
data/ext/iodine/siphash.c
DELETED
@@ -1,154 +0,0 @@
|
|
1
|
-
/*
|
2
|
-
Copyright: Boaz segev, 2016-2017
|
3
|
-
License: MIT except for any non-public-domain algorithms (none that I'm aware
|
4
|
-
of), which might be subject to their own licenses.
|
5
|
-
|
6
|
-
Feel free to copy, use and enjoy in accordance with to the license(s).
|
7
|
-
*/
|
8
|
-
#include "siphash.h"
|
9
|
-
#include <stdint.h>
|
10
|
-
#include <stdlib.h>
|
11
|
-
|
12
|
-
// clang-format off
|
13
|
-
#if !defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__)
|
14
|
-
# if defined(__has_include)
|
15
|
-
# if __has_include(<endian.h>)
|
16
|
-
# include <endian.h>
|
17
|
-
# elif __has_include(<sys/endian.h>)
|
18
|
-
# include <sys/endian.h>
|
19
|
-
# endif
|
20
|
-
# endif
|
21
|
-
# if !defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__) && \
|
22
|
-
__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
23
|
-
# define __BIG_ENDIAN__
|
24
|
-
# endif
|
25
|
-
#endif
|
26
|
-
|
27
|
-
#ifndef UNUSED_FUNC
|
28
|
-
# define UNUSED_FUNC __attribute__((unused))
|
29
|
-
#endif
|
30
|
-
// clang-format on
|
31
|
-
|
32
|
-
/** 64Bit left rotation, inlined. */
|
33
|
-
#define _lrot64(i, bits) \
|
34
|
-
(((uint64_t)(i) << (bits)) | ((uint64_t)(i) >> (64 - (bits))))
|
35
|
-
|
36
|
-
#ifdef __BIG_ENDIAN__
|
37
|
-
/* the algorithm was designed as little endian */
|
38
|
-
/** inplace byte swap 64 bit integer */
|
39
|
-
#define sip_local64(i) \
|
40
|
-
(((i)&0xFFULL) << 56) | (((i)&0xFF00ULL) << 40) | \
|
41
|
-
(((i)&0xFF0000ULL) << 24) | (((i)&0xFF000000ULL) << 8) | \
|
42
|
-
(((i)&0xFF00000000ULL) >> 8) | (((i)&0xFF0000000000ULL) >> 24) | \
|
43
|
-
(((i)&0xFF000000000000ULL) >> 40) | (((i)&0xFF00000000000000ULL) >> 56)
|
44
|
-
|
45
|
-
#else
|
46
|
-
/** no need */
|
47
|
-
#define sip_local64(i) (i)
|
48
|
-
#endif
|
49
|
-
|
50
|
-
uint64_t siphash24(const void *data, size_t len, uint64_t iv_key[2]) {
|
51
|
-
/* initialize the 4 words */
|
52
|
-
uint64_t v0 = iv_key[0] ^ 0x736f6d6570736575ULL;
|
53
|
-
uint64_t v1 = iv_key[1] ^ 0x646f72616e646f6dULL;
|
54
|
-
uint64_t v2 = iv_key[0] ^ 0x6c7967656e657261ULL;
|
55
|
-
uint64_t v3 = iv_key[1] ^ 0x7465646279746573ULL;
|
56
|
-
const uint64_t *w64 = data;
|
57
|
-
uint8_t len_mod = len & 255;
|
58
|
-
union {
|
59
|
-
uint64_t i;
|
60
|
-
uint8_t str[8];
|
61
|
-
} word;
|
62
|
-
|
63
|
-
#define _bs_map_SipRound \
|
64
|
-
do { \
|
65
|
-
v2 += v3; \
|
66
|
-
v3 = _lrot64(v3, 16) ^ v2; \
|
67
|
-
v0 += v1; \
|
68
|
-
v1 = _lrot64(v1, 13) ^ v0; \
|
69
|
-
v0 = _lrot64(v0, 32); \
|
70
|
-
v2 += v1; \
|
71
|
-
v0 += v3; \
|
72
|
-
v1 = _lrot64(v1, 17) ^ v2; \
|
73
|
-
v3 = _lrot64(v3, 21) ^ v0; \
|
74
|
-
v2 = _lrot64(v2, 32); \
|
75
|
-
} while (0);
|
76
|
-
|
77
|
-
while (len >= 8) {
|
78
|
-
word.i = sip_local64(*w64);
|
79
|
-
v3 ^= word.i;
|
80
|
-
/* Sip Rounds */
|
81
|
-
_bs_map_SipRound;
|
82
|
-
_bs_map_SipRound;
|
83
|
-
v0 ^= word.i;
|
84
|
-
w64 += 1;
|
85
|
-
len -= 8;
|
86
|
-
}
|
87
|
-
word.i = 0;
|
88
|
-
uint8_t *pos = word.str;
|
89
|
-
uint8_t *w8 = (void *)w64;
|
90
|
-
switch (len) { // fallthrough is intentional
|
91
|
-
case 7:
|
92
|
-
pos[6] = w8[6];
|
93
|
-
case 6:
|
94
|
-
pos[5] = w8[5];
|
95
|
-
case 5:
|
96
|
-
pos[4] = w8[4];
|
97
|
-
case 4:
|
98
|
-
pos[3] = w8[3];
|
99
|
-
case 3:
|
100
|
-
pos[2] = w8[2];
|
101
|
-
case 2:
|
102
|
-
pos[1] = w8[1];
|
103
|
-
case 1:
|
104
|
-
pos[0] = w8[0];
|
105
|
-
}
|
106
|
-
word.str[7] = len_mod;
|
107
|
-
// word.i = sip_local64(word.i);
|
108
|
-
|
109
|
-
/* last round */
|
110
|
-
v3 ^= word.i;
|
111
|
-
_bs_map_SipRound;
|
112
|
-
_bs_map_SipRound;
|
113
|
-
v0 ^= word.i;
|
114
|
-
/* Finalization */
|
115
|
-
v2 ^= 0xff;
|
116
|
-
/* d iterations of SipRound */
|
117
|
-
_bs_map_SipRound;
|
118
|
-
_bs_map_SipRound;
|
119
|
-
_bs_map_SipRound;
|
120
|
-
_bs_map_SipRound;
|
121
|
-
/* XOR it all together */
|
122
|
-
v0 ^= v1 ^ v2 ^ v3;
|
123
|
-
#undef _bs_map_SipRound
|
124
|
-
return v0;
|
125
|
-
}
|
126
|
-
|
127
|
-
#undef sip_local64
|
128
|
-
#undef _lrot64
|
129
|
-
|
130
|
-
#if defined(DEBUG) && DEBUG == 1
|
131
|
-
|
132
|
-
#include <stdio.h>
|
133
|
-
#include <time.h>
|
134
|
-
|
135
|
-
void bscrypt_test_siphash(void) {
|
136
|
-
uint64_t result =
|
137
|
-
siphash24("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e",
|
138
|
-
15, SIPHASH_DEFAULT_KEY);
|
139
|
-
fprintf(stderr, "===================================\n");
|
140
|
-
fprintf(stderr, "SipHash simple test %s\n",
|
141
|
-
(result == 0xa129ca6149be45e5ULL) ? "passed" : "FAILED");
|
142
|
-
clock_t start;
|
143
|
-
start = clock();
|
144
|
-
for (size_t i = 0; i < 100000; i++) {
|
145
|
-
__asm__ volatile("" ::: "memory");
|
146
|
-
result = siphash24("The quick brown fox jumps over the lazy dog ", 43,
|
147
|
-
SIPHASH_DEFAULT_KEY);
|
148
|
-
}
|
149
|
-
fprintf(stderr, "bscrypt 100K SipHash: %lf\n",
|
150
|
-
(double)(clock() - start) / CLOCKS_PER_SEC);
|
151
|
-
fprintf(stderr, "===================================\n");
|
152
|
-
}
|
153
|
-
|
154
|
-
#endif
|
data/ext/iodine/siphash.h
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
/*
|
2
|
-
Copyright: Boaz segev, 2016-2017
|
3
|
-
License: MIT except for any non-public-domain algorithms (none that I'm aware
|
4
|
-
of), which might be subject to their own licenses.
|
5
|
-
|
6
|
-
Feel free to copy, use and enjoy in accordance with to the license(s).
|
7
|
-
*/
|
8
|
-
#ifndef BS_SIPHASH_H
|
9
|
-
#define BS_SIPHASH_H
|
10
|
-
#include <stdint.h>
|
11
|
-
#include <stdlib.h>
|
12
|
-
|
13
|
-
#define SIPHASH_DEFAULT_KEY \
|
14
|
-
(uint64_t[]) { 0x0706050403020100, 0x0f0e0d0c0b0a0908 }
|
15
|
-
uint64_t siphash24(const void *data, size_t len, uint64_t iv_key[2]);
|
16
|
-
|
17
|
-
#if defined(DEBUG) && DEBUG == 1
|
18
|
-
void bscrypt_test_siphash(void);
|
19
|
-
|
20
|
-
#endif
|
21
|
-
|
22
|
-
#endif
|
data/ext/iodine/xor-crypt.c
DELETED
@@ -1,193 +0,0 @@
|
|
1
|
-
/*
|
2
|
-
Copyright: Boaz segev, 2016-2017
|
3
|
-
License: MIT except for any non-public-domain algorithms (none that I'm aware
|
4
|
-
of), which might be subject to their own licenses.
|
5
|
-
|
6
|
-
Feel free to copy, use and enjoy in accordance with to the license(s).
|
7
|
-
*/
|
8
|
-
#ifndef _GNU_SOURCE
|
9
|
-
#define _GNU_SOURCE
|
10
|
-
#endif
|
11
|
-
#include "xor-crypt.h"
|
12
|
-
/*****************************************************************************
|
13
|
-
Useful Macros
|
14
|
-
*/
|
15
|
-
|
16
|
-
/** 32Bit left rotation, inlined. */
|
17
|
-
#define left_rotate32(i, bits) \
|
18
|
-
(((uint32_t)(i) << (bits)) | ((uint32_t)(i) >> (32 - (bits))))
|
19
|
-
/** 32Bit right rotation, inlined. */
|
20
|
-
#define right_rotate32(i, bits) \
|
21
|
-
(((uint32_t)(i) >> (bits)) | ((uint32_t)(i) << (32 - (bits))))
|
22
|
-
/** 64Bit left rotation, inlined. */
|
23
|
-
#define left_rotate64(i, bits) \
|
24
|
-
(((uint64_t)(i) << (bits)) | ((uint64_t)(i) >> (64 - (bits))))
|
25
|
-
/** 64Bit right rotation, inlined. */
|
26
|
-
#define right_rotate64(i, bits) \
|
27
|
-
(((uint64_t)(i) >> (bits)) | ((uint64_t)(i) << (64 - (bits))))
|
28
|
-
/** unknown size element - left rotation, inlined. */
|
29
|
-
#define left_rotate(i, bits) (((i) << (bits)) | ((i) >> (sizeof((i)) - (bits))))
|
30
|
-
/** unknown size element - right rotation, inlined. */
|
31
|
-
#define right_rotate(i, bits) \
|
32
|
-
(((i) >> (bits)) | ((i) << (sizeof((i)) - (bits))))
|
33
|
-
/** inplace byte swap 16 bit integer */
|
34
|
-
#define bswap16(i) \
|
35
|
-
do { \
|
36
|
-
(i) = (((i)&0xFFU) << 8) | (((i)&0xFF00U) >> 8); \
|
37
|
-
} while (0);
|
38
|
-
/** inplace byte swap 32 bit integer */
|
39
|
-
#define bswap32(i) \
|
40
|
-
do { \
|
41
|
-
(i) = (((i)&0xFFUL) << 24) | (((i)&0xFF00UL) << 8) | \
|
42
|
-
(((i)&0xFF0000UL) >> 8) | (((i)&0xFF000000UL) >> 24); \
|
43
|
-
} while (0);
|
44
|
-
/** inplace byte swap 64 bit integer */
|
45
|
-
#define bswap64(i) \
|
46
|
-
do { \
|
47
|
-
(i) = (((i)&0xFFULL) << 56) | (((i)&0xFF00ULL) << 40) | \
|
48
|
-
(((i)&0xFF0000ULL) << 24) | (((i)&0xFF000000ULL) << 8) | \
|
49
|
-
(((i)&0xFF00000000ULL) >> 8) | (((i)&0xFF0000000000ULL) >> 24) | \
|
50
|
-
(((i)&0xFF000000000000ULL) >> 40) | \
|
51
|
-
(((i)&0xFF00000000000000ULL) >> 56); \
|
52
|
-
} while (0);
|
53
|
-
|
54
|
-
#ifdef HAVE_X86Intrin
|
55
|
-
#undef bswap64
|
56
|
-
#define bswap64(i) \
|
57
|
-
{ __asm__("bswapq %0" : "+r"(i) :); }
|
58
|
-
|
59
|
-
// shadow sched_yield as _mm_pause for spinwait
|
60
|
-
#define sched_yield() _mm_pause()
|
61
|
-
#endif
|
62
|
-
|
63
|
-
/* ***************************************************************************
|
64
|
-
XOR encryption
|
65
|
-
*/
|
66
|
-
|
67
|
-
/**
|
68
|
-
Uses an XOR key `xor_key_s` to encrypt / decrypt the data provided.
|
69
|
-
|
70
|
-
Encryption/decryption can be destructive (the target and the source can point
|
71
|
-
to the same object).
|
72
|
-
|
73
|
-
The key's `on_cycle` callback option should be utilized to er-calculate the
|
74
|
-
key every cycle. Otherwise, XOR encryption should be avoided.
|
75
|
-
|
76
|
-
A more secure encryption would be easier to implement using seperate
|
77
|
-
`xor_key_s` objects for encryption and decription.
|
78
|
-
|
79
|
-
If `target` is NULL, the source will be used as the target (destructive mode).
|
80
|
-
|
81
|
-
Returns -1 on error and 0 on success.
|
82
|
-
*/
|
83
|
-
int bscrypt_xor_crypt(xor_key_s *key, void *target, const void *source,
|
84
|
-
size_t length) {
|
85
|
-
if (!source || !key)
|
86
|
-
return -1;
|
87
|
-
if (!length)
|
88
|
-
return 0;
|
89
|
-
if (!target)
|
90
|
-
target = (void *)source;
|
91
|
-
if (key->on_cycle) {
|
92
|
-
/* loop to provide vector initialization when needed. */
|
93
|
-
while (key->position >= key->length) {
|
94
|
-
if (key->on_cycle(key))
|
95
|
-
return -1;
|
96
|
-
key->position -= key->length;
|
97
|
-
}
|
98
|
-
} else if (key->position >= key->length)
|
99
|
-
key->position = 0; /* no callback? no need for vector alterations. */
|
100
|
-
size_t i = 0;
|
101
|
-
|
102
|
-
/* start decryption */
|
103
|
-
while (length > i) {
|
104
|
-
while ((key->length - key->position >= 8) // we have 8 bytes for key.
|
105
|
-
&& ((i + 8) <= length) // we have 8 bytes for stream.
|
106
|
-
&& (((uintptr_t)((uintptr_t)target + i)) & 7) ==
|
107
|
-
0 // target memory is aligned.
|
108
|
-
&& (((uintptr_t)((uintptr_t)source + i)) & 7) ==
|
109
|
-
0 // source memory is aligned.
|
110
|
-
&& ((uintptr_t)(key->key + key->position) & 7) == 0 // key aligned.
|
111
|
-
) {
|
112
|
-
// fprintf(stderr, "XOR optimization used i= %lu, key pos = %lu.\n", i,
|
113
|
-
// key->position);
|
114
|
-
*((uint64_t *)((uintptr_t)target + i)) =
|
115
|
-
*((uint64_t *)((uintptr_t)source + i)) ^
|
116
|
-
*((uint64_t *)(key->key + key->position));
|
117
|
-
key->position += 8;
|
118
|
-
i += 8;
|
119
|
-
if (key->position < key->length)
|
120
|
-
continue;
|
121
|
-
if (key->on_cycle && key->on_cycle(key))
|
122
|
-
return -1;
|
123
|
-
key->position = 0;
|
124
|
-
}
|
125
|
-
|
126
|
-
if (i < length) {
|
127
|
-
// fprintf(stderr, "XOR single byte.\n");
|
128
|
-
*((uint8_t *)((uintptr_t)target + i)) =
|
129
|
-
*((uint8_t *)((uintptr_t)source + i)) ^
|
130
|
-
*((uint8_t *)(key->key + key->position));
|
131
|
-
++i;
|
132
|
-
++key->position;
|
133
|
-
if (key->position == key->length) {
|
134
|
-
if (key->on_cycle && key->on_cycle(key))
|
135
|
-
return -1;
|
136
|
-
key->position = 0;
|
137
|
-
}
|
138
|
-
}
|
139
|
-
}
|
140
|
-
return 0;
|
141
|
-
}
|
142
|
-
|
143
|
-
/**
|
144
|
-
Similar to the bscrypt_xor_crypt except with a fixed key size of 128bits.
|
145
|
-
*/
|
146
|
-
int bscrypt_xor128_crypt(uint64_t *key, void *target, const void *source,
|
147
|
-
size_t length, int (*on_cycle)(uint64_t *key)) {
|
148
|
-
length = length & 31;
|
149
|
-
uint8_t pos = 0;
|
150
|
-
for (size_t i = 0; i < (length >> 3); i++) {
|
151
|
-
((uint64_t *)target)[0] = ((uint64_t *)source)[0] ^ key[pos++];
|
152
|
-
target = (void *)((uintptr_t)target + 8);
|
153
|
-
source = (void *)((uintptr_t)source + 8);
|
154
|
-
if (pos < 2)
|
155
|
-
continue;
|
156
|
-
if (on_cycle && on_cycle(key))
|
157
|
-
return -1;
|
158
|
-
pos = 0;
|
159
|
-
}
|
160
|
-
length = length & 7;
|
161
|
-
for (size_t i = 0; i < length; i++) {
|
162
|
-
((uint64_t *)target)[i] = ((uint64_t *)source)[i] ^ key[pos];
|
163
|
-
}
|
164
|
-
return 0;
|
165
|
-
}
|
166
|
-
/**
|
167
|
-
Similar to the bscrypt_xor_crypt except with a fixed key size of 256bits.
|
168
|
-
*/
|
169
|
-
int bscrypt_xor256_crypt(uint64_t *key, void *target, const void *source,
|
170
|
-
size_t length, int (*on_cycle)(uint64_t *key)) {
|
171
|
-
for (size_t i = 0; i < (length >> 5); i++) {
|
172
|
-
((uint64_t *)target)[0] = ((uint64_t *)source)[0] ^ key[0];
|
173
|
-
((uint64_t *)target)[1] = ((uint64_t *)source)[1] ^ key[1];
|
174
|
-
((uint64_t *)target)[2] = ((uint64_t *)source)[2] ^ key[2];
|
175
|
-
((uint64_t *)target)[3] = ((uint64_t *)source)[3] ^ key[3];
|
176
|
-
target = (void *)((uintptr_t)target + 32);
|
177
|
-
source = (void *)((uintptr_t)source + 32);
|
178
|
-
if (on_cycle && on_cycle(key))
|
179
|
-
return -1;
|
180
|
-
}
|
181
|
-
length = length & 31;
|
182
|
-
uint8_t pos = 0;
|
183
|
-
for (size_t i = 0; i < (length >> 3); i++) {
|
184
|
-
((uint64_t *)target)[0] = ((uint64_t *)source)[0] ^ key[pos++];
|
185
|
-
target = (void *)((uintptr_t)target + 8);
|
186
|
-
source = (void *)((uintptr_t)source + 8);
|
187
|
-
}
|
188
|
-
length = length & 7;
|
189
|
-
for (size_t i = 0; i < length; i++) {
|
190
|
-
((uint64_t *)target)[i] = ((uint64_t *)source)[i] ^ key[pos];
|
191
|
-
}
|
192
|
-
return 0;
|
193
|
-
}
|