class TSS::Combiner
Warning, you probably don't want to use this directly. Instead see the TSS
module.
TSS::Combiner
has responsibility for combining an Array of String shares back into the original secret the shares were split from. It is also responsible for doing extensive validation of user provided shares and ensuring that any recovered secret matches the hash of the original secret.
Constants
- C
Attributes
padding[R]
select_by[R]
Public Class Methods
new(opts = {})
click to toggle source
# File lib/tss/combiner.rb, line 18 def initialize(opts = {}) # clone the incoming shares so the object passed to this # function doesn't get modified. @shares = opts.fetch(:shares).clone @select_by = opts.fetch(:select_by, 'FIRST') @padding = opts.fetch(:padding, true) end
Public Instance Methods
combine()
click to toggle source
# File lib/tss/combiner.rb, line 66 def combine # unwrap 'human' shares into binary shares if all_shares_appear_human?(shares) @shares = convert_shares_human_to_binary(shares) end validate_all_shares(shares) start_processing_time = Time.now h = Util.extract_share_header(shares.sample) threshold = h[:threshold] identifier = h[:identifier] hash_id = h[:hash_id] # Select a subset of the shares provided using the chosen selection # method. If there are exactly the right amount of shares this is a no-op. if select_by == 'FIRST' @shares = shares.shift(threshold) elsif select_by == 'SAMPLE' @shares = shares.sample(threshold) end # slice out the data after the header bytes in each share # and unpack the byte string into an Array of Byte Arrays shares_bytes = shares.map do |s| bytestring = s.byteslice(Splitter::SHARE_HEADER_STRUCT.size..s.bytesize) bytestring.unpack('C*') unless bytestring.nil? end.compact shares_bytes_have_valid_indexes!(shares_bytes) if select_by == 'COMBINATIONS' share_combinations_mode_allowed!(hash_id) share_combinations_out_of_bounds!(shares, threshold) # Build an Array of all possible `threshold` size combinations. share_combos = shares_bytes.combination(threshold).to_a # Try each combination until one works. secret = nil while secret.nil? && share_combos.present? # Check a combination and shift it off the Array result = extract_secret_from_shares!(hash_id, share_combos.shift) next if result.nil? secret = result end else secret = extract_secret_from_shares!(hash_id, shares_bytes) end # Return a Hash with the secret and metadata { hash: secret[:hash], hash_alg: secret[:hash_alg], identifier: identifier, process_time: ((Time.now - start_processing_time)*1000).round(2), secret: Util.bytes_to_utf8(secret[:secret]), threshold: threshold } end