# wc32

A custom Python encoding library with optional salt support for non-deterministic output.

## Installation

```bash
pip install wc32
```

## Usage

### Basic Encoding/Decoding

```python
from wc32 import encode, decode

# Encode with a key (deterministic - same input always produces same output)
encoded = encode("Hello, World!", "my_secret_key")
print(encoded)  # e.g., "kR.TV.rx.r-.yU.mD.Hj"

# Decode with the same key
decoded = decode(encoded, "my_secret_key")
print(decoded)  # "Hello, World!"
```

### Non-Deterministic Encoding (Recommended)

By default, encoding is deterministic (same text + key = same output). For security, you can enable random salt:

```python
# With random salt (recommended for sensitive data)
encoded = encode("Hello", "key", salt=True)
# Each call produces different output:
#   "a1b2c3d4.e5f6.g7h8.i9j0.k1l2"  (first call)
#   "f5e6d7c8.9a0b.1c2d.3e4f.5g6h"  (second call)

# Decode works automatically (salt is embedded in encoded string)
decoded = decode(encoded, "key")  # "Hello"
```

### Custom Salt

You can provide your own salt for reproducible non-deterministic output:

```python
# Custom salt (must be 8-32 hex characters)
encoded = encode("Hello", "key", salt="deadbeef12345678")
decoded = decode(encoded, "key")  # "Hello"
```

### Integrity Check

Add an HMAC-based integrity tag to detect wrong keys or tampered data:

```python
# Encode with integrity check
encoded = encode("Hello", "key", integrity=True)
# Output: "iA1B2C3D4.salt.e5f6.g7h8..."

# Decode with automatic verification (default)
decoded = decode(encoded, "key")  # "Hello"

# Wrong key raises error
decode(encoded, "wrong_key")  # ValueError: Integrity check failed

# Disable verification if needed
decoded = decode(encoded, "key", verify_integrity=False)
```

### Binary Data

Encode and decode binary data using Base64:

```python
# Encode binary data
data = b"\x00\x01\x02\xff\xfe\xfd"
encoded = encode(data, "key", binary=True)
# Decode back
decoded = decode(encoded, "key", binary=True)
print(decoded)  # b'\x00\x01\x02\xff\xfe\xfd'
```

### Custom Charset

Use your own character set (must be at least 10 unique characters):

```python
# Custom charset
encoded = encode("Hello", "key", charset="ABC123!@#")
decoded = decode(encoded, "key", charset="ABC123!@#")
```

### Batch Processing

Encode or decode multiple strings at once:

```python
from wc32 import encode_batch, decode_batch

texts = ["Hello", "World", "Test"]
encoded = encode_batch(texts, "key", salt=True)
# ['a1b2c3d4.e5f6...', 'f5e6d7c8.9a0b...', ...]

decoded = decode_batch(encoded, "key")
# ['Hello', 'World', 'Test']
```

## API Reference

### encode(text: str, key: str, salt: Union[bool, str] = False, integrity: bool = False, binary: bool = False, charset: Optional[str] = None) -> str

Encodes text using a custom base encoding with optional salt.

- **text**: The string (or bytes with binary=True) to encode
- **key**: Secret key for encoding
- **salt**: 
  - `False` (default): Deterministic encoding
  - `True`: Generate random salt
  - `str`: Use custom hex salt (8-32 characters)
- **integrity**: Add HMAC-based integrity tag (default: False)
- **binary**: Treat input as binary data (default: False)
- **charset**: Custom character set, minimum 10 chars (default: None)

### decode(encoded_text: str, key: str, binary: bool = False, charset: Optional[str] = None, verify_integrity: bool = True) -> Union[str, bytes]

Decodes previously encoded text.

- **encoded_text**: The encoded string
- **key**: Must match the key used for encoding
- **binary**: Return as bytes instead of string (default: False)
- **charset**: Custom character set used for encoding (default: None)
- **verify_integrity**: Verify integrity tag if present (default: True)

### encode_batch(texts: List, key: str, ...) -> List[str]

Batch version of encode().

### decode_batch(encoded_texts: List[str], key: str, ...) -> List[Union[str, bytes]]

Batch version of decode().

## Error Handling

The library raises descriptive errors for invalid inputs:

```python
from wc32 import encode, decode

# Empty key
encode("text", "")  # ValueError: Key must not be empty

# Wrong key with integrity
decode("iA1B2C3D4.salt.encoded", "wrong_key")  # ValueError: Integrity check failed

# Invalid characters
decode("invalid!!!", "key")  # ValueError: Invalid character
```

## Security Notes

- This is **not** encryption. It provides obfuscation only.
- Without salt, output is deterministic - don't use for sensitive data without salt.
- With `salt=True`, same text produces different outputs (semantically secure).
- With `integrity=True`, wrong keys are detected automatically.
- For proper security, use established encryption libraries like `cryptography`.
