lib/sixword/lib.rb in sixword-0.3.1 vs lib/sixword/lib.rb in sixword-0.3.2
- old
+ new
@@ -1,7 +1,28 @@
module Sixword
+
+ # The Lib module contains various internal utility functions. They are not
+ # really part of the public API and will probably not be useful to external
+ # callers.
module Lib
+
+ # Encode an array of 8 bytes as an array of 6 words.
+ #
+ # @param byte_array [Array<Fixnum>] An array of length 8 containing
+ # integers in 0..255
+ #
+ # @return [Array<String>] An array of length 6 containing String words from
+ # {Sixword::WORDS}
+ #
+ # @example
+ # >> Sixword::Lib.encode_64_bits([0] * 8)
+ # => ["A", "A", "A", "A", "A", "A"]
+ #
+ # @example
+ # >> Sixword::Lib.encode_64_bits([0xff] * 8)
+ # => ["YOKE", "YOKE", "YOKE", "YOKE", "YOKE", "YEAR"]
+ #
def self.encode_64_bits(byte_array)
unless byte_array.length == 8
raise ArgumentError.new("Must pass an 8-byte array")
end
@@ -21,10 +42,26 @@
end
encoded
end
+ # Decode an array of 6 words into a 64-bit integer (representing 8 bytes).
+ #
+ # @param word_array [Array<String>] A 6 element array of String words
+ # @param padding_ok [Boolean]
+ #
+ # @return [Array(Integer, Integer)] a 64-bit integer (the data) and the
+ # length of the byte array that it represents (will always be 8 unless
+ # padding_ok)
+ #
+ # @example
+ # >> Sixword::Lib.decode_6_words(%w{COAT ACHE A A A ACT6}, true)
+ # => [26729, 2]
+ #
+ # >> Sixword::Lib.decode_6_words(%w{ACRE ADEN INN SLID MAD PAP}, false)
+ # => [5217737340628397156, 8]
+ #
def self.decode_6_words(word_array, padding_ok)
unless word_array.length == 6
raise ArgumentError.new("Must pass a six-word array")
end
@@ -66,24 +103,55 @@
int >>= padding * 8
[int, 8 - padding]
end
- # Extract the padding from a word, e.g. 'WORD3' => 'WORD', 3
+ # Extract the numeric padding from a word.
+ #
+ # @param word [String]
+ # @return [Array(String, Integer)] The String word, the Integer padding
+ #
+ # @example
+ # >> Sixword::Lib.extract_padding("WORD3")
+ # => ["WORD", 3]
+ #
def self.extract_padding(word)
unless word[-1] =~ /[1-7]/
raise ArgumentError.new("Not a valid padded word: #{word.inspect}")
end
return word[0...-1], Integer(word[-1])
end
+ # Decode an array of 6 words into a String of bytes.
+ #
+ # @param word_array [Array<String>] A 6 element array of String words
+ # @param padding_ok [Boolean]
+ #
+ # @return [String]
+ #
+ # @see Sixword.decode_6_words
+ # @see Sixword.int_to_byte_array
+ #
+ # @example
+ # >> Lib.decode_6_words_to_bstring(%w{COAT ACHE A A A ACT6}, true)
+ # => "hi"
+ #
+ # >> Lib.decode_6_words_to_bstring(%w{ACRE ADEN INN SLID MAD PAP}, false)
+ # => "Hi world"
+ #
def self.decode_6_words_to_bstring(word_array, padding_ok)
int_to_byte_array(*decode_6_words(word_array, padding_ok)).
map(&:chr).join
end
+ # Given a word, return the 11 bits it represents as an integer (i.e. its
+ # index in the WORDS list).
+ #
+ # @param word [String]
+ # @return [Fixnum] An integer 0..2047
+ #
def self.word_to_bits(word)
word = word.upcase
return WORDS_HASH.fetch(word)
rescue KeyError
if (1..4).include?(word.length)
@@ -92,10 +160,17 @@
raise InvalidWord.new("Word must be 1-4 chars, not #{word.inspect}")
end
end
# Compute two-bit parity on a byte array by summing each pair of bits.
+ # TODO: figure out which is faster
+ #
+ # @param byte_array [Array<Fixnum>]
+ # @return [Fixnum] An integer 0..3
+ #
+ # @see parity_int
+ #
def self.parity_array(byte_array)
# sum pairs of bits through the whole array
parity = 0
byte_array.each do |byte|
@@ -107,11 +182,19 @@
# return the least significant two bits
parity & 0b11
end
- # Compute parity in a different way. TODO: figure out which is faster
+ # Compute two-bit parity on a 64-bit integer representing an 8-byte array
+ # by summing each pair of bits.
+ # TODO: figure out which is faster
+ #
+ # @param int [Integer] A 64-bit integer representing 8 bytes
+ # @return [Fixnum] An integer 0..3
+ #
+ # @see parity_array
+ #
def self.parity_int(int)
parity = 0
while int > 0
parity += int & 0b11
int >>= 2
@@ -120,18 +203,18 @@
parity & 0b11
end
# Given an array of bytes, pack them into a single Integer.
#
- # For example:
+ # @example
#
# >> byte_array_to_int([1, 2])
# => 258
#
# @param byte_array [Array<Fixnum>]
#
- # @return Integer
+ # @return [Integer]
#
def self.byte_array_to_int(byte_array)
int = 0
byte_array.each do |byte|
int <<= 8
@@ -140,22 +223,22 @@
int
end
# Given an Integer, unpack it into an array of bytes.
#
- # For example:
- #
+ # @example
# >> int_to_byte_array(258)
# => [1, 2]
#
+ # @example
# >> int_to_byte_array(258, 3)
# => [0, 1, 2]
#
# @param int [Integer]
- # @param length [Integer] (nil) Left zero padded size of byte array to
- # return. If not provided, no leading zeroes will be added.
+ # @param length [Integer] Left zero padded size of byte array to return. If
+ # not provided, no leading zeroes will be added.
#
- # @return Array<Fixnum>
+ # @return [Array<Fixnum>]
#
def self.int_to_byte_array(int, length=nil)
unless int >= 0
raise ArgumentError.new("Not sure what to do with negative numbers")
end