Module: Lightning::Onion::ChaCha20

Defined in:
lib/lightning/onion/chacha20.rb

Class Method Summary collapse

Class Method Details

.chacha20_block(key, counter, nonce) ⇒ Object

key: 32 bytes counter: integer (4 bytes) nonce: 12 bytes



36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/lightning/onion/chacha20.rb', line 36

def self.chacha20_block(key, counter, nonce)
  # reverse order
  key = key.unpack('V*').pack('N*')
  counter = [counter].pack('N*')
  nonce = nonce.unpack('V*').pack('N*')
  state = constants + key + counter + nonce
  working_state = state.unpack('N*')
  10.times do
    inner_block(working_state)
  end
  plus_for_string(state, working_state)
end

.chacha20_encrypt(key, counter, nonce, plaintext) ⇒ Object



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/lightning/onion/chacha20.rb', line 10

def self.chacha20_encrypt(key, counter, nonce, plaintext)
  encrypted_message = +''
  (plaintext.length / 64).times do |i|
    key_stream = chacha20_block(key, counter + i, nonce)
    block = plaintext[(i * 64)...(i + 1) * 64]
    encrypted_message += xor(block, key_stream)
  end
  if plaintext.length % 64 != 0
    i = plaintext.length / 64
    key_stream = chacha20_block(key, counter + i, nonce)
    block = plaintext[(i * 64)...plaintext.length]
    block = block.ljust(64, "\x00")
    encrypted_message += xor(block, key_stream)[0...(plaintext.length % 64)]
  end
  encrypted_message
end

.constantsObject



6
7
8
# File 'lib/lightning/onion/chacha20.rb', line 6

def self.constants
  [0x61707865, 0x3320646e, 0x79622d32, 0x6b206574].pack('N*')
end

.inner_block(x) ⇒ Object



49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/lightning/onion/chacha20.rb', line 49

def self.inner_block(x)
  # column rounds
  x[0], x[4], x[8], x[12] = quater_round(x[0], x[4], x[8], x[12])
  x[1], x[5], x[9], x[13] = quater_round(x[1], x[5], x[9], x[13])
  x[2], x[6], x[10], x[14] = quater_round(x[2], x[6], x[10], x[14])
  x[3], x[7], x[11], x[15] = quater_round(x[3], x[7], x[11], x[15])
  # diagonal rounds
  x[0], x[5], x[10], x[15] = quater_round(x[0], x[5], x[10], x[15])
  x[1], x[6], x[11], x[12] = quater_round(x[1], x[6], x[11], x[12])
  x[2], x[7], x[8], x[13] = quater_round(x[2], x[7], x[8], x[13])
  x[3], x[4], x[9], x[14] = quater_round(x[3], x[4], x[9], x[14])
end

.plus(x, y) ⇒ Object



68
69
70
# File 'lib/lightning/onion/chacha20.rb', line 68

def self.plus(x, y)
  (x + y) & 0xffffffff
end

.plus_for_string(a, b) ⇒ Object



62
63
64
65
66
# File 'lib/lightning/onion/chacha20.rb', line 62

def self.plus_for_string(a, b)
  a.unpack('N*').map.with_index do |x, i|
    plus(x, b[i])
  end.pack('V*')
end

.quater_round(a, b, c, d) ⇒ Object



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/lightning/onion/chacha20.rb', line 78

def self.quater_round(a, b, c, d)
  a = plus(a, b)
  d ^= a
  d = rotate(d, 16)

  c = plus(c, d)
  b ^= c
  b = rotate(b, 12)

  a = plus(a, b)
  d ^= a
  d = rotate(d, 8)

  c = plus(c, d)
  b ^= c
  b = rotate(b, 7)
  [a, b, c, d]
end

.rotate(x, n) ⇒ Object



72
73
74
75
76
# File 'lib/lightning/onion/chacha20.rb', line 72

def self.rotate(x, n)
  y = x << n
  z = x >> (32 - n)
  (y | z) & 0xffffffff
end

.xor(a, b) ⇒ Object



27
28
29
30
31
# File 'lib/lightning/onion/chacha20.rb', line 27

def self.xor(a, b)
  a = a.unpack('N*')
  b = b.unpack('N*')
  a.zip(b).map { |x, y| (x ^ y) & 0xffffffff }.pack('N*')
end