aboutsummaryrefslogtreecommitdiffstats
path: root/docs/research
diff options
context:
space:
mode:
Diffstat (limited to 'docs/research')
-rw-r--r--docs/research/140-spec-suite.md60
1 files changed, 60 insertions, 0 deletions
diff --git a/docs/research/140-spec-suite.md b/docs/research/140-spec-suite.md
index 24d488a..4b799df 100644
--- a/docs/research/140-spec-suite.md
+++ b/docs/research/140-spec-suite.md
@@ -118,6 +118,66 @@
- **메시지의 행은 중첩의 땜질인가?** 레코드의 리스트를 메시지에만 허락한 것은 중첩이 없어서 낸 길로 보인다. 중첩이 들어오면 따로 둘
까닭이 없다.
+## 027의 1단계: SHA-256 (2026-10-13)
+
+[027](../design/027-computation-core.md)의 1단계를 만들었다.
+- **Pure.** 명령 넷이다.
+ - `I64_BITS`: and, or, xor, 두 시프트. `~x`는 xor −1이다.
+ - `BYTE_AT`: 자리의 바이트.
+ - `BYTES_OF`: i64 리스트의 바이트.
+ - `INDEX_AT`: 자리의 항목. 끝을 넘으면 멈춰 서지 않고 `not_found`다.
+- **aup.**
+ - 16진 리터럴, 파이썬의 우선순위를 따르는 비트 연산자, `b[i]`
+ - `list of i64`(`number`, `bool`, `text`)와 그 리터럴, 자리로 읽고 쓰기, `bytes(xs)`
+ - 한 번에 주기 `a, b = x, y`와 `let a, b = …`
+- **SHA-256.** aup의 `examples/sha256.aup`에 썼다.
+
+**맞음.** 공식 벡터를 Pure 안에서 돌려 맞는지 본다.
+- 대조한 메시지는 142개다: FIPS 180-2의 예 넷("", "abc", 448비트, 896비트), 채움의 모든 경계를 덮는 길이 0–129, 255–32,000바이트.
+- 다이제스트가 세 실행 길(묶음, 실행기만, 기계어)과 기본 길에서 모두 `hashlib`와 같다.
+- 이 대조는 Pure의 `make check`(`module_assumptions`, 메시지 135개)에 들어갔다.
+- aup의 검사에는 다음이 들어갔다.
+ - 진단 12건
+ - 받아들이는 꼴 하나
+ - 무작위 비트 식 192개: 사건 768개, 그중 넘침과 한도 실패 196개가 파이썬의 정수와 같다
+ - 바이트와 리스트의 앱 하나
+- Pure 단위 시험(`bits_and_bytes`)은 비트 연산의 끝값 27개, 바이트 읽기 11개, 거절 7개를 본다.
+
+**막대.**
+
+| 막대 | 잰 것 | |
+|---|---|---|
+| 공식 벡터 모두 | 142/142, 세 길 | 지남 |
+| 줄 수 ≤ 파이썬 참조 | aup 52줄(닫는 괄호만인 줄 7) 대 파이썬 28줄 | **못 미침** |
+| C 대비 시간 | 65,536바이트에서 바이트당 1,591 ns 대 C 9.0 ns: **176배**. 순수 파이썬은 3,708 ns(Pure가 2.3배 빠름) | 기록(막대 없음) |
+| 기존 일의 명령 수 | 아래 | 아래 |
+
+원본: `research/experiments/044-specs/`
+- `check.py`: 맞음과 줄 수
+- `time.c`: 같은 바이트로 C와 견준 시간. 다이제스트가 같아야 잰다.
+- `sha256.py`: 파이썬 참조
+- `2026-10-13-sha256.jsonl`: 잰 수
+
+**줄을 길게 한 것.** 처음 쓴 것은 72줄이었다. 한 번에 주기가 없어서 상태 여덟 개를 옮기는 데만 24줄이 들었다. 그것을 1단계에
+넣어(싸고 범용이다) 52줄이 됐다. 남은 차이는 다음이다.
+- 형식 지정이 없다. 16진 다이제스트에 7줄이 들었고, 파이썬은 `f'{x:08x}'` 한 줄이다.
+- 바이트를 잇거나 자르지 못한다. 채움에 fn 하나와 바이트마다의 조건이 들었고, 낱말 만들기에 5줄이 들었다. 파이썬은 `data + b'\x80' + …`와
+ `int.from_bytes` 한 줄씩이다.
+- 리스트를 값으로 짓지 못한다. 메시지 스케줄을 블록마다 다시 만들지 못하고, 64칸을 미리 채워 덮어쓴다.
+- `let`의 리스트는 핸들러 맨 바깥에만 둔다. 그래서 해시값을 리스트 대신 이름 여덟 개에 두었다.
+- 닫는 괄호의 줄이 7줄이다.
+
+앞의 넷은 값의 일이라 2단계에 넣는다. 027의 2단계에 형식 지정(16진, 자릿수), 바이트 잇기와 자르기, 값으로서의 리스트를 더한다.
+
+**시간이 가는 곳.** 블록 하나에 Pure 명령 19,129개가 든다.
+- 비트 연산이 21%다.
+- fn 호출의 몫(인자를 꺼내는 PICK 16%, 리터럴 CONST 16%, 시프트 수를 바꾸는 I64_FROM 7%)이 39%다.
+- `rotr(x, 7)`의 7은 상수인데도 fn을 펼칠 때 접히지 않아, `32 - n`을 매번 수로 계산하고 i64로 바꾼다. 인라인에서 리터럴 인자를 접으면
+ 명령의 3분의 1 남짓이 줄 것으로 본다. 컴파일러의 구현 일이다.
+- 명령 하나에 약 5.3 ns가 든다. 값의 칸(`Slot`)이 바이트 참조를 함께 들어 PICK마다 48바이트를 옮기는 꼴이다.
+- 기계어 계층은 이 루프를 빠르게 하지 못했다. `PURE_JIT=all`이어도 시간이 같다. 새 명령마다 실행기의 걸음을 불러서다.
+- 바이트와 비트의 일을 빠르게 하는 것은 핵이 선 뒤의 일이다(027). 그 과녁은 이제 수치 루프가 아니라 이런 일이다.
+
## 착수 기준 (다음 일)
- **바꿀 결정.** 계산의 핵을 설계한다(027). 위 표의 여덟 후보 가운데 무엇을 어떤 모양으로 받을지 정한다.