id_shuffler 0.0.6 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -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