id_shuffler 0.0.6 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -13,9 +13,15 @@
13
13
  *
14
14
  * - the feistel network round function returns 15 bits instead of 16
15
15
  *
16
- * - use uint32_t explicitely where necessary to ensure 32-bit numbers
16
+ * - use uint32_t explicitly where necessary to ensure 32-bit numbers
17
17
  * on 64-bit platforms
18
18
  *
19
+ * - use uint8_t also, instead of char, to ensure unsignedness as well as
20
+ * express that we're not really treating them are chars, but as small
21
+ * numbers. the original code used vanilla char which resulted in
22
+ * compile-time differences in output depending on the compiler/platform
23
+ * etc.
24
+ *
19
25
  * - use 6-digits of 'crockford' base-32 armor on the shuffled ids. this not
20
26
  * only prevents them from looking completely like numbers but also ensures
21
27
  * they are a constant length, which is very handy for the sake of future
@@ -31,9 +37,7 @@
31
37
  *
32
38
  */
33
39
 
34
- const int i = 1;
35
-
36
- const unsigned char ftable[256] = {
40
+ const uint8_t ftable[256] = {
37
41
  0xa3,0xd7,0x09,0x83,0xf8,0x48,0xf6,0xf4,0xb3,0x21,0x15,0x78,0x99,0xb1,0xaf,0xf9,
38
42
  0xe7,0x2d,0x4d,0x8a,0xce,0x4c,0xca,0x2e,0x52,0x95,0xd9,0x1e,0x4e,0x38,0x44,0x28,
39
43
  0x0a,0xdf,0x02,0xa0,0x17,0xf1,0x60,0x68,0x12,0xb7,0x7a,0xc3,0xe9,0xfa,0x3d,0x53,
@@ -52,7 +56,7 @@ const unsigned char ftable[256] = {
52
56
  0x5e,0x6c,0xa9,0x13,0x57,0x25,0xb5,0xe3,0xbd,0xa8,0x3a,0x01,0x05,0x59,0x2a,0x46
53
57
  };
54
58
 
55
- uint32_t g(unsigned char key[10], int k, uint32_t w)
59
+ uint32_t g(uint8_t key[10], uint8_t k, uint32_t w)
56
60
  {
57
61
  uint8_t g1, g2, g3, g4, g5, g6;
58
62
 
@@ -67,25 +71,11 @@ uint32_t g(unsigned char key[10], int k, uint32_t w)
67
71
  return (((g5<<8) + g6) & 32767); /* clip result to 15 bits */
68
72
  }
69
73
 
70
- static VALUE r_is_big_endian(VALUE self) {
71
- return ULONG2NUM(is_bigendian());
72
- }
73
-
74
- static VALUE r_g1(VALUE self) {
75
- unsigned char key[10] = {1,2,3,4,5,6,7,8,9,10};
76
- return ULONG2NUM(g(key,1,1));
77
- }
78
-
79
- static VALUE r_g2(VALUE self) {
80
- unsigned char key[10] = {1,2,3,4,5,6,7,8,9,10};
81
- return ULONG2NUM(g(key,1,32767));
82
- }
83
-
84
- uint32_t skip30(unsigned char key[10], uint32_t num, int encrypt)
74
+ uint32_t skip30(uint8_t key[10], uint32_t num, int encrypt)
85
75
  {
86
- int k; /* round number */
87
- int i; /* round counter */
88
- int kstep;
76
+ uint8_t k; /* round number */
77
+ uint8_t i; /* round counter */
78
+ int8_t kstep;
89
79
  uint32_t wl, wr;
90
80
 
91
81
  /* sort out direction */
@@ -109,44 +99,6 @@ uint32_t skip30(unsigned char key[10], uint32_t num, int encrypt)
109
99
  return (wr << 15) + (wl);
110
100
  }
111
101
 
112
- static VALUE r_skip1(VALUE self) {
113
- unsigned char key[10] = {1,2,3,4,5,6,7,8,9,10};
114
- return ULONG2NUM(skip30(key,1,1));
115
- }
116
-
117
- static VALUE r_skip2(VALUE self) {
118
- unsigned char key[10] = {1,2,3,4,5,6,7,8,9,10};
119
- return ULONG2NUM(skip30(key,32767,1));
120
- }
121
-
122
- static VALUE r_skip3(VALUE self, VALUE original_num) {
123
- unsigned char key[10] = {1,2,3,4,5,6,7,8,9,10};
124
- unsigned long original_ulong;
125
- original_ulong = NUM2ULONG(original_num);
126
- uint32_t original = original_ulong;
127
- return ULONG2NUM(skip30(key,original,1));
128
- }
129
-
130
- static VALUE r_skip4(VALUE self, VALUE original_num, VALUE key_str) {
131
- unsigned char *key = StringValuePtr(key_str);
132
- unsigned long original_ulong;
133
- original_ulong = NUM2ULONG(original_num);
134
- uint32_t original = original_ulong;
135
- return ULONG2NUM(skip30(key,original,1));
136
- }
137
-
138
- //uint32_t little_endian_swap(uint32_t num)
139
- //{
140
- // if (is_bigendian()) {
141
- // return num;
142
- // } else {
143
- // return ((num>>24)&0xff) | // move byte 3 to byte 0
144
- // ((num<<8)&0xff0000) | // move byte 1 to byte 2
145
- // ((num>>8)&0xff00) | // move byte 2 to byte 1
146
- // ((num<<24)&0xff000000); // byte 0 to byte 3
147
- // }
148
- //}
149
-
150
102
  static VALUE r_base32_shuffle(VALUE self, VALUE original_num, VALUE key_str) {
151
103
  /* takes a number and a key string as input and returns a base-32 encoded
152
104
  * shuffled id. */
@@ -154,7 +106,7 @@ static VALUE r_base32_shuffle(VALUE self, VALUE original_num, VALUE key_str) {
154
106
  /* convert from ruby objects */
155
107
  unsigned long original_ulong;
156
108
  original_ulong = NUM2ULONG(original_num);
157
- unsigned char *key = StringValuePtr(key_str);
109
+ uint8_t *key = StringValuePtr(key_str);
158
110
 
159
111
  /* bounds check the id */
160
112
  if (original_ulong >= (1 << 30)) {
@@ -168,13 +120,12 @@ static VALUE r_base32_shuffle(VALUE self, VALUE original_num, VALUE key_str) {
168
120
 
169
121
  /* encrypt */
170
122
  uint32_t original = original_ulong;
171
- //uint32_t shuffled = skip30(key, little_endian_swap(original), 1);
172
123
  uint32_t shuffled = skip30(key, original, 1);
173
124
 
174
125
  /* base-32 encode the result using "crockford 32" alphabet */
175
126
  unsigned char buf[6];
176
127
  unsigned char *digits = "0123456789abcdefghjkmnpqrstvwxyz";
177
- int cpos;
128
+ uint8_t cpos;
178
129
  for (cpos = 0; cpos < 6; cpos ++) {
179
130
  buf[cpos] = digits[((shuffled >> (5*(5-cpos))) & 31)];
180
131
  }
@@ -183,20 +134,6 @@ static VALUE r_base32_shuffle(VALUE self, VALUE original_num, VALUE key_str) {
183
134
  return rb_str_new(buf,6);
184
135
  }
185
136
 
186
- static VALUE r_b32(VALUE self, VALUE original_num) {
187
- unsigned char buf[6];
188
- unsigned char *digits = "0123456789abcdefghjkmnpqrstvwxyz";
189
- int cpos;
190
- unsigned long original_ulong;
191
- original_ulong = NUM2ULONG(original_num);
192
- uint32_t original = original_ulong;
193
- for (cpos = 0; cpos < 6; cpos ++) {
194
- buf[cpos] = digits[((original >> (5*(5-cpos))) & 31)];
195
- }
196
- return rb_str_new(buf,6);
197
- }
198
-
199
-
200
137
  static VALUE r_base32_unshuffle(VALUE self, VALUE shuffled_str, VALUE key_str) {
201
138
  /* take the a base-32 encoded ruby string and a key string, decodes and
202
139
  * unshuffles it, producing the original number. */
@@ -206,12 +143,12 @@ static VALUE r_base32_unshuffle(VALUE self, VALUE shuffled_str, VALUE key_str) {
206
143
  * -> "a" etc. */
207
144
 
208
145
  /* convert from ruby string to char buf */
209
- unsigned char *b32 = StringValuePtr(shuffled_str);
146
+ uint8_t *b32 = StringValuePtr(shuffled_str);
210
147
  if (RSTRING_LEN(shuffled_str) != 6) {
211
148
  /* must be 6 base-32 digits */
212
149
  return INT2NUM(-1);
213
150
  }
214
- unsigned char *key = StringValuePtr(key_str);
151
+ uint8_t *key = StringValuePtr(key_str);
215
152
  if (RSTRING_LEN(key_str) < 10) {
216
153
  return rb_str_new2("invalid key length");
217
154
  }
@@ -220,11 +157,11 @@ static VALUE r_base32_unshuffle(VALUE self, VALUE shuffled_str, VALUE key_str) {
220
157
  uint32_t shuffled = 0;
221
158
  unsigned char *found;
222
159
  unsigned char *digits = "0123456789abcdefghjkmnpqrstvwxyz";
223
- int cpos = 0;
160
+ uint8_t cpos = 0;
224
161
  for (cpos = 0; cpos < 6; cpos++) {
225
162
  found = strchr(digits,b32[cpos]);
226
163
  if (found) {
227
- int pos = (found - digits);
164
+ uint8_t pos = (found - digits);
228
165
  shuffled = shuffled + (pos << (5 * (5-cpos)));
229
166
  } else {
230
167
  /* not valid "crockford" base-32 */
@@ -233,28 +170,51 @@ static VALUE r_base32_unshuffle(VALUE self, VALUE shuffled_str, VALUE key_str) {
233
170
  }
234
171
 
235
172
  /* decrypt */
236
- //uint32_t original = little_endian_swap( skip30(key, shuffled, 0) );
237
173
  uint32_t original = skip30(key, shuffled, 0);
238
174
 
239
175
  /* return a ruby number */
240
176
  return ULONG2NUM(original);
241
177
  }
242
178
 
179
+ /* like above, but no base 32: */
180
+
181
+ static VALUE r_shuffle(VALUE self, VALUE original_num, VALUE key_str) {
182
+ unsigned long original_ulong;
183
+ original_ulong = NUM2ULONG(original_num);
184
+ uint8_t *key = StringValuePtr(key_str);
185
+ if (original_ulong >= (1 << 30)) {
186
+ return rb_str_new2("input integer exceeds 30-bit maximum");
187
+ }
188
+ if (RSTRING_LEN(key_str) < 10) {
189
+ return rb_str_new2("invalid key length");
190
+ }
191
+ uint32_t original = original_ulong;
192
+ uint32_t shuffled = skip30(key, original, 1);
193
+ return ULONG2NUM(shuffled);
194
+ }
195
+
196
+ static VALUE r_unshuffle(VALUE self, VALUE shuffled_num, VALUE key_str) {
197
+ unsigned long shuffled_ulong;
198
+ shuffled_ulong = NUM2ULONG(shuffled_num);
199
+ uint8_t *key = StringValuePtr(key_str);
200
+ if (RSTRING_LEN(key_str) < 10) {
201
+ return rb_str_new2("invalid key length");
202
+ }
203
+ uint32_t shuffled = shuffled_ulong;
204
+ uint32_t original = skip30(key, shuffled, 0);
205
+ return ULONG2NUM(original);
206
+ }
207
+
243
208
  void Init_id_shuffler(void) {
244
209
  /* add two class methods to our IdShuffler class: shuffle and unshuffle, each
245
210
  * of which take the object to be [unshuffled] and the key. the ruby module
246
211
  * in id_shuffler.rb should be the only one to ever call these, clients
247
212
  * should use the module's interface */
248
213
  VALUE klass = rb_define_class("IdShuffler", rb_cObject);
249
- rb_define_singleton_method(klass, "shuffle_with_raw_key", r_base32_shuffle, 2);
250
- rb_define_singleton_method(klass, "unshuffle_with_raw_key", r_base32_unshuffle, 2);
251
- rb_define_singleton_method(klass, "is_bigendian", r_is_big_endian,0);
252
- rb_define_singleton_method(klass, "g1", r_g1,0);
253
- rb_define_singleton_method(klass, "g2", r_g2,0);
254
- rb_define_singleton_method(klass, "skip1", r_skip1,0);
255
- rb_define_singleton_method(klass, "skip2", r_skip2,0);
256
- rb_define_singleton_method(klass, "skip3", r_skip3,1);
257
- rb_define_singleton_method(klass, "skip4", r_skip4,2);
258
- rb_define_singleton_method(klass, "b32", r_b32,1);
214
+ rb_define_singleton_method(klass, "b32_shuffle_with_raw_key", r_base32_shuffle, 2);
215
+ rb_define_singleton_method(klass, "b32_unshuffle_with_raw_key", r_base32_unshuffle, 2);
216
+ /* and the non-base32 versions, which are only used for testing and inspection */
217
+ rb_define_singleton_method(klass, "shuffle_with_raw_key", r_shuffle, 2);
218
+ rb_define_singleton_method(klass, "unshuffle_with_raw_key", r_unshuffle, 2);
259
219
  }
260
220
 
@@ -9,6 +9,8 @@ require 'digest/md5'
9
9
 
10
10
  class IdShuffler
11
11
 
12
+ VERSION = "0.0.8"
13
+
12
14
  def initialize(key)
13
15
  @key = Digest::MD5.digest(key)
14
16
  end
@@ -22,11 +24,21 @@ class IdShuffler
22
24
  # - unshuffle_with_raw_key
23
25
 
24
26
  def shuffle(i)
25
- self.class.shuffle_with_raw_key(i.to_i, @key)
27
+ self.class.b32_shuffle_with_raw_key(i.to_i, @key)
26
28
  end
27
29
 
28
30
  def unshuffle(s)
29
- self.class.unshuffle_with_raw_key(s.to_s, @key)
31
+ self.class.b32_unshuffle_with_raw_key(s.to_s, @key)
32
+ end
33
+
34
+ # and now these, too, for testing.
35
+
36
+ def i_shuffle(i)
37
+ self.class.shuffle_with_raw_key(i.to_i, @key)
38
+ end
39
+
40
+ def i_unshuffle(i)
41
+ self.class.unshuffle_with_raw_key(i.to_i, @key)
30
42
  end
31
43
 
32
44
  # these class methods are here for convenience but they are slower because the
@@ -34,11 +46,258 @@ class IdShuffler
34
46
  # key.
35
47
 
36
48
  def self.shuffle(i, key)
37
- shuffle_with_raw_key(i.to_i, Digest::MD5.digest(key))
49
+ b32_shuffle_with_raw_key(i.to_i, Digest::MD5.digest(key))
38
50
  end
39
51
 
40
52
  def self.unshuffle(s, key)
41
- unshuffle_with_raw_key(s.to_s, Digest::MD5.digest(key))
53
+ b32_unshuffle_with_raw_key(s.to_s, Digest::MD5.digest(key))
54
+ end
55
+
56
+ def self.i_shuffle(i, key)
57
+ shuffle_with_raw_key(i.to_i, Digest::MD5.digest(key))
58
+ end
59
+
60
+ def self.i_unshuffle(i, key)
61
+ unshuffle_with_raw_key(i.to_i, Digest::MD5.digest(key))
62
+ end
63
+
64
+ # a sanity check using precomputed values. returns true if tests pass.
65
+ def self.test(verbose = false)
66
+ keys = %w{
67
+ 9628461411983823
68
+ 1734283002173318
69
+ 016326850581415475
70
+ 6484228424403272
71
+ 061268721086567
72
+ 13691235382636435
73
+ 3211531955213043
74
+ 11726965179508919
75
+ 7766920746107023
76
+ 5595470614030541
77
+ 8801161592508207
78
+ 3061758398848765
79
+ 4245735393732285
80
+ 23026931842058007
81
+ 17291255562103658
82
+ 5341931588780643
83
+ 7960006634049325
84
+ 023251244403061144
85
+ 37605530799342857
86
+ 27669384149797127
87
+ 9437905104510069
88
+ 4114673054649628
89
+ 20168465656121792
90
+ 5482562496994766
91
+ 7324290711933842
92
+ 009976875465969703
93
+ 7168968770799556
94
+ 8149447986805111
95
+ 08491242832314072
96
+ 8223714655402778
97
+ 3876565402541112
98
+ 46733376760423295
99
+ 5298977054488807
100
+ 5935723180013883
101
+ 0317512792098289
102
+ 9310742102954396
103
+ 17829324559545612
104
+ 6746884367300644
105
+ 3535616496028713
106
+ 5127263511285141
107
+ 3164406333857237
108
+ 0343119765601525
109
+ 011512965180400236
110
+ 15982217865696302
111
+ 443806710798218
112
+ 12100659169950201
113
+ 147579537614696
114
+ 8322004794028289
115
+ 5514473449313436
116
+ 16312956181460625
117
+ 650702449763699
118
+ 9498182202542627
119
+ 10722624566120331
120
+ 4883115307765591
121
+ 20424102208596506
122
+ 5142750054579913
123
+ 05537581122671387
124
+ 20762553275459616
125
+ 04917099540401215
126
+ 07918051495924183
127
+ 2522783158673356
128
+ 4111833188359838
129
+ 6774194800874695
130
+ 7660083998825198
131
+ 31163333711689467
132
+ 15678056488782888
133
+ 265278223696121
134
+ 41643913578769354
135
+ 6030043722242956
136
+ 2960307106289347
137
+ 5549096461395291
138
+ 8915190041698866
139
+ 4057759730209265
140
+ 8018734599400228
141
+ 5543421583995795
142
+ 9979325828812361
143
+ 5617682617366149
144
+ 15112497024998717
145
+ 4689113002173503
146
+ 7874401856697474
147
+ 20106075965085923
148
+ 5965386545158813
149
+ 4814632612885722
150
+ 22075362777051932
151
+ 23472709637587308
152
+ 10373982789260561
153
+ 09897287005029487
154
+ 4768655223208501
155
+ 6849139321392613
156
+ 29168126625962554
157
+ 7833789806365968
158
+ 7114460449930401
159
+ 8385015784891404
160
+ 7960586688341696
161
+ 7048858419071817
162
+ 9921461615055903
163
+ 6129622811680446
164
+ 6516458355309123
165
+ 20860516685452057
166
+ 6474867677950523
167
+ }
168
+
169
+ expect = %w{
170
+ 69h72p 211328086
171
+ 99adag 311768400
172
+ 8501gw 273679900
173
+ w1pk93 941313315
174
+ 1w46c9 63052169
175
+ st2ww4 866218884
176
+ z7d2mk 1047956115
177
+ svmb8v 867839259
178
+ c1c4ab 404099403
179
+ 1xzam9 64989833
180
+ 3a2fng 111230640
181
+ 5wrbd0 197930400
182
+ 5rvmr1 193843969
183
+ zc6xvc 1052997484
184
+ byvpxv 401464251
185
+ whcgh9 957760041
186
+ t0txmv 873297563
187
+ 2rvjn6 93178534
188
+ 2km7gg 87694864
189
+ 8kccv7 288764775
190
+ 0pjh06 23675910
191
+ vvcc35 934686821
192
+ d9xtqk 446622451
193
+ 44sz7b 139263211
194
+ j04s48 604136584
195
+ ynds7p 1029104886
196
+ 56348t 174166298
197
+ kg6vdw 654536124
198
+ evvn76 498980070
199
+ 38qnz4 109828068
200
+ x98cf6 982790630
201
+ 6w25ba 230757738
202
+ pv42jt 766642778
203
+ 19snhy 43832894
204
+ gbghn5 548947621
205
+ nc2p2s 717314137
206
+ n9bwzc 714470380
207
+ 4y9sjn 165996117
208
+ n375hx 708023869
209
+ q6rnnv 778852027
210
+ r4vwq6 810414822
211
+ 016hdm 1263028
212
+ d004px 436212445
213
+ 6a4qbb 211967339
214
+ nf55ec 720541132
215
+ 7y47vk 266477427
216
+ betn9j 384652594
217
+ 4jgmwy 153637790
218
+ 9f01fc 317720044
219
+ bsstgf 396159503
220
+ x7crj6 980836934
221
+ g5ba33 542484579
222
+ r1ngmj 807060114
223
+ 12emzz 36131839
224
+ ejj7cd 489233805
225
+ kezz0c 653261836
226
+ 3agtj4 111700548
227
+ jcc9h3 616965667
228
+ m4tkd9 676154793
229
+ 7jg3n0 254283424
230
+ jmg1sv 625477435
231
+ z1gk1q 1041779767
232
+ mg61bq 688063863
233
+ f39p9d 506779949
234
+ d0nr82 436920578
235
+ sy0w1f 870346799
236
+ bmqyag 390854992
237
+ khftn1 655878817
238
+ 7xp5ef 266016207
239
+ mhb4bd 689279341
240
+ 1mvtwf 55438223
241
+ sae8m0 849814144
242
+ 1y55ac 65181004
243
+ 512d2y 168899678
244
+ faegj3 514277955
245
+ 47x2v6 142510950
246
+ jxf340 634883200
247
+ 5xvyzy 199097342
248
+ 0qttna 24996522
249
+ 865qrn 274915093
250
+ akdyyb 355924939
251
+ sa2dy1 849426369
252
+ t6keqv 879344379
253
+ 6zgqsk 234381107
254
+ jqhtfq 628681207
255
+ vbpw6r 918253784
256
+ q9np1b 781899819
257
+ 70bwc3 235270531
258
+ sw21qn 868288245
259
+ mn4dsk 693253939
260
+ y9s1ze 1016891374
261
+ mxrtpk 702311123
262
+ 95bew4 307608452
263
+ 2ksg3g 87867504
264
+ zhr2ym 1058802644
265
+ mvjv77 700017895
266
+ 97svdz 310177215
267
+ 92js4d 304702605
268
+ fdybg4 517942788
269
+ azgfjm 368590420
270
+ }
271
+
272
+ if verbose
273
+ puts "IdShuffler version: #{VERSION}"
274
+ printf "orig -> shuf32 (shuf int) [expect shuf32 (shuf int)] -> unshuf32 (unshuf) : result\n"
275
+ end
276
+ n = 0
277
+ idx = 0
278
+ all_pass = true
279
+ keys.each do |key|
280
+ shuffled = self.shuffle(n,key)
281
+ unshuffled = self.unshuffle(shuffled,key)
282
+ i_shuffled = self.i_shuffle(n,key)
283
+ i_unshuffled = self.i_unshuffle(i_shuffled,key)
284
+ expect_shuffled = expect[idx * 2]
285
+ expect_i_shuffled = expect[idx * 2 + 1].to_i
286
+ pass = (n == unshuffled && n == i_unshuffled && shuffled == expect_shuffled && i_shuffled == expect_i_shuffled)
287
+ if verbose
288
+ printf "%d -> %s (%d) [expect %s (%d)] -> %d (%d) : %s\n", n, shuffled, i_shuffled, expect_shuffled, expect_i_shuffled, unshuffled, i_unshuffled, (pass ? "PASS" : "FAIL")
289
+ end
290
+ n = i_shuffled
291
+ idx += 1
292
+ all_pass = all_pass && pass
293
+ end
294
+ if all_pass
295
+ puts "ALL PASSED" if verbose
296
+ return true
297
+ else
298
+ puts "FAILED" if verbose
299
+ return false
300
+ end
42
301
  end
43
302
 
44
303
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: id_shuffler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.8
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-03-20 00:00:00.000000000 Z
12
+ date: 2013-06-12 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: ! '
15
15