SHA256 的“纯粹”方案实现(R5RS)?

2023-11-27

我可以在Scheme中使用SHA256,使用外部库(Java、C或系统相关)或使用特定的Scheme实现(例如Chicken),但我想知道是否有一个“纯粹的”scheme实现。


我今天写了一个实现。唉,R5RS 既没有字节向量也没有二进制 I/O,因此它使用 R7RS API 来处理字节向量和二进制 I/O。将这些 API 桥接到您的 Scheme 实现的本机 API 应该很容易(例如,我实际上在 Racket 和 Guile 上测试了我的实现)。

一些注意事项:

  • 此代码假定区分大小写。这是 R7RS 的默认设置,但不是 R5RS,因此如果您使用 R5RS 实现,请小心。
  • 它需要 SRFI1, 26, 43, and 60.
  • 我强调优雅和清晰而不是速度。事实上,代码相当慢。
  • 与我的个人资料所述相反,我仅根据以下许可授权此代码阿帕奇许可证 2.0(除了标准 Stack Overflow 许可证之外抄送-SA 3.0),并且不在 CC0 或类似公共领域的任何内容下。

无论如何,事不宜迟,这就是(也可以作为要点):

;;; 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, etc.):

(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))))
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SHA256 的“纯粹”方案实现(R5RS)? 的相关文章

  • 非加密用途的最快哈希值?

    我本质上是在准备要放入数据库的短语 它们可能格式错误 所以我想存储它们的简短散列 我将简单地比较它们是否存在 所以散列是理想的 我假设 MD5 在处理 100 000 个请求时相当慢 所以我想知道散列短语的最佳方法是什么 也许推出我自己的散
  • 防止 .exe 时间戳发生变化

    有谁知道如何防止可执行文件的时间戳更改 我正在尝试为 exe 生成一致的哈希代码 但我认为时间戳可能会阻止这种情况发生 每次我重新编译代码 VS C 时 FastSum 都会生成不同的校验和 Thanks PE 文件格式 如 EXE 中 具
  • 哈希表的空间复杂度是多少?

    具有 32 位键和指向单独存储的值的 32 位指针的哈希表的大小是多少 是 2 32 个槽 4 字节 键 4 字节 指向值的指针 4 10 9 4 4 32GB 我想了解哈希表的空间复杂度 我认为你问错了问题 数据结构的空间复杂度表示它占用
  • 数学组合的完美最小哈希

    首先定义两个整数N and K where N gt K 两者都在编译时已知 例如 N 8 and K 3 接下来 定义一组整数 0 N or 1 N 如果这使答案更简单 并调用它S 例如 0 1 2 3 4 5 6 7 的子集数量S wi
  • 为什么Racket中foldl的定义方式很奇怪?

    在 Haskell 中 与许多其他函数式语言一样 函数foldl被定义为 例如 foldl 0 1 2 3 4 10 这没关系 因为foldl 0 1 2 3 4 根据定义 0 1 2 3 4 但是 在 球拍 中 foldl 0 1 2 3
  • 使用 secp256r1 曲线和 SHA256 算法生成 ECDSA 签名 - BouncyCastle

    我正在尝试使用带有 secp256r1 曲线 P256 的 ECDSA 和用于消息哈希的 SHA256 算法生成签名 我也在使用 Bouncy Castle 库 下面的代码 public class MyTest param args pu
  • 使用 PBKDF2 和 SHA256 生成 128 位 AES 密钥是否安全?

    我想使用 PBKDF2 和一些加密哈希函数来生成 128 位 AES 密钥 SHA1 也是 128 位 所以我想将其与 PBKDF2 一起使用 但它已损坏 所以我选择使用 SHA256 这是否安全 或者散列大小和生成的密钥大小之间的差异是否
  • 从哈希中删除 nil 值

    我希望从哈希中删除具有nil value article是一个存储每篇文章的类 并且attributes方法将文章存储为散列 预期结果 articles results author null title Former bar manage
  • 如何通过 md5 比较图像?

    该方法是否比较图像的像素值 我猜它不会起作用 因为它们的尺寸彼此不同 但如果它们相同但格式不同怎么办 例如 我截图并保存为 jpg另一个并保存为 gif MD5哈希是实际的二进制数据 因此不同的格式将具有完全不同的二进制数据 因此 要使 M
  • 是否存在可以保证哈希算法唯一的情况?

    如果我使用字节大小大于数据 例如 sha 256 的哈希算法对大小受限的类似数据 例如社会安全号码 进行哈希处理 哈希是否能保证与数据具有相同级别的唯一性 原始数据 哈希冲突的概率与输入字符串的大小无关 除非它指示需要多少个输入来保持唯一性
  • 重新加载页面时删除哈希值?

    我使用哈希来切换我的图像滑块 当我重新加载页面并且哈希值设置为 e h 3 没有图片 当图库在几秒钟后自动滑动时 它显示下一个 所以几秒钟内什么也没有 有没有办法在加载页面时检查哈希并将其删除 我只想关心那些用散列为页面添加书签的人 问候
  • 当我使用加盐 CRYPT_MD5 加密我的密码时,正在加密什么?

    对字符串使用 md5 总是会产生字母数字加密结果 即 没有符号 然而 当我使用 php crypt 函数 特别是带有盐的 CRYPT MD5 并且它已打开 我已经检查过 时 它返回的假定 md5 哈希看起来不像 md5 哈希 例如 如果我
  • 哈希 freezeset 与排序元组

    在 Python 中 给定一组可比较的 可散列的元素s 散列是否更好frozenset s or tuple sorted s 这取决于你在做什么 创建一个更快frozenset 比排序tuple but frozenset占用的内存比tu
  • 直接对文件的哈希值进行数字签名,而不是对文件进行签名

    我的问题是 是否可以直接对文件的哈希值而不是文件进行数字签名 我必须通过电子令牌在 Web 环境中对 xml 文件进行数字签名 所以我必须将文件从服务器下载到客户端 然后从客户端计算机上的电子令牌 USB 获取证书并对文件进行签名并将其上传
  • 数字签名(PKCS#7 - 延迟签名)/自应用签名以来文档已被更改或损坏

    我已经浏览了所有类似的问题 但找不到应用 itextsharp 延迟签名的情况 基本上 我的应用程序使用以下方式签署 pdf 文档PKCS 7由远程 Web 服务创建的签名 我的应用程序向此 Web 服务发送原始文档的哈希值 添加空签名字段
  • 检测重复文件

    我想检测目录树中的重复文件 当发现两个相同的文件时 将仅保留其中一个重复文件 并删除其余的重复文件以节省磁盘空间 重复是指具有相同内容的文件 但文件名和路径可能不同 我正在考虑为此目的使用哈希算法 但不同的文件有可能具有相同的哈希值 因此我
  • URL 哈希在重定向之间持续存在

    由于某种原因 当发送服务器端重定向 使用 Location 标头 时 非 IE 浏览器似乎会保留 URL 哈希 如果存在 例子 a simple redirect using Response Redirect http www yahoo
  • java中的散列是如何工作的?

    我正在尝试弄清楚java中的哈希值 例如 如果我想在哈希图中存储一些数据 它是否会有某种带有哈希值的底层哈希表 或者 如果有人能够对哈希的工作原理给出一个很好且简单的解释 我将非常感激 HashMap 基本上在内部实现为数组Entry 如果
  • 当今常用的最强哈希算法是什么?

    我正在构建一个 Web 应用程序 并希望对密码使用最强的哈希算法 sha512 whirlpool ripemd160 和 Tiger192 4 之间有什么区别 如果有 哪一个在密码学上被认为更强 bCrypt 为什么会是一个很长的解释 我
  • 散列 hash_hmac 时,Convert.ToChar(0) 散列结果与 PHP 中的 chr(0) 不同的字符串

    我在 PHP 中有一个字符串 它被转换为字节数组并进行哈希处理 转换为字节数组的字符串如下所示 G 字符 0 便便 我需要 C 中的等效字节数组 这样我才能得到相同的哈希值 编辑 这是完整的问题 生成的哈希值不同 PHP api secre

随机推荐

  • API 19 上的 Android Gradle Multidex 构建问题

    我有一个已启用的项目multidex避免65k limit并且productFlavors 开发 API 21 和产品 API 19 用于定制 构建我的项目API 21即开发风格是成功的 但是API 19即产品风味 它在应用程序任务中不断给
  • 如何使用python连接三个excel文件xlsx?

    你好 我想使用 python 连接三个 excel 文件 xlsx 我尝试过使用 openpyxl 但我不知道哪个函数可以帮助我将三个工作表附加到一个中 您有什么想法如何做到这一点吗 多谢 这是一个pandas基于的方法 它正在使用open
  • OpenCover/NUnit 找不到 PDB 文件

    我正在使用 OpenCoverhttp nuget org packages opencover并编写了以下批处理文件来运行单元测试并生成代码覆盖率统计信息 echo off echo echo Running NUnit tests ec
  • 启动 django 服务器时,我不断收到 NotImplementedError 错误 [重复]

    这个问题在这里已经有答案了 下面是错误的完整跟踪 请告诉我什么可以解决这个问题 env C Users LENOVO Desktop SD backend gt python manage py runserver Watching for
  • Python 2.X 中的 range 和 xrange 函数有什么区别?

    显然 xrange 更快 但我不知道为什么它更快 除了到目前为止的轶事之外没有证据表明它更快 或者除此之外还有什么不同 for i in range 0 20 for i in xrange 0 20 在 Python 2 x 中 rang
  • C 中大量字符的字节顺序

    我正在用 C 语言进行一些套接字编程 并尝试解决字节顺序问题 我的请求 发送 很好 但是当我收到数据时 我的字节全部乱序 我从这样的事情开始 char aResponse char malloc 512 int total recv soc
  • 错误:[错误号 10053]

    如果我在 Flask 上编码 有时会出现以下错误 Traceback most recent call last File C Python27 lib SocketServer py line 284 in handle request
  • 在 SQL 中选择 CHAR 而不是 VARCHAR 的用例有哪些?

    我意识到如果我的所有值都是固定宽度的 则建议使用 CHAR 但是 那又怎样 为了安全起见 为什么不为所有文本字段选择 VARCHAR 一般规则是选择CHAR如果所有行都接近相同长度 Pick VARCHAR or NVARCHAR 当 的时
  • 为什么我不能为 ThreadStart 使用/强制转换 Action?

    两者都是委托并且具有相同的签名 但我不能使用 Action 作为 ThreadStart Why Action doIt doIt gt MyMethod test Thread t t new Thread doIt t Start 但这
  • 节点串行端口在 alpine linux 上失败

    我正在开发一个使用node serialport的小型nodejs nodejs v4 3 项目https github com voodootikigod node serialport 我把它包装在一个 docker 镜像中 首先 我成
  • 如何在模型中验证来自控制器的数据

    因此 我有一些从控制器中的另一个 Rails 应用程序中获取的数据 我们将其称为 ExampleController 我想在允许向导进入下一步之前验证它是否存在于我的模型中 但我不太清楚如何实现我应该这样做 我知道直接从控制器获取这些数据到
  • TensorFlow 检查点保存和读取

    我有一个基于 TensorFlow 的神经网络和一组变量 训练函数是这样的 def train load True step Defining the neural network is skipped here train step tf
  • 取消所有Javascript setTimeout 和 setInterval

    在给定的秒数后取消所有 JS setTimeout setInterval 和 requestAnimationFrame 的正确方法是什么 编辑 抱歉 我应该解释更多 该代码来自数据库或某些 API 因此我无法跟踪超时 raf 或间隔 I
  • 是否可以以编程方式隐藏停靠栏图标

    是否可以根据需要以编程方式隐藏停靠栏图标 我知道在 plist 中定义属性 应用程序是代理 UIElement 的一种方法 我们将可可应用程序作为用户代理 但这会导致永久隐藏停靠图标 我正在寻找一种可以控制停靠图标可见性的方法 任何想法 有
  • 如何在重新加载数据表时传递参数

    我有一个像这样初始化的数据表 mytable DataTable ajax url url getTableData dataSrc sortClasses false paging false scrollY 300 columns co
  • 如何在 Laravel 5.1 中实现“记住我”?

    如何在 Laravel 5 1 中实现记住我功能 谁能给我举个例子吗 Laravel 身份验证优惠记住账号开箱即用的功能 为了使用它 你需要做两件事 add 记住令牌用户表中的列 这是存储令牌的位置 pass true作为第二个参数验证 尝
  • Kivy 不工作(错误:无法找到任何有价值的 Window 提供程序。)

    我收到此错误 无法找到任何有价值的 Window 提供程序 kivy 继承了 完整 错误 INFO Logger Record log in C Users Victor kivy logs kivy 17 05 27 10 txt INF
  • 设备 emulator-5554 未获得授权。 (安卓)

    我遇到过类似的问题 emulator 5554 未经授权使用 adb 设备 1 基本上 我正在尝试使用 Windows 10 在 Android 虚拟设备上进行一些 flutter 编程 尽管我不认为这个问题是 flutter 特有的 启动
  • Git for Windows(64 位)中的 Maven classworlds.launcher.Launcher 错误

    我已经在 Git Bash 64 位 上使用 Maven 几个月了 突然它停止工作 并且现在在任何 Maven 命令上生成此错误 myuser mypc MINGW64 master mvn v Error Could not find o
  • SHA256 的“纯粹”方案实现(R5RS)?

    我可以在Scheme中使用SHA256 使用外部库 Java C或系统相关 或使用特定的Scheme实现 例如Chicken 但我想知道是否有一个 纯粹的 scheme实现 我今天写了一个实现 唉 R5RS 既没有字节向量也没有二进制 I