Lowent 매뉴얼←↑→

crypto_hw — 기계가 도와주는 암호 셈

소스
lib/crypto_hw.low
층
L0 — 순수 계산(호출자의 뒷받침)
권한
없음

암호가 쓰는 셈 가운데 CPU 에 명령이 있는 것을 모은다. 오늘은 GF(2128) 곱 하나다 — GCM 의 GHASH 가 그 위에 서고, CRC 도 같은 셈이다.

이 모듈에 unsafe 가 없다

기계 명령을 내는 것은 처리기이고, 이 소스가 쓰는 것은 평범한 낱말(clmul_lo · clmul_hi)이다. 그래서 효과가 번지지 않는다 — 부르는 쪽은 effects none 그대로다. 어셈블리를 직접 쓰면 unsafe 가 TLS 까지 올라간다(30장 장의 「흡수 경계」).
op하는 일요구
clmul128캐리 없는 곱 한 번 — 128 비트 결과를 낱말 둘로out ≥ 2
gf128_mulGF(2128) 곱 — GCM 의 뒤집힌 표현, 카라추바로 곱셈 셋out · x · h 각 ≥ 2

표 50.1 — crypto_hw 의 op

캐리 없는 곱셈이란. 자리 올림 없이 하는 곱셈이다 — 더하기가 배타합(XOR)이다. 그래서 답이 입력 비트의 조합이고, 암호와 검사합이 그 위에 선다. 답이 128 비트인데 이 언어에는 128 비트 타입이 없으므로 낱말 둘(아랫말 · 윗말)로 나온다.

빠르기는 빌드가 정한다. lowentc --hw auto 로 지으면 기계에 명령이 있을 때 그것을 쓰고, 없으면 같은 답을 내는 셈으로 돈다. --hw none(기본)이면 언제나 셈이다. 답은 어느 쪽이든 같다 — 다른 것은 빠르기와 타이밍 성질뿐이다.

재 보니 이랬다. 잎 ghash 82 → 6562 MB/s · 잎 aes_ctr 80 → 5475 · AES-128-GCM 전체 41 → 2848 MB/s(4 MiB, gcc, 정렬 판 셋 가운데 각 열의 최선). AES 쪽 명령(--hw aes)과 함께 켜야 그 수가 나온다 — 하나만 켜면 병목이 다른 쪽으로 옮겨 갈 뿐이다.

명령을 담는 것으로 끝이 아니었다. 같은 명령을 쓰면서 처음에는 천장의 절반만 뽑아냈다. 남은 절반은 쓰는 법이었다 — 덩이를 여덟씩 엮고, 축약을 여덟 블록에 한 번만 하고, 카운터를 메모리 왕복 없이 레지스터에서 세우고, 축약 자체를 곱셈 둘로 줄였다. 잎 aes_ctr 는 이제 같은 상자의 OpenSSL 과 같은 속도다.

확인하는 것 — 이 모듈의 gf128_mul 과 처리기의 잎 ghash 가 같은 답을 내는지 회귀 시험이 본다. 같은 곱을 서로 다른 자리에서 셈하므로, 한쪽이 틀리면 다른 쪽이 그것을 드러낸다. 기계 명령 판과 셈 판, 그리고 VM 까지 셋을 같은 입력으로 맞대는 것도 같은 자리에서 한다.

상수시간을 약속하지 않는다

기계 명령 경로는 표를 읽지 않아 타이밍 성질이 더 낫다. 그래도 이 저장소의 크립토는 상수시간을 약속하지 않고 감사받지 않았다 — 다른 자리가 남아 있기 때문이다. 약속하지 않는다는 말을 지키려고 이 사실을 적는다.