Lowent 매뉴얼←↑→

ecdsa — ECDSA P-256 서명 생성

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

개인키와 메시지 해시를 받아 서명 (r, s) 를 낸다(RFC 6979). 검증은 p256 의 ecdsa_verify 다. TLS 서버가 CertificateVerify 를 자기 개인키로 서명할 때 쓴다 — 서명 없이는 서버가 없다.

무엇을 약속하고 무엇을 하지 않나

상수 시간은 여기서만, 크기를 적어 약속한다. 없애는 것은 비밀 스칼라(개인키 d · 논스 k)에 의존하는 분기와 메모리 접근이다. 몽고메리 곱의 마지막 조건부 뺄셈 · 캐시 계층 · 전력 · 전자기 · 컴파일러가 만들어 낼 수 있는 것은 약속하지 않는다. 감사받지 않았다. P-256 뿐이고 키 생성은 없다. r = 0 또는 s = 0 이면 다시 하지 않고 실패로 답한다(확률 2−128 쯤) — 그 갈래를 지으면 시험할 수 없는 코드가 생기고, 시험 안 된 암호 코드는 없느니만 못하다.

왜 논스를 난수가 아니라 유도하는가. ECDSA 에서 논스는 한 번 새거나 한 번 되풀이되면 개인키가 통째로 드러난다.

s = k⁻¹ (h + r·d)   ⇒   d = (s·k − h) / r

k 를 알면 그 한 줄로 끝이고, 같은 k 를 두 번 쓰면 두 서명에서 k 가 풀린다. 그리고 난수원이 실패하는 경로는 조용하다 — 빈 엔트로피, 포크 뒤의 같은 상태, 가상 머신 스냅숏 복원. 그래서 난수원을 아예 쓰지 않는다. k = HMAC-DRBG(개인키, 메시지 해시) 다. 같은 (키, 메시지)면 같은 서명이 나오고, 그것은 결함이 아니라 성질이다.

op하는 일요구
nonce6979RFC 6979 §3.2 — (d, h) → kw ≥ 480 바이트 · wu ≥ 16 조각
sign(d, h) → r ‖ s 64 바이트wb ≥ 512 바이트 · wu ≥ 908 조각

표 50.1 — ecdsa 의 op

곡선 상수(p · n · Gx · Gy)는 호출자가 준다 — 이 모듈은 표를 들고 있지 않다. 서명은 p256 의 smul_ct 만 쓰고, 그것을 시험이 확인한다. k⁻¹ 은 페르마 거듭제곱인데 지수(n − 2)가 공개라 연산 순서가 고정이다.

넉넉함은 공짜가 아니다. 작업 공간을 처음엔 1052 조각으로 잡았는데 그러면 --run 의 배열 인자 상한(u64 1024)을 넘어 VM 에서 시험할 수 없었다. 빈 자리를 두 번 당겨 908 로 줄였다 — 시험할 수 없는 크기는 크기가 아니라 결함이다. 성능 — sign 은 파라미터 · 지역 · 명령이 많아 타입이 붙은 빠른 경로에 들어가지 않는다. 연결당 서명 한 번이라 지금은 견딜 만하다.

확인하는 것 — RFC 6979 §A.2.5 공식 벡터(논스 k, 메시지 "sample" · "test" 의 r · s 를 바이트로), 낸 서명을 우리 검증기가 받는지, 한 비트를 뒤집으면 거절하는지. 벡터 대조는 “규격대로인가”, 왕복은 “우리 두 쪽이 서로 맞는가” 를 묻는다.