2

This question is a follow up to my previous question here: How can I convert a UUID to a string using a custom character set in Ruby? But I will try to formulate it as a separate and specific question.

I do have a Ruby 128 bit UUID as hex value:

SecureRandom.uuid #=> "2d931510-d99f-494a-8c67-87feb05e1594"

If I get the IFC specification correctly (http://www.buildingsmart-tech.org/ifc/IFC2x3/TC1/html/ifcutilityresource/lexical/ifcgloballyuniqueid.htm), I want to Base64 encode this, but instead of getting padding at the end, I want the output to begin with a 2bit character(4 options), instead of 6 bits(needed for 64 options).

This way I think I can end up with a string of 22 characters (1 of 2bits, and 21 of 6bits for a total of 128 bits).

Is it possible to tweak the Ruby base64 in this way?

1 Answers1

2

Short answer: no. Technically speaking, that is not standard Base64 so Ruby's standard lib will not deal with it.

Ruby's Base64 lib takes its input as bytes, so you need to get your input data to be divisible by 8. But you want 4 zero bits in front of your UUID, so that's 4+128=132 so the next closest multiple of 8 is 136 i.e. 17 bytes. You can discard the extra randomness at the end:

x = SecureRandom.gen_random 17   # get a little extra randomness
x[0] = (x[0].ord & 0x0f).chr     # 0 out the first four bits
Base64.strict_encode64(x)[0...22] # discard extra randomness

The one downside of this approach is that your 128 bit UUID is weirdly aligned inside x and hard to see on its own. If you want to get the 128 bits out you can do that with some pack/unpack:

[x.unpack("B*")[0][4...132]].pack("B*")
Max
  • 21,123
  • 5
  • 49
  • 71
  • I think that I do need sets of 6 bits to get the correct result, so if base64 only takes bytes as input, then probably my question itself is incorrect. (6 bits needed for 64 options) Could that be? Then "no" is indeed the correct answer, and I have to find another way to map these bits the way I want.In the link I provided is also a piece of "C" example code, but I have difficulty reading it. – Jan Brouwer Dec 20 '17 at 21:49
  • @JanBrouwer Your reasoning is correct, actually. The problem is that on the one hand there is "base 64", which is simply a numerical representation which works exactly as you have described, then there is "base 64 _encoding_" which is a standardized byte-based encoding scheme. It's perfectly valid to turn 128 binary digits into 22 base 64 digits. But that's not _standard_, so Ruby does not handle it in its stdlib. – Max Dec 20 '17 at 21:53