# 12. `example_objectidentifier.py` — ObjectIdentifier constructors and operations
[← Example index](index.md) · [example_objectidentifier.py on Codeberg](https://codeberg.org/abbra/synta/src/branch/main/examples/example_objectidentifier.py)
Bindings: `ObjectIdentifier(str)`, `ObjectIdentifier.from_components`,
`ObjectIdentifier.from_der_value`, `ObjectIdentifier.components`,
`ObjectIdentifier.__eq__`, `ObjectIdentifier.__hash__`,
`Decoder.decode_oid`, `Encoder.encode_oid`, `Encoder.encode_oid_object`.
- Construct OIDs via all three constructors; verify they compare equal.
- Show `__eq__` working against a dotted string.
- Use OIDs as dict keys (demonstrate hashability).
- Round-trip through `encode_oid` / `decode_oid`.
- Show `from_der_value` with the raw content bytes from an implicit-tag context.
## Source
```python
#!/usr/bin/env python3
"""
Example 11: ObjectIdentifier constructors and operations.
Demonstrates: ObjectIdentifier(str), ObjectIdentifier.from_components,
ObjectIdentifier.from_der_value, ObjectIdentifier.components,
ObjectIdentifier.__eq__ (against string and OID), ObjectIdentifier.__hash__,
Decoder.decode_oid, Encoder.encode_oid, Encoder.encode_oid_object.
"""
import synta
import synta.oids as oids
def section(title):
print(f"\n{'─' * 60}\n{title}\n{'─' * 60}")
def demo_constructors():
section("Three constructors — all yield equivalent OIDs")
# 1. From dotted-decimal string
oid_str = synta.ObjectIdentifier("1.2.840.113549.1.1.11") # sha256WithRSAEncryption
# 2. From component list
oid_comp = synta.ObjectIdentifier.from_components([1, 2, 840, 113549, 1, 1, 11])
# 3. From DER value bytes (the OID content without tag/length)
# sha256WithRSAEncryption DER content: 2a 86 48 86 f7 0d 01 01 0b
der_value = bytes.fromhex("2a864886f70d01010b")
oid_der = synta.ObjectIdentifier.from_der_value(der_value)
print(f" from string: {oid_str}")
print(f" from components: {oid_comp}")
print(f" from_der_value: {oid_der}")
assert oid_str == oid_comp == oid_der
print(" All three are equal: OK")
def demo_components():
section("components() — tuple of integer arcs")
oid = synta.ObjectIdentifier("2.5.4.3") # id-at-commonName
comps = oid.components()
print(f" OID: {oid}")
print(f" components: {comps}")
assert list(comps) == [2, 5, 4, 3]
def demo_equality():
section("__eq__ — compare against OID or dotted string")
rsa_oid = oids.RSA_ENCRYPTION # ObjectIdentifier("1.2.840.113549.1.1.1")
# Compare OID to OID
other = synta.ObjectIdentifier("1.2.840.113549.1.1.1")
assert rsa_oid == other
print(f" {rsa_oid} == ObjectIdentifier(same): True")
# Compare OID to dotted string
assert rsa_oid == "1.2.840.113549.1.1.1"
assert not (rsa_oid == "1.2.840.113549.1.1.11")
print(f" {rsa_oid} == '1.2.840.113549.1.1.1': True")
print(f" {rsa_oid} == '1.2.840.113549.1.1.11': False")
def demo_hashability():
section("__hash__ — use OIDs as dict keys")
alg_names = {
oids.RSA_ENCRYPTION: "RSA",
oids.EC_PUBLIC_KEY: "EC",
oids.ED25519: "Ed25519",
}
test_oid = synta.ObjectIdentifier("1.2.840.113549.1.1.1")
print(f" alg_names[RSA_ENCRYPTION] = {alg_names[test_oid]!r}")
assert alg_names[test_oid] == "RSA"
# hash is consistent with hash(str(oid))
oid = oids.SHA256
assert hash(oid) == hash(str(oid))
print(f" hash(oid) == hash(str(oid)) for {oid}: OK")
def demo_encode_decode_roundtrip():
section("encode_oid / decode_oid round-trip")
oid = synta.ObjectIdentifier("1.3.6.1.5.5.7.48.1.1") # id-pkix-ocsp-basic
enc = synta.Encoder(synta.Encoding.DER)
enc.encode_oid(oid)
encoded = enc.finish()
print(f" DER: {encoded.hex()}")
dec = synta.Decoder(encoded, synta.Encoding.DER)
decoded = dec.decode_oid()
assert decoded == oid
print(f" Decoded: {decoded}")
print(" encode_oid / decode_oid round-trip: OK")
def demo_encode_oid_object():
section("encode_oid_object — encode an ObjectIdentifier instance")
oid = oids.ED25519 # 1.3.101.112
enc = synta.Encoder(synta.Encoding.DER)
enc.encode_oid_object(oid)
encoded = enc.finish()
dec = synta.Decoder(encoded, synta.Encoding.DER)
decoded = dec.decode_oid()
assert decoded == oid
print(f" encode_oid_object({oid}) → {encoded.hex()}")
print(f" Decoded back: {decoded}")
print(" encode_oid_object round-trip: OK")
def demo_from_der_value_implicit():
section("from_der_value — decode OID in implicit-tag context")
# In an implicit context (e.g. [0] IMPLICIT OID), the tag is replaced
# but the content bytes remain standard OID encoding.
# Content for id-ce-basicConstraints (2.5.29.19):
content = bytes.fromhex("551d13")
oid = synta.ObjectIdentifier.from_der_value(content)
print(f" content: {content.hex()}")
print(f" OID: {oid}")
assert oid == "2.5.29.19"
# Also handles id-at-commonName (2.5.4.3 → 55 04 03)
content_cn = bytes.fromhex("550403")
oid_cn = synta.ObjectIdentifier.from_der_value(content_cn)
print(f" id-at-commonName: {oid_cn}")
assert oid_cn == "2.5.4.3"
def main():
print("=" * 60)
print("Example 11: ObjectIdentifier constructors and operations")
print("=" * 60)
demo_constructors()
demo_components()
demo_equality()
demo_hashability()
demo_encode_decode_roundtrip()
demo_encode_oid_object()
demo_from_der_value_implicit()
print("\nAll ObjectIdentifier examples completed.")
if __name__ == "__main__":
main()
```