SHA-256

Pure Raku

The following implementation takes all data as input. Ideally, input should be given lazily or something.

say sha256 "Rosetta code";

our proto sha256($) returns blob8 {*}

multi sha256(Str $str) { samewith $str.encode }
multi sha256(blob8 $data) {
  sub rotr { $^a +> $^b +| $a +< (32 - $b) }
  sub init { ^Inf .grep(&is-prime).map: { (($_ - .Int)*2**32).Int } o &^f } 
  sub   Ch { $^x +& $^y +^ +^$x +& $^z }
  sub  Maj { $^x +& $^y +^ $x +& $^z +^ $y +& $z }
  sub   Σ0 { rotr($^x,  2) +^ rotr($x, 13) +^ rotr($x, 22) }
  sub   Σ1 { rotr($^x,  6) +^ rotr($x, 11) +^ rotr($x, 25) }
  sub   σ0 { rotr($^x,  7) +^ rotr($x, 18) +^ $x +>  3 }
  sub   σ1 { rotr($^x, 17) +^ rotr($x, 19) +^ $x +> 10 }

  return blob8.new: 
    map |*.polymod(256 xx 3).reverse,
	|reduce -> $H, $block {
	  blob32.new: $H[] Z+
	    reduce -> $h, $j {
	      my uint32 ($T1, $T2) =
		$h[7] + Σ1($h[4]) + Ch(|$h[4..6])
		+ (BEGIN init(* **(1/3))[^64])[$j] +
		(
		 (state buf32 $w .= new)[$j] = $j < 16 ?? $block[$j] !!
		 σ0($w[$j-15]) + $w[$j-7] + σ1($w[$j-2]) + $w[$j-16]
		),
	      Σ0($h[0]) + Maj(|$h[0..2]);
	      blob32.new: $T1 + $T2, |$h[0..2], $h[3] + $T1, |$h[4..6];
	    }, $H, |^64;
	},
	(BEGIN init(&sqrt)[^8]),
	|blob32.new(
	    blob8.new(
	      @$data,
	      0x80,
	      0 xx (-($data + 1 + 8) mod 64),
	      (8*$data).polymod(256 xx 7).reverse
	      ).rotor(4)
	    .map: { :256[@$_] }
	  ).rotor(16)
}

Output:

Blob[uint8]:0x<76 4F AF 5C 61 AC 31 5F 14 97 F9 DF A5 42 71 39 65 B7 85 E5 CC 2F 70 7D 64 68 D7 D1 12 4C DF CF>

Native implementation

use Digest::SHA256::Native;

# If you want a string
say sha256-hex 'Rosetta code';

# If you want a binary Blob
say sha256 'Rosetta code';

Output:

764faf5c61ac315f1497f9dfa542713965b785e5cc2f707d6468d7d1124cdfcf
Blob:0x<76 4F AF 5C 61 AC 31 5F 14 97 F9 DF A5 42 71 39 65 B7 85 E5 CC 2F 70 7D 64 68 D7 D1 12 4C DF CF>

Last updated