Module: Bitcoin::BIP324::ChaCha20

Defined in:
lib/bitcoin/bip324/fs_chacha20.rb

Constant Summary collapse

INDICES =
[
  [0, 4, 8, 12], [1, 5, 9, 13], [2, 6, 10, 14], [3, 7, 11, 15],
  [0, 5, 10, 15], [1, 6, 11, 12], [2, 7, 8, 13], [3, 4, 9, 14]
]
CONSTANTS =
[0x61707865, 0x3320646e, 0x79622d32, 0x6b206574]

Class Method Summary collapse

Class Method Details

.block(key, nonce, count) ⇒ String

Compute the 64-byte output of the ChaCha20 block function.

Parameters:

  • key (String)

    32-bytes key with binary format.

  • nonce (String)

    12-byte nonce with binary format.

  • count (Integer)

    32-bit integer counter.

Returns:

  • (String)

    64-byte output.

Raises:



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/bitcoin/bip324/fs_chacha20.rb', line 47

def block(key, nonce, count)
  raise Bitcoin::BIP324::Error, "key must be 32 byte string" if !key.is_a?(String) || key.bytesize != 32
  raise Bitcoin::BIP324::Error, "nonce must be 12 byte string" if !nonce.is_a?(String) || nonce.bytesize != 12
  raise Bitcoin::BIP324::Error, "count must be integer" unless count.is_a?(Integer)
  # Initialize state
  init = Array.new(16, 0)
  4.times {|i| init[i] = CONSTANTS[i]}
  key = key.unpack("V*")
  8.times {|i| init[4 + i] = key[i]}
  init[12] = count
  nonce = nonce.unpack("V*")
  3.times {|i| init[13 + i] = nonce[i]}
  # Perform 20 rounds
  state = init.dup
  10.times do
    state = double_round(state)
  end
  # Add initial values back into state.
  16.times do |i|
    state[i] = (state[i] + init[i]) & 0xffffffff
  end
  state.pack("V16")
end

.double_round(s) ⇒ Object

Apply a ChaCha20 double round to 16-element state array s.

Parameters:

Returns:

Raises:



27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/bitcoin/bip324/fs_chacha20.rb', line 27

def double_round(s)
  raise Bitcoin::BIP324::Error, "s must be Array" unless s.is_a?(Array)
  INDICES.each do |a, b, c, d|
    s[a] = (s[a] + s[b]) & 0xffffffff
    s[d] = rotl32(s[d] ^ s[a], 16)
    s[c] = (s[c] + s[d]) & 0xffffffff
    s[b] = rotl32(s[b] ^ s[c], 12)
    s[a] = (s[a] + s[b]) & 0xffffffff
    s[d] = rotl32(s[d] ^ s[a], 8)
    s[c] = (s[c] + s[d]) & 0xffffffff
    s[b] = rotl32(s[b] ^ s[c], 7)
  end
  s
end

.rotl32(v, bits) ⇒ Integer

Rotate the 32-bit value v left by bits bits.

Parameters:

Returns:

Raises:



18
19
20
21
22
# File 'lib/bitcoin/bip324/fs_chacha20.rb', line 18

def rotl32(v, bits)
  raise Bitcoin::BIP324::Error, "v must be integer" unless v.is_a?(Integer)
  raise Bitcoin::BIP324::Error, "bits must be integer" unless bits.is_a?(Integer)
  ((v << bits) & 0xffffffff) | (v >> (32 - bits))
end