Class: WOTS::Param
- Inherits:
-
Object
- Object
- WOTS::Param
- Includes:
- Util
- Defined in:
- lib/wots/param.rb,
lib/wots/param/sha256.rb,
lib/wots/param/sha512.rb,
lib/wots/param/shake256.rb
Overview
WOTS+ parameters defined in rfc8391. https://datatracker.ietf.org/doc/html/rfc8391
Constant Summary collapse
- SUPPORTED_NAMES =
The parameter sets defined in RFC 8391 and the
nthey require. { 'WOTSP-SHA2_256' => 32, 'WOTSP-SHA2_512' => 64, 'WOTSP-SHAKE_256' => 32 }.freeze
- SUPPORTED_W =
The Winternitz parameter is a member of the set 16. Other values break the checksum encoding below and allow signature forgery.
[4, 16].freeze
- SHA256 =
new( name: 'WOTSP-SHA2_256', n: 32, w: 16 )
- SHA512 =
new( name: 'WOTSP-SHA2_512', n: 64, w: 16 )
- SHAKE256 =
new( name: 'WOTSP-SHAKE_256', n: 32, w: 16 )
Instance Attribute Summary collapse
-
#n ⇒ Object
readonly
Returns the value of attribute n.
-
#name ⇒ Object
readonly
Returns the value of attribute name.
-
#w ⇒ Object
readonly
Returns the value of attribute w.
Instance Method Summary collapse
- #==(other) ⇒ Object
-
#base_w(data, out_len) ⇒ Array
Convert data as base w representation.
-
#chain(x, start_idx, steps, seed, addr) ⇒ String
WOTS+ Chaining Function.
-
#compute_checksum(base_w) ⇒ String
Compute checksum for
base_w. -
#f(k, m) ⇒ String
Hex string.
-
#h(k, m) ⇒ String
Hex string.
-
#h_msg(k, m) ⇒ String
Hex string.
-
#initialize(opts) ⇒ Param
constructor
public key, or signature element in bytes.
- #len ⇒ Object
- #len1 ⇒ Object
- #len2 ⇒ Object
-
#lg_w ⇒ Integer
log2(w), i.e.
-
#prf(k, m) ⇒ String
PRF function.
-
#to_byte(value, length) ⇒ String
Convert
valuetolengthsize binary string.
Methods included from Util
#bin_to_hex, #hex_string?, #hex_to_bin
Constructor Details
#initialize(opts) ⇒ Param
public key, or signature element in bytes.
34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
# File 'lib/wots/param.rb', line 34 def initialize(opts) raise ArgumentError, 'name must be string.' unless opts[:name].is_a?(String) raise ArgumentError, 'n must be integer.' unless opts[:n].is_a?(Integer) raise ArgumentError, 'w must be integer.' unless opts[:w].is_a?(Integer) expected_n = SUPPORTED_NAMES[opts[:name]] raise ArgumentError, "name must be one of #{SUPPORTED_NAMES.keys.join(', ')}." if expected_n.nil? raise ArgumentError, "n must be #{expected_n} for #{opts[:name]}." unless opts[:n] == expected_n raise ArgumentError, "w must be one of #{SUPPORTED_W.join(', ')}." unless SUPPORTED_W.include?(opts[:w]) @name = opts[:name] @n = opts[:n] @w = opts[:w] end |
Instance Attribute Details
#n ⇒ Object (readonly)
Returns the value of attribute n.
25 26 27 |
# File 'lib/wots/param.rb', line 25 def n @n end |
#name ⇒ Object (readonly)
Returns the value of attribute name.
24 25 26 |
# File 'lib/wots/param.rb', line 24 def name @name end |
#w ⇒ Object (readonly)
Returns the value of attribute w.
26 27 28 |
# File 'lib/wots/param.rb', line 26 def w @w end |
Instance Method Details
#==(other) ⇒ Object
178 179 180 181 |
# File 'lib/wots/param.rb', line 178 def ==(other) return false unless other.is_a?(Param) name == other.name && n == other.n && w == other.w end |
#base_w(data, out_len) ⇒ Array
Convert data as base w representation.
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/wots/param.rb', line 101 def base_w(data, out_len) x = hex_to_bin(data) raise ArgumentError, 'out_len must be integer.' unless out_len.is_a?(Integer) raise ArgumentError, 'out_len must be positive.' unless out_len.positive? required = ((out_len * lg_w) / 8.0).ceil raise ArgumentError, "data must be at least #{required} bytes to produce #{out_len} digits." if x.bytesize < required basew = [] in_idx = 0 total = 0 bits = 0 out_len.times do if bits == 0 total = x.getbyte(in_idx) in_idx += 1 bits += 8 end bits -= lg_w basew << ((total >> bits) & (w - 1)) end basew end |
#chain(x, start_idx, steps, seed, addr) ⇒ String
WOTS+ Chaining Function.
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
# File 'lib/wots/param.rb', line 150 def chain(x, start_idx, steps, seed, addr) raise ArgumentError, 'x must be hex string.' unless hex_string?(x) raise ArgumentError, 'start_idx must be integer.' unless start_idx.is_a?(Integer) raise ArgumentError, 'steps must be integer.' unless steps.is_a?(Integer) raise ArgumentError, 'start_idx must not be negative.' if start_idx.negative? raise ArgumentError, 'steps must not be negative.' if steps.negative? raise ArgumentError, 'Invalid range' if (start_idx + steps) > (w - 1) return x if steps == 0 result = x.dup steps.times do |i| addr.hash_addr = (start_idx + i) addr.key_and_mask = 0 key = prf(seed, bin_to_hex(addr.to_payload)) addr.key_and_mask = 1 mask = prf(seed, bin_to_hex(addr.to_payload)) masked = xor_bytes(result, mask) result = f(key, masked) end result end |
#compute_checksum(base_w) ⇒ String
Compute checksum for base_w.
131 132 133 134 135 136 137 138 139 |
# File 'lib/wots/param.rb', line 131 def compute_checksum(base_w) c_sum = 0 len1.times do |i| c_sum = (c_sum + w - 1 - base_w[i]) end c_sum = (c_sum << (8 - ((len2 * lg_w) % 8))) len_2_bytes = ((len2 * lg_w) / 8.0).ceil bin_to_hex(to_byte(c_sum, len_2_bytes)) end |
#f(k, m) ⇒ String
Returns Hex string.
70 71 72 |
# File 'lib/wots/param.rb', line 70 def f(k, m) keyed_hash(0, k, m) end |
#h(k, m) ⇒ String
Returns Hex string.
77 78 79 |
# File 'lib/wots/param.rb', line 77 def h(k, m) keyed_hash(1, k, m) end |
#h_msg(k, m) ⇒ String
Returns Hex string.
84 85 86 |
# File 'lib/wots/param.rb', line 84 def h_msg(k, m) keyed_hash(2, k, m) end |
#len ⇒ Object
63 64 65 |
# File 'lib/wots/param.rb', line 63 def len @len ||= len1 + len2 end |
#len1 ⇒ Object
55 56 57 |
# File 'lib/wots/param.rb', line 55 def len1 @len1 ||= (8.0 * n / Math.log2(w)).ceil end |
#len2 ⇒ Object
59 60 61 |
# File 'lib/wots/param.rb', line 59 def len2 @len2 ||= (Math.log2(len1 * (w - 1)) / Math.log2(w)).floor + 1 end |
#lg_w ⇒ Integer
log2(w), i.e. the number of bits consumed by a single base w digit.
51 52 53 |
# File 'lib/wots/param.rb', line 51 def lg_w @lg_w ||= Math.log2(w).to_i end |
#prf(k, m) ⇒ String
PRF function.
92 93 94 |
# File 'lib/wots/param.rb', line 92 def prf(k, m) keyed_hash(3, k, m) end |
#to_byte(value, length) ⇒ String
Convert value to length size binary string.
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 |
# File 'lib/wots/param.rb', line 188 def to_byte(value, length) raise ArgumentError, 'value must be integer.' unless value.is_a?(Integer) raise ArgumentError, 'length must be integer.' unless length.is_a?(Integer) raise ArgumentError, 'value must not be negative.' if value.negative? raise ArgumentError, "value does not fit in #{length} bytes." if value.bit_length > length * 8 bytes = [] length.times do bytes.unshift(value & 0xFF) value >>= 8 end bytes.pack("C*") end |