Class: Cyphera::FF3

Inherits:
Object
  • Object
show all
Defined in:
lib/cyphera/ff3.rb

Instance Method Summary collapse

Constructor Details

#initialize(key, tweak, alphabet = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') ⇒ FF3

Returns a new instance of FF3.

Raises:

  • (ArgumentError)


5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# File 'lib/cyphera/ff3.rb', line 5

def initialize(key, tweak, alphabet = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
  raise ArgumentError, "Key must be 16, 24, or 32 bytes" unless [16, 24, 32].include?(key.bytesize)
  raise ArgumentError, "Tweak must be exactly 8 bytes" unless tweak.bytesize == 8
  raise ArgumentError, "Alphabet must have >= 2 characters" if alphabet.length < 2

  @key = key.reverse
  @tweak = tweak
  @alphabet = alphabet
  @radix = alphabet.length
  @char_map = {}
  alphabet.each_char.with_index { |c, i| @char_map[c] = i }
  # NIST FF3 maximum length: 2 * floor(log_radix(2^96)), exact arithmetic.
  limit = 2**96
  k = 0
  k += 1 while @radix**(k + 1) <= limit
  @max_len = 2 * k
end

Instance Method Details

#check_length(n) ⇒ Object

NIST SP 800-38G: length >= 2, radix^length >= 1,000,000, length <= max.

Raises:

  • (ArgumentError)


24
25
26
27
28
29
30
# File 'lib/cyphera/ff3.rb', line 24

def check_length(n)
  if n < 2 || @radix**n < 1_000_000
    raise ArgumentError,
          "input too short (NIST minimum: length >= 2 and radix^length >= 1,000,000)"
  end
  raise ArgumentError, "input too long (FF3 maximum for this radix is #{@max_len})" if n > @max_len
end

#decrypt(ciphertext) ⇒ Object



38
39
40
41
42
# File 'lib/cyphera/ff3.rb', line 38

def decrypt(ciphertext)
  digits = to_digits(ciphertext)
  result = ff3_decrypt(digits)
  from_digits(result)
end

#encrypt(plaintext) ⇒ Object



32
33
34
35
36
# File 'lib/cyphera/ff3.rb', line 32

def encrypt(plaintext)
  digits = to_digits(plaintext)
  result = ff3_encrypt(digits)
  from_digits(result)
end