Module: Melos::SecretTree

Defined in:
lib/melos/secret_tree.rb

Class Method Summary collapse

Class Method Details

.create(suite, n_leaves, encryption_secret) ⇒ Object



5
6
7
8
9
# File 'lib/melos/secret_tree.rb', line 5

def self.create(suite, n_leaves, encryption_secret)
  st = Melos::Tree.empty_tree(n_leaves)
  populate_tree(suite, st, encryption_secret)
  st
end

.populate_tree(suite, tree, root_secret) ⇒ Object



11
12
13
# File 'lib/melos/secret_tree.rb', line 11

def self.populate_tree(suite, tree, root_secret)
  populate_tree_impl(suite, tree, tree.root, root_secret)
end

.populate_tree_impl(suite, tree, index, secret) ⇒ Object



15
16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/melos/secret_tree.rb', line 15

def self.populate_tree_impl(suite, tree, index, secret)
  tree.array[index] = {
    'handshake_ratchet_secret' => Melos::Crypto.expand_with_label(suite, secret, "handshake",   "", suite.kdf.n_h),
    'application_ratchet_secret' => Melos::Crypto.expand_with_label(suite, secret, "application", "", suite.kdf.n_h),
    'next_handshake_ratchet_secret_generation' => 0,
    'next_application_ratchet_secret_generation' => 0
  }
  unless Melos::Tree.leaf?(index)
    left_secret  = Melos::Crypto.expand_with_label(suite, secret, "tree", "left", suite.kdf.n_h)
    right_secret = Melos::Crypto.expand_with_label(suite, secret, "tree", "right", suite.kdf.n_h)
    populate_tree_impl(suite, tree, Melos::Tree.left(index), left_secret)
    populate_tree_impl(suite, tree, Melos::Tree.right(index), right_secret)
  end
end

.ratchet_and_get(suite, content_type, tree, leaf_index) ⇒ Object



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/melos/secret_tree.rb', line 50

def self.ratchet_and_get(suite, content_type, tree, leaf_index)
  # TODO: clear the value on tree when getting
  case content_type
  when 0x02, 0x03
    ratchet_handshake(suite, tree, leaf_index)
    [
      tree.leaf_at(leaf_index)['handshake_key'],
      tree.leaf_at(leaf_index)['handshake_nonce'],
      tree.leaf_at(leaf_index)['next_handshake_ratchet_secret_generation'] - 1, # returns current generation
    ]
  else
    ratchet_application(suite, tree, leaf_index)
    [
      tree.leaf_at(leaf_index)['application_key'],
      tree.leaf_at(leaf_index)['application_nonce'],
      tree.leaf_at(leaf_index)['next_application_ratchet_secret_generation'] - 1, # returns current generation
    ]
  end
end

.ratchet_application(suite, tree, leaf_index) ⇒ Object



84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/melos/secret_tree.rb', line 84

def self.ratchet_application(suite, tree, leaf_index)
  node_index = leaf_index * 2
  generation = tree.array[node_index]['next_application_ratchet_secret_generation']
  application_ratchet_secret = tree.array[node_index]['application_ratchet_secret']
  application_nonce = Melos::Crypto.derive_tree_secret(suite, application_ratchet_secret, "nonce", generation, suite.hpke.n_n)
  application_key   = Melos::Crypto.derive_tree_secret(suite, application_ratchet_secret, "key",   generation, suite.hpke.n_k)
  next_application_ratchet_secret = Melos::Crypto.derive_tree_secret(suite, application_ratchet_secret, "secret", generation, suite.kdf.n_h)
  tree.array[node_index]['next_application_ratchet_secret_generation'] = generation + 1
  tree.array[node_index]['application_ratchet_secret'] = next_application_ratchet_secret
  tree.array[node_index]['application_nonce'] = application_nonce
  tree.array[node_index]['application_key']   = application_key
end

.ratchet_application_until(suite, tree, leaf_index, generation) ⇒ Object



70
71
72
73
74
# File 'lib/melos/secret_tree.rb', line 70

def self.ratchet_application_until(suite, tree, leaf_index, generation)
  while (tree.leaf_at(leaf_index)['next_application_ratchet_secret_generation'] <= generation)
    ratchet_application(suite, tree, leaf_index)
  end
end

.ratchet_handshake(suite, tree, leaf_index) ⇒ Object



97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/melos/secret_tree.rb', line 97

def self.ratchet_handshake(suite, tree, leaf_index)
  node_index = leaf_index * 2
  generation = tree.array[node_index]['next_handshake_ratchet_secret_generation']
  handshake_ratchet_secret = tree.array[node_index]['handshake_ratchet_secret']
  handshake_nonce = Melos::Crypto.derive_tree_secret(suite, handshake_ratchet_secret, "nonce", generation, suite.hpke.n_n)
  handshake_key   = Melos::Crypto.derive_tree_secret(suite, handshake_ratchet_secret, "key",   generation, suite.hpke.n_k)
  next_handshake_ratchet_secret = Melos::Crypto.derive_tree_secret(suite, handshake_ratchet_secret, "secret", generation, suite.kdf.n_h)
  tree.array[node_index]['next_handshake_ratchet_secret_generation'] = generation + 1
  tree.array[node_index]['handshake_ratchet_secret'] = next_handshake_ratchet_secret
  tree.array[node_index]['handshake_nonce'] = handshake_nonce
  tree.array[node_index]['handshake_key']   = handshake_key
end

.ratchet_handshake_until(suite, tree, leaf_index, generation) ⇒ Object

Raises:

  • (ArgumentError)


76
77
78
79
80
81
82
# File 'lib/melos/secret_tree.rb', line 76

def self.ratchet_handshake_until(suite, tree, leaf_index, generation)
  raise ArgumentError.new('cannot generate past generation') if generation < tree.leaf_at(leaf_index)['next_handshake_ratchet_secret_generation'] - 1
  # if current generation, do nothing
  while (tree.leaf_at(leaf_index)['next_handshake_ratchet_secret_generation'] <= generation)
    ratchet_handshake(suite, tree, leaf_index)
  end
end

.ratchet_until_and_get(suite, content_type, tree, leaf_index, generation) ⇒ Object



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/melos/secret_tree.rb', line 30

def self.ratchet_until_and_get(suite, content_type, tree, leaf_index, generation)
  # TODO: clear the value on tree when getting
  case content_type
  when 0x02, 0x03
    ratchet_handshake_until(suite, tree, leaf_index, generation)
    [
      tree.leaf_at(leaf_index)['handshake_key'],
      tree.leaf_at(leaf_index)['handshake_nonce'],
      generation
    ]
  else
    ratchet_application_until(suite, tree, leaf_index, generation)
    [
      tree.leaf_at(leaf_index)['application_key'],
      tree.leaf_at(leaf_index)['application_nonce'],
      generation
    ]
  end
end