- QR 코드에 우연히 생길 수 있는 스와스티카 문양을 탐지하고, 선택적으로 문양 없는 QR 코드를 생성하는 Rust 크레이트임
- QR 표준의 8개 마스크 패턴을 모두 렌더링해 문양 없는 후보를 추린 뒤, ISO/IEC 18004 페널티가 가장 낮은 마스크를 선택함
- 파인더·타이밍·정렬·포맷·버전 모듈을 검사에서 제외하고 주변 대비를 고려해, 기능 요소나 눈에 보이지 않는 형태를 오인하지 않도록 함
- 기본 탐지기는 외부 의존성이 없고
unsafe코드를 금지하며, 여러 QR 라이브러리와Vec<Vec<bool>>표현을 지원함 - 탐지 범위는 축에 정렬된 5×5·7×7 갈고리 십자형의 양쪽 방향과 두 색상 극성으로 한정되며, 45도·대각선 형태와 임의 회전은 지원하지 않음
우발적 문양을 피해야 하는 이유
- qr-swastika-avoider는 QR 코드에 무작위로 나타날 수 있는 스와스티카 패턴을 탐지하고 회피함
- QR 코드는 서로 교체 가능한 8개 마스크 패턴 중 가독성 점수가 가장 좋은 것을 선택하지만, 불쾌감을 줄 수 있는 기호까지 검사하지는 않음
- 작고 얇은 문양은 QR 표준의 평가 과정에서 걸러지기 어려워 최종 코드에 우연히 남을 수 있음
기능 요소와 대비를 고려한 탐지
- 기본 탐지기는 외부 의존성이 없으며
#![forbid(unsafe_code)]를 적용함 - 두 개 메서드로 구성된 작은
QrModules트레이트를 통해 다양한 QR 표현 형식을 검사할 수 있음 - 파인더·타이밍·정렬·포맷·버전 모듈을 탐지 대상에서 제외해 파인더 모서리를 스와스티카로 오인하지 않음
- 같은 색 모듈 안에 묻혀 실제로 보이지 않는 문양은 주변 대비를 기준으로 무시하며, 이 기준은 조정 가능함
- 기존 QR 코드는
contains_swastika로 검사할 수 있고, 문양이 발견되면 다시 생성하거나 사용자에게 경고할 수 있음
지원하는 QR 표현과 라이브러리
- Cargo 기능으로 다음 어댑터를 제공함
qrcodegen:qrcodegen::QrCode용QrModulesqrcode:qrcode::QrCode용QrModulesfast_qr:fast_qr::QRCode용QrModules
- 원시 모듈 행렬인
Vec<Vec<bool>>도 별도 어댑터 없이 지원하며,true는 어두운 모듈을 뜻함
문양 없는 QR 코드 생성
generate기능의encode_safe는 콘텐츠와 오류 정정 수준을 받아 문양 없는 스캔 가능한 QR 코드를 반환하며, 생성할 수 없으면 명시적 오류를 돌려줌- 생성 과정에서는 8개 마스크를 모두 렌더링한 뒤 탐지 대상 문양이 없는 후보만 유지함
- 남은 후보 중 ISO/IEC 18004 페널티가 가장 낮은 마스크를 반환해 표준의 가독성 최적화를 유지함
- 반환값의
matrix()로 모듈 행렬을 가져오고mask()로 선택된 마스크를 확인할 수 있음
Cargo 기능 구성
- 기본 기능에는 의존성 없는 탐지기만 포함됨
qrcodegen,qrcode,fast_qr기능은 각 라이브러리용 어댑터를 추가함generate기능은qrcodegen을 의존성으로 가져오며encode_safe를 제공함
탐지 범위와 라이선스
- 고전적인 축 정렬 갈고리 십자형 중 5×5와 7×7 크기, 양쪽 방향, 밝고 어두운 두 색상 극성을 작은 허용 오차 안에서 탐지함
- 45도 또는 대각선 문양과 임의 각도로 회전한 형태는 탐지 범위에 포함되지 않음
- MIT License로 배포됨
댓글과 토론
Lobste.rs 의견들
-
이 프로젝트가 종교적 만자문은 피하면서 정작 나치가 사용한 만자는 피하지 않는다는 점이 혼란스러움. 나치 문양은 45도 회전한 형태인데, 프로젝트는 “45도·대각선 모티프와 임의 회전은 범위 밖”이라고 명시함
- 회전하지 않은 만자도 똑같이 나치 상징으로 받아들여짐. 그렇게 생각하지 않는다면 회전하지 않은 만자를 잘 보이는 곳에 임시 문신으로 붙이고 거리에 나가 보면 됨
QR 코드에서 우연히 생기는 이미지는 해상도가 낮아서, 오히려 회전하지 않은 형태만 무작위 픽셀 무늬가 아니라 만자로 선명하게 인식될 가능성이 큼. 여기에 집중하는 것이 합리적임 - 나도 그 점이 눈에 띄었음. 탐지 알고리즘이 행과 열을 훑는 롤링 체크섬처럼 본질적으로 직사각형 패턴만 처리하는 구조인지 궁금함
또 “파인더·타이밍·정렬·형식 및 버전 모듈은 제외해 파인더 모서리를 만자로 오인하지 않는다”고 하는데, 사람이 QR 코드에서 불쾌한 상징을 봤을 때 그 픽셀이 데이터인지 타이밍 패턴인지에 따라 반응이 달라지지는 않을 것임. 파인더 모서리는 그냥 사각형인데 굳이 분석에서 제외해야 하는 이유도 모르겠고, 파고들수록 말이 안 맞아서 AI가 대충 생성한 결과물인지 의심됨
- 회전하지 않은 만자도 똑같이 나치 상징으로 받아들여짐. 그렇게 생각하지 않는다면 회전하지 않은 만자를 잘 보이는 곳에 임시 문신으로 붙이고 거리에 나가 보면 됨
-
이런 프로젝트가 존재한다는 사실이 슬픔. QR 코드 안에 불쾌한 상징이 우연히 나타날 수 있다는 생각조차 해본 적이 없었음
-
“간단한 QR 코드를 만들다가 거대한 나치 문양이 무작위로 생기는 일이 대체 얼마나 자주 있나?”에 직접 계산해 봄. QR 코드가 완전히 무작위는 아니지만 여기서는 무시함
5×5와 7×7 만자를 독립적으로 보면 각각 좌우 두 방향, 두 극성, 반전·일반 형태가 있어 총 8개 패턴이 나옴. 전체 패턴은 5×5에서 2^25=3,300만 개, 7×7에서 2^49=562조 개이므로 만자가 포함될 확률은 각각 2.38e-7과 1.42e-14임. QR 코드 안에는 5×5 영역 289개와 7×7 영역 225개가 있으므로, 무작위 QR 코드 형태에서 만자가 하나라도 나올 총확률은 약 0.00006, 즉 14,500개 중 1개임. 9×9 이상도 계산할 수 있지만 특정 픽셀 조합의 확률이 너무 낮아 결과에 의미 있는 영향을 주지 않음. 아쉽게도 소스를 보니 이 프로젝트는 바이브 코딩으로 만든 듯하지만, 계산은 직접 손으로 했음- 눈에 잘 띄게 쓸 QR 코드에서 그런 무늬가 나오면 그냥 일부 픽셀을 칠해도 코드는 계속 작동함. 한 사람만 보거나 실제로 스캔될 가능성이 거의 없는 코드라면 신경 쓸 이유도 없고, 대부분 QR 코드에서 우연히 그런 패턴이 생길 수 있다는 점을 이해할 것임
-
이렇게 구체적인 프로젝트라면 배경에 어떤 사연이나 농담이 있는지 궁금함
다만 Microsoft photoDNA의 지각 해시가 학습 데이터에 가득한 CSAM 썸네일 격자에 제대로 대응하지 못해 스프레드시트와 Minecraft 제작 격자 스크린샷만으로 Discord 사용자 계정을 정지시키는 등 결함 많은 AI가 쓰이는 상황을 보면, 더 범용적인 위험 패턴 회피 도구는 꽤 매력적으로 보임 -
과거의 문제를 새로운 방식으로 되풀이하기보다 현실의 문제를 해결해야 함. 세상에는 이런 프로젝트를 흥미롭게 받아들일 지나치게 민감한 사람이 너무 많음
-
데이터 패턴에서 만자를 피하려는 목적이더라도, 웹페이지 자체에 문양을 표시하므로 독일에서 불법이 될 수 있는지 궁금함
- 정보 제공 목적이라면 단순히 표시하는 행위 자체는 불법이 아님. 예를 들어 제2차 세계대전 기록 영상을 사용한 다큐멘터리에서는 만자를 검열하지 않아도 되지만, 면책 안내문을 두는 편이 안전할 수 있음
- 금지 여부는 기본적으로 맥락에 따라 달라짐: https://bundesgerichtshof.de/SharedDocs/Pressemitteilungen/…
독일 연방대법원의 해당 판결에 따르면 선을 그어 지운 만자는 허용되며, 나머지도 코드가 걸러낼 패턴의 표본으로 제시된 것이므로 문제가 생길 가능성은 낮아 보임 - 법률가는 아니지만 짧게 답하면 불법이 아니며, 길게 답하면 맥락에 달려 있음. 이 페이지의 맥락은 문제가 없어 보임
https://en.wikipedia.org/wiki/Strafgesetzbuch_section_86a