Class: Confium::Composite::Signature

Inherits:
Object
  • Object
show all
Defined in:
lib/confium/composite.rb

Overview

JSON transport for composite signatures. The native extension defines Signature with algorithms/component_count/verify over component Hashes (algorithm, public_key, signature) whose binary fields cannot ride JSON directly, so the wire format hex-encodes them:

json = Confium::Composite::Signature.components_to_json(components)
sig  = Confium::Composite::Signature.from_json(json)
sig.verify(message)

Constant Summary collapse

BINARY_FIELDS =
%w[public_key signature].freeze

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.__native_newObject

magnus exposes the constructor as a class-level new; capture it before this reopen shadows it (plain super falls through to Class#new instead).



36
# File 'lib/confium/composite.rb', line 36

alias __native_new new

.canonical_json(json, data) ⇒ Object

The canonical wire form of whatever the caller handed us: a String passes through untouched; parsed structures are re-generated from their components array.



73
74
75
76
77
# File 'lib/confium/composite.rb', line 73

def self.canonical_json(json, data)
  return json if json.is_a?(String)

  JSON.generate(data.is_a?(Hash) ? data['components'] : data)
end

.components_to_json(components) ⇒ Object



45
46
47
48
49
50
51
# File 'lib/confium/composite.rb', line 45

def self.components_to_json(components)
  JSON.generate(components.map do |component|
    component.transform_values do |value|
      value.encoding == Encoding::ASCII_8BIT ? value.unpack1('H*') : value
    end
  end)
end

.from_json(json) ⇒ Object

Accepts either a bare JSON array of component Hashes or a [...] envelope, with public_key/signature hex-encoded on the wire. Takes a JSON string or an already-parsed Array/Hash.



57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/confium/composite.rb', line 57

def self.from_json(json)
  data = json.is_a?(String) ? JSON.parse(json) : json
  components = data.is_a?(Hash) ? data['components'] : data
  unless components.is_a?(Array) && !components.empty?
    raise ArgumentError, 'expected a non-empty "components" array'
  end

  sig = new(components.map { |c| decode_binary_fields(c) })
  sig.instance_variable_set(:@confium_components, components)
  sig.instance_variable_set(:@confium_components_json, canonical_json(json, data))
  sig
end

.new(*args) ⇒ Object



38
39
40
41
42
# File 'lib/confium/composite.rb', line 38

def new(*args)
  sig = __native_new(*args)
  sig.instance_variable_set(:@confium_components, args.first) if args.first.is_a?(Array)
  sig
end

Instance Method Details

#to_json(*_args) ⇒ Object

Serialize the components this instance was built from, in the canonical wire format. Instances remember their source: built from components, or from a JSON document (which is emitted verbatim when it was canonical).



23
24
25
26
27
28
29
30
# File 'lib/confium/composite.rb', line 23

def to_json(*_args)
  cached = @confium_components_json
  return cached if cached

  components = @confium_components or
    raise Confium::Error, 'Signature was not built with component data; use Signature.new or from_json'
  Signature.components_to_json(components)
end