← All tasks Task 6 of 12 unsolved

6. Format-Preserving Phone Masking

Hashing Format Preservation ~25 min

Mask a phone number while preserving the visible structure — country code, separators, length. Apps that validate format on the masked data (regex, length checks, libphonenumber) keep working; analysts can still see "looks like a UK number".

Country code: keep the first digit-group after +. All separators (+, space, dash, parens) stay in their positions. Remaining digits are replaced from a deterministic hash of salt:phone.

Tests this task must pass

  1. Determinism — same input gives the same output.
  2. Format preserved+7 702 365 6813 output starts with +7 , has 3 spaces, same total length.
  3. Different inputs differ — distinct numbers produce distinct masks.
  4. Null in → null out.
  5. Multi-digit country codes — UK +44 20 7946 0958 output starts with +44  and keeps 3 spaces.
import java.security.MessageDigest //sampleStart fun maskPhone(phone: String?, salt: String = "s3cret"): String? { // Preserve format: spaces, dashes, plus sign stay in same positions // Replace digits (except country code) with deterministic digits from hash // Country code: first 1-3 digits after "+" are preserved // Same input + salt → always same output TODO() } //sampleEnd fun main() { // Test 1: Determinism val a = maskPhone("+7 702 365 6813") val b = maskPhone("+7 702 365 6813") check(a == b) { "FAIL: must be deterministic. Got $a and $b" } println("✅ Test 1: Deterministic — $a") // Test 2: Format preserved check(a!!.startsWith("+7 ")) { "FAIL: country code preserved" } check(a.count { it == ' ' } == 3) { "FAIL: spaces preserved. Got: $a" } check(a.length == "+7 702 365 6813".length) { "FAIL: length preserved" } println("✅ Test 2: Format preserved — $a") // Test 3: Different input → different output val c = maskPhone("+7 999 111 2222") check(a != c) { "FAIL: different inputs must differ" } println("✅ Test 3: Different outputs") // Test 4: Null handling check(maskPhone(null) == null) { "FAIL: null → null" } println("✅ Test 4: Null handling") // Test 5: Different format preserved val d = maskPhone("+44 20 7946 0958") check(d!!.startsWith("+44 ")) { "FAIL: +44 preserved" } check(d.count { it == ' ' } == 3) { "FAIL: spaces preserved for UK number" } println("✅ Test 5: UK format — $d") println("\n🎉 ALL TESTS PASSED!") }
← Previous Next: Bounded Queue →