# 25. `example_pkixalgs.py` — RFC 3279 algorithm parameter types
[← Example index](index.md) · [example_pkixalgs.py on Codeberg](https://codeberg.org/abbra/synta/src/branch/main/examples/example_pkixalgs.py)
Bindings: `synta.pkixalgs.DssParms`, `synta.pkixalgs.ECParameters`,
`synta.pkixalgs.EcdsaSigValue`, `synta.pkixalgs.DssSigValue` and OID constants.
- Parse `DssParms` (DSA domain parameters P/Q/G) from hand-crafted DER; verify round-trip.
- Parse `ECParameters` in `namedCurve` form; access `arm` and `named_curve_oid`.
- Parse `EcdsaSigValue` (r and s components of an ECDSA signature).
- Use OID constants: `ID_DSA`, `ID_EC_PUBLIC_KEY`, `ECDSA_WITH_SHA256`, `PRIME256V1`.
## Source
```python
#!/usr/bin/env python3
"""
Example: RFC 3279 algorithm parameter types (synta.pkixalgs).
Demonstrates ``DssParms``, ``DssSigValue``, ``EcdsaSigValue``, and
``ECParameters``, plus the OID constants for DSA, DH, EC, and named-curve
algorithms.
All DER inputs are constructed in-process using the synta encoder so that
no external files are required.
"""
import synta
import synta.pkixalgs as pa
def section(title):
print(f"\n{'─' * 60}\n{title}\n{'─' * 60}")
# ── DER building helpers ──────────────────────────────────────────────────────
def _enc(fn):
"""Encode one element and return its DER bytes."""
enc = synta.Encoder(synta.Encoding.DER)
fn(enc)
return enc.finish()
def _seq(*parts):
"""Wrap raw TLV bytes in a SEQUENCE."""
enc = synta.Encoder(synta.Encoding.DER)
enc.encode_sequence(b"".join(parts))
return enc.finish()
def _int_bytes(b: bytes) -> bytes:
"""DER INTEGER TLV from big-endian unsigned bytes.
Prepends a 0x00 padding byte when the most-significant bit is set
(to keep the encoding non-negative in two's-complement).
Assumes short-form length (< 128 bytes of content).
"""
if b[0] & 0x80:
b = b"\x00" + b
return bytes([0x02, len(b)]) + b
def _oid(dotted: str) -> bytes:
"""DER OID TLV from a dotted-decimal string."""
return _enc(lambda e: e.encode_oid(synta.ObjectIdentifier(dotted)))
# ── Pre-built DER ─────────────────────────────────────────────────────────────
# DSA domain parameters: small illustrative p, q, g values.
# All have a clear MSB so _int_bytes() does not prepend 0x00; the bytes
# returned by .p / .q / .g will equal these exact values.
_P = b"\x73\xd0" + b"\xff" * 13 # 15 bytes (simulated prime modulus)
_Q = b"\x25\xf1" * 9 + b"\x25" # 19 bytes (simulated subgroup order)
_G = b"\x01\xaa" * 7 + b"\x01" # 15 bytes (simulated generator)
DSS_PARMS_DER = _seq(_int_bytes(_P), _int_bytes(_Q), _int_bytes(_G))
# DSA signature: illustrative r and s (31 bytes each, MSB clear)
_R_DSA = b"\x41" + b"\xbb" * 30
_S_DSA = b"\x42" + b"\xcc" * 30
DSS_SIG_DER = _seq(_int_bytes(_R_DSA), _int_bytes(_S_DSA))
# ECDSA signature: illustrative r and s (32 bytes each, MSB clear)
_R_ECDSA = b"\x41" + b"\xbb" * 31
_S_ECDSA = b"\x42" + b"\xcc" * 31
ECDSA_SIG_DER = _seq(_int_bytes(_R_ECDSA), _int_bytes(_S_ECDSA))
# ECParameters namedCurve: the curve OID is the entire encoding.
# ECParameters is a CHOICE { ecParameters SEQUENCE, namedCurve OID, implicitlyCA NULL }.
# The DER tag of each alternative identifies the arm — no context tags are used.
PRIME256V1_DOTTED = "1.2.840.10045.3.1.7"
EC_PARAMS_NAMED_CURVE_DER = _oid(PRIME256V1_DOTTED) # bare OID TLV
# ── Demo functions ─────────────────────────────────────────────────────────────
def demo_dss_parms():
section("DssParms — DSA domain parameters (RFC 3279 §2.3.2)")
parms = pa.DssParms.from_der(DSS_PARMS_DER)
# .p / .q / .g return the big-endian two's-complement bytes of each INTEGER
assert parms.p == _P, f"p mismatch: {parms.p.hex()}"
assert parms.q == _Q, f"q mismatch: {parms.q.hex()}"
assert parms.g == _G, f"g mismatch: {parms.g.hex()}"
print(f" p ({len(parms.p)} bytes): {parms.p.hex()[:20]}…")
print(f" q ({len(parms.q)} bytes): {parms.q.hex()[:20]}…")
print(f" g ({len(parms.g)} bytes): {parms.g.hex()[:20]}…")
print(f" repr: {repr(parms)}")
# Round-trip: re-encode and parse again
der2 = parms.to_der()
parms2 = pa.DssParms.from_der(der2)
assert parms2.p == parms.p
assert parms2.q == parms.q
assert parms2.g == parms.g
print(" round-trip: ✓")
def demo_dss_sig_value():
section("DssSigValue — DSA signature (RFC 3279 §2.2.2)")
sig = pa.DssSigValue.from_der(DSS_SIG_DER)
assert sig.r == _R_DSA, f"r mismatch: {sig.r.hex()}"
assert sig.s == _S_DSA, f"s mismatch: {sig.s.hex()}"
print(f" r ({len(sig.r)} bytes): {sig.r.hex()[:16]}…")
print(f" s ({len(sig.s)} bytes): {sig.s.hex()[:16]}…")
print(f" repr: {repr(sig)}")
# Round-trip
der2 = sig.to_der()
sig2 = pa.DssSigValue.from_der(der2)
assert sig2.r == sig.r
assert sig2.s == sig.s
print(" round-trip: ✓")
def demo_ecdsa_sig_value():
section("EcdsaSigValue — ECDSA signature (RFC 3279 §2.2.3, X9.62)")
sig = pa.EcdsaSigValue.from_der(ECDSA_SIG_DER)
assert sig.r == _R_ECDSA, f"r mismatch: {sig.r.hex()}"
assert sig.s == _S_ECDSA, f"s mismatch: {sig.s.hex()}"
print(f" r ({len(sig.r)} bytes): {sig.r.hex()[:16]}…")
print(f" s ({len(sig.s)} bytes): {sig.s.hex()[:16]}…")
print(f" repr: {repr(sig)}")
# Round-trip
der2 = sig.to_der()
sig2 = pa.EcdsaSigValue.from_der(der2)
assert sig2.r == sig.r
assert sig2.s == sig.s
print(" round-trip: ✓")
def demo_ec_parameters_named_curve():
section("ECParameters namedCurve — P-256 (RFC 3279 §2.3.5, X9.62)")
# ECParameters is decoded from its bare DER encoding:
# namedCurve → OID TLV (tag 0x06)
# ecParameters → SEQUENCE TLV (tag 0x30)
# implicitlyCA → NULL TLV (tag 0x05)
params = pa.ECParameters.from_der(EC_PARAMS_NAMED_CURVE_DER)
assert params.arm == "namedCurve", f"unexpected arm: {params.arm!r}"
oid = params.named_curve_oid
assert oid is not None
assert str(oid) == PRIME256V1_DOTTED, f"OID mismatch: {oid}"
print(f" arm: {params.arm!r}")
print(f" named_curve_oid: {oid} (P-256 / prime256v1)")
print(f" repr: {repr(params)}")
# ecParameters arm → named_curve_oid is None
# Build a minimal SpecifiedECDomain SEQUENCE (just enough for parsing)
# A real ecParameters would contain field, curve, base, order, cofactor.
# For this example, demonstrate that named_curve_oid is None for the other arms.
# implicitlyCA arm: encoded as NULL (05 00)
null_der = b"\x05\x00"
implicit_params = pa.ECParameters.from_der(null_der)
assert implicit_params.arm == "implicitlyCA"
assert implicit_params.named_curve_oid is None
print(f" implicitlyCA arm: named_curve_oid = {implicit_params.named_curve_oid}")
# Round-trip for namedCurve
der2 = params.to_der()
params2 = pa.ECParameters.from_der(der2)
assert params2.arm == "namedCurve"
assert str(params2.named_curve_oid) == PRIME256V1_DOTTED
print(" round-trip: ✓")
def demo_oid_constants():
section("OID constants — synta.pkixalgs")
constants = [
# (attribute_name, ObjectIdentifier, expected_dotted_string)
("ID_DSA", pa.ID_DSA, "1.2.840.10040.4.1"),
("ID_DSA_WITH_SHA1", pa.ID_DSA_WITH_SHA1, "1.2.840.10040.4.3"),
("DHPUBLICNUMBER", pa.DHPUBLICNUMBER, "1.2.840.10046.2.1"),
("ID_EC_PUBLIC_KEY", pa.ID_EC_PUBLIC_KEY, "1.2.840.10045.2.1"),
("ECDSA_WITH_SHA1", pa.ECDSA_WITH_SHA1, "1.2.840.10045.4.1"),
("ECDSA_WITH_SHA256", pa.ECDSA_WITH_SHA256, "1.2.840.10045.4.3.2"),
("ECDSA_WITH_SHA384", pa.ECDSA_WITH_SHA384, "1.2.840.10045.4.3.3"),
("ECDSA_WITH_SHA512", pa.ECDSA_WITH_SHA512, "1.2.840.10045.4.3.4"),
("PRIME192V1", pa.PRIME192V1, "1.2.840.10045.3.1.1"),
("PRIME256V1", pa.PRIME256V1, "1.2.840.10045.3.1.7"),
("SECP224R1", pa.SECP224R1, "1.3.132.0.33"),
("SECP384R1", pa.SECP384R1, "1.3.132.0.34"),
("SECP521R1", pa.SECP521R1, "1.3.132.0.35"),
]
for name, oid, expected in constants:
dotted = str(oid)
assert dotted == expected, f"{name}: expected {expected!r}, got {dotted!r}"
print(f" pa.{name:<22} = {dotted}")
# OID constants are ObjectIdentifier objects — usable directly with the encoder
enc = synta.Encoder(synta.Encoding.DER)
enc.encode_oid(pa.PRIME256V1)
prime256_der = enc.finish()
assert prime256_der == _oid(PRIME256V1_DOTTED)
print()
print(f" PRIME256V1 DER: {prime256_der.hex()}")
# OID constants compare equal to ObjectIdentifier constructed from dotted string
assert pa.ID_EC_PUBLIC_KEY == synta.ObjectIdentifier("1.2.840.10045.2.1")
print(" OID equality check: ✓")
# ── main ──────────────────────────────────────────────────────────────────────
def main():
print("=" * 60)
print("Example: RFC 3279 algorithm parameter types (synta.pkixalgs)")
print("=" * 60)
demo_dss_parms()
demo_dss_sig_value()
demo_ecdsa_sig_value()
demo_ec_parameters_named_curve()
demo_oid_constants()
print("\nAll pkixalgs examples completed.")
if __name__ == "__main__":
main()
```