confium 0.5.0-aarch64-linux → 0.6.0-aarch64-linux
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +47 -0
- data/Cargo.lock +432 -12
- data/lib/confium/audit/otlp_sink.rb +23 -6
- data/lib/confium/native_windows.rb +31 -0
- data/lib/confium/tc/coordinator.rb +24 -36
- data/lib/confium/tc/signing_session.rb +93 -0
- data/lib/confium/tc.rb +4 -6
- data/lib/confium/version.rb +1 -1
- data/lib/confium.rb +5 -16
- data/lib/confium_native/3.1/confium_native.so +0 -0
- data/lib/confium_native/3.2/confium_native.so +0 -0
- data/lib/confium_native/3.3/confium_native.so +0 -0
- data/lib/confium_native/3.4/confium_native.so +0 -0
- data/lib/confium_native/4.0/confium_native.so +0 -0
- metadata +4 -9
- data/lib/confium/cfm.rb +0 -23
- data/lib/confium/crypto.rb +0 -51
- data/lib/confium/digest.rb +0 -62
- data/lib/confium/ffi.rb +0 -23
- data/lib/confium/lib.rb +0 -33
- data/lib/confium/tc/session.rb +0 -51
- data/lib/confium/tc/session_stub.rb +0 -43
|
@@ -16,19 +16,24 @@ module Confium
|
|
|
16
16
|
# service_name: 'confium-issuer'
|
|
17
17
|
# )
|
|
18
18
|
#
|
|
19
|
-
# Delivery is synchronous per record
|
|
20
|
-
#
|
|
21
|
-
#
|
|
19
|
+
# Delivery is synchronous per record, retried with exponential
|
|
20
|
+
# backoff (retries: attempts after the first, base doubled per
|
|
21
|
+
# attempt). After the final failure the record is dropped with a
|
|
22
|
+
# $stderr report — the audit core's policy: a telemetry outage
|
|
23
|
+
# must never break signing. stdlib only.
|
|
22
24
|
class OtlpSink < Sink
|
|
23
25
|
DEFAULT_ENDPOINT = 'http://localhost:4318/v1/logs'
|
|
24
26
|
SEVERITY = { 'success' => 9, 'failure' => 17, 'error' => 17 }.freeze # INFO / ERROR
|
|
25
27
|
|
|
26
|
-
def initialize(endpoint: DEFAULT_ENDPOINT, headers: {}, service_name: 'confium', timeout: 5
|
|
28
|
+
def initialize(endpoint: DEFAULT_ENDPOINT, headers: {}, service_name: 'confium', timeout: 5,
|
|
29
|
+
retries: 2, retry_base: 0.1)
|
|
27
30
|
super()
|
|
28
31
|
@uri = URI.parse(endpoint)
|
|
29
32
|
@headers = headers
|
|
30
33
|
@service_name = service_name
|
|
31
34
|
@timeout = timeout
|
|
35
|
+
@retries = retries
|
|
36
|
+
@retry_base = retry_base
|
|
32
37
|
@dropped = 0
|
|
33
38
|
end
|
|
34
39
|
|
|
@@ -37,8 +42,7 @@ module Confium
|
|
|
37
42
|
|
|
38
43
|
def write(record)
|
|
39
44
|
payload = envelope(record)
|
|
40
|
-
|
|
41
|
-
raise "collector responded #{response.code}" unless response.is_a?(Net::HTTPSuccess)
|
|
45
|
+
deliver(JSON.generate(payload))
|
|
42
46
|
rescue StandardError => e
|
|
43
47
|
@dropped += 1
|
|
44
48
|
warn "confium: OTLP delivery failed, audit record dropped (##{@dropped}): #{e.class}: #{e.message}"
|
|
@@ -48,6 +52,19 @@ module Confium
|
|
|
48
52
|
|
|
49
53
|
private
|
|
50
54
|
|
|
55
|
+
# Attempts grow the backoff: retry_base * 2**attempt. When
|
|
56
|
+
# retry_base is 0 (specs) retries run without delay.
|
|
57
|
+
def deliver(body)
|
|
58
|
+
(@retries + 1).times do |attempt|
|
|
59
|
+
sleep(@retry_base * (2**attempt)) if attempt.positive? && @retry_base.positive?
|
|
60
|
+
|
|
61
|
+
response = Net::HTTP.post(@uri, body, headers.merge('Content-Type' => 'application/json'))
|
|
62
|
+
return response if response.is_a?(Net::HTTPSuccess)
|
|
63
|
+
|
|
64
|
+
raise "collector responded #{response.code}" if attempt == @retries
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
51
68
|
def headers
|
|
52
69
|
{ 'User-Agent' => "confium-otlp-sink #{Confium::VERSION}" }.merge(@headers)
|
|
53
70
|
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Confium
|
|
4
|
+
# Pure resolution of which native-extension ABI windows to try, in
|
|
5
|
+
# order. Extracted from the loader so the decision — the piece with
|
|
6
|
+
# the release-incident history (3.1-window segfaults on 3.2, the
|
|
7
|
+
# cross-major 3.3→4.0 TypeError, windowless platform gems) — is
|
|
8
|
+
# testable without installing eight platform gems.
|
|
9
|
+
module NativeWindows
|
|
10
|
+
# Ordered candidate windows for +ruby_version+ (e.g. "3.4.8").
|
|
11
|
+
#
|
|
12
|
+
# Background: platform gems ship one extension per ABI window.
|
|
13
|
+
# Ruby 3.2 broke the 3.1 ABI (object shapes) and rb-sys references
|
|
14
|
+
# a VM pointer libruby stopped exporting in 3.3, so 3.1/3.2/4.0
|
|
15
|
+
# get exact-minor builds while a 3.3-window binary loads on both
|
|
16
|
+
# 3.3 and 3.4. The 3.3 fallback applies within the 3.x line
|
|
17
|
+
# alone: a cross-major load (4.x) fails TypedData class-identity
|
|
18
|
+
# checks, so 4.0 must not fall back to it.
|
|
19
|
+
def self.candidates(ruby_version)
|
|
20
|
+
minor = ruby_version[/\A\d+\.\d+/]
|
|
21
|
+
raise ArgumentError, "not a ruby version: #{ruby_version.inspect}" unless minor
|
|
22
|
+
|
|
23
|
+
major = ruby_version[/\A\d+/].to_i
|
|
24
|
+
if major == 3 && Gem::Version.new(ruby_version) >= Gem::Version.new('3.3')
|
|
25
|
+
[minor, '3.3'].uniq
|
|
26
|
+
else
|
|
27
|
+
[minor]
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -3,9 +3,13 @@
|
|
|
3
3
|
# Confium::TC::Coordinator coordinates an in-process threshold
|
|
4
4
|
# signing session: signers submit commitments and shares at their own
|
|
5
5
|
# pace; once the threshold is met, aggregation runs the real
|
|
6
|
-
# threshold-ECDSA combine (CMP20 or GG18
|
|
7
|
-
#
|
|
8
|
-
#
|
|
6
|
+
# threshold-ECDSA combine (CMP20 or GG18) and returns a 64-byte
|
|
7
|
+
# (r, s) signature verifiable under the quorum public key.
|
|
8
|
+
#
|
|
9
|
+
# The session semantics (state machine, duplicate-signer rejection,
|
|
10
|
+
# the combine) live in SigningSession; this class is the session
|
|
11
|
+
# registry and quorum-scoped entry point. NetworkCoordinator is the
|
|
12
|
+
# TCP/NDJSON adapter over the same sessions.
|
|
9
13
|
#
|
|
10
14
|
# Usage:
|
|
11
15
|
# coordinator = Confium::TC::Coordinator.new(quorum_id: "biml-root")
|
|
@@ -27,54 +31,38 @@ module Confium
|
|
|
27
31
|
@sessions = {}
|
|
28
32
|
end
|
|
29
33
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
'GG18-ECDSA-P256' => ->(shares, threshold, message) { Gg18.sign(shares, threshold, message) }
|
|
33
|
-
}.freeze
|
|
34
|
-
|
|
35
|
-
def create_session(message:, threshold:, unlock_window: 14_400, scheme: 'CMP20-ECDSA-P256')
|
|
36
|
-
raise ArgumentError, "unknown scheme: #{scheme} (known: #{SCHEMES.keys.join(', ')})" unless SCHEMES.key?(scheme)
|
|
37
|
-
|
|
34
|
+
def create_session(message:, threshold:, unlock_window: SigningSession::DEFAULT_UNLOCK_WINDOW,
|
|
35
|
+
scheme: 'CMP20-ECDSA-P256')
|
|
38
36
|
session_id = "session-#{@sessions.length + 1}"
|
|
39
|
-
@sessions[session_id] =
|
|
40
|
-
message: message,
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
scheme: scheme,
|
|
44
|
-
state: :pending,
|
|
45
|
-
commitments: [],
|
|
46
|
-
shares: []
|
|
47
|
-
}
|
|
37
|
+
@sessions[session_id] = SigningSession.new(
|
|
38
|
+
message: message, threshold: threshold,
|
|
39
|
+
unlock_window: unlock_window, scheme: scheme
|
|
40
|
+
)
|
|
48
41
|
session_id
|
|
49
42
|
end
|
|
50
43
|
|
|
51
44
|
def session_state(session_id)
|
|
52
|
-
|
|
45
|
+
fetch(session_id).state
|
|
53
46
|
end
|
|
54
47
|
|
|
55
48
|
def submit_commitment(session_id, signer_id, commitment_bytes)
|
|
56
|
-
|
|
57
|
-
session[:commitments] << { signer_id: signer_id, bytes: commitment_bytes }
|
|
58
|
-
return unless session[:commitments].length >= session[:threshold]
|
|
59
|
-
|
|
60
|
-
session[:state] = :commitments_collected
|
|
49
|
+
fetch(session_id).add_commitment(signer_id, commitment_bytes)
|
|
61
50
|
end
|
|
62
51
|
|
|
63
52
|
def submit_share(session_id, signer_id, share_bytes)
|
|
64
|
-
|
|
65
|
-
session[:shares] << { signer_id: signer_id, bytes: share_bytes }
|
|
53
|
+
fetch(session_id).add_share(signer_id, share_bytes)
|
|
66
54
|
end
|
|
67
55
|
|
|
68
56
|
def aggregate(session_id)
|
|
69
|
-
|
|
70
|
-
|
|
57
|
+
fetch(session_id).aggregate
|
|
58
|
+
end
|
|
71
59
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
session
|
|
77
|
-
|
|
60
|
+
private
|
|
61
|
+
|
|
62
|
+
def fetch(session_id)
|
|
63
|
+
@sessions.fetch(session_id) do
|
|
64
|
+
raise NotFoundError.new("Unknown session: #{session_id}", kind: :session, identifier: session_id)
|
|
65
|
+
end
|
|
78
66
|
end
|
|
79
67
|
end
|
|
80
68
|
end
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Confium
|
|
4
|
+
module TC
|
|
5
|
+
# One threshold-signing session: the state machine and the combine
|
|
6
|
+
# behind every coordinator surface. Coordinator (in-process) and
|
|
7
|
+
# NetworkCoordinator (TCP/NDJSON) are adapters over this class —
|
|
8
|
+
# they own registries and framing; the session owns the semantics:
|
|
9
|
+
#
|
|
10
|
+
# pending → commitments_collected (T distinct commitments)
|
|
11
|
+
# → completed (aggregate runs the scheme combine)
|
|
12
|
+
#
|
|
13
|
+
# Aggregate may be called again after completion — the combine
|
|
14
|
+
# randomizes its nonce, so each call yields a fresh (verifiable)
|
|
15
|
+
# signature over the same shares, which is what a network client
|
|
16
|
+
# retrying after a dropped response needs.
|
|
17
|
+
#
|
|
18
|
+
# Signer identity is load-bearing: one signer submitting two
|
|
19
|
+
# shares must never count twice toward the threshold, so
|
|
20
|
+
# commitments and shares are keyed by signer_id and duplicates
|
|
21
|
+
# raise.
|
|
22
|
+
class SigningSession
|
|
23
|
+
DEFAULT_UNLOCK_WINDOW = 14_400
|
|
24
|
+
|
|
25
|
+
SCHEMES = {
|
|
26
|
+
'CMP20-ECDSA-P256' => ->(shares, threshold, message) { Cmp20.sign(shares, threshold, message) },
|
|
27
|
+
'GG18-ECDSA-P256' => ->(shares, threshold, message) { Gg18.sign(shares, threshold, message) }
|
|
28
|
+
}.freeze
|
|
29
|
+
|
|
30
|
+
attr_reader :message, :threshold, :unlock_window, :scheme, :state
|
|
31
|
+
|
|
32
|
+
def initialize(message:, threshold:, unlock_window: DEFAULT_UNLOCK_WINDOW, scheme: 'CMP20-ECDSA-P256')
|
|
33
|
+
raise ArgumentError, "unknown scheme: #{scheme} (known: #{SCHEMES.keys.join(', ')})" unless SCHEMES.key?(scheme)
|
|
34
|
+
|
|
35
|
+
@message = message
|
|
36
|
+
@threshold = threshold
|
|
37
|
+
@unlock_window = unlock_window
|
|
38
|
+
@scheme = scheme
|
|
39
|
+
@state = :pending
|
|
40
|
+
# @type ivar @commitments: Hash[String, String]
|
|
41
|
+
@commitments = {}
|
|
42
|
+
# @type ivar @shares: Hash[String, String]
|
|
43
|
+
@shares = {}
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def add_commitment(signer_id, commitment_bytes)
|
|
47
|
+
record(@commitments, signer_id, commitment_bytes)
|
|
48
|
+
@state = :commitments_collected if @commitments.length >= @threshold
|
|
49
|
+
self
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def add_share(signer_id, share_bytes)
|
|
53
|
+
record(@shares, signer_id, share_bytes)
|
|
54
|
+
self
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def commitment_count
|
|
58
|
+
@commitments.length
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def share_count
|
|
62
|
+
@shares.length
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def threshold_met?
|
|
66
|
+
@shares.length >= @threshold
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def aggregate
|
|
70
|
+
unless threshold_met?
|
|
71
|
+
raise ThresholdError.new('Threshold not met', have_count: @shares.length, need_count: @threshold)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
signature = SCHEMES.fetch(@scheme).call(@shares.values, @threshold, @message)
|
|
75
|
+
@state = :completed
|
|
76
|
+
signature
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
private
|
|
80
|
+
|
|
81
|
+
def record(store, signer_id, bytes)
|
|
82
|
+
if store.key?(signer_id)
|
|
83
|
+
raise ValidationError.new(
|
|
84
|
+
"duplicate submission from signer #{signer_id}",
|
|
85
|
+
param: :signer_id, expected: 'one submission per signer', actual: signer_id
|
|
86
|
+
)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
store[signer_id] = bytes
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
data/lib/confium/tc.rb
CHANGED
|
@@ -11,12 +11,10 @@
|
|
|
11
11
|
# for the full interface specification.
|
|
12
12
|
module Confium
|
|
13
13
|
module TC
|
|
14
|
-
# The native extension defines Confium::TC; this namespace file
|
|
15
|
-
# eager-required from confium.rb, so autoloads
|
|
16
|
-
#
|
|
17
|
-
|
|
18
|
-
# external libconfium dylib, so it stays lazy.
|
|
19
|
-
autoload :Session, 'confium/tc/session'
|
|
14
|
+
# The native extension defines Confium::TC; this namespace file
|
|
15
|
+
# is eager-required from confium.rb, so autoloads never fire —
|
|
16
|
+
# the pure-Ruby companions load with the namespace directly.
|
|
17
|
+
require_relative 'tc/signing_session'
|
|
20
18
|
require_relative 'tc/coordinator'
|
|
21
19
|
require_relative 'tc/network_coordinator'
|
|
22
20
|
require_relative 'tc/share_file'
|
data/lib/confium/version.rb
CHANGED
data/lib/confium.rb
CHANGED
|
@@ -10,25 +10,14 @@
|
|
|
10
10
|
# are loaded lazily via autoload — see lib/confium/<name>.rb.
|
|
11
11
|
|
|
12
12
|
require_relative 'confium/version'
|
|
13
|
+
require_relative 'confium/native_windows'
|
|
13
14
|
|
|
14
15
|
begin
|
|
15
|
-
# Pre-built platform gems ship one extension per
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
# 3.1 and 3.2 get exact-minor builds while 3.3 covers 3.3+).
|
|
19
|
-
# Source builds install the extension flat, without a version
|
|
20
|
-
# directory.
|
|
21
|
-
minor = RUBY_VERSION[/\A\d+\.\d+/]
|
|
16
|
+
# Pre-built platform gems ship one extension per ABI window (the
|
|
17
|
+
# window rules live in Confium::NativeWindows). Source builds
|
|
18
|
+
# install the extension flat, without a version directory.
|
|
22
19
|
dlext = RbConfig::CONFIG['DLEXT'] || 'so'
|
|
23
|
-
|
|
24
|
-
# 3.3-window binaries load on 3.3/3.4 only; a cross-major load
|
|
25
|
-
# (4.x) fails TypedData class checks, so the fallback applies
|
|
26
|
-
# within the 3.x line alone.
|
|
27
|
-
candidates = major == 3 && Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3.3') ? [minor, '3.3'].uniq : [minor]
|
|
28
|
-
# Windows gems carry an exact-minor window per Ruby (a PE import
|
|
29
|
-
# names the version-specific ruby DLL); other platforms share the
|
|
30
|
-
# 3.3 window for 3.3+. Prefer the exact minor when present.
|
|
31
|
-
windowed = candidates.filter_map do |w|
|
|
20
|
+
windowed = Confium::NativeWindows.candidates(RUBY_VERSION).filter_map do |w|
|
|
32
21
|
path = File.expand_path("confium_native/#{w}/confium_native.#{dlext}", __dir__ || '.')
|
|
33
22
|
w if File.exist?(path)
|
|
34
23
|
end
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: confium
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.6.0
|
|
5
5
|
platform: aarch64-linux
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Open
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-08-
|
|
11
|
+
date: 2026-08-25 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rake
|
|
@@ -100,10 +100,7 @@ files:
|
|
|
100
100
|
- lib/confium.rb
|
|
101
101
|
- lib/confium/audit.rb
|
|
102
102
|
- lib/confium/audit/otlp_sink.rb
|
|
103
|
-
- lib/confium/cfm.rb
|
|
104
103
|
- lib/confium/composite.rb
|
|
105
|
-
- lib/confium/crypto.rb
|
|
106
|
-
- lib/confium/digest.rb
|
|
107
104
|
- lib/confium/errors.rb
|
|
108
105
|
- lib/confium/errors/coerce.rb
|
|
109
106
|
- lib/confium/errors/crypto_error.rb
|
|
@@ -115,8 +112,7 @@ files:
|
|
|
115
112
|
- lib/confium/errors/unresolved_signer_error.rb
|
|
116
113
|
- lib/confium/errors/validation_error.rb
|
|
117
114
|
- lib/confium/errors/verification_error.rb
|
|
118
|
-
- lib/confium/
|
|
119
|
-
- lib/confium/lib.rb
|
|
115
|
+
- lib/confium/native_windows.rb
|
|
120
116
|
- lib/confium/openpgp.rb
|
|
121
117
|
- lib/confium/pki.rb
|
|
122
118
|
- lib/confium/pki/certificate_builder.rb
|
|
@@ -128,9 +124,8 @@ files:
|
|
|
128
124
|
- lib/confium/tc.rb
|
|
129
125
|
- lib/confium/tc/coordinator.rb
|
|
130
126
|
- lib/confium/tc/network_coordinator.rb
|
|
131
|
-
- lib/confium/tc/session.rb
|
|
132
|
-
- lib/confium/tc/session_stub.rb
|
|
133
127
|
- lib/confium/tc/share_file.rb
|
|
128
|
+
- lib/confium/tc/signing_session.rb
|
|
134
129
|
- lib/confium/transparency.rb
|
|
135
130
|
- lib/confium/transparency/ots.rb
|
|
136
131
|
- lib/confium/version.rb
|
data/lib/confium/cfm.rb
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'ffi'
|
|
4
|
-
|
|
5
|
-
module Confium
|
|
6
|
-
class CFM
|
|
7
|
-
attr_reader :ptr
|
|
8
|
-
|
|
9
|
-
def initialize
|
|
10
|
-
pptr = ::FFI::MemoryPointer.new(:pointer)
|
|
11
|
-
Confium.call_ffi(:cfm_create, pptr)
|
|
12
|
-
@ptr = ::FFI::AutoPointer.new(pptr.read_pointer, self.class.method(:destroy))
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def self.destroy(ptr)
|
|
16
|
-
Confium::Lib.cfm_destroy(ptr)
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def load_plugin(name, path)
|
|
20
|
-
Confium.call_ffi(:cfm_plugin_load, @ptr, name, path, nil, nil)
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
end
|
data/lib/confium/crypto.rb
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# {Confium::Crypto} is the registry namespace for Confium's cryptographic
|
|
4
|
-
# interfaces.
|
|
5
|
-
#
|
|
6
|
-
# Mirroring the Rust plugin-interface registry (TODO #02), each Ruby
|
|
7
|
-
# interface module (Digest, and future Cipher, AEAD, KDF, RNG, Signature,
|
|
8
|
-
# KEM, ...) registers itself here on load rather than being enumerated in
|
|
9
|
-
# a central case statement. This keeps the registry open for extension
|
|
10
|
-
# (OCP) and makes the set of available interfaces a single source of
|
|
11
|
-
# truth.
|
|
12
|
-
#
|
|
13
|
-
# Example:
|
|
14
|
-
#
|
|
15
|
-
# module Confium
|
|
16
|
-
# module Digest
|
|
17
|
-
# Confium::Crypto.register(:hash, self)
|
|
18
|
-
# end
|
|
19
|
-
# end
|
|
20
|
-
#
|
|
21
|
-
# Confium::Crypto.lookup(:hash) # => Confium::Digest
|
|
22
|
-
module Confium
|
|
23
|
-
module Crypto
|
|
24
|
-
# @type ivar @interfaces: Hash[Symbol, untyped]
|
|
25
|
-
@interfaces = {}
|
|
26
|
-
|
|
27
|
-
class << self
|
|
28
|
-
# Register an interface +klass+ under the symbolic +name+. Adding a
|
|
29
|
-
# new interface is a one-line registration; no central switch needs
|
|
30
|
-
# editing.
|
|
31
|
-
def register(name, klass)
|
|
32
|
-
@interfaces[name] = klass
|
|
33
|
-
klass
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
# Resolve a registered interface by +name+. Raises ArgumentError if
|
|
37
|
-
# nothing has been registered under that name.
|
|
38
|
-
def lookup(name)
|
|
39
|
-
@interfaces.fetch(name) do
|
|
40
|
-
raise ArgumentError, "unknown interface #{name.inspect}"
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
# Enumerate the names of every registered interface. Primarily for
|
|
45
|
-
# introspection and tooling.
|
|
46
|
-
def interfaces
|
|
47
|
-
@interfaces.keys.dup
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
end
|
data/lib/confium/digest.rb
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'ffi'
|
|
4
|
-
require 'digest'
|
|
5
|
-
|
|
6
|
-
module Confium
|
|
7
|
-
class Digest < ::Digest::Class
|
|
8
|
-
attr_reader :name, :ptr
|
|
9
|
-
|
|
10
|
-
def initialize(cfm, name)
|
|
11
|
-
@name = name
|
|
12
|
-
pptr = ::FFI::MemoryPointer.new(:pointer)
|
|
13
|
-
Confium.call_ffi(:cfm_hash_create, cfm.ptr, pptr, name, nil, nil, nil)
|
|
14
|
-
ptr = pptr.read_pointer
|
|
15
|
-
raise if ptr.null?
|
|
16
|
-
|
|
17
|
-
@ptr = ::FFI::AutoPointer.new(ptr, self.class.method(:destroy))
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def initialize_copy(source)
|
|
21
|
-
@name = source.name
|
|
22
|
-
pptr = ::FFI::MemoryPointer.new(:pointer)
|
|
23
|
-
Confium.call_ffi(:cfm_hash_clone, source.ptr, pptr)
|
|
24
|
-
ptr = pptr.read_pointer
|
|
25
|
-
@ptr = ::FFI::AutoPointer.new(ptr, self.class.method(:destroy))
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def self.destroy(ptr)
|
|
29
|
-
Confium::Lib.cfm_hash_destroy(ptr)
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def block_length
|
|
33
|
-
plength = ::FFI::MemoryPointer.new(:uint32)
|
|
34
|
-
Confium.call_ffi(:cfm_hash_block_size, @ptr, plength)
|
|
35
|
-
plength.read(:uint32)
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def digest_length
|
|
39
|
-
plength = ::FFI::MemoryPointer.new(:uint32)
|
|
40
|
-
Confium.call_ffi(:cfm_hash_output_size, @ptr, plength)
|
|
41
|
-
plength.read(:uint32)
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def update(data)
|
|
45
|
-
Confium.call_ffi(:cfm_hash_update, @ptr, data, data.bytesize)
|
|
46
|
-
self
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def reset
|
|
50
|
-
Confium.call_ffi(:cfm_hash_reset, @ptr)
|
|
51
|
-
self
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def finish
|
|
55
|
-
buf = ::FFI::MemoryPointer.new(:uint8, digest_length)
|
|
56
|
-
Confium.call_ffi(:cfm_hash_finalize, @ptr, buf, buf.size)
|
|
57
|
-
buf.read_bytes(buf.size)
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
alias << update
|
|
61
|
-
end
|
|
62
|
-
end
|
data/lib/confium/ffi.rb
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'ffi'
|
|
4
|
-
|
|
5
|
-
# {Confium::FFI} is the namespace for everything that touches the native
|
|
6
|
-
# Confium shared library through Ruby-FFI.
|
|
7
|
-
#
|
|
8
|
-
# This file registers autoload entries for the planned FFI helper modules
|
|
9
|
-
# (Library, Error, Options). They are listed in the TODO #14 architecture
|
|
10
|
-
# (see `TODO.finalize/14-ruby-bindings-architecture.md`) and will be added
|
|
11
|
-
# as the bindings grow; until then the autoloads are inert — they only
|
|
12
|
-
# trigger a load when the corresponding constant is first referenced.
|
|
13
|
-
#
|
|
14
|
-
# Note: the legacy FFI library wrapper still lives at `Confium::Lib`
|
|
15
|
-
# (file `confium/lib.rb`) and is autoloaded from `confium.rb`. It will be
|
|
16
|
-
# migrated into `Confium::FFI::Library` in a follow-up.
|
|
17
|
-
module Confium
|
|
18
|
-
module FFI
|
|
19
|
-
autoload :Library, 'confium/ffi/library'
|
|
20
|
-
autoload :Error, 'confium/ffi/error'
|
|
21
|
-
autoload :Options, 'confium/ffi/options'
|
|
22
|
-
end
|
|
23
|
-
end
|
data/lib/confium/lib.rb
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'ffi'
|
|
4
|
-
|
|
5
|
-
module Confium
|
|
6
|
-
module Lib
|
|
7
|
-
extend ::FFI::Library
|
|
8
|
-
|
|
9
|
-
FFI_LAYOUT = {
|
|
10
|
-
cfm_create: [%i[pointer], :uint32],
|
|
11
|
-
cfm_destroy: [%i[pointer], :uint32],
|
|
12
|
-
cfm_plugin_load: [%i[pointer string string pointer pointer], :uint32],
|
|
13
|
-
cfm_hash_create: [%i[pointer pointer pointer pointer pointer pointer], :uint32],
|
|
14
|
-
cfm_hash_output_size: [%i[pointer pointer], :uint32],
|
|
15
|
-
cfm_hash_block_size: [%i[pointer pointer], :uint32],
|
|
16
|
-
cfm_hash_update: [%i[pointer pointer uint32], :uint32],
|
|
17
|
-
cfm_hash_reset: [%i[pointer], :uint32],
|
|
18
|
-
cfm_hash_clone: [%i[pointer pointer], :uint32],
|
|
19
|
-
cfm_hash_finalize: [%i[pointer pointer uint32], :uint32],
|
|
20
|
-
cfm_hash_destroy: [%i[pointer], :void]
|
|
21
|
-
}.freeze
|
|
22
|
-
|
|
23
|
-
ffi_lib([ENV.fetch('CONFIUM_LIB', nil), 'confium', 'libconfium'].compact)
|
|
24
|
-
|
|
25
|
-
FFI_LAYOUT.each do |func, ary|
|
|
26
|
-
class_eval do
|
|
27
|
-
attach_function(func, ary.first, ary.last)
|
|
28
|
-
end
|
|
29
|
-
rescue ::FFI::NotFoundError
|
|
30
|
-
# that's okay
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
end
|
data/lib/confium/tc/session.rb
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'confium/lib'
|
|
4
|
-
|
|
5
|
-
# Confium::TC::Session wraps a threshold cryptography session.
|
|
6
|
-
#
|
|
7
|
-
# A session represents one signing or decryption operation involving
|
|
8
|
-
# T-of-N parties. The session goes through states: pending →
|
|
9
|
-
# commitments_collected → shares_collected → completed.
|
|
10
|
-
#
|
|
11
|
-
# Usage:
|
|
12
|
-
# session = Confium::TC::Session.new(scheme: "FROST-ed25519",
|
|
13
|
-
# threshold: 3,
|
|
14
|
-
# num_parties: 5,
|
|
15
|
-
# party_index: 0)
|
|
16
|
-
# session.set_local_share(share_bytes)
|
|
17
|
-
# session.round(incoming_messages) # returns outgoing messages
|
|
18
|
-
# result = session.result if session.complete?
|
|
19
|
-
module Confium
|
|
20
|
-
module TC
|
|
21
|
-
class Session
|
|
22
|
-
attr_reader :scheme, :threshold, :num_parties, :party_index, :state
|
|
23
|
-
|
|
24
|
-
def initialize(scheme:, threshold:, num_parties:, party_index:)
|
|
25
|
-
@scheme = scheme
|
|
26
|
-
@threshold = threshold
|
|
27
|
-
@num_parties = num_parties
|
|
28
|
-
@party_index = party_index
|
|
29
|
-
@state = :pending
|
|
30
|
-
@local_share = nil
|
|
31
|
-
@result = nil
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def set_local_share(share_bytes)
|
|
35
|
-
raise ArgumentError, 'share must be a String' unless share_bytes.is_a?(String)
|
|
36
|
-
|
|
37
|
-
@local_share = share_bytes
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def complete?
|
|
41
|
-
@state == :completed
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def result
|
|
45
|
-
raise 'Session not complete' unless complete?
|
|
46
|
-
|
|
47
|
-
@result
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
end
|