GT47THY
New Member
- Joined
- Oct 29, 2026
- Messages
- 6
- Reaction score
- 2
Hi all—I built POPIA-Format, a C# and Python tool for transforming South African ID-shaped values in test datasets.
The use case is legacy test systems that need values with a particular numeric shape, checksum, or consistent joins. Where practical, purpose-built synthetic test data is preferable; this is for cases where replacing real values with ordinary random data breaks existing workflows. If you can replace it with fully synthetic data, do that—use this only where random data breaks joins/validation and you can't refactor yet.
What it currently does
- In the default mode, preserves the first six digits (the date of birth) and recomputes the final Luhn check digit.
- With the same key and tweak, the same input produces the same transformed value, so matching records can still join. That also reveals when records contain the same input value.
- Includes an optional DOB-hiding mode. Treat its output as transformed digits unless you have verified and documented how it preserves valid calendar dates.
- This preserves a 13-digit shape and a Luhn check digit; it does not guarantee that every output is a valid South African ID under all application-specific checks, or that an output has never been assigned to a real person. The default mode also leaves the date of birth visible. This is a data transformation tool, not a claim of anonymization or POPIA compliance.
Implementation and testing
The implementation uses FF1, rather than a custom cipher. My test suite checks it against published test vectors; the repository lists the sources, parameters, and expected outputs. The C# and Python implementations also produce matching outputs on synthetic test fixtures.
Test vectors and cross-language agreement are useful checks, but they are not an independent security audit.
Limitations
- It has not been independently audited.
- The output has no authentication tag, so tampering is not detected by the encryption operation itself.
- The implementation uses BigInteger arithmetic and is not constant-time. I intend it for controlled batch processing, not as a network-facing encryption oracle.
- It does not protect data if someone obtains the key.
- In the default mode, the date of birth remains visible.
- This tool alone does not make a dataset POPIA-compliant. POPIA assessments depend on the whole system, key management, and risk.
I’d be interested in feedback from people who have dealt with test data in legacy systems: when is a format-preserving transformation useful, and when should a team invest in synthetic data instead?
The use case is legacy test systems that need values with a particular numeric shape, checksum, or consistent joins. Where practical, purpose-built synthetic test data is preferable; this is for cases where replacing real values with ordinary random data breaks existing workflows. If you can replace it with fully synthetic data, do that—use this only where random data breaks joins/validation and you can't refactor yet.
What it currently does
- In the default mode, preserves the first six digits (the date of birth) and recomputes the final Luhn check digit.
- With the same key and tweak, the same input produces the same transformed value, so matching records can still join. That also reveals when records contain the same input value.
- Includes an optional DOB-hiding mode. Treat its output as transformed digits unless you have verified and documented how it preserves valid calendar dates.
- This preserves a 13-digit shape and a Luhn check digit; it does not guarantee that every output is a valid South African ID under all application-specific checks, or that an output has never been assigned to a real person. The default mode also leaves the date of birth visible. This is a data transformation tool, not a claim of anonymization or POPIA compliance.
Implementation and testing
The implementation uses FF1, rather than a custom cipher. My test suite checks it against published test vectors; the repository lists the sources, parameters, and expected outputs. The C# and Python implementations also produce matching outputs on synthetic test fixtures.
Test vectors and cross-language agreement are useful checks, but they are not an independent security audit.
Limitations
- It has not been independently audited.
- The output has no authentication tag, so tampering is not detected by the encryption operation itself.
- The implementation uses BigInteger arithmetic and is not constant-time. I intend it for controlled batch processing, not as a network-facing encryption oracle.
- It does not protect data if someone obtains the key.
- In the default mode, the date of birth remains visible.
- This tool alone does not make a dataset POPIA-compliant. POPIA assessments depend on the whole system, key management, and risk.
I’d be interested in feedback from people who have dealt with test data in legacy systems: when is a format-preserving transformation useful, and when should a team invest in synthetic data instead?