Class: PqcAsn1::OID
- Inherits:
-
Object
- Object
- PqcAsn1::OID
- Defined in:
- lib/pqc_asn1/oid.rb
Overview
OID value class for post-quantum algorithm identifiers standardised by NIST.
All OID instances are frozen at construction time (initialize calls freeze). Each constant wraps a dotted-decimal string. Pass them directly to DER.build_spki or DER.build_pkcs8; dotted Strings are also accepted by the build methods.
DER.parse_spki and DER.parse_pkcs8 return the OID as a PqcAsn1::OID instance that can be compared directly against these constants using ==.
Sources (verified 2026-03-14):
ML-DSA: NIST FIPS 204, Table 2; NIST CSOR OID arc 2.16.840.1.101.3.4.3
ML-KEM: NIST FIPS 203; NIST CSOR OID arc 2.16.840.1.101.3.4.4
SLH-DSA: NIST FIPS 205, Table 2; NIST CSOR OID arc 2.16.840.1.101.3.4.3
Constant Summary collapse
- ML_DSA_44 =
OID 2.16.840.1.101.3.4.3.17 — 128-bit security (NIST level 2)
new("2.16.840.1.101.3.4.3.17")
- ML_DSA_65 =
OID 2.16.840.1.101.3.4.3.18 — 192-bit security (NIST level 3)
new("2.16.840.1.101.3.4.3.18")
- ML_DSA_87 =
OID 2.16.840.1.101.3.4.3.19 — 256-bit security (NIST level 5)
new("2.16.840.1.101.3.4.3.19")
- ML_KEM_512 =
OID 2.16.840.1.101.3.4.4.1 — 128-bit security (NIST level 1)
new("2.16.840.1.101.3.4.4.1")
- ML_KEM_768 =
OID 2.16.840.1.101.3.4.4.2 — 192-bit security (NIST level 3)
new("2.16.840.1.101.3.4.4.2")
- ML_KEM_1024 =
OID 2.16.840.1.101.3.4.4.3 — 256-bit security (NIST level 5)
new("2.16.840.1.101.3.4.4.3")
- SLH_DSA_SHA2_128S =
OID 2.16.840.1.101.3.4.3.20 — SHA-2, 128-bit, small (NIST level 1)
new("2.16.840.1.101.3.4.3.20")
- SLH_DSA_SHA2_128F =
OID 2.16.840.1.101.3.4.3.21 — SHA-2, 128-bit, fast (NIST level 1)
new("2.16.840.1.101.3.4.3.21")
- SLH_DSA_SHA2_192S =
OID 2.16.840.1.101.3.4.3.22 — SHA-2, 192-bit, small (NIST level 3)
new("2.16.840.1.101.3.4.3.22")
- SLH_DSA_SHA2_192F =
OID 2.16.840.1.101.3.4.3.23 — SHA-2, 192-bit, fast (NIST level 3)
new("2.16.840.1.101.3.4.3.23")
- SLH_DSA_SHA2_256S =
OID 2.16.840.1.101.3.4.3.24 — SHA-2, 256-bit, small (NIST level 5)
new("2.16.840.1.101.3.4.3.24")
- SLH_DSA_SHA2_256F =
OID 2.16.840.1.101.3.4.3.25 — SHA-2, 256-bit, fast (NIST level 5)
new("2.16.840.1.101.3.4.3.25")
- SLH_DSA_SHAKE_128S =
OID 2.16.840.1.101.3.4.3.26 — SHAKE, 128-bit, small (NIST level 1)
new("2.16.840.1.101.3.4.3.26")
- SLH_DSA_SHAKE_128F =
OID 2.16.840.1.101.3.4.3.27 — SHAKE, 128-bit, fast (NIST level 1)
new("2.16.840.1.101.3.4.3.27")
- SLH_DSA_SHAKE_192S =
OID 2.16.840.1.101.3.4.3.28 — SHAKE, 192-bit, small (NIST level 3)
new("2.16.840.1.101.3.4.3.28")
- SLH_DSA_SHAKE_192F =
OID 2.16.840.1.101.3.4.3.29 — SHAKE, 192-bit, fast (NIST level 3)
new("2.16.840.1.101.3.4.3.29")
- SLH_DSA_SHAKE_256S =
OID 2.16.840.1.101.3.4.3.30 — SHAKE, 256-bit, small (NIST level 5)
new("2.16.840.1.101.3.4.3.30")
- SLH_DSA_SHAKE_256F =
OID 2.16.840.1.101.3.4.3.31 — SHAKE, 256-bit, fast (NIST level 5)
new("2.16.840.1.101.3.4.3.31")
Class Attribute Summary collapse
- .custom_registry ⇒ Object readonly
- .der_tlv_cache ⇒ Object readonly private
Instance Attribute Summary collapse
-
#dotted ⇒ String
readonly
The dotted-decimal OID string (e.g. "2.16.840.1.101.3.4.3.17").
Class Method Summary collapse
-
.[](key) ⇒ PqcAsn1::OID?
Look up a built-in or registered OID by name or dotted string.
-
.builtin_by_dotted ⇒ Object
Lazily build the built-in OID reverse lookup hash on first access.
-
.register(dotted, name, key_sizes: nil) ⇒ PqcAsn1::OID
Register a custom OID so that name_for and OID.[] recognise it and key-size validation works for the new algorithm.
-
.registered ⇒ Hash{String => PqcAsn1::OID}
Enumerate all OIDs registered at runtime via OID.register.
Instance Method Summary collapse
-
#==(other) ⇒ Boolean
Compare against another OID or a dotted String.
-
#der_tlv ⇒ String
DER TLV bytes (tag 0x06 + length + value).
-
#eql?(other) ⇒ Boolean
Strict equality for use in Hash / eql? contexts (OID vs OID only).
- #hash ⇒ Integer
-
#initialize(dotted) ⇒ OID
constructor
A new instance of OID.
- #inspect ⇒ String
-
#name ⇒ String?
Human-readable constant name, e.g.
-
#to_s ⇒ String
The dotted-decimal string representation.
Constructor Details
#initialize(dotted) ⇒ OID
Returns a new instance of OID.
32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/pqc_asn1/oid.rb', line 32 def initialize(dotted) @dotted = dotted.frozen? ? dotted : dotted.dup.freeze # Pre-compute DER TLV if the C extension is already loaded. # Built-in constants (ML_DSA_44, etc.) are defined before the extension # loads, so from_dotted is not yet available for them — they fall back # to the class-level cache in #der_tlv. OIDs constructed at runtime # (OID.new, OID.register) always get @der_tlv set here, skipping the # class-level hash entirely. @der_tlv = self.class.respond_to?(:from_dotted) ? self.class.from_dotted(@dotted) : nil freeze end |
Class Attribute Details
.custom_registry ⇒ Object (readonly)
193 194 195 |
# File 'lib/pqc_asn1/oid.rb', line 193 def custom_registry @custom_registry end |
.der_tlv_cache ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
190 191 192 |
# File 'lib/pqc_asn1/oid.rb', line 190 def der_tlv_cache @der_tlv_cache end |
Instance Attribute Details
#dotted ⇒ String (readonly)
Returns the dotted-decimal OID string (e.g. "2.16.840.1.101.3.4.3.17").
29 30 31 |
# File 'lib/pqc_asn1/oid.rb', line 29 def dotted @dotted end |
Class Method Details
.[](key) ⇒ PqcAsn1::OID?
Look up a built-in or registered OID by name or dotted string.
Built-in constants are found via const_get; registered OIDs are
found via the runtime registry populated by register.
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 |
# File 'lib/pqc_asn1/oid.rb', line 219 def [](key) key = key.to_s if key.include?(".") # Dotted notation: O(1) hash lookup for built-in, then custom registry. builtin_by_dotted[key] || @custom_oid_by_dotted[key] else # Name: try built-in constant first, then custom registry. begin val = const_get(key, false) return val if val.is_a?(OID) rescue NameError end @custom_oid_by_name[key] end end |
.builtin_by_dotted ⇒ Object
Lazily build the built-in OID reverse lookup hash on first access.
196 197 198 199 200 201 202 203 204 205 |
# File 'lib/pqc_asn1/oid.rb', line 196 def builtin_by_dotted @builtin_by_dotted ||= begin h = {} constants.each do |c| val = const_get(c, false) h[val.dotted] = val if val.is_a?(OID) end h.freeze end end |
.register(dotted, name, key_sizes: nil) ⇒ PqcAsn1::OID
Register a custom OID so that name_for and [] recognise it and key-size validation works for the new algorithm.
Unlike the previous behaviour, this method does not define a Ruby
constant on PqcAsn1::OID. If you want a constant, assign the
return value explicitly:
PqcAsn1::OID::MY_ALGO = PqcAsn1::OID.register("1.3.x", "MY_ALGO")
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 |
# File 'lib/pqc_asn1/oid.rb', line 262 def register(dotted, name, key_sizes: nil) name = name.to_s.freeze dotted = dotted.to_s.freeze @register_mutex.synchronize do if @custom_oid_by_name.key?(name) raise ArgumentError, "OID name #{name.inspect} is already registered" end if @custom_oid_by_dotted.key?(dotted) raise ArgumentError, "OID #{dotted} is already registered as #{@custom_registry[dotted]}" end # Prevent shadowing built-in OID constants. begin existing = const_get(name, false) if existing.is_a?(OID) raise ArgumentError, "OID name #{name.inspect} conflicts with built-in constant #{name}" end rescue NameError # name is not a built-in constant — fine to register end # Prevent registering a dotted string that belongs to a built-in OID. if builtin_by_dotted.key?(dotted) builtin = builtin_by_dotted[dotted] builtin_name = constants.find { |c| const_get(c, false).equal?(builtin) } raise ArgumentError, "OID #{dotted} is already defined as built-in #{builtin_name}" end oid = new(dotted) @custom_oid_by_dotted[dotted] = oid @custom_oid_by_name[name] = oid @custom_registry[dotted] = name PqcAsn1::DER::REGISTERED_KEY_SIZES[oid] = key_sizes.freeze if key_sizes oid end end |
.registered ⇒ Hash{String => PqcAsn1::OID}
Enumerate all OIDs registered at runtime via register.
238 239 240 |
# File 'lib/pqc_asn1/oid.rb', line 238 def registered @custom_oid_by_name.dup.freeze end |
Instance Method Details
#==(other) ⇒ Boolean
Compare against another OID or a dotted String.
47 48 49 50 51 52 53 |
# File 'lib/pqc_asn1/oid.rb', line 47 def ==(other) case other when OID then @dotted == other.dotted when String then @dotted == other else false end end |
#der_tlv ⇒ String
DER TLV bytes (tag 0x06 + length + value). For OIDs created after the C extension loads, returns the pre-computed ivar set in initialize (O(1), no hash lookup). For the built-in constants (created at load time before the extension), falls back to the class-level cache on first access. Requires the C extension to be loaded (called at runtime, not load time).
84 85 86 87 |
# File 'lib/pqc_asn1/oid.rb', line 84 def der_tlv return @der_tlv if @der_tlv OID.der_tlv_cache[@dotted] ||= PqcAsn1::OID.from_dotted(@dotted) end |
#eql?(other) ⇒ Boolean
Strict equality for use in Hash / eql? contexts (OID vs OID only).
58 59 60 |
# File 'lib/pqc_asn1/oid.rb', line 58 def eql?(other) other.is_a?(OID) && @dotted == other.dotted end |
#hash ⇒ Integer
63 64 65 |
# File 'lib/pqc_asn1/oid.rb', line 63 def hash @dotted.hash end |
#inspect ⇒ String
73 74 75 |
# File 'lib/pqc_asn1/oid.rb', line 73 def inspect "#<PqcAsn1::OID #{@dotted}>" end |
#name ⇒ String?
Human-readable constant name, e.g. "ML_DSA_44", or nil if unknown. Checks both built-in OIDs and user-registered OIDs.
92 93 94 |
# File 'lib/pqc_asn1/oid.rb', line 92 def name PqcAsn1::OID.name_for(self) end |
#to_s ⇒ String
Returns the dotted-decimal string representation.
68 69 70 |
# File 'lib/pqc_asn1/oid.rb', line 68 def to_s @dotted end |