ref: a31ba7cf16c2335fe7478a3d08bd4bb649a311bf
parent: 41ff8acc4af96fb161fa0fa3e46b5a3b510590dc
author: Philip McGrath <philip@philipmcgrath.com>
date: Fri May 27 11:39:12 CDT 2022
Zuo: Use SHA-256. Also, document the use of concatenated SHA-256 strings for multi-file targets.
--- a/LICENSE.txt
+++ b/LICENSE.txt
@@ -8,3 +8,6 @@
and
https://github.com/racket/racket/blob/master/racket/src/LICENSE-MIT.txt
for the full text of the licenses.
+
+The SHA-256 implementation is from mbed TLS. mbed TLS is licensed
+under the Apache v2.0 License.
--- a/lib/zuo/build.zuo
+++ b/lib/zuo/build.zuo
@@ -19,9 +19,10 @@
rule?
phony-rule?
- sha1?
- file-sha1
- no-sha1
+ sha256?
+ file-sha256
+ no-sha256
+ sha256-length
build
build/command-line
@@ -43,7 +44,7 @@
;; Targets and rules
;; A token represents a build in progress, used by a target's `get-rule` or `build`
-;; function to make recursive call or get SHA-1s (possibly cached)
+;; function to make recursive call or get SHA-256s (possibly cached)
(struct token (target ; the target that received this token
ch ; a channel to access the build state
seen ; to detect dependency cycles
@@ -58,8 +59,8 @@
;; A rule is a result from `get-rule`:
(struct rule (deps ; list of targets
- build ; (-> any), called when deps SHA-1s different than recorded
- sha1)) ; #f => computed via `file-sha1`
+ build ; (-> any), called when deps SHA-256s different than recorded
+ sha256)) ; #f => computed via `file-sha256`
;; A phony target returns a phony-rule, instead:
(struct phony-rule (deps
@@ -68,16 +69,16 @@
;; During a target's `get-rule` or `build`, calls to `build/dep`
;; trigger recording of additional dependencies
-(define no-sha1 "")
-(define phony-sha1 (string->uninterned-symbol "x")) ; internal use
-(define (sha1? s)
+(define no-sha256 "")
+(define phony-sha256 (string->uninterned-symbol "x")) ; internal use
+(define (sha256? s)
(or (and (string? s)
- (or (= (string-length s) 40)
- (string=? s no-sha1)
- ;; also allow a concatenation of SHA-1s for multi-file targets
- (and (>= (string-length s) 40)
- (= 0 (modulo (string-length s) 40)))))
- (eq? s phony-sha1)))
+ (or (= (string-length s) sha256-length)
+ (string=? s no-sha256)
+ ;; also allow a concatenation of SHA-256s for multi-file targets
+ (and (>= (string-length s) sha256-length)
+ (= 0 (modulo (string-length s) sha256-length)))))
+ (eq? s phony-sha256)))
;; public constructor
(define make-target
@@ -100,7 +101,7 @@
;; public constructor
(define make-rule
(let ([rule
- (lambda (deps [build #f] [sha1 #f])
+ (lambda (deps [build #f] [sha256 #f])
(let ([norm-deps (and (list? deps) (map coerce-to-target deps))])
(unless (and norm-deps (andmap target? norm-deps))
(arg-error 'rule "list of targets" deps))
@@ -107,9 +108,9 @@
(unless (or (not build)
(procedure? build))
(arg-error 'rule "procedure or #f" build))
- (unless (or (not sha1) (sha1? sha1))
- (arg-error 'rule "sha1 or #f" sha1))
- (rule norm-deps build sha1)))])
+ (unless (or (not sha256) (sha256? sha256))
+ (arg-error 'rule "sha256 or #f" sha256))
+ (rule norm-deps build sha256)))])
rule))
;; An input-file target has no dependencies
@@ -139,12 +140,12 @@
t))
(coerce-to-target t)))
-;; An input-data target supplies its SHA-1 up front
+;; An input-data target supplies its SHA-256 up front
(define (input-data-target name v)
(unless (symbol? name) (arg-error 'input-data-target "symbol" name))
(target (symbol->key name)
name
- (lambda (path token) (make-rule '() #f (string-sha1 (~s v))))
+ (lambda (path token) (make-rule '() #f (string-sha256 (~s v))))
'input
(hash)))
@@ -167,8 +168,8 @@
(rule (phony-rule-deps r)
(lambda ()
((phony-rule-build r))
- phony-sha1)
- phony-sha1)))
+ phony-sha256)
+ phony-sha256)))
(define (target-path t)
(unless (target? t) (arg-error 'target-path "target" t))
@@ -192,23 +193,23 @@
;; When a target is built, the build result is recorded as
;;
-;; (list sha1 (list dep-sym-or-path-rel-to-target sha1) ..)
+;; (list sha256 (list dep-sym-or-path-rel-to-target sha256) ...)
;;
;; This result is in the `target-state` field of a build state, while
;; `db` holds the same-shaped information from the previous build.
;;
;; The `time-cache` field of a build state is a shortcut for getting
-;; input-file SHA-1s on the assumption that a SHA-1 recorded last time
+;; input-file SHA-256s on the assumption that a SHA-256 recorded last time
;; is still right if the file's timestamp hasn't changed.
-;; Where the contracts below say "dep-sha1s", that's a hash table
-;; mapping a dependency's key to a SHA-1.
+;; Where the contracts below say "dep-sha256s", that's a hash table
+;; mapping a dependency's key to a SHA-256.
(struct build-state (ch ; channel to hold the state while target is running
- target-state ; key -> (cons sha1 dep-sha1s) | 'pending | channel
- target-accum ; key -> dep-sha1s
- db ; key -> (cons sha1 dep-sha1s) | #t [for db file itself]
- time-cache ; key -> (cons timestamp sha1)
+ target-state ; key -> (cons sha256 dep-sha256s) | 'pending | channel
+ target-accum ; key -> dep-sha256s
+ db ; key -> (cons sha256 dep-sha256s) | #t [for db file itself]
+ time-cache ; key -> (cons timestamp sha256)
saw-targets ; key -> target [to detect multiple for same output]
resource-ch ; channel with available resources enqueued
log? ; logging enabled?
@@ -314,9 +315,9 @@
[(eq? (target-kind t) 'input)
;; no dependencies, not need for a thread to build, etc.
(define r ((target-get-rule t) (target-name t) #f))
- (define sha1 (or (rule-sha1 r) (file-sha1/state (target-path t) state)))
- (when (equal? sha1 no-sha1) ((rule-build r)))
- (update-target-state state t (list sha1))]
+ (define sha256 (or (rule-sha256 r) (file-sha256/state (target-path t) state)))
+ (when (equal? sha256 no-sha256) ((rule-build r)))
+ (update-target-state state t (list sha256))]
[else (build-unbuilt t state seen top?)]))
;; Starts a build for a specific target
@@ -336,10 +337,10 @@
;; get previously recorded result, possibly loading from a file
;; that is cached in the build state
- (define loaded-state (load-sha1s state t path))
+ (define loaded-state (load-sha256s state t path))
(define prev-ts (previous-target-state loaded-state (target-key t)))
- (define prev-sha1 (car prev-ts))
- (define prev-dep-sha1s/raw-symbols (cdr prev-ts))
+ (define prev-sha256 (car prev-ts))
+ (define prev-dep-sha256s/raw-symbols (cdr prev-ts))
;; record a channel as the start's current build state
(define result-ch (channel))
@@ -357,23 +358,23 @@
(unless (rule? r)
(error "build: target result is not a rule" r))
(define deps (rule-deps r))
- (define sha1 (or (rule-sha1 r) (if (pair? co-outputs)
- (files-sha1 (cons path co-outputs) tok)
- (file-sha1 path tok))))
+ (define sha256 (or (rule-sha256 r) (if (pair? co-outputs)
+ (files-sha256 (cons path co-outputs) tok)
+ (file-sha256 path tok))))
(define to-build (rule-build r))
- (define build-to-sha1? (and (rule-sha1 r) #t))
+ (define build-to-sha256? (and (rule-sha256 r) #t))
;; if we recorded any data targets, we need to fix up the keys
- (define prev-dep-sha1s (foldl (lambda (dep-key dep-sha1s)
- (cond
- [(symbol-key? dep-key)
- (let ([actual-key (translate-key dep-key deps t)])
- (hash-set (hash-remove dep-sha1s dep-key)
- actual-key
- (hash-ref dep-sha1s dep-key)))]
- [else dep-sha1s]))
- prev-dep-sha1s/raw-symbols
- (hash-keys prev-dep-sha1s/raw-symbols)))
+ (define prev-dep-sha256s (foldl (lambda (dep-key dep-sha256s)
+ (cond
+ [(symbol-key? dep-key)
+ (let ([actual-key (translate-key dep-key deps t)])
+ (hash-set (hash-remove dep-sha256s dep-key)
+ actual-key
+ (hash-ref dep-sha256s dep-key)))]
+ [else dep-sha256s]))
+ prev-dep-sha256s/raw-symbols
+ (hash-keys prev-dep-sha256s/raw-symbols)))
(define rule-state (get-state (token-ch tok) "rule"))
@@ -386,14 +387,14 @@
rule-state
deps))
- ;; extract results, assemble in a hash table: <rel-path> -> <sha1>
- (define dep-reported-sha1s
- (foldl (lambda (dep dep-sha1s)
- (add-dependent-target-state dep dep-sha1s new-state))
+ ;; extract results, assemble in a hash table: <rel-path> -> <sha256>
+ (define dep-reported-sha256s
+ (foldl (lambda (dep dep-sha256s)
+ (add-dependent-target-state dep dep-sha256s new-state))
(hash)
deps))
- (define dep-sha1s
- (cdr (merge-target-accumulated new-state t (cons #f dep-reported-sha1s))))
+ (define dep-sha256s
+ (cdr (merge-target-accumulated new-state t (cons #f dep-reported-sha256s))))
;; calling the build step for `t` might generate more dependencies, but those
;; extra dependencies are supposed to be determined only by the ones declared
@@ -402,26 +403,26 @@
;; then we can assume that the extra dependencies generated previously are still
;; the extra dependencies this time
(define same-so-far?
- (and (log-changed (and (equal? sha1 prev-sha1) (not (equal? sha1 no-sha1))) path state)
+ (and (log-changed (and (equal? sha256 prev-sha256) (not (equal? sha256 no-sha256))) path state)
(andmap (lambda (dep-key)
- (log-changed (equal? (hash-ref dep-sha1s dep-key)
- (hash-ref prev-dep-sha1s dep-key #f))
+ (log-changed (equal? (hash-ref dep-sha256s dep-key)
+ (hash-ref prev-dep-sha256s dep-key #f))
dep-key
state))
- (hash-keys dep-sha1s))))
+ (hash-keys dep-sha256s))))
(define more-deps
(if same-so-far?
- (foldl (lambda (dep-key more-sha1s)
+ (foldl (lambda (dep-key more-sha256s)
;; currently, we assume that any additional dependencies
;; added in the build phase were and would be inputs
- (if (or (hash-ref dep-sha1s dep-key #f)
+ (if (or (hash-ref dep-sha256s dep-key #f)
(symbol-key? dep-key))
- more-sha1s
+ more-sha256s
(cons (input-file-target (symbol->string dep-key))
- more-sha1s)))
+ more-sha256s)))
'()
- (hash-keys prev-dep-sha1s))
+ (hash-keys prev-dep-sha256s))
'()))
(for-each (make-fetch-dep new-state new-seen dep-top?) more-deps)
(define newer-state
@@ -428,10 +429,10 @@
(foldl (lambda (dep state) (do-build dep state new-seen dep-top?))
new-state
more-deps))
- (define all-dep-sha1s
- (foldl (lambda (dep dep-sha1s)
- (add-dependent-target-state dep dep-sha1s newer-state))
- dep-sha1s
+ (define all-dep-sha256s
+ (foldl (lambda (dep dep-sha256s)
+ (add-dependent-target-state dep dep-sha256s newer-state))
+ dep-sha256s
more-deps))
;; compare to recorded result, and rebuild if different
@@ -438,18 +439,18 @@
(cond
[(and same-so-far?
(andmap (lambda (dep-key)
- (log-changed (equal? (hash-ref all-dep-sha1s dep-key #f)
- (hash-ref prev-dep-sha1s dep-key #f))
+ (log-changed (equal? (hash-ref all-dep-sha256s dep-key #f)
+ (hash-ref prev-dep-sha256s dep-key #f))
dep-key
state))
- (hash-keys all-dep-sha1s)))
+ (hash-keys all-dep-sha256s)))
;; no need to rebuild
(when path-handle (cleanable-cancel path-handle))
(when (and (or alert-top? (hash-ref (target-options t) 'noisy? #f))
- (equal? prev-sha1 sha1)
- (not (equal? sha1 phony-sha1)))
+ (equal? prev-sha256 sha256)
+ (not (equal? sha256 phony-sha256)))
(alert (~a (target-name t) " is up to date")))
- (define done-state (update-target-state newer-state t (cons sha1 all-dep-sha1s)))
+ (define done-state (update-target-state newer-state t (cons sha256 all-dep-sha256s)))
(channel-put result-ch 'done)
done-state]
[else
@@ -456,15 +457,15 @@
(unless to-build
(error "build: out-of-date target has no build procedure" (target-name t)))
(define (build-one finish)
- (let* ([maybe-sha1 (to-build)] ; build!
- [sha1 (if build-to-sha1?
- maybe-sha1
- (if (pair? co-outputs)
- (files-sha1 (cons path co-outputs) tok)
- (file-sha1 path tok)))])
- (unless (sha1? sha1)
- (error "build: target-build result is not a sha1" sha1))
- (when (equal? sha1 no-sha1)
+ (let* ([maybe-sha256 (to-build)] ; build!
+ [sha256 (if build-to-sha256?
+ maybe-sha256
+ (if (pair? co-outputs)
+ (files-sha256 (cons path co-outputs) tok)
+ (file-sha256 path tok)))])
+ (unless (sha256? sha256)
+ (error "build: target-build result is not a sha256" sha256))
+ (when (equal? sha256 no-sha256)
(error "rule for target did not create it" (if (pair? co-outputs)
(cons path co-outputs)
path)))
@@ -472,11 +473,11 @@
(finish
(lambda (state)
;; record result:
- (let* ([ts (if (eq? sha1 phony-sha1)
- (cons no-sha1 (hash))
- (cons sha1 dep-sha1s))]
+ (let* ([ts (if (eq? sha256 phony-sha256)
+ (cons no-sha256 (hash))
+ (cons sha256 dep-sha256s))]
[ts (merge-target-accumulated state t ts)]
- [state (update-target-state/record-sha1s state t ts co-outputs)])
+ [state (update-target-state/record-sha256s state t ts co-outputs)])
(channel-put result-ch 'done)
state)))))
(let ([state-ch (build-state-ch newer-state)])
@@ -681,25 +682,25 @@
(define (target-state state t)
(hash-ref (build-state-target-state state) (target-key t) #f))
-(define (add-dependent-target-state dep dep-sha1s state)
+(define (add-dependent-target-state dep dep-sha256s state)
(define ts (target-state state dep))
- (define sha1 (car ts))
- (hash-set dep-sha1s (target-key dep) (if (eq? sha1 phony-sha1) no-sha1 sha1)))
+ (define sha256 (car ts))
+ (hash-set dep-sha256s (target-key dep) (if (eq? sha256 phony-sha256) no-sha256 sha256)))
(define (record-target-accumulated state for-t t)
(let* ([accum-key (target-key for-t)]
- [dep-sha1s (hash-ref (build-state-target-accum state) accum-key (hash))]
- [dep-sha1s (add-dependent-target-state t dep-sha1s state)])
- (build-state-set-target-accum state (hash-set (build-state-target-accum state) accum-key dep-sha1s))))
+ [dep-sha256s (hash-ref (build-state-target-accum state) accum-key (hash))]
+ [dep-sha256s (add-dependent-target-state t dep-sha256s state)])
+ (build-state-set-target-accum state (hash-set (build-state-target-accum state) accum-key dep-sha256s))))
(define (merge-target-accumulated state t ts)
- (let ([more-dep-sha1s (hash-ref (build-state-target-accum state) (target-key t) #f)])
- (if more-dep-sha1s
+ (let ([more-dep-sha256s (hash-ref (build-state-target-accum state) (target-key t) #f)])
+ (if more-dep-sha256s
(cons (car ts)
- (foldl (lambda (dep-key dep-sha1s)
- (hash-set dep-sha1s dep-key (hash-ref more-dep-sha1s dep-key)))
+ (foldl (lambda (dep-key dep-sha256s)
+ (hash-set dep-sha256s dep-key (hash-ref more-dep-sha256s dep-key)))
(cdr ts)
- (hash-keys more-dep-sha1s)))
+ (hash-keys more-dep-sha256s)))
ts)))
(define (update-target-state state t ts)
@@ -708,19 +709,19 @@
(target-key t)
ts)))
-(define (update-target-state/record-sha1s state t ts co-outputs)
+(define (update-target-state/record-sha256s state t ts co-outputs)
(unless (eq? 'phony (target-kind t))
- (db-record-target-sha1s (target-db-dir t) (target-name t) ts co-outputs))
+ (db-record-target-sha256s (target-db-dir t) (target-name t) ts co-outputs))
(update-target-state state t ts))
-(define (load-sha1s state t path)
+(define (load-sha256s state t path)
(cond
[(symbol? path) state]
[else
- (define db+tc (db-load-sha1s (target-db-dir t)
- path
- (build-state-db state)
- (build-state-time-cache state)))
+ (define db+tc (db-load-sha256s (target-db-dir t)
+ path
+ (build-state-db state)
+ (build-state-time-cache state)))
(if db+tc
(let ([state (build-state-set-db state (car db+tc))])
(build-state-set-time-cache state (cdr db+tc)))
@@ -728,7 +729,7 @@
(define (previous-target-state state key)
(or (hash-ref (build-state-db state) key #f)
- (cons no-sha1 (hash))))
+ (cons no-sha256 (hash))))
(define (ensure-consistent state t)
(let* ([saw (build-state-saw-targets state)]
@@ -743,22 +744,22 @@
[else
(build-state-set-saw-targets state (hash-set saw (target-key t) t))])))
-(define (file-sha1 path token)
- (unless (path-string? path) (arg-error 'file-sha1 "path string" path))
- (unless (or (not token) (token? token)) (error 'file-sha1 "build-token" token))
- (let ([state (and token (get-state (token-ch token) "sha1"))])
- (when state (put-state (token-ch token) state "sha1"))
- (file-sha1/state path state)))
+(define (file-sha256 path token)
+ (unless (path-string? path) (arg-error 'file-sha256 "path string" path))
+ (unless (or (not token) (token? token)) (error 'file-sha256 "build-token" token))
+ (let ([state (and token (get-state (token-ch token) "sha256"))])
+ (when state (put-state (token-ch token) state "sha256"))
+ (file-sha256/state path state)))
-(define (files-sha1 paths token)
- (let ([sha1s (map (lambda (path) (file-sha1 path token)) paths)])
- (if (ormap (lambda (s) (string=? s no-sha1)) sha1s)
- no-sha1
- (apply ~a sha1s))))
+(define (files-sha256 paths token)
+ (let ([sha256s (map (lambda (path) (file-sha256 path token)) paths)])
+ (if (ormap (lambda (s) (string=? s no-sha256)) sha256s)
+ no-sha256
+ (apply ~a sha256s))))
-(define (file-sha1/state path state)
- (or (file-sha1/cached path (and state (build-state-time-cache state)))
- no-sha1))
+(define (file-sha256/state path state)
+ (or (file-sha256/cached path (and state (build-state-time-cache state)))
+ no-sha256))
;; translate a data key as loaded from a previous-run to a key as
;; instantiated for this run
--- a/lib/zuo/private/build-db.zuo
+++ b/lib/zuo/private/build-db.zuo
@@ -5,7 +5,7 @@
;; directory, the goal here is to be able to load information for all
;; the targets at once.
-;; A timestamp-based SHA-1 cache for input files is stored in
+;; A timestamp-based SHA-256 cache for input files is stored in
;; "_zuo_tc.db" alongside "_zuo.db" --- in the directory of a target
;; that depends on the input files, not in the input file's directory
;; (which is likely to be in the source tree). An input used by
@@ -19,14 +19,16 @@
;; format of each file is a top-level sequence of
;; (<rel-path> . <info>)
;; For "_zuo.db", it's more specifically
-;; (<rel-path> <sha1> (<dep-rel-path> <sha1>) ...)
+;; (<rel-path> <sha256> (<dep-rel-path> <sha256>) ...)
;; For "_zuo_tc.db", it's
-;; (<rel-path> (<time-secs> . <time-msec>) <sha1>)
+;; (<rel-path> (<time-secs> . <time-msec>) <sha256>)
-(provide db-record-target-sha1s
- db-load-sha1s
+(provide db-record-target-sha256s
+ db-load-sha256s
- file-sha1/cached
+ sha256-length
+
+ file-sha256/cached
path->absolute-path
dir-part
@@ -34,7 +36,9 @@
symbol-key?
symbol-key->symbol)
-;; for serialization and deserialization of dep-sha1s tables
+(define sha256-length 64)
+
+;; for serialization and deserialization of dep-sha256s tables
(define (hash->list ht db-dir)
(map (lambda (k) (list (serialize-key k db-dir) (hash-ref ht k)))
(hash-keys ht)))
@@ -79,12 +83,12 @@
(k rel-target-path db-dir db-path tc-path))
;; Records the result of a build of `name`, mainly storing the
-;; SHA-1 and dep SHA-1s in "_zuo.db", but also recording a timestamp
-;; plus SHA-1 for dependencies in "_zuo_tc.db".
+;; SHA-256 and dep SHA-256s in "_zuo.db", but also recording a timestamp
+;; plus SHA-256 for dependencies in "_zuo_tc.db".
;; All relative file names are stored relative to `db-dir`, which
;; defaults to the directory of target-path. On entry, `target-path`
;; and keys in `ts` are relative to the current directory.
-(define (db-record-target-sha1s maybe-db-dir target-path ts co-outputs)
+(define (db-record-target-sha256s maybe-db-dir target-path ts co-outputs)
(db-paths
maybe-db-dir target-path
(lambda (rel-target-path db-dir db-path tc-path)
@@ -92,8 +96,8 @@
(if (file-exists? db-path)
(string-read (file->string db-path) 0 db-path)
'()))
- (define dep-sha1s-l (hash->list (cdr ts) db-dir))
- (define new-db-content (reassoc (list* rel-target-path (car ts) dep-sha1s-l) db-content))
+ (define dep-sha256s-l (hash->list (cdr ts) db-dir))
+ (define new-db-content (reassoc (list* rel-target-path (car ts) dep-sha256s-l) db-content))
(update-file db-path new-db-content)
(unless (ormap (lambda (p) (string=? (car p) "SOURCE_DATE_EPOCH")) (hash-ref (runtime-env) 'env))
(define tc-content
@@ -110,19 +114,19 @@
(build-path db-dir dep-name)
dep-name)))
(cond
- [time (reassoc (list dep-name time (substring (cadr dep) 0 40)) tc-content)]
+ [time (reassoc (list dep-name time (substring (cadr dep) 0 sha256-length)) tc-content)]
[else tc-content])]))
tc-content
(if (pair? co-outputs)
- (append (split-sha1s rel-target-path co-outputs (car ts) db-dir)
- dep-sha1s-l)
- (cons (list rel-target-path (car ts)) dep-sha1s-l))))
+ (append (split-sha256s rel-target-path co-outputs (car ts) db-dir)
+ dep-sha256s-l)
+ (cons (list rel-target-path (car ts)) dep-sha256s-l))))
(update-file tc-path new-tc-content)))))
;; Loads previous-build information for `abs-path`, as well as cached
-;; SHA-1s for things that might be dependencies; loading needs to
+;; SHA-256s for things that might be dependencies; loading needs to
;; happen only once per directory that has a (non-input) build target
-(define (db-load-sha1s maybe-db-dir target-path db tc)
+(define (db-load-sha256s maybe-db-dir target-path db tc)
(db-paths
maybe-db-dir target-path
(lambda (name db-dir db-path tc-path)
@@ -159,8 +163,8 @@
(define new-tc (read-in tc-path tc (lambda (v) v)))
(cons new-db new-tc)]))))
-;; Helpers to get an input file's SHA-1, possibly cached
-(define (file-sha1/cached path time-cache)
+;; Helpers to get an input file's SHA-256, possibly cached
+(define (file-sha256/cached path time-cache)
(let ([timestamp (file-timestamp path)])
(and timestamp
(let ([cached (and time-cache
@@ -168,15 +172,17 @@
(string->symbol path)
#f))])
(if (and cached
- (equal? (car cached) timestamp))
+ (equal? (car cached) timestamp)
+ ;; might be a stale SHA-1 rather than an SHA-256
+ (= sha256-length (string-length (cadr cached))))
(cadr cached)
- (string-sha1 (file->string path)))))))
+ (string-sha256 (file->string path)))))))
-;; Split "sha1", which should have a sha1 for each of `rel-target-path`
-;; and each element of `co-outputs`, into a list of sha1s
-(define (split-sha1s rel-target-path co-outputs sha1 db-dir)
- (cons (list rel-target-path (substring sha1 0 40))
- (let loop ([co-outputs co-outputs] [start 40])
+;; Split "sha256", which should have a sha256 for each of `rel-target-path`
+;; and each element of `co-outputs`, into a list of sha256s
+(define (split-sha256s rel-target-path co-outputs sha256 db-dir)
+ (cons (list rel-target-path (substring sha256 0 sha256-length))
+ (let loop ([co-outputs co-outputs] [start sha256-length])
(cond
[(null? co-outputs) '()]
[else
@@ -184,8 +190,8 @@
(cons (list (if (relative-path? co-output)
(find-relative-path db-dir co-output)
co-output)
- (substring sha1 start (+ start 40)))
- (loop (cdr co-outputs) (+ start 40))))]))))
+ (substring sha256 start (+ start sha256-length)))
+ (loop (cdr co-outputs) (+ start sha256-length))))]))))
;; Atomic write by write-to-temporary-and-move
(define (update-file path new-content)
--- a/local/image.zuo
+++ b/local/image.zuo
@@ -44,7 +44,7 @@
(define (image-target cmd)
(target
- (hash-ref cmd 'output) ; the output file; `target` uses SHA-1 on this
+ (hash-ref cmd 'output) ; the output file; `target` uses SHA-256 on this
(lambda (path token)
;; when a target is demanded, we report dependencies and more via `rule`
(rule
--- a/tests/string.zuo
+++ b/tests/string.zuo
@@ -89,7 +89,7 @@
(unless (= j (string-length s)) (j-loop (+ j 1))))
(unless (= i (string-length s)) (i-loop (+ i 1)))))
-(check (string-sha1 "hello\n") "f572d396fae9206628714fb2ce00f72e94f2258f")
+(check (string-sha256 "hello\n") "5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03")
(check (string->integer "10") 10)
(check (string->integer "-10") -10)
--- a/zuo-doc/fake-zuo.rkt
+++ b/zuo-doc/fake-zuo.rkt
@@ -104,7 +104,7 @@
string->uninterned-symbol
symbol->string
string
- string-sha1
+ string-sha256
char
string-split string-join string-trim
string-tree?
@@ -210,9 +210,10 @@
token?
rule?
phony-rule?
- sha1?
- file-sha1
- no-sha1
+ sha256?
+ file-sha256
+ no-sha256
+ sha256-length
build
build/command-line
build/command-line*
--- a/zuo-doc/lang-zuo-kernel.scrbl
+++ b/zuo-doc/lang-zuo-kernel.scrbl
@@ -77,7 +77,7 @@
bitwise-and bitwise-ior bitwise-xor bitwise-not
string? string-length string-ref string-u32-ref substring string
- string=? string-ci=? string-sha1 string-split
+ string=? string-ci=? string-sha256 string-split
symbol? symbol->string string->symbol string->uninterned-symbol
--- a/zuo-doc/lang-zuo.scrbl
+++ b/zuo-doc/lang-zuo.scrbl
@@ -440,9 +440,11 @@
Tries to parse @racket[str] as an integer returning @racket[#f] if
that fails.}
-@defproc[(string-sha1 [str string?]) string?]{
+@defproc[(string-sha256 [str string?]) string?]{
-Returns the SHA-1 hash of @racket[str] as a 40-digit hexadecimal string.}
+Returns the SHA-256 hash of @racket[str] as a 64-digit hexadecimal string.
+
+See also @racket[file-sha256] and @racket[sha256-length].}
@defform[(char str)]{
--- a/zuo-doc/overview.scrbl
+++ b/zuo-doc/overview.scrbl
@@ -13,7 +13,7 @@
base language, the primary intended use of Zuo is with
@racket[@#,hash-lang[] @#,racketmodname[zuo]], which includes the
@racketmodname[zuo/build] library for using @seclink["zuo-build"]{Zuo
-as a @tt{make} replacement}.
+as a @exec{make} replacement}.
The name ``Zuo'' is derived from the Chinese word for ``make.''
--- a/zuo-doc/zuo-build.scrbl
+++ b/zuo-doc/zuo-build.scrbl
@@ -6,7 +6,7 @@
@(define shake-url "https://shakebuild.com/")
-@title[#:tag "zuo-build"]{Zuo as a @tt{make} Replacement}
+@title[#:tag "zuo-build"]{Zuo as a @exec{make} Replacement}
@defzuomodule[zuo/build]
@@ -26,13 +26,15 @@
A @tech{target} represents either an input to a build (such as a
source file) or a generated output, and a target can depend on any
-number of other targets. A target's output is represented by 40-character
-string that is normally a SHA-1 hash; the @racket[build] procedure
+number of other targets. A target's output is represented by a
+string that is normally an SHA-256 hash: more precisely, it is
+represented by a value satisfying the predicate @racket[sha256?].
+The @racket[build] procedure
records hashes and dependencies in a database located alongside
non-input targets, so it can avoid rebuilding targets when nothing has
-changed since the last build. Unlike @tt{make}, timestamps are used
-only as a shortcut to avoiding computing the SHA-1 of a file (i.e., if
-the timestamp has not changes, the SHA-1 result is assumed to be
+changed since the last build. Unlike @exec{make}, timestamps are used
+only as a shortcut to avoiding computing the SHA-256 of a file (i.e., if
+the timestamp has not changed, the SHA-256 result is assumed to be
unchanged).
``Recursive make'' is encouraged in the sense that a target's build
@@ -55,7 +57,7 @@
are needed. The @racket[_get-rule] procedure returns up to three
results in a @racket[rule] record: a list of dependencies; the hash of
an already-built version of the target, if one exists, where
-@racket[file-sha1] is used by default; and a @racket[_rebuild]
+@racket[file-sha256] is used by default; and a @racket[_rebuild]
procedure that is called if the returned hash, the hash of
dependencies (rebuilt if needed), and recorded results from a previous
build together determine that a rebuild is needed.
@@ -62,7 +64,7 @@
When a target's @racket[_rebuild] function is called, it optionally
returns a hash for the result of the build if the target's
-@racket[rule] had one, otherwise @racket[file-sha1] is used to get a
+@racket[rule] had one, otherwise @racket[file-sha256] is used to get a
result hash. Either way, it's possible that the result hash is the
same the one returned by @racket[_get-rule]; that is, maybe a
dependency of the target changed, but the change turned out not to
@@ -105,7 +107,7 @@
filename, then it reports an error.
The @racket[build/command-line] function is a convenience to implement
-get @tt{make}-like command-line handling for building targets. The
+get @exec{make}-like command-line handling for building targets. The
@racket[build/command-line] procedure takes a list of targets, and it
calls @racket[build] on one or more of them based on command-line
arguments (with help from @racket[find-target]).
@@ -121,7 +123,7 @@
(supplied as just @racket[build-path] by default) to apply to each
target path when building a list of targets, and a hash table of
variables (analogous to variables that a makefile might provide to
-another makefile via @tt{make} arguments).
+another makefile via @exec{make} arguments).
As a further convenience following the @racketidfont{targets-at}
model, the @racket[provide-targets] form takes an identifier for such a
@@ -173,7 +175,7 @@
@section{Recording Results}
Build results are stored in a @filepath{_zuo.db} file in the same
-directory as a target (by default). Cached SHA-1 results with associated
+directory as a target (by default). Cached SHA-256 results with associated
file timestamps are stored in a @filepath{_zuo_tc.db} in the same
directory (i.e., the cached value for dependency is kept with the
target, which is in a writable build space, while an input-file target
@@ -244,7 +246,7 @@
Creates a @tech{target} that represents an input file. An input-file
target has no build procedure, and it's state is summarized as a hash
-via @racket[file-sha1].}
+via @racket[file-sha256].}
@defproc[(input-data-target [name symbol?] [content any/c]) target?]{
@@ -276,7 +278,7 @@
when applying an @racket[_at-dir] function to create @racket[name].
The @deftech{build token} argument to @racket[get-deps] represents the
-target build in progress. It's useful with @racket[file-sha1] to take
+target build in progress. It's useful with @racket[file-sha256] to take
advantage of caching, with @racket[build/dep] to report
discovered targets, and with @racket[build/no-dep] or @racket[build].
@@ -328,8 +330,8 @@
@deftogether[(
@defproc[(rule [dependencies (listof (or/c target? path-string?))]
- [rebuild (or/c (-> (or/c sha1? any/c)) #f) #f]
- [sha1 (or/c sha1? #f) #f])
+ [rebuild (or/c (-> (or/c sha256? any/c)) #f) #f]
+ [sha256 (or/c sha256? #f) #f])
rule?]
@defproc[(rule? [v any/c]) boolean?]
)]{
@@ -339,9 +341,9 @@
A path string can be reported as a dependency in
@racket[dependencies], in which case it is coerced to a target using
-@racket[input-file-target]. If @racket[sha1] is @racket[#f],
-@racket[file-sha1] is used to compute the target's current hash, and
-@racket[rebuild] is not expected to return a hash. If @racket[sha1] is
+@racket[input-file-target]. If @racket[sha256] is @racket[#f],
+@racket[file-sha256] is used to compute the target's current hash, and
+@racket[rebuild] is not expected to return a hash. If @racket[sha256] is
not @racket[#f], then if @racket[rebuild] is called, it must return a
new hash.}
@@ -355,7 +357,7 @@
The @racket[phony-rule] procedure combines the two results expected
from a procedure passed to @racket[target] to create a @tech{phony}
-target. Compared to the non-phonu protocol, the result SHA-1 is
+target. Compared to the non-phony protocol, the result SHA-256 is
omitted.}
@defproc[(token? [v any/c]) boolean?]{
@@ -376,7 +378,7 @@
If @racket[target] is a path, then it is coerced to target via
@racket[input-file-target], but the only effect will be to compute the
-file's SHA-1 or error if the file does not exist.
+file's SHA-256 or error if the file does not exist.
The @racket[options] argument supplies build options, and the
following keys are recognized:
@@ -494,19 +496,26 @@
target is built.}
@deftogether[(
-@defproc[(file-sha1 [file path-string?] [token (or/c token? #f)]) sha1?]
-@defproc[(sha1? [v any/c]) booelan?]
+@defproc[(file-sha256 [file path-string?] [token (or/c token? #f)]) sha256?]
+@defproc[(sha256? [v any/c]) booelan?]
+@defthing[sha256-length integer? #:value 64]
)]{
-The @racket[file-sha1] procedure returns the SHA-1 hash of the content
-of @racket[file], or it returns @racket[no-sha1] if @racket[file] does
-not exist.
+The @racket[file-sha256] procedure returns the SHA-256 hash of the
+content of @racket[file] as a 64-character hexadecimal string (thus,
+@racket[sha256-length]), or it returns @racket[no-sha256] if
+@racket[file] does not exist.
-The @racket[sha1?] predicate recognizes values that are either a
-40-character string or @racket[no-sha1].}
+The @racket[sha256?] predicate recognizes @racket[no-sha256] and
+strings for which @racket[string-length] returns either
+@racket[sha256-length] or a multiple of @racket[sha256-length]. The
+later case is used for multi-file targets, which concatenate the
+constituent SHA-256 strings.
-@defthing[no-sha1 sha1? ""]{
+See also @racket[string-sha256].}
+@defthing[no-sha256 sha256? ""]{
+
The empty string represents a non-existent target or one that needs to
be rebuilt.}
@@ -546,13 +555,13 @@
@defproc[(make-targets [specs list?]) list?]{
-Converts a @tt{make}-like specification into a list of targets for use
-with @racket[build]. In this @tt{make}-like specification, extra
+Converts a @exec{make}-like specification into a list of targets for use
+with @racket[build]. In this @exec{make}-like specification, extra
dependencies can be listed separately from a build rule, and
dependencies can be written in terms of paths instead of @tech{target}
objects.
-Although it might seem natural for this @tt{make}-like specification
+Although it might seem natural for this @exec{make}-like specification
to be provided as a syntactic form, typical makefiles use patterns and
variables to generate sets of rules. In Zuo, @racket[map] and similar
are available for generating sets of rules. So, @racket[make-targets]
--- a/zuo.c
+++ b/zuo.c
@@ -55,6 +55,7 @@
typedef uint32_t zuo_uint32_t;
typedef intptr_t zuo_intptr_t;
+typedef uintptr_t zuo_uintptr_t;
typedef int zuo_raw_handle_t;
#endif
@@ -68,8 +69,10 @@
# ifdef _WIN64
typedef long long zuo_intptr_t;
+typedef unsigned long long zuo_uintptr_t;
# else
typedef long zuo_intptr_t;
+typedef unsigned long zuo_uintptr_t;
# endif
typedef HANDLE zuo_raw_handle_t;
@@ -6116,163 +6119,489 @@
}
/*======================================================================*/
-/* SHA-1 */
+/* SHA-256 */
/*======================================================================*/
+/*
+ * FIPS-180-2 compliant SHA-256 implementation
+ *
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This file is part of mbed TLS (https://tls.mbed.org)
+ */
+/*
+ * The SHA-256 Secure Hash Standard was published by NIST in 2002.
+ *
+ * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf
+ */
+/* Adjusted by Matthew Flatt for rktio */
+/* This code is also used in "rktio_sha2.c". */
-/* Based on
- SHA-1 in C
- By Steve Reid <sreid@sea-to-sky.net>
- including changes by Saul Kravitz <Saul.Kravitz@celera.com>
- and Ralph Giles <giles@ghostscript.com> */
+typedef struct zuo_sha2_ctx_t {
+ unsigned total[2];
+ unsigned state[8];
+ unsigned char buffer[64];
+ int is224;
+} zuo_sha2_ctx_t;
-static int zuo_little_endian;
+#define ZUO_SHA256_DIGEST_SIZE 32
-static void zuo_init_sha1() {
- zuo_little_endian = ((zuo_magic() & 0xF) == 0);
+typedef zuo_uint32_t uint32_sha2_t;
+typedef zuo_uintptr_t size_sha2_t;
+
+typedef zuo_sha2_ctx_t mbedtls_sha256_context;
+
+/*
+ * 32-bit integer manipulation macros (big endian)
+ */
+#define GET_UINT32_BE(n,b,i) \
+do { \
+ (n) = ( (uint32_sha2_t) (b)[(i) ] << 24 ) \
+ | ( (uint32_sha2_t) (b)[(i) + 1] << 16 ) \
+ | ( (uint32_sha2_t) (b)[(i) + 2] << 8 ) \
+ | ( (uint32_sha2_t) (b)[(i) + 3] ); \
+} while( 0 )
+
+#define PUT_UINT32_BE(n,b,i) \
+do { \
+ (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \
+ (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \
+ (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \
+ (b)[(i) + 3] = (unsigned char) ( (n) ); \
+} while( 0 )
+
+static void mbedtls_sha256_init( mbedtls_sha256_context *ctx )
+{
+ memset( ctx, 0, sizeof( mbedtls_sha256_context ) );
}
-typedef unsigned char zuo_uint8_t;
+/*
+ * SHA-256 context setup
+ */
+static int mbedtls_sha256_starts_ret( mbedtls_sha256_context *ctx, int is224 )
+{
+ ctx->total[0] = 0;
+ ctx->total[1] = 0;
-typedef struct zuo_sha1_ctx_t {
- unsigned int state[5];
- unsigned int count[2];
- unsigned char buffer[64];
-} zuo_sha1_ctx_t;
+ if( is224 == 0 )
+ {
+ /* SHA-256 */
+ ctx->state[0] = 0x6A09E667;
+ ctx->state[1] = 0xBB67AE85;
+ ctx->state[2] = 0x3C6EF372;
+ ctx->state[3] = 0xA54FF53A;
+ ctx->state[4] = 0x510E527F;
+ ctx->state[5] = 0x9B05688C;
+ ctx->state[6] = 0x1F83D9AB;
+ ctx->state[7] = 0x5BE0CD19;
+ }
+ else
+ {
+ /* SHA-224 */
+ ctx->state[0] = 0xC1059ED8;
+ ctx->state[1] = 0x367CD507;
+ ctx->state[2] = 0x3070DD17;
+ ctx->state[3] = 0xF70E5939;
+ ctx->state[4] = 0xFFC00B31;
+ ctx->state[5] = 0x68581511;
+ ctx->state[6] = 0x64F98FA7;
+ ctx->state[7] = 0xBEFA4FA4;
+ }
-#define ZUO_SHA1_DIGEST_SIZE 20
+ ctx->is224 = is224;
-#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+ return( 0 );
+}
-/* blk0() and blk() perform the initial expand; assumes input has been converted to bigendian */
-#define blk0(i) block->l[i]
-#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
- ^block->l[(i+2)&15]^block->l[i&15],1))
+static const uint32_sha2_t K[] =
+{
+ 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5,
+ 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,
+ 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3,
+ 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,
+ 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC,
+ 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,
+ 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7,
+ 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,
+ 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13,
+ 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,
+ 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3,
+ 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,
+ 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5,
+ 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,
+ 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208,
+ 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2,
+};
-/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
-#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
-#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
-#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
-#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
-#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+#define SHR(x,n) ((x & 0xFFFFFFFF) >> n)
+#define ROTR(x,n) (SHR(x,n) | (x << (32 - n)))
-/* Hash a single 512-bit block. This is the core of the algorithm. */
-static void zuo_sha1_transform(zuo_uint32_t state[5], const zuo_uint8_t buffer[64]) {
- zuo_uint32_t a, b, c, d, e;
- typedef union {
- zuo_uint8_t c[64];
- zuo_uint32_t l[16];
- } CHAR64LONG16;
- CHAR64LONG16 *block;
+#define S0(x) (ROTR(x, 7) ^ ROTR(x,18) ^ SHR(x, 3))
+#define S1(x) (ROTR(x,17) ^ ROTR(x,19) ^ SHR(x,10))
- block = (CHAR64LONG16 *) buffer;
+#define S2(x) (ROTR(x, 2) ^ ROTR(x,13) ^ ROTR(x,22))
+#define S3(x) (ROTR(x, 6) ^ ROTR(x,11) ^ ROTR(x,25))
- if (zuo_little_endian) {
- int i;
- for (i = 0; i < 16; i++)
- block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) | (rol(block->l[i], 8) & 0x00FF00FF);
- }
+#define F0(x,y,z) ((x & y) | (z & (x | y)))
+#define F1(x,y,z) (z ^ (x & (y ^ z)))
- /* Copy context->state[] to working vars */
- a = state[0];
- b = state[1];
- c = state[2];
- d = state[3];
- e = state[4];
+#define R(t) \
+( \
+ W[t] = S1(W[t - 2]) + W[t - 7] + \
+ S0(W[t - 15]) + W[t - 16] \
+)
- /* 4 rounds of 20 operations each. Loop unrolled. */
- R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
- R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
- R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
- R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
- R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
- R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
- R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
- R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
- R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
- R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
- R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
- R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
- R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
- R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
- R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
- R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
- R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
- R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
- R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
- R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+#define P(a,b,c,d,e,f,g,h,x,K) \
+{ \
+ temp1 = h + S3(e) + F1(e,f,g) + K + x; \
+ temp2 = S2(a) + F0(a,b,c); \
+ d += temp1; h = temp1 + temp2; \
+}
- /* Add the working vars back into context.state[] */
- state[0] += a;
- state[1] += b;
- state[2] += c;
- state[3] += d;
- state[4] += e;
+static int mbedtls_internal_sha256_process( mbedtls_sha256_context *ctx,
+ const unsigned char data[64] )
+{
+ uint32_sha2_t temp1, temp2, W[64];
+ uint32_sha2_t A[8];
+ unsigned int i;
+
+ for( i = 0; i < 8; i++ )
+ A[i] = ctx->state[i];
+
+#if defined(MBEDTLS_SHA256_SMALLER)
+ for( i = 0; i < 64; i++ )
+ {
+ if( i < 16 )
+ GET_UINT32_BE( W[i], data, 4 * i );
+ else
+ R( i );
+
+ P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i], K[i] );
+
+ temp1 = A[7]; A[7] = A[6]; A[6] = A[5]; A[5] = A[4]; A[4] = A[3];
+ A[3] = A[2]; A[2] = A[1]; A[1] = A[0]; A[0] = temp1;
+ }
+#else /* MBEDTLS_SHA256_SMALLER */
+ for( i = 0; i < 16; i++ )
+ GET_UINT32_BE( W[i], data, 4 * i );
+
+ for( i = 0; i < 16; i += 8 )
+ {
+ P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i+0], K[i+0] );
+ P( A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], W[i+1], K[i+1] );
+ P( A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], W[i+2], K[i+2] );
+ P( A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], W[i+3], K[i+3] );
+ P( A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], W[i+4], K[i+4] );
+ P( A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], W[i+5], K[i+5] );
+ P( A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], W[i+6], K[i+6] );
+ P( A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], W[i+7], K[i+7] );
+ }
+
+ for( i = 16; i < 64; i += 8 )
+ {
+ P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(i+0), K[i+0] );
+ P( A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(i+1), K[i+1] );
+ P( A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(i+2), K[i+2] );
+ P( A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(i+3), K[i+3] );
+ P( A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(i+4), K[i+4] );
+ P( A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(i+5), K[i+5] );
+ P( A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(i+6), K[i+6] );
+ P( A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(i+7), K[i+7] );
+ }
+#endif /* MBEDTLS_SHA256_SMALLER */
+
+ for( i = 0; i < 8; i++ )
+ ctx->state[i] += A[i];
+
+ return( 0 );
}
-static void zuo_sha1_init(zuo_sha1_ctx_t *context) {
- /* SHA1 initialization constants */
- context->state[0] = 0x67452301;
- context->state[1] = 0xEFCDAB89;
- context->state[2] = 0x98BADCFE;
- context->state[3] = 0x10325476;
- context->state[4] = 0xC3D2E1F0;
- context->count[0] = context->count[1] = 0;
+/*
+ * SHA-256 process buffer
+ */
+static int mbedtls_sha256_update_ret( mbedtls_sha256_context *ctx,
+ const unsigned char *input,
+ size_sha2_t ilen )
+{
+ int ret;
+ size_sha2_t fill;
+ uint32_sha2_t left;
+
+ if( ilen == 0 )
+ return( 0 );
+
+ left = ctx->total[0] & 0x3F;
+ fill = 64 - left;
+
+ ctx->total[0] += (uint32_sha2_t) ilen;
+ ctx->total[0] &= 0xFFFFFFFF;
+
+ if( ctx->total[0] < (uint32_sha2_t) ilen )
+ ctx->total[1]++;
+
+ if( left && ilen >= fill )
+ {
+ memcpy( (void *) (ctx->buffer + left), input, fill );
+
+ if( ( ret = mbedtls_internal_sha256_process( ctx, ctx->buffer ) ) != 0 )
+ return( ret );
+
+ input += fill;
+ ilen -= fill;
+ left = 0;
+ }
+
+ while( ilen >= 64 )
+ {
+ if( ( ret = mbedtls_internal_sha256_process( ctx, input ) ) != 0 )
+ return( ret );
+
+ input += 64;
+ ilen -= 64;
+ }
+
+ if( ilen > 0 )
+ memcpy( (void *) (ctx->buffer + left), input, ilen );
+
+ return( 0 );
}
-/* Run your data through this. */
-static void zuo_sha1_update(zuo_sha1_ctx_t *context, const zuo_uint8_t *data, const zuo_intptr_t len) {
- zuo_intptr_t i, j;
+static const unsigned char sha256_padding[64] =
+{
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
- j = (context->count[0] >> 3) & 63;
- if ((context->count[0] += len << 3) < (len << 3))
- context->count[1]++;
- context->count[1] += (len >> 29);
- if ((j + len) > 63) {
- memcpy(&context->buffer[j], data, (i = 64 - j));
- zuo_sha1_transform(context->state, context->buffer);
- for (; i + 63 < len; i += 64)
- zuo_sha1_transform(context->state, data + i);
- j = 0;
- } else
- i = 0;
- memcpy(&context->buffer[j], &data[i], len - i);
+/*
+ * SHA-256 final digest
+ */
+static int mbedtls_sha256_finish_ret( mbedtls_sha256_context *ctx,
+ unsigned char output[32] )
+{
+ int ret;
+ uint32_sha2_t last, padn;
+ uint32_sha2_t high, low;
+ unsigned char msglen[8];
+
+ high = ( ctx->total[0] >> 29 )
+ | ( ctx->total[1] << 3 );
+ low = ( ctx->total[0] << 3 );
+
+ PUT_UINT32_BE( high, msglen, 0 );
+ PUT_UINT32_BE( low, msglen, 4 );
+
+ last = ctx->total[0] & 0x3F;
+ padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
+
+ if( ( ret = mbedtls_sha256_update_ret( ctx, sha256_padding, padn ) ) != 0 )
+ return( ret );
+
+ if( ( ret = mbedtls_sha256_update_ret( ctx, msglen, 8 ) ) != 0 )
+ return( ret );
+
+ PUT_UINT32_BE( ctx->state[0], output, 0 );
+ PUT_UINT32_BE( ctx->state[1], output, 4 );
+ PUT_UINT32_BE( ctx->state[2], output, 8 );
+ PUT_UINT32_BE( ctx->state[3], output, 12 );
+ PUT_UINT32_BE( ctx->state[4], output, 16 );
+ PUT_UINT32_BE( ctx->state[5], output, 20 );
+ PUT_UINT32_BE( ctx->state[6], output, 24 );
+
+ if( ctx->is224 == 0 )
+ PUT_UINT32_BE( ctx->state[7], output, 28 );
+
+ return( 0 );
}
-static int hex_char(int c) {
- return (c < 10) ? (c + '0') : (c + 'a'-10);
+#if defined(MBEDTLS_SELF_TEST)
+/*
+ * FIPS-180-2 test vectors
+ */
+static const unsigned char sha256_test_buf[3][57] =
+{
+ { "abc" },
+ { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" },
+ { "" }
+};
+
+static const size_sha2_t sha256_test_buflen[3] =
+{
+ 3, 56, 1000
+};
+
+static const unsigned char sha256_test_sum[6][32] =
+{
+ /*
+ * SHA-224 test vectors
+ */
+ { 0x23, 0x09, 0x7D, 0x22, 0x34, 0x05, 0xD8, 0x22,
+ 0x86, 0x42, 0xA4, 0x77, 0xBD, 0xA2, 0x55, 0xB3,
+ 0x2A, 0xAD, 0xBC, 0xE4, 0xBD, 0xA0, 0xB3, 0xF7,
+ 0xE3, 0x6C, 0x9D, 0xA7 },
+ { 0x75, 0x38, 0x8B, 0x16, 0x51, 0x27, 0x76, 0xCC,
+ 0x5D, 0xBA, 0x5D, 0xA1, 0xFD, 0x89, 0x01, 0x50,
+ 0xB0, 0xC6, 0x45, 0x5C, 0xB4, 0xF5, 0x8B, 0x19,
+ 0x52, 0x52, 0x25, 0x25 },
+ { 0x20, 0x79, 0x46, 0x55, 0x98, 0x0C, 0x91, 0xD8,
+ 0xBB, 0xB4, 0xC1, 0xEA, 0x97, 0x61, 0x8A, 0x4B,
+ 0xF0, 0x3F, 0x42, 0x58, 0x19, 0x48, 0xB2, 0xEE,
+ 0x4E, 0xE7, 0xAD, 0x67 },
+
+ /*
+ * SHA-256 test vectors
+ */
+ { 0xBA, 0x78, 0x16, 0xBF, 0x8F, 0x01, 0xCF, 0xEA,
+ 0x41, 0x41, 0x40, 0xDE, 0x5D, 0xAE, 0x22, 0x23,
+ 0xB0, 0x03, 0x61, 0xA3, 0x96, 0x17, 0x7A, 0x9C,
+ 0xB4, 0x10, 0xFF, 0x61, 0xF2, 0x00, 0x15, 0xAD },
+ { 0x24, 0x8D, 0x6A, 0x61, 0xD2, 0x06, 0x38, 0xB8,
+ 0xE5, 0xC0, 0x26, 0x93, 0x0C, 0x3E, 0x60, 0x39,
+ 0xA3, 0x3C, 0xE4, 0x59, 0x64, 0xFF, 0x21, 0x67,
+ 0xF6, 0xEC, 0xED, 0xD4, 0x19, 0xDB, 0x06, 0xC1 },
+ { 0xCD, 0xC7, 0x6E, 0x5C, 0x99, 0x14, 0xFB, 0x92,
+ 0x81, 0xA1, 0xC7, 0xE2, 0x84, 0xD7, 0x3E, 0x67,
+ 0xF1, 0x80, 0x9A, 0x48, 0xA4, 0x97, 0x20, 0x0E,
+ 0x04, 0x6D, 0x39, 0xCC, 0xC7, 0x11, 0x2C, 0xD0 }
+};
+
+/*
+ * Checkup routine
+ */
+int mbedtls_sha256_self_test( int verbose )
+{
+ int i, j, k, buflen, ret = 0;
+ unsigned char *buf;
+ unsigned char sha256sum[32];
+ mbedtls_sha256_context ctx;
+
+ buf = mbedtls_calloc( 1024, sizeof(unsigned char) );
+ if( NULL == buf )
+ {
+ if( verbose != 0 )
+ mbedtls_printf( "Buffer allocation failed\n" );
+
+ return( 1 );
+ }
+
+ mbedtls_sha256_init( &ctx );
+
+ for( i = 0; i < 6; i++ )
+ {
+ j = i % 3;
+ k = i < 3;
+
+ if( verbose != 0 )
+ mbedtls_printf( " SHA-%d test #%d: ", 256 - k * 32, j + 1 );
+
+ if( ( ret = mbedtls_sha256_starts_ret( &ctx, k ) ) != 0 )
+ goto fail;
+
+ if( j == 2 )
+ {
+ memset( buf, 'a', buflen = 1000 );
+
+ for( j = 0; j < 1000; j++ )
+ {
+ ret = mbedtls_sha256_update_ret( &ctx, buf, buflen );
+ if( ret != 0 )
+ goto fail;
+ }
+
+ }
+ else
+ {
+ ret = mbedtls_sha256_update_ret( &ctx, sha256_test_buf[j],
+ sha256_test_buflen[j] );
+ if( ret != 0 )
+ goto fail;
+ }
+
+ if( ( ret = mbedtls_sha256_finish_ret( &ctx, sha256sum ) ) != 0 )
+ goto fail;
+
+
+ if( memcmp( sha256sum, sha256_test_sum[i], 32 - k * 4 ) != 0 )
+ {
+ ret = 1;
+ goto fail;
+ }
+
+ if( verbose != 0 )
+ mbedtls_printf( "passed\n" );
+ }
+
+ if( verbose != 0 )
+ mbedtls_printf( "\n" );
+
+ goto exit;
+
+fail:
+ if( verbose != 0 )
+ mbedtls_printf( "failed\n" );
+
+exit:
+ mbedtls_sha256_free( &ctx );
+ mbedtls_free( buf );
+
+ return( ret );
}
-/* Add padding and return the message digest. */
-static void zuo_sha1_final(zuo_sha1_ctx_t *context, zuo_uint8_t digest[ZUO_SHA1_DIGEST_SIZE]) {
- zuo_uint32_t i;
- zuo_uint8_t finalcount[8];
+#endif /* MBEDTLS_SELF_TEST */
- for (i = 0; i < 8; i++)
- finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 3)) * 8)) & 255);
- zuo_sha1_update(context, (zuo_uint8_t *)"\200", 1);
- while ((context->count[0] & 504) != 448)
- zuo_sha1_update(context, (zuo_uint8_t *)"\0", 1);
- zuo_sha1_update(context, finalcount, 8);
- for (i = 0; i < ZUO_SHA1_DIGEST_SIZE; i++)
- digest[i] = (zuo_uint8_t)((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);
+typedef unsigned char zuo_uint8_t;
+
+static void zuo_sha256_init(zuo_sha2_ctx_t *context) {
+ int is224 = 0;
+ (void)mbedtls_sha256_init(context);
+ (void)mbedtls_sha256_starts_ret(context, is224);
}
-static zuo_t *zuo_string_sha1(zuo_t *str) {
- zuo_sha1_ctx_t context;
- zuo_uint8_t digest[ZUO_SHA1_DIGEST_SIZE];
- char digest_hex[2 * ZUO_SHA1_DIGEST_SIZE];
+/* Run your data through this. */
+static void zuo_sha256_update(zuo_sha2_ctx_t *context, const zuo_uint8_t *data, const zuo_intptr_t len) {
+ (void)mbedtls_sha256_update_ret(context, data, len);
+}
+
+/* Get the final hash value after all bytes have been added */
+static void zuo_sha256_final(zuo_sha2_ctx_t *context, zuo_uint8_t digest[ZUO_SHA256_DIGEST_SIZE]) {
+ (void)mbedtls_sha256_finish_ret(context, digest);
+}
+
+/* ************************************************************ */
+
+static int hex_char(int c) {
+ return (c < 10) ? (c + '0') : (c + 'a'-10);
+}
+
+static zuo_t *zuo_string_sha256(zuo_t *str) {
+ zuo_sha2_ctx_t context;
+ zuo_uint8_t digest[ZUO_SHA256_DIGEST_SIZE];
+ char digest_hex[2 * ZUO_SHA256_DIGEST_SIZE];
int i;
- zuo_sha1_init(&context);
- zuo_sha1_update(&context, (zuo_uint8_t *)ZUO_STRING_PTR(str), ZUO_STRING_LEN(str));
- zuo_sha1_final(&context, digest);
+ zuo_sha256_init(&context);
+ zuo_sha256_update(&context, (zuo_uint8_t *)ZUO_STRING_PTR(str), ZUO_STRING_LEN(str));
+ zuo_sha256_final(&context, digest);
- for (i = 0; i < ZUO_SHA1_DIGEST_SIZE; i++) {
+ for (i = 0; i < ZUO_SHA256_DIGEST_SIZE; i++) {
digest_hex[2*i] = hex_char(digest[i] >> 4);
digest_hex[2*i+1] = hex_char(digest[i] & 0xF);
}
- return zuo_sized_string(digest_hex, 2 * ZUO_SHA1_DIGEST_SIZE);
+ return zuo_sized_string(digest_hex, 2 * ZUO_SHA256_DIGEST_SIZE);
}
/*======================================================================*/
@@ -6495,7 +6824,6 @@
zuo_configure();
zuo_init_terminal();
zuo_init_signal_handler();
- zuo_init_sha1();
/* these initial constants and tables might get replaced by loading
an image, but we need them to register primitives: */
@@ -6615,7 +6943,7 @@
ZUO_TOP_ENV_SET_PRIMITIVE0("resume-signal", zuo_resume_signal);
ZUO_TOP_ENV_SET_PRIMITIVE1("string->shell", zuo_string_to_shell);
ZUO_TOP_ENV_SET_PRIMITIVEb("shell->strings", zuo_shell_to_strings);
- ZUO_TOP_ENV_SET_PRIMITIVE1("string-sha1", zuo_string_sha1);
+ ZUO_TOP_ENV_SET_PRIMITIVE1("string-sha256", zuo_string_sha256);
ZUO_TOP_ENV_SET_PRIMITIVE1("cleanable-file", zuo_cleanable_file);
ZUO_TOP_ENV_SET_PRIMITIVE1("cleanable-cancel", zuo_cleanable_cancel);