diff options
Diffstat (limited to 'docs/research/026-secure-peer-link.md')
| -rw-r--r-- | docs/research/026-secure-peer-link.md | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/docs/research/026-secure-peer-link.md b/docs/research/026-secure-peer-link.md new file mode 100644 index 0000000..de31986 --- /dev/null +++ b/docs/research/026-secure-peer-link.md @@ -0,0 +1,105 @@ +# 026 — 선택형 Pure 피어 연결과 실제 비용 + +2026-09-24. Linux AArch64, GCC 14.2, Zig 0.15.2, OpenSSL 3.x. 첫 공개 체크포인트의 **중간 결과**다. +이 문서의 크기는 전체 용량 scalar 모듈을 사용한 첫 구현 기준이다. 이후 고정 정의 빌드의 +비용 변화는 [027](027-fixed-native-capacity.md)에 기록했다. + +## 구현한 경계 + +기존 `routed-layout.pure`를 준비한 같은 앱 인스턴스에 `pure-peer`가 입력·조회·저장·복원을 제출한다. +서버는 TCP 소켓에서 TLS 1.3을 수립한 뒤 길이가 명시된 작은 바이너리 메시지를 읽고, 기존 +`PureNativeApp`과 실행 코어를 호출한다. HTTP 문자열 헤더·메서드·URL이나 SQL 저장소를 이 +연결의 내부 형식으로 사용하지 않는다. 일반 Python `ssl` 클라이언트도 이 형식을 구현해 +상태를 읽고 작업을 제출했다. 기존 평문 HTTP 경계도 별도로 유지한다. + +```text +외부 TCP → TLS 1.3 → 선택형 peer.c/peer-wire.c → 같은 앱 작업 → 실행 코어 → scalar·저장 +``` + +이것은 **앱 선택 호스트**다. `runtime.c`, scalar 모듈, 실행 전용 `pure-native`에는 소켓·TLS +형식이 들어가지 않는다. OpenSSL을 직접 구현하지 않고 검증 가능한 라이브러리로 사용한다. +TLS에서 체인 검증과 이름 검증은 별도 확인이 필요하다. `SSL_get_verify_result()`의 성공 값만 +으로 피어 인증서를 받았다고 판단하지 않으며 실제 인증서 존재도 검사한다. +[OpenSSL 검증 결과](https://docs.openssl.org/3.5/man3/SSL_get_verify_result/), +[호스트 이름 검증](https://docs.openssl.org/3.5/man3/SSL_set1_host/). + +서버와 클라이언트 모두 CA·인증서·개인키를 지정하고 서로의 DNS 이름을 검증한다. TLS 1.3과 +ALPN `pure/1`이 맞지 않으면 종료하며 평문으로 낮추지 않는다. 0-RTT는 사용하지 않는다. +부작용 있는 작업을 0-RTT에서 안전하게 재생할 수 있다고 가정하지 않는 선택이다. +[TLS 1.3 RFC §8](https://www.rfc-editor.org/rfc/rfc8446.html#section-8), +[OpenSSL ALPN](https://docs.openssl.org/3.3/man3/SSL_CTX_set_alpn_select_cb/). + +## 이번 앱에 필요한 최소 메시지 + +TLS는 바이트 스트림이므로 각 메시지 앞에 2바이트 big-endian 길이를 둔다. 핸드셰이크 후 +서버가 `PUR1` 4바이트, 작성 정의 SHA-256 32바이트, 상태 수 1바이트, 로컬/저장 버전 각 +8바이트로 된 53바이트 hello를 보낸다. Pure 클라이언트는 정의가 다르면 작업 전에 거절한다. +일반 클라이언트는 필요에 맞게 이 식별자를 확인할 수 있다. + +| 메시지 | payload 길이 | 의미 | +|---|---:|---| +| 상태 조회 | 1 B | 현재 값과 버전. 작업 효과 없음 | +| 저장·복원 | 9 B | 동작 1 B + 기대 로컬 버전 8 B | +| 키·프레임·초기화 | 12 B | 동작·버전·입력·위상·대상 | +| 수치 입력 | 20 B | 위 필드 + IEEE binary64 값 | +| 포인터 입력 | 28 B | 위 필드 + 좌표 2개 | +| 결과 | 26 + 상태 수 × 8 B | 명시적 결과 코드·버전·오류·held·숫자 상태 | + +선택한 앱의 상태·입력 한도에 따라 요청은 최대 28 B, 결과는 최대 282 B다. 앱 내부 구조체, +포인터, 패딩을 직렬화하지 않는다. 필드 길이·바이트 순서·유한 숫자·입력 종류와 대상·상태 수를 +확인한 뒤 실행한다. 슬롯 숫자는 **현재 준비 정의의 연결 인덱스**이며 범용 안정 ABI가 아니다. +이 때문에 정의의 identity를 세션 시작에 확인한다. + +서버는 작업의 `expected revision`이 현재 로컬 버전과 다르면 상태를 바꾸지 않고 충돌을 +돌려준다. 한 연결에서 동시에 대기하는 작업은 하나로 제한한다. 응답이 유실되면 성공 여부를 +알 수 없으므로 클라이언트가 자동 재시도하지 않는다. 다시 연결해 상태·저장 버전을 읽어야 +한다. 연결이 끊어지면 해당 연결이 누른 키와 포인터 입력을 해제·취소한다. + +## 재현한 동작과 비용 + +[실행 결과](../../prototypes/workbench/results/2026-09-24-secure-peer/peer-check.json), +[빌드 식별](../../prototypes/workbench/results/2026-09-24-secure-peer/build.json), +[크기 원자료](../../prototypes/workbench/results/2026-09-24-secure-peer/size.txt). +테스트는 1일짜리 임시 CA·서버·클라이언트 인증서를 `/tmp`에 만들고 종료 시 삭제한다. +실제 비밀키를 저장소에 넣지 않는다. + +- 일반 Python TLS 클라이언트가 정의 hello와 현재 상태를 읽고, 버전 불일치 작업의 충돌과 + 상태 불변을 확인했다. 연결을 끊은 뒤 서버가 held 입력을 해제하는 것도 확인했다. +- 불명 동작·과장된 길이의 프레임, 인증서 없음·잘못된 클라이언트 이름, 잘못된 서버 이름, + ALPN 불일치를 거절했다. 인증을 끝낸 뒤 요청을 보내지 않는 클라이언트도 약 5초의 + 요청 기한 후 연결을 닫고, 다음 클라이언트가 같은 앱을 읽을 수 있었다. +- Pure 클라이언트가 녹색 상자를 잡아 이동·놓고 저장했다. 새 서버 프로세스의 첫 상태가 + `green.x=220`, `green.y=200`, 저장 버전 1, held 0임을 확인했다. +- 기존 네이티브/Wasm 9개 작성물·156개 이벤트의 일치 검사가 일반·C 호스트 ASan/UBSan에서 + 통과했고, Workbench Node 회귀 검사 87개가 통과했다. 같은 피어 통합 시나리오도 C 호스트를 + ASan/UBSan으로 계측한 실행물에서 통과했다. Zig 모듈과 OpenSSL 라이브러리까지 계측했다는 + 뜻은 아니다. + +동일한 준비 정의에 대해 `-O2 -g`로 만든 실행 파일을 비교했다. `size`의 text는 ELF 섹션 +합계이며 실제 상주 메모리와 다르다. stripped 파일 크기도 라이브러리 파일을 포함하지 않는다. + +| 범위 | 이 호스트에서 관찰한 값 | +|---|---:| +| 공통 실행 코어 아카이브 `text/data/bss`, `make check-core` | 5,932 / 0 / 0 B, 6 KiB 예산 통과 | +| `runtime.c` 단일 오브젝트 `text`, 이 명령의 `cc -O2` | 5,012 B | +| 기존 실행 전용 CLI `text`, stripped ELF | 62,827 B, 68,000 B | +| 선택형 피어 실행물 `text`, stripped ELF | 75,969 B, 133,936 B | +| 피어 실행물에 추가된 `text` | 13,142 B | +| 피어 서버 유휴 VmRSS / 인증 연결 중 VmRSS | 7,904 / 8,480 KiB, 각각 한 번 관찰 | +| 피어 실행물의 직접 동적 의존성 | OpenSSL `libssl.so.3`, `libcrypto.so.3`, libc 및 라이브러리 하위 의존성 | + +이 피어 프로세스를 “8 MiB 이하 런타임”이라 일반화하지 않는다. 인증서·TLS 연결·동적 +라이브러리·호스트 환경의 비용이 포함되며 동시 연결, 실제 부하, macOS에서는 아직 측정하지 +않았다. 실행 전용 CLI는 OpenSSL을 링크하지 않는다. 이 분리가 마이크로 비용의 현재 증거다. + +## 남은 한계와 다음 판단 + +서버는 단일 앱 인스턴스에서 한 피어씩 처리한다. DNS 조회와 동기 저장 효과는 현재 5초 +네트워크 기한에 포함되지 않는다. 원격 정의 교체, 다중 작업·스트림, 느린 소비자의 장기 예산, +권한별 역할, 인증서 교체 운영, 실제 인터넷 장애·손실·재연결 정책은 미구현이다. 5초는 현재 +프로토타입의 고정값이다. macOS Apple Silicon에서는 빌드·실행을 확인하지 못했다. + +TLS 1.3 위의 인증된 앱 작업 **정확성**을 확인했을 뿐 QUIC 수준 전송 특성이나 Kitex 수준 +성능을 보이지 않았다. 추가 성능 실험은 유휴 숫자 반복이 아니라 같은 앱 작업·보안·완료 +조건에서 실제 병목이 나타날 때 진행한다. 체크포인트에는 큰 작성물과 혼합 작업, 전체 +피크 메모리·작업별 비용, 사용자 작성·배포 경로가 더 필요하다. |
