# 15. `example_integer_advanced.py` — Integer edge cases and bigint
[← Example index](index.md) · [example_integer_advanced.py on Codeberg](https://codeberg.org/abbra/synta/src/branch/main/examples/example_integer_advanced.py)
Bindings: `Integer(int)`, `Integer.from_bytes`, `Integer.from_u64`,
`Integer.to_int`, `Integer.to_i128`, `Integer.to_bytes`,
`Encoder.encode_integer` (bigint path), `Encoder.encode_integer_object`.
- Construct integers via all three constructors.
- Show `to_int()` succeeds for small values; raises `OverflowError` for 20-byte serials.
- Use `to_i128()` for up to 16-byte values (i128 max = 2¹²⁷−1); show `OverflowError` beyond that.
- Use `to_bytes()` for arbitrary-precision big-endian representation.
- Encode a 20-byte certificate serial number via `encode_integer(large_python_int)`.
- Verify `encode_integer_object` round-trip.
## Source
```python
#!/usr/bin/env python3
"""
Example 14: Integer edge cases and bigint.
Demonstrates: Integer(int), Integer.from_bytes, Integer.from_u64,
Integer.to_int, Integer.to_i128, Integer.to_bytes,
Encoder.encode_integer (bigint path), Encoder.encode_integer_object.
"""
import synta
def section(title):
print(f"\n{'─' * 60}\n{title}\n{'─' * 60}")
def demo_constructors():
section("Integer — three constructors")
# Constructor 1: Integer(int)
i1 = synta.Integer(42)
print(f" Integer(42).to_int() = {i1.to_int()}")
assert i1.to_int() == 42
# Constructor 2: Integer.from_u64(value)
i2 = synta.Integer.from_u64(2**32)
print(f" Integer.from_u64(2**32).to_bytes() = {i2.to_bytes().hex()}")
assert i2.to_bytes() == (2**32).to_bytes(5, "big", signed=True)
# Constructor 3: Integer.from_bytes(big_endian_signed_bytes)
# Use a large 20-byte positive integer (2^159 - 1)
serial_bytes = b'\x7f' + b'\xff' * 19
i3 = synta.Integer.from_bytes(serial_bytes)
print(f" Integer.from_bytes(20-byte): to_bytes={i3.to_bytes().hex()[:20]}...")
def demo_to_int_overflow():
section("to_int() — succeeds for small values, OverflowError for big ones")
small = synta.Integer(2**62)
print(f" Integer(2**62).to_int() = {small.to_int()}")
# A 20-byte serial number overflows i64
big_bytes = b'\x7f' + b'\xff' * 19 # 20 bytes, fits i128 but not i64
big = synta.Integer.from_bytes(big_bytes)
try:
big.to_int()
print(" No OverflowError (unexpected)")
except OverflowError as e:
print(f" OverflowError from to_int(): {e}")
def demo_to_i128():
section("to_i128() — works for 17–16 byte values")
# 17-byte signed value fits in i128
val = 2**127 - 1 # i128 max
val_bytes = val.to_bytes(16, "big", signed=True) # 16 bytes, fits i128
i = synta.Integer.from_bytes(val_bytes)
print(f" 16-byte value (i128 max = 2^127-1): {i.to_i128()}")
assert i.to_i128() == val
# Negative value via two's complement
neg = synta.Integer(-1)
print(f" Integer(-1).to_i128() = {neg.to_i128()}")
assert neg.to_i128() == -1
# Too large for i128: 17 bytes of 0x80 + 16 bytes 0x00 → > i128 max
too_big = b'\x00\x80' + b'\x00' * 16 # 18 bytes signed
big = synta.Integer.from_bytes(too_big)
try:
big.to_i128()
print(" No OverflowError (unexpected)")
except OverflowError as e:
print(f" OverflowError from to_i128(): {e}")
def demo_to_bytes():
section("to_bytes() — big-endian signed representation")
# Positive value
i = synta.Integer(255)
b = i.to_bytes()
print(f" Integer(255).to_bytes() = {b.hex()!r} (0x00ff — sign byte preserved)")
# Negative value uses two's complement
neg = synta.Integer(-1)
b = neg.to_bytes()
print(f" Integer(-1).to_bytes() = {b.hex()!r} (0xff)")
# Large value
large = synta.Integer.from_bytes(b'\x7f' + b'\xff' * 19)
b = large.to_bytes()
print(f" 20-byte serial: {b.hex()[:20]}... ({len(b)} bytes)")
def demo_encode_integer_large():
section("encode_integer — arbitrary-magnitude Python int (bigint path)")
# Normal small int (i64 path)
enc = synta.Encoder(synta.Encoding.DER)
enc.encode_integer(42)
print(f" encode_integer(42) → {enc.finish().hex()}")
# 20-byte certificate serial (beyond i64)
serial = 2**159 - 1 # 0x7ffff...fff, 20 bytes
enc = synta.Encoder(synta.Encoding.DER)
enc.encode_integer(serial)
out = enc.finish()
print(f" encode_integer(2**159-1): tag=0x{out[0]:02x} length={out[1]} value={out[2:4].hex()}...")
assert out[0] == 0x02 # INTEGER tag
assert out[1] == 20 # 20-byte content
# Round-trip via decode
dec = synta.Decoder(out, synta.Encoding.DER)
decoded = dec.decode_integer()
assert decoded.to_bytes() == b'\x7f' + b'\xff' * 19
print(" Decode round-trip: OK")
# Value needing 0x00 sign prefix (high bit set, positive)
val = 2**127 # bit_length=128, needs 17 bytes signed
enc = synta.Encoder(synta.Encoding.DER)
enc.encode_integer(val)
out2 = enc.finish()
assert out2[2] == 0x00 # leading sign byte
print(f" encode_integer(2**127) → content starts 0x{out2[2]:02x}0x{out2[3]:02x} (sign prefix + high byte)")
# Negative values use two's complement
enc = synta.Encoder(synta.Encoding.DER)
enc.encode_integer(-128)
assert enc.finish() == b'\x02\x01\x80'
enc = synta.Encoder(synta.Encoding.DER)
enc.encode_integer(-129)
assert enc.finish() == b'\x02\x02\xff\x7f'
print(" Negative values (two's complement): OK")
def demo_encode_integer_object():
section("encode_integer_object — encode an Integer instance")
big = synta.Integer.from_bytes(b'\x01' + b'\x00' * 16) # 2**128
enc = synta.Encoder(synta.Encoding.DER)
enc.encode_integer_object(big)
data = enc.finish()
dec = synta.Decoder(data, synta.Encoding.DER)
decoded = dec.decode_integer()
assert decoded.to_bytes() == big.to_bytes()
print(f" encode_integer_object round-trip: {decoded.to_bytes().hex()}")
print(" encode_integer_object: OK")
def main():
print("=" * 60)
print("Example 14: Integer edge cases and bigint")
print("=" * 60)
demo_constructors()
demo_to_int_overflow()
demo_to_i128()
demo_to_bytes()
demo_encode_integer_large()
demo_encode_integer_object()
print("\nAll Integer advanced examples completed.")
if __name__ == "__main__":
main()
```