- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我可以使用外部库(Java,C或系统相关)或使用特定的Scheme实现(例如Chicken)在Scheme中使用SHA256,但我想知道是否有一个“纯粹的”scheme实现。
最佳答案
我今天写了一个实现。唉,R5RS 既没有字节向量也没有二进制 I/O,因此它使用 R7RS API 来处理字节向量和二进制 I/O。将这些 API 桥接到您的 Scheme 实现的 native API 应该很容易(例如,我实际上在 Racket 和 Guile 上测试了我的实现)。
一些注意事项:
无论如何,事不宜迟,这就是(也可用 as a Gist ):
;;; Auxiliary definitions to avoid having to use giant tables of constants.
(define primes80 '(2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73
79 83 89 97 101 103 107 109 113 127 131 137 139 149 151 157
163 167 173 179 181 191 193 197 199 211 223 227 229 233 239
241 251 257 263 269 271 277 281 283 293 307 311 313 317 331
337 347 349 353 359 367 373 379 383 389 397 401 409))
(define (sqrt x)
(fold (lambda (_ y) (/ (+ (/ x y) y) 2)) 4 (iota 7)))
(define (cbrt x)
(fold (lambda (_ y) (/ (+ (/ x y y) y y) 3)) 4 (iota 8)))
(define (frac x scale base)
(bitwise-and (floor (* x (arithmetic-shift 1 scale)))
(- (arithmetic-shift 1 base) 1)))
;;; The actual initialisation and constant values.
(define sha1-init '(#x67452301 #xefcdab89 #x98badcfe #x10325476 #xc3d2e1f0))
(define sha2-init (map (lambda (x) (frac (sqrt x) 64 64)) (take primes80 16)))
(define-values (sha512-init sha384-init) (split-at sha2-init 8))
(define sha256-init (map (cut arithmetic-shift <> -32) sha512-init))
(define sha224-init (map (cut frac <> 0 32) sha384-init))
(define sha1-const (map (lambda (x) (frac (sqrt x) 30 32)) '(2 3 5 10)))
(define sha512-const (map (lambda (x) (frac (cbrt x) 64 64)) primes80))
(define sha256-const (map (cut arithmetic-shift <> -32) (take sha512-const 64)))
;;; Utility functions used by the compression and driver functions.
(define (u32+ . xs) (bitwise-and (apply + xs) #xffffffff))
(define (u64+ . xs) (bitwise-and (apply + xs) #xffffffffffffffff))
(define (bitwise-majority x y z)
(bitwise-xor (bitwise-and x y) (bitwise-and x z) (bitwise-and y z)))
(define (bytevector-be-ref bv base n)
(let loop ((res 0) (i 0))
(if (< i n)
(loop (+ (arithmetic-shift res 8) (bytevector-u8-ref bv (+ base i)))
(+ i 1))
res)))
(define (bytevector-u64-ref bv i)
(bytevector-be-ref bv (arithmetic-shift i 3) 8))
(define (bytevector-u32-ref bv i)
(bytevector-be-ref bv (arithmetic-shift i 2) 4))
(define (bytevector-be-set! bv base n val)
(let loop ((i n) (val val))
(when (positive? i)
(bytevector-u8-set! bv (+ base i -1) (bitwise-and val 255))
(loop (- i 1) (arithmetic-shift val -8)))))
(define (md-pad! bv offset count counter-size)
(define block-size (bytevector-length bv))
(unless (negative? offset)
(bytevector-u8-set! bv offset #x80))
(let loop ((i (+ offset 1)))
(when (< i block-size)
(bytevector-u8-set! bv i 0)
(loop (+ i 1))))
(when count
(bytevector-be-set! bv (- block-size counter-size) counter-size
(arithmetic-shift count 3))))
(define (hash-state->bytevector hs trunc word-size)
(define result (make-bytevector (* trunc word-size)))
(for-each (lambda (h i)
(bytevector-be-set! result i word-size h))
hs (iota trunc 0 word-size))
result)
;;; The compression functions.
(define (sha2-compress K Σ0 Σ1 σ0 σ1 mod+ getter hs)
(define W (vector->list (apply vector-unfold
(lambda (_ a b c d e f g h i j k l m n o p)
(values a b c d e f g h i j k l m n o p
(mod+ a (σ0 b) j (σ1 o))))
(length K)
(list-tabulate 16 getter))))
(define (loop k w a b c d e f g h)
(if (null? k)
(map mod+ hs (list a b c d e f g h))
(let ((T1 (mod+ h (Σ1 e) (bitwise-if e f g) (car k) (car w)))
(T2 (mod+ (Σ0 a) (bitwise-majority a b c))))
(loop (cdr k) (cdr w) (mod+ T1 T2) a b c (mod+ d T1) e f g))))
(apply loop K W hs))
(define (sha512-compress bv hs)
(define (rotr x y) (rotate-bit-field x (- y) 0 64))
(define (shr x y) (arithmetic-shift x (- y)))
(sha2-compress sha512-const
(lambda (x) (bitwise-xor (rotr x 28) (rotr x 34) (rotr x 39)))
(lambda (x) (bitwise-xor (rotr x 14) (rotr x 18) (rotr x 41)))
(lambda (x) (bitwise-xor (rotr x 1) (rotr x 8) (shr x 7)))
(lambda (x) (bitwise-xor (rotr x 19) (rotr x 61) (shr x 6)))
u64+ (cut bytevector-u64-ref bv <>) hs))
(define (sha256-compress bv hs)
(define (rotr x y) (rotate-bit-field x (- y) 0 32))
(define (shr x y) (arithmetic-shift x (- y)))
(sha2-compress sha256-const
(lambda (x) (bitwise-xor (rotr x 2) (rotr x 13) (rotr x 22)))
(lambda (x) (bitwise-xor (rotr x 6) (rotr x 11) (rotr x 25)))
(lambda (x) (bitwise-xor (rotr x 7) (rotr x 18) (shr x 3)))
(lambda (x) (bitwise-xor (rotr x 17) (rotr x 19) (shr x 10)))
u32+ (cut bytevector-u32-ref bv <>) hs))
(define (sha1-compress bv hs)
(define (getter x) (bytevector-u32-ref bv x))
(define (rotl x y) (rotate-bit-field x y 0 32))
(define W (vector->list (apply vector-unfold
(lambda (_ a b c d e f g h i j k l m n o p)
(values a b c d e f g h i j k l m n o p
(rotl (bitwise-xor a c i n) 1)))
80
(list-tabulate 16 getter))))
(define (outer f k w a b c d e)
(if (null? k)
(map u32+ hs (list a b c d e))
(let inner ((i 0) (w w) (a a) (b b) (c c) (d d) (e e))
(if (< i 20)
(let ((T (u32+ (rotl a 5) ((car f) b c d) e (car k) (car w))))
(inner (+ i 1) (cdr w) T a (rotl b 30) c d))
(outer (cdr f) (cdr k) w a b c d e)))))
(apply outer (list bitwise-if bitwise-xor bitwise-majority bitwise-xor)
sha1-const W hs))
;;; The Merkle-Damgård "driver" function.
(define (md-loop init compress block-size trunc word-size counter-size in)
(define leftover (- block-size counter-size))
(define bv (make-bytevector block-size))
(define pad! (cut md-pad! bv <> <> counter-size))
(define hs->bv (cut hash-state->bytevector <> trunc word-size))
(let loop ((count 0) (hs init))
(define read-size (read-bytevector! bv in))
(cond ((eof-object? read-size)
(pad! 0 count)
(hs->bv (compress bv hs)))
((= read-size block-size)
(loop (+ count read-size) (compress bv hs)))
((< read-size leftover)
(pad! read-size (+ count read-size))
(hs->bv (compress bv hs)))
(else
(pad! read-size #f)
(let ((pen (compress bv hs)))
(pad! -1 (+ count read-size))
(hs->bv (compress bv pen)))))))
;;; SHA-512/t stuff.
(define sha512/t-init (map (cut bitwise-xor <> #xa5a5a5a5a5a5a5a5) sha512-init))
(define (make-sha512/t-init t)
(define key (string->utf8 (string-append "SHA-512/" (number->string t))))
(define size (bytevector-length key))
(define bv (make-bytevector 128))
(bytevector-copy! bv 0 key)
(md-pad! bv size size 16)
(sha512-compress bv sha512/t-init))
(define (make-sha512/t t)
(define init (make-sha512/t-init t))
(define words (arithmetic-shift t -6))
(if (zero? (bitwise-and t 63))
(cut md-loop init sha512-compress 128 words 8 16 <>)
(lambda (in)
(bytevector-copy
(md-loop init sha512-compress 128 (ceiling words) 8 16 in)
0 (arithmetic-shift t -3)))))
;;; Public entry points.
(define sha1 (cut md-loop sha1-init sha1-compress 64 5 4 8 <>))
(define sha224 (cut md-loop sha224-init sha256-compress 64 7 4 8 <>))
(define sha256 (cut md-loop sha256-init sha256-compress 64 8 4 8 <>))
(define sha384 (cut md-loop sha384-init sha512-compress 128 6 8 16 <>))
(define sha512 (cut md-loop sha512-init sha512-compress 128 8 8 16 <>))
(define sha512/256 (make-sha512/t 256))
(define sha512/224 (make-sha512/t 224))
我实现了 FIPS 180-4 中的所有算法,但您可以删除不需要的任何算法。
<小时/>如前所述,我在 Racket 上对此进行了测试;我添加的用于桥接到 Racket 的 API 的定义如下:
#lang racket
(require (only-in srfi/1 iota)
(only-in srfi/26 cut)
(only-in srfi/43 vector-unfold)
(only-in srfi/60 bitwise-if rotate-bit-field)
(rename-in racket/base [build-list list-tabulate]
[bytes-copy! bytevector-copy!]
[bytes-length bytevector-length]
[bytes-ref bytevector-u8-ref]
[bytes-set! bytevector-u8-set!]
[foldl fold]
[make-bytes make-bytevector]
[read-bytes! read-bytevector!]
[string->bytes/utf-8 string->utf8]
[subbytes bytevector-copy]))
下面是 Guile 的定义(需要 2.0.11 或更高版本):
(use-modules (srfi srfi-1) (srfi srfi-26) (srfi srfi-43) (srfi srfi-60)
(rnrs bytevectors) (ice-9 binary-ports))
(define* (bytevector-copy bv #:optional (start 0) (end (bytevector-length bv)))
(define copy (make-bytevector (- end start)))
(bytevector-copy! copy 0 bv start end)
copy)
(define* (bytevector-copy! to at from #:optional (start 0)
(end (bytevector-length from)))
((@ (rnrs bytevectors) bytevector-copy!) from start to at (- end start)))
(define* (read-bytevector! bv #:optional (port (current-input-port)) (start 0)
(end (bytevector-length bv)))
(get-bytevector-n! port bv start (- end start)))
为您选择的实现制作类似的东西应该很容易。
<小时/>我还有一个函数,可以将输出打印为十六进制字符串,以便与各种命令行 SHA-1 和 SHA-2 实用程序(例如,sha1sum
、sha256sum
、sha512sum
等):
(define (hex bv)
(define out (open-output-string))
(do ((i 0 (+ i 1)))
((>= i (bytevector-length bv)) (get-output-string out))
(let-values (((q r) (truncate/ (bytevector-u8-ref bv i) 16)))
(display (number->string q 16) out)
(display (number->string r 16) out))))
关于hash - SHA256 的 "pure"方案实现(R5RS)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24093199/
在我学习期间Typoclassopedia我遇到了这个证明,但我不确定我的证明是否正确。问题是: One might imagine a variant of the interchange law
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 这个问题似乎与 help center 中定义的范围内的编程无关。 . 已关闭 8 年前。 Improve
我的理解是,“纯 OCaml”是指 OCaml 中标准的所有内容,包括其非“纯”功能特性,而“纯功能”是指通常的属性:没有副作用、没有异常处理等。从这个意义上说,“纯 OCaml” 实现与使用 C 或
Haskell 被称为“纯函数式语言”。 在这种情况下“纯粹”是什么意思?这会给程序员带来什么后果? 最佳答案 在纯函数式语言中,您不能做任何有副作用的事情。 副作用意味着计算表达式会改变某些内部状态
这是接口(interface)契约类的一部分。 [Pure] public bool IsDirty() { throw new NotImplementedException(); } pu
我想问一下 pure-g 和 pure-g-r 有什么区别。我曾经认为响应式会让我的 div 在较低的分辨率下不会崩溃但是使用 pure-g 也帮助我实现了同样的效果,所以我对它们之间的正确区别感到困
在source code of GHC.Base , Applicative Maybe 定义为: instance Applicative Maybe where pure = Just
这个问题在这里已经有了答案: Purpose of (0, obj.method)(param1, param2) in Closure Compiler minified code (1 个回答)
如何向 React 发出信号,表明函数组件是“纯”的,相当于组件类的 React.PureComponent ? function C(props) { return {props.n} } 没有
已阅读官方React documentation ,我遇到过this关于PureComponent: Furthermore, React.PureComponent’s shouldComponen
我有以下代码片段,我想知道它是纯 C 还是包含一些 C++ 元素。这个问题源于我认为它只是 C,但有些编译器不接受代码。 // User struct derived from Function
一个简单的问题。我应该如何在数据库中存储电话号码和电子邮件地址?只是像 email@email.com 这样的纯文本(或数字),还是用 key 对其进行编码更好(有点像密码在数据库中的保存方式)。在那
有人可以向我展示一个示例,说明我如何使用 purecss.io 来实现固定宽度/响应式设计,类似于 bootstrap 等 960 网格???? 流体宽度根本不适用于我的特定设计,这是我目前拥有的:
是否有一套通用规则/指南可以帮助您了解何时更喜欢pragma Pure,pragma Preelaborate或其他什么东西? standard (Ada 2012)中提供的规则和定义有些繁琐,我很高
我试图区分包含字母字符数据的单元格和数字数据单元格。我使用 istext() 和 isnumber() 取得了部分成功。但是当出现字母数字字符时,这种逻辑就会失败。 我的目的是检测只有字母的单元格。包
在Clash官方网站上,有以下示例: >>> sampleN @System 4 (register 0 (pure (8 :: Signed 8))) 我知道什么是纯函数,但为什么这里有 this
据我了解,javascript 要么在浏览器中运行,要么作为 Node.js 中的后端运行。 浏览器或 Node.js,根据您运行 JavaScript 的位置,将通过 Web API 或 C++ A
class Applicative f => Monad f where return :: a -> f a (>>=) :: f a -> (a -> f b) ->
在我看来,Fortran 中所谓的纯函数对于那些使用函数式编程的人来说似乎不够纯粹。这是我的问题。假设我有以下代码: MODULE basics IMPLICIT NONE INTEGER,
在Clash官方网站上,有以下示例: >>> sampleN @System 4 (register 0 (pure (8 :: Signed 8))) 我知道什么是纯函数,但为什么这里有 this
我是一名优秀的程序员,十分优秀!