SHA-256 Merkle tree: Difference between revisions

From Rosetta Code
Content added Content deleted
m (Thundergnat moved page SHA-256 Merkle Tree to SHA-256 Merkle tree: Follow normal task title capitalization policy)
(Added Go)
Line 5: Line 5:


Implement this algorithm in your language; you can use the code from the [[SHA-256]] task for the actual hash computations. For better manageability and portability, build the tree using a smaller block size of only 1024 bytes, and demonstrate it on [https://{{SERVERNAME}}/mw/title.png the RosettaCode title image] with that block size. The final result should be the hexadecimal digest value <tt style="font-weight:bold">a4f902cf9d51fe51eda156a6792e1445dff65edf3a217a1f3334cc9cf1495c2c</tt>.
Implement this algorithm in your language; you can use the code from the [[SHA-256]] task for the actual hash computations. For better manageability and portability, build the tree using a smaller block size of only 1024 bytes, and demonstrate it on [https://{{SERVERNAME}}/mw/title.png the RosettaCode title image] with that block size. The final result should be the hexadecimal digest value <tt style="font-weight:bold">a4f902cf9d51fe51eda156a6792e1445dff65edf3a217a1f3334cc9cf1495c2c</tt>.

=={{header|Go}}==
<lang go>package main

import (
"crypto/sha256"
"fmt"
"io"
"log"
"os"
)

func main() {
const bufferSize = 1024
f, err := os.Open("title.png")
if err != nil {
log.Fatal(err)
}
defer f.Close()

var hashes [][]byte
buffer := make([]byte, 1024)
h := sha256.New()
for {
bytesRead, err := f.Read(buffer)
if err != nil {
if err != io.EOF {
log.Fatal(err)
}
break
}
h.Reset()
h.Write(buffer[:bytesRead])
hashes = append(hashes, h.Sum(nil))
}
for len(hashes) > 1 {
var hashes2 [][]byte
for i := 0; i < len(hashes); i += 2 {
if i < len(hashes)-1 {
buffer := make([]byte, 64)
copy(buffer, hashes[i])
copy(buffer[32:], hashes[i+1])
h.Reset()
h.Write(buffer)
hashes2 = append(hashes2, h.Sum(nil))
} else {
hashes2 = append(hashes2, hashes[i])
}
}
hashes = hashes2
}
fmt.Printf("%x", hashes[0])
fmt.Println()
}</lang>

{{out}}
<pre>
a4f902cf9d51fe51eda156a6792e1445dff65edf3a217a1f3334cc9cf1495c2c
</pre>


=={{header|Raku}}==
=={{header|Raku}}==

Revision as of 18:55, 7 November 2020

Task
SHA-256 Merkle tree
You are encouraged to solve this task according to the task description, using any language you may know.

As described in its documentation, Amazon S3 Glacier requires that all uploaded files come with a checksum computed as a Merkle Tree using SHA-256.

Specifically, the SHA-256 hash is computed for each 1MiB block of the file. And then, starting from the beginning of the file, the raw hashes of consecutive blocks are paired up and concatenated together, and a new hash is computed from each concatenation. Then these are paired up and concatenated and hashed, and the process continues until there is only one hash left, which is the final checksum. The hexadecimal representation of this checksum is the value that must be included with the AWS API call to upload the object (or complete a multipart upload).

Implement this algorithm in your language; you can use the code from the SHA-256 task for the actual hash computations. For better manageability and portability, build the tree using a smaller block size of only 1024 bytes, and demonstrate it on the RosettaCode title image with that block size. The final result should be the hexadecimal digest value a4f902cf9d51fe51eda156a6792e1445dff65edf3a217a1f3334cc9cf1495c2c.

Go

<lang go>package main

import (

   "crypto/sha256"
   "fmt"
   "io"
   "log"
   "os"

)

func main() {

   const bufferSize = 1024
   f, err := os.Open("title.png")
   if err != nil {
       log.Fatal(err)
   }
   defer f.Close()
   var hashes [][]byte
   buffer := make([]byte, 1024)
   h := sha256.New()
   for {
       bytesRead, err := f.Read(buffer)
       if err != nil {
           if err != io.EOF {
               log.Fatal(err)
           }
           break
       }
       h.Reset()
       h.Write(buffer[:bytesRead])
       hashes = append(hashes, h.Sum(nil))
   }
   for len(hashes) > 1 {
       var hashes2 [][]byte
       for i := 0; i < len(hashes); i += 2 {
           if i < len(hashes)-1 {
               buffer := make([]byte, 64)
               copy(buffer, hashes[i])
               copy(buffer[32:], hashes[i+1])
               h.Reset()
               h.Write(buffer)
               hashes2 = append(hashes2, h.Sum(nil))
           } else {
               hashes2 = append(hashes2, hashes[i])
           }
       }
       hashes = hashes2
   }
   fmt.Printf("%x", hashes[0])
   fmt.Println()

}</lang>

Output:
a4f902cf9d51fe51eda156a6792e1445dff65edf3a217a1f3334cc9cf1495c2c

Raku

<lang Raku>#!/usr/bin/env raku

  1. compute the root label for a SHA256 Merkle tree built on blocks of a given
  2. size (default 1MB) taken from the given file(s)

use Digest::SHA256::Native;

sub MAIN(Int :b(:$block-size) = 1024 * 1024, *@args) {

 my ($block, @blocks);
 my $in = @args ?? IO::CatHandle.new(@args) !! $*IN;
 @blocks.push(sha256($block)) while $block = $in.read($block-size);
 while (@blocks > 1) {
   my @out;
   for @blocks.batch(2) -> @b {
     @out.push( @b > 1 ?? sha256(@b[0] ~ @b[1]) !! @b[0] );
   }
   @blocks = @out;
 }
 say @blocks[0]».fmt('%02x').join;

}</lang>

Output:
$ sha256tree --block-size=1024 title.png
a4f902cf9d51fe51eda156a6792e1445dff65edf3a217a1f3334cc9cf1495c2c