Skip to content

Zodiac Target System - Complete Documentation

State on 2026-08-25 — this is implemented now, and it is 24 marks.

Until this date zodiac was an alias onto GeometricForms. The family exists in sawabona-proof/src/targets/sets/zodiac.rs: the 12 signs, then the 12 classical planetary and alchemical symbols — sun, moon, mercury, venus, mars, jupiter, saturn, uranus, neptune, pluto, earth, salt.

Twelve would have been a weakening. The figure is chosen by index over the collection, so a family of 12 halves the unknown against the 24 of the other two. The symbols are not decoration; they are what makes the family safe to draw from.

Nothing selects this family. Which of the three a challenge draws from is derived from the licence's bootstrap secret, per challenge. It is not configurable and not named on the wire.

Overview

The Zodiac target system is an alternative to Greek for Geometric Proof (GP) authentication. It combines Western zodiac (12 signs) and Chinese zodiac (12 animals) for a total of 24 geometric primitives — matching the cardinality of the Greek alphabet target set.

Key Features:

  • 24 zodiac primitives (12 Western + 12 Chinese)
  • SVG-like path definitions for each sign
  • Same geometric transformations as Greek (rotate, mirror, translate, scale, shear)
  • Same invariant extraction (center of mass, perimeter, angle histogram)
  • Same HMAC-based proof mechanism

Architecture

Western Zodiac Signs (1–12)

The 12 classical Western zodiac signs:

  1. Aries (♈) - Ram symbol - Fire, Cardinal, Mars
  2. Taurus (♉) - Bull symbol - Earth, Fixed, Venus
  3. Gemini (♊) - Twins symbol - Air, Mutable, Mercury
  4. Cancer (♋) - Crab symbol - Water, Cardinal, Moon
  5. Leo (♌) - Lion symbol - Fire, Fixed, Sun
  6. Virgo (♍) - Maiden symbol - Earth, Mutable, Mercury
  7. Libra (♎) - Scales symbol - Air, Cardinal, Venus
  8. Scorpio (♏) - Scorpion symbol - Water, Fixed, Pluto
  9. Sagittarius (♐) - Archer symbol - Fire, Mutable, Jupiter
  10. Capricorn (♑) - Goat symbol - Earth, Cardinal, Saturn
  11. Aquarius (♒) - Water Bearer symbol - Air, Fixed, Uranus
  12. Pisces (♓) - Fish symbol - Water, Mutable, Neptune

Chinese Zodiac Animals (13–24)

The 12 animals of the Chinese zodiac (生肖, shēngxiào):

  1. Rat (鼠) - Clever, resourceful - Yang, Water
  2. Ox (牛) - Diligent, dependable - Yin, Earth
  3. Tiger (虎) - Brave, competitive - Yang, Wood
  4. Rabbit (兔) - Gentle, quiet - Yin, Wood
  5. Dragon (龙) - Confident, intelligent - Yang, Earth
  6. Snake (蛇) - Enigmatic, wise - Yin, Fire
  7. Horse (马) - Animated, active - Yang, Fire
  8. Goat (羊) - Calm, gentle - Yin, Earth
  9. Monkey (猴) - Sharp, clever - Yang, Metal
  10. Rooster (鸡) - Observant, hardworking - Yin, Metal
  11. Dog (狗) - Loyal, honest - Yang, Earth
  12. Pig (猪) - Compassionate, generous - Yin, Water

Geometric Representation

Each zodiac sign is defined as a geometric path with:

  • Segments - Line segments connecting points
  • Curves - Bezier curves for smooth shapes
  • Transformations - Rotation, mirroring, translation, scaling, shearing

Data Structure

Zodiac signs are stored in src/sawabona/targets/zodiac/zodiac_set.json:

{
  "zodiac_primitives": {
    "horn_left": ["L|180|1U", "L|225|1.41U"],
    "horn_right": ["L|0|1U", "L|315|1.41U"],
    "vertical_line": ["L|90|2U"],
    ...
  },
  "Zodiac_set": {
    "aries": {
      "symbol": "♈",
      "origin": "western",
      "element": "fire",
      "quality": "cardinal",
      "ruling_planet": "mars",
      "path_square": [["2U, 2U"], "S", "horn_left", "Y|0", "horn_right"],
      "latin_equiv": "ram"
    },
    ...
    "rat": {
      "symbol": "鼠",
      "origin": "chinese",
      "element": "water",
      "polarity": "yang",
      "path_square": [["2U, 2U"], "S", "ear_left", "Y|0", "ear_right", "tail_curve"],
      "latin_equiv": "rattus"
    },
    ...
  }
}

Key Fields:

  • symbol: Unicode symbol for the sign (e.g., "♈" or "鼠")
  • origin: "western" or "chinese"
  • element: Fire, Earth, Air, Water, Wood, or Metal
  • quality (Western): Cardinal, Fixed, or Mutable
  • polarity (Chinese): Yin or Yang
  • ruling_planet (Western): Astrological ruling planet
  • path_square: Geometric path definition using primitives
  • latin_equiv: Latin name equivalent

Usage

The family is not chosen — it is derived

Nothing selects zodiac, and nothing can. Which of the three families a challenge draws from is derived from the bootstrap secret by derive_target_set(bootstrap_secret, challenge_id), on the server and on the client, per challenge. The challenge does not carry it and the server never sends it, so an observer reading the traffic learns neither the family nor the figure.

This section used to say otherwise. It told an operator to set target_set: "zodiac" in config/challenges/default.yaml, or to export SAWABONA_TARGET_SET=zodiac, and to pass target_set="zodiac" to build_tile and compute_proof. None of that works now, and the reason it was removed is the point: a deployment that could pin the family would be announcing its choice to anyone who read its configuration, which is exactly what deriving it prevents.

target_set still exists in the configuration file and is informational only — see docs/security/GEOMETRIC-PROOF.md.

What a client passes instead

Nothing. compute_proof derives the family itself, from the same secret the server used:

# The family is absent from the call. It is derived inside, from the bootstrap
# secret, and matches the server's derivation for this challenge id.
proof = compute_proof(
    challenge_seed=12345,
    ops=ops,
    challenge_id="challenge-123",
    client_secret=b"secret",
)

Every SDK does the same, in nine languages, and the C ABI has no target_set parameter: sawabona_compute_proof_v2 (the _v2 is the ABI generation — see sawabona-proof-ffi/include/sawabona_proof.h).

Seeing this family's figures

A challenge draws from zodiac roughly one time in three, so a run that wants these figures specifically is a test concern, not a deployment one. Drive resolve_collection("zodiac") directly:

from sawabona.targets import resolve_collection

collection = resolve_collection("zodiac")   # the figures, not a deployment choice

Classes and Functions

ZodiacSign Class

Located in src/sawabona/targets/zodiac/zodiac_keys.py:

class ZodiacSign(KimbangulaItem):
    """Represents a zodiac sign as a geometric primitive."""

    def __init__(self, seed: int, zodiac_sign: str, segment_length: float = 1.0):
        """Initialize zodiac sign."""
        self.seed = seed
        self.zodiac_sign = zodiac_sign
        self.segment_length = segment_length
        self.segments = []
        self._load_sign()

    def apply_operation(self, op_type: str, *args: Any) -> None:
        """Apply geometric transformation."""
        # rotate, mirror_h, mirror_v, translate, scale, shear

    def draw2D(self) -> None:
        """Draw 2D representation using matplotlib."""

    def draw3D(self) -> None:
        """Draw 3D representation using matplotlib."""

ZodiacTile Class

Located in src/sawabona/client/geometric_proof_core.py:

class ZodiacTile(GeometricProofTile):
    """GP tile using zodiac signs as geometric primitives."""

    def __init__(self, seed: int, zodiac_sign: str = "aries", segment_length: float = 1.0):
        """Initialize zodiac tile."""
        self.seed = seed
        self.zodiac_sign = zodiac_sign
        self.segment_length = segment_length
        self.segments = []
        self._generate_base_tile()

Geometric Transformations

All transformations work the same as Greek:

Rotation

tile.apply_operation("rotate", angle=45)  # Rotate 45 degrees

Mirroring

tile.apply_operation("mirror_h")  # Mirror horizontally
tile.apply_operation("mirror_v")  # Mirror vertically

Translation

tile.apply_operation("translate", dx=1, dy=-1, dz=0)  # Move by (1, -1, 0)

Scaling

tile.apply_operation("scale", factor=2.0)  # Scale by 2x

Shearing

tile.apply_operation("shear", factor=0.5)  # Shear by 0.5

Invariant Extraction

The same invariants are extracted from zodiac tiles as from Greek tiles:

  1. Center of Mass - Geometric center of all segments
  2. Total Perimeter - Sum of all segment lengths
  3. Stroke Order Parity - XOR of segment count and seed
  4. Angle Histogram - Distribution of segment angles (4 bins)

These 12 floats form the Geometric Proof Vector (GPV).


Comparison: Greek vs Zodiac

Feature Greek Zodiac
Primitives 24 Greek letters 24 zodiac signs (12 Western + 12 Chinese)
Cultural origin Ancient Greek alphabet Western astrology + Chinese zodiac (生肖)
Geometric complexity High (detailed letters) Medium (symbolic shapes)
Default ✅ Yes (default) No (alternative)
Transformations rotate, mirror, translate, scale, shear rotate, mirror, translate, scale, shear
Invariant extraction Same algorithm Same algorithm
HMAC proof Same mechanism Same mechanism
Security Equivalent Equivalent

Testing

Unit Tests

Located in tests/unit/test_zodiac_targets.py:

def test_zodiac_sign_creation():
    """Test creating a zodiac sign."""
    sign = ZodiacSign(seed=12345, zodiac_sign="aries")
    assert sign.zodiac_sign == "aries"
    assert len(sign.segments) > 0

def test_zodiac_transformations():
    """Test zodiac transformations."""
    sign = ZodiacSign(seed=12345, zodiac_sign="leo")
    sign.apply_operation("rotate", 45)
    # Verify rotation was applied

Integration Tests

Located in tests/integration/test_zodiac_gp.py:

def test_zodiac_gp_flow():
    """Test complete zodiac Geometric Proof flow."""
    engine = get_challenge_engine("default")
    ops = engine.generate_challenge_ops()
    # The family is not passed. `build_tile` and `compute_proof` derive it
    # from the bootstrap secret, so a test that wants zodiac specifically
    # exercises the collection directly rather than steering the proof.
    collection = resolve_collection("zodiac")
    tile = build_tile(12345, ops, collection=collection)
    proof = compute_proof(12345, ops, "id", b"secret")
    assert len(proof) == 32

Performance

Zodiac signs are generally faster than Greek due to simpler geometry:

  • Zodiac tile creation: ~1-2ms
  • Zodiac transformation: ~0.5-1ms per operation
  • Invariant extraction: ~2-3ms
  • Total proof computation: ~5-10ms

Security

Zodiac target set provides equivalent security to Greek:

  • ✅ Same HMAC-based proof mechanism
  • ✅ Same invariant extraction algorithm
  • ✅ Same challenge-response protocol
  • ✅ Same computational difficulty

The security comes from the HMAC secret, not the geometric primitives.


Troubleshooting

Issue: "Zodiac module not available"

Cause: Zodiac module not installed

Solution: Ensure sawabona.targets.zodiac is available:

try:
    from sawabona.targets.zodiac import ZodiacSign
    print("Zodiac available")
except ImportError:
    print("Zodiac not available")

Issue: Invalid zodiac sign

Cause: Zodiac sign name not recognized

Solution: Use valid sign names:

valid_signs = [
    # Western zodiac (12)
    "aries", "taurus", "gemini", "cancer", "leo", "virgo",
    "libra", "scorpio", "sagittarius", "capricorn", "aquarius", "pisces",
    # Chinese zodiac (12)
    "rat", "ox", "tiger", "rabbit", "dragon", "snake",
    "horse", "goat", "monkey", "rooster", "dog", "pig",
]

References

  • Geometric Proof System: ../GEOMETRIC-PROOF.md
  • Greek Target Set: GREEK-TARGETS.md (default)
  • Challenge Engine: ../IMPLEMENTATION_ROADMAP.md
  • API Reference: ../reference/API-REFERENCE.md