diff --git a/src/HMAC.mo b/src/HMAC.mo index 1ae600a..8d443c8 100644 --- a/src/HMAC.mo +++ b/src/HMAC.mo @@ -21,6 +21,8 @@ module HMAC { public func size() : Nat { outer.size() }; + public func checkSum() : [Nat8] { [0] }; + public func sum(bs : [Nat8]) : [Nat8] { let l = bs.size(); let p = inner.sum(bs); diff --git a/src/Hash.mo b/src/Hash.mo index 1deac45..9e32885 100644 --- a/src/Hash.mo +++ b/src/Hash.mo @@ -6,6 +6,9 @@ module Hash { reset() : (); // Returns the number of bytes that sum will return. size() : Nat; + // Return the hash. + // TODO: Should probably rename this + checkSum() : [Nat8]; // Adds the current hash to the resulting slice. // The underlying hash is not modified. sum(bs : [Nat8]) : [Nat8]; diff --git a/src/SHA/Keccak.mo b/src/SHA/Keccak.mo new file mode 100644 index 0000000..e4a14ee --- /dev/null +++ b/src/SHA/Keccak.mo @@ -0,0 +1,242 @@ +import Array "mo:base-0.7.3/Array"; +import Nat "mo:base-0.7.3/Nat"; +import Nat8 "mo:base-0.7.3/Nat8"; +import Nat64 "mo:base-0.7.3/Nat64"; +import Int "mo:base-0.7.3/Int"; +import Iter "mo:base-0.7.3/Iter"; + +import Hash "../Hash"; + +import Hex "mo:encoding/Hex"; +import Debug "mo:base-0.7.3/Debug"; + +module { + + // Keccak constants + private let keccakf_rndc : [Nat64] = [ + 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, + 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, + 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, + 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, + 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, + 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, + 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, + 0x8000000000008080, 0x0000000080000001, 0x8000000080008008 + ]; + + // Keccak constants + private let keccakf_rotc : [Nat64] = [ + 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, + 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44 + ]; + + // Keccak constants + private let keccakf_piln : [Nat] = [ + 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, + 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1 + ]; + + public class Keccak( + initialState : [Nat64], // unused for now + hashSize : Nat, + delimitedSuffix: Nat8, + ) : Hash.Hash = { + // Keccak l-parameter selects "bus size". For SHA3, l = 6 and + // this is the only value supported at this time. + private let keccakf_l : Nat = 6; + + // Number of rounds + private let n_rounds: Nat = 12 + 2*keccakf_l; + + // Bus sizes in bits + private let bsize: Nat = 25 * 2**keccakf_l; + + // Capactiy in bits + private let cap: Nat = hashSize * 2; + + // Block size in bytes + assert(bsize > cap+8); + private let rsize: Nat = (bsize - cap)/8; + + // Internal state + private let state: [var Nat64] = Array.init(bsize/64, 0); + + // Current write state index + private var pt: Nat = 0; + + // blockSize in bytes + public func blockSize() : Nat { rsize; }; + + // Function to initialize + public func reset() : () { + for (i in Iter.range(0, state.size()-1)) { + state[i] := 0; + }; + pt := 0; + }; + + // Return size of hash in bits + public func size() : Nat { hashSize; }; + + // Turn array of Nat8s into Nat64, LSB first + private func pack64(data : [Nat8]) : Nat64 { + let dsize = data.size(); + assert(dsize <= 8 and dsize > 0); + + var q: Nat64 = 0; + // Avoid reverse() here to optimize? Maybe unroll? + for (i in Iter.range(0, dsize-1:Nat)) { + q |= Nat64.fromNat(Nat8.toNat(data[dsize-1:Nat-i])); + if (i < (dsize-1:Nat)) { + q <<= 8; + }; + }; + return q; + }; + + // Unpack Nat64 into array of Nat8s, LSB first + private func unpack64(q : Nat64) : [Nat8] { + var t = q; + let qbuf = Array.init(8, 0); + for (i in Iter.range(0, qbuf.size()-1)) { + qbuf[i] := Nat8.fromNat(Nat64.toNat(t & 0xff)); + t >>= 8; + }; + return Array.freeze(qbuf); + }; + + private func dump() { + Debug.print("State"); + for (i in Iter.range(0, state.size()-1)) { + let b = Array.reverse(unpack64(state[i])); + Debug.print(Hex.encode(b)); + }; + }; + + // Repeated from SHA2. Candidate for DRY principle refactor? + public func sum(bs : [Nat8]) : [Nat8] { + let cs = checkSum(); + let size = bs.size(); + Array.tabulate( + size + cs.size(), + func (x : Nat) { + if (x < size) return bs[x]; + cs[x - size]; + } + ); + }; + + // Function to finalize hashing + public func checkSum() : [Nat8] { + state[pt/8] ^= Nat64.fromNat(Nat8.toNat(delimitedSuffix)) << Nat64.fromNat((pt%8)*8); + state[(rsize-1:Nat)/8] ^= 0x80 : Nat64 << Nat64.fromNat(((rsize-1):Nat%8)*8); + + //dump(); + keccak_f(state); + + let md = Array.init(hashSize/8, 0); + + var i = 0; + label done for (q in state.vals()) { + for (b in unpack64(q).vals()) { + if (i >= md.size()) { + break done; + }; + md[i] := b; + i += 1; + }; + }; + return Array.freeze(md); + }; + + // Function to update internal state with content + // TODO: should data be a blob? Sticking with Array from Hash type + public func write(data : [Nat8]) : () { + if (data.size() == 0) { + return; + }; + + // Creating qbuf to apply against the entire Nat64 to + // avoid repacking because we don't have unions in + // Motoko. First time might require leading zeros, so it's + // initialized to zero + let qbuf = Array.init(8, 0); + let dlast = data.size()-1:Nat; + + for (i in Iter.range(0, dlast)) { + qbuf[pt % 8] := data[i]; + + // Set zeros at the end of our quad-word before submitting + if (i >= dlast and (pt+1) % 8 != 0) { + for (j in Iter.range((pt+1) % 8, 7)) { + qbuf[j] := 0; + }; + }; + + // Finished 8 bytes (64-bits) chunk to apply to state + if (i >= dlast or (pt+1) % 8 == 0) { + // Debug.print(Nat.toText(pt/8)); + // Debug.print(Hex.encode(Array.freeze(qbuf))); + // let b = Array.reverse(unpack64(state[pt/8])); + // Debug.print(Hex.encode(b)); + state[pt/8] ^= pack64(Array.freeze(qbuf)); + }; + pt += 1; + + if (pt >= rsize) { + keccak_f(state); + pt := 0; + }; + }; + //dump(); + + // Sanitize buffer for sensitive information + for (j in Iter.range(0, 7)) { + qbuf[j] := 0; + }; + }; + + // Main Keccak hashing function. See: + // https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf + func keccak_f(st : [var Nat64]) { + var t : Nat64 = 0; + let bc = Array.init(5, 0); + var j: Nat = 0; + + for (r in Iter.range(0, n_rounds - 1)) { + // Theta + for (i in Iter.range(0, 4)) { + bc[i] := st[i] ^ st[i + 5] ^ st[i + 10] ^ st[i + 15] ^ st[i + 20]; + }; + for (i in Iter.range(0, 4)) { + t := bc[(i + 4) % 5] ^ Nat64.bitrotLeft(bc[(i + 1) % 5], 1); + for (j in Iter.range(0, 4)) { + st[j*5 + i] ^= t; + }; + }; + + // Rho Pi + t := st[1]; + for (i in Iter.range(0, keccakf_piln.size()-1)) { + j := keccakf_piln[i]; + bc[0] := st[j]; + st[j] := Nat64.bitrotLeft(t, keccakf_rotc[i]); + t := bc[0]; + }; + + // Chi + for (j in Iter.range(0, 4)) { + for (i in Iter.range(0, 4)) { + bc[i] := st[j*5 + i]; + }; + for (i in Iter.range(0, 4)) { + st[j*5 + i] ^= (^bc[(i + 1) % 5]) & bc[(i + 2) % 5]; + }; + }; + + // Iota + st[0] ^= keccakf_rndc[r]; + }; + }; + }; +}; diff --git a/src/SHA/Keccak_256.mo b/src/SHA/Keccak_256.mo new file mode 100644 index 0000000..20fb69f --- /dev/null +++ b/src/SHA/Keccak_256.mo @@ -0,0 +1,16 @@ +import Keccak "Keccak"; + +import Hash "../Hash"; + +module Keccak_256 { + + public func New() : Hash.Hash { Keccak.Keccak([], 256, 0x01); }; + + /// Returns the Keccak-256 checksum of the data. + public func sum(bs : [Nat8]) : [Nat8] { + let h = New(); + h.write(bs); + h.checkSum(); + }; + +}; diff --git a/src/SHA/SHA3_224.mo b/src/SHA/SHA3_224.mo new file mode 100644 index 0000000..be4110c --- /dev/null +++ b/src/SHA/SHA3_224.mo @@ -0,0 +1,16 @@ +import Keccak "Keccak"; + +import Hash "../Hash"; + +module SHA3_224 { + + public func New() : Hash.Hash { Keccak.Keccak([], 224, 0x06); }; + + /// Returns the SHA3-224 checksum of the data. + public func sum(bs : [Nat8]) : [Nat8] { + let h = New(); + h.write(bs); + h.checkSum(); + }; + +}; diff --git a/src/SHA/SHA3_256.mo b/src/SHA/SHA3_256.mo new file mode 100644 index 0000000..7a06a7c --- /dev/null +++ b/src/SHA/SHA3_256.mo @@ -0,0 +1,16 @@ +import Keccak "Keccak"; + +import Hash "../Hash"; + +module SHA3_256 { + + public func New() : Hash.Hash { Keccak.Keccak([], 256, 0x06); }; + + /// Returns the SHA3-256 checksum of the data. + public func sum(bs : [Nat8]) : [Nat8] { + let h = New(); + h.write(bs); + h.checkSum(); + }; + +}; diff --git a/src/SHA/SHA3_384.mo b/src/SHA/SHA3_384.mo new file mode 100644 index 0000000..f0343d8 --- /dev/null +++ b/src/SHA/SHA3_384.mo @@ -0,0 +1,16 @@ +import Keccak "Keccak"; + +import Hash "../Hash"; + +module SHA3_384 { + + public func New() : Hash.Hash { Keccak.Keccak([], 384, 0x06); }; + + /// Returns the SHA3-384 checksum of the data. + public func sum(bs : [Nat8]) : [Nat8] { + let h = New(); + h.write(bs); + h.checkSum(); + }; + +}; diff --git a/src/SHA/SHA3_512.mo b/src/SHA/SHA3_512.mo new file mode 100644 index 0000000..04dfd33 --- /dev/null +++ b/src/SHA/SHA3_512.mo @@ -0,0 +1,16 @@ +import Keccak "Keccak"; + +import Hash "../Hash"; + +module SHA3_512 { + + public func New() : Hash.Hash { Keccak.Keccak([], 512, 0x06); }; + + /// Returns the SHA3-512 checksum of the data. + public func sum(bs : [Nat8]) : [Nat8] { + let h = New(); + h.write(bs); + h.checkSum(); + }; + +}; diff --git a/test/Keccak_256.mo b/test/Keccak_256.mo new file mode 100644 index 0000000..05c85f9 --- /dev/null +++ b/test/Keccak_256.mo @@ -0,0 +1,45 @@ +import Blob "mo:base-0.7.3/Blob"; +import Hex "mo:encoding/Hex"; +import Text "mo:base-0.7.3/Text"; + +import Debug "mo:base-0.7.3/Debug"; + +import Keccak_256 "../src/SHA/Keccak_256"; + +//Debug.print("Testing Keccak_256"); +let shasum = Keccak_256.sum(Blob.toArray(Text.encodeUtf8("hello world\n"))); +//Debug.print(Hex.encode(shasum)); +assert(Hex.encode(shasum) == "70e3788906c57c18999ba6b0389a768ff3333e3d6136fdf85743e66a03bc29f9"); + +//Debug.print("Testing Keccak_256 sum"); +let h = Keccak_256.New(); +h.write(Blob.toArray(Text.encodeUtf8("hello world\n"))); +assert(Hex.encode(shasum) == Hex.encode(h.sum([]))); + +//Debug.print("Testing Keccak_256 vectors"); +for (v in [ + ("", "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"), + ("a", "3ac225168df54212a25c1c01fd35bebfea408fdac2e31ddd6f80a4bbf9a5f1cb"), + ("ab", "67fad3bfa1e0321bd021ca805ce14876e50acac8ca8532eda8cbf924da565160"), + ("abc", "4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45"), + ("abcd", "48bed44d1bcd124a28c27f343a817e5f5243190d3c52bf347daf876de1dbbf77"), + ("abcde", "6377c7e66081cb65e473c1b95db5195a27d04a7108b468890224bedbe1a8a6eb"), + ("abcdef", "acd0c377fe36d5b209125185bc3ac41155ed1bf7103ef9f0c2aff4320460b6df"), + ("abcdefg", "a82aec019867b7307551dc397acde18b541e742fa1a4e53df4ce3b02d462f524"), + ("abcdefgh", "48624fa43c68d5c552855a4e2919e74645f683f5384f72b5b051b71ea41d4f2d"), + ("abcdefghi", "34fb2702da7001bf4dbf26a1e4cf31044bd95b85e1017596ee2d23aedc90498b"), + ("123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", "9f475334b0dafde0fdbe358fbe2b65b7129e0b52e242e2e1317479f9b590f581"), + ].vals()) { + let hv = Hex.encode(Keccak_256.sum(Blob.toArray(Text.encodeUtf8(v.0)))); + //Debug.print(hv); + assert(hv == v.1); +}; + +//Debug.print("Testing Keccak_256 write pieces"); +do { + let h = Keccak_256.New(); + h.write(Blob.toArray(Text.encodeUtf8("hello"))); + h.write(Blob.toArray(Text.encodeUtf8(" "))); + h.write(Blob.toArray(Text.encodeUtf8("world\n"))); + assert(Hex.encode(h.sum([])) == "70e3788906c57c18999ba6b0389a768ff3333e3d6136fdf85743e66a03bc29f9"); +}; diff --git a/test/SHA3_224.mo b/test/SHA3_224.mo new file mode 100644 index 0000000..434c76e --- /dev/null +++ b/test/SHA3_224.mo @@ -0,0 +1,45 @@ +import Blob "mo:base-0.7.3/Blob"; +import Hex "mo:encoding/Hex"; +import Text "mo:base-0.7.3/Text"; + +import Debug "mo:base-0.7.3/Debug"; + +import SHA3_224 "../src/SHA/SHA3_224"; + +//Debug.print("Testing SHA3_224"); +let shasum = SHA3_224.sum(Blob.toArray(Text.encodeUtf8("hello world\n"))); +//Debug.print(Hex.encode(shasum)); +assert(Hex.encode(shasum) == "7eda3e8d26f147821a258850956f9ed640fb0b3a8a04ae56a2f58a32"); + +//Debug.print("Testing SHA3_224 sum"); +let h = SHA3_224.New(); +h.write(Blob.toArray(Text.encodeUtf8("hello world\n"))); +assert(Hex.encode(shasum) == Hex.encode(h.sum([]))); + +//Debug.print("Testing SHA3_224 vectors"); +for (v in [ + ("", "6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7"), + ("a", "9e86ff69557ca95f405f081269685b38e3a819b309ee942f482b6a8b"), + ("ab", "09d27a15bcbab5da828d84dbd66062e5d37049f9b165a65dc581e853"), + ("abc", "e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf"), + ("abcd", "dd886b5fd8421fb3871d24e39e53967ce4fc80dd348bedbea0109c0e"), + ("abcde", "6acfaab70afd8439cea3616b41088bd81c939b272548f6409cf30e57"), + ("abcdef", "ceb3f4cd85af081120bf69ecf76bf61232bd5d810866f0eca3c8907d"), + ("abcdefg", "8a00ff4ec6b96377f1e69b2f72ed3c8da4bfe2f2f8357dc2aac13433"), + ("abcdefgh", "48bf2e8640cffe77b67c6182a6a47f8b5af73f60bd204ef348371d03"), + ("abcdefghi", "e7b4cd92a5ab3abc2c08841d0f6aa49f88f9f39be40b5a104dd0f114"), + ("123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", "4223016829bb302b45e0825d085bbcb579d0638462543f341dcb0ef7"), + ].vals()) { + let hv = Hex.encode(SHA3_224.sum(Blob.toArray(Text.encodeUtf8(v.0)))); + // Debug.print(hv); + assert(hv == v.1); +}; + +//Debug.print("Testing SHA3_224 write pieces"); +do { + let h = SHA3_224.New(); + h.write(Blob.toArray(Text.encodeUtf8("hello"))); + h.write(Blob.toArray(Text.encodeUtf8(" "))); + h.write(Blob.toArray(Text.encodeUtf8("world\n"))); + assert(Hex.encode(h.sum([])) == "7eda3e8d26f147821a258850956f9ed640fb0b3a8a04ae56a2f58a32"); +}; diff --git a/test/SHA3_256.mo b/test/SHA3_256.mo new file mode 100644 index 0000000..dc0b251 --- /dev/null +++ b/test/SHA3_256.mo @@ -0,0 +1,45 @@ +import Blob "mo:base-0.7.3/Blob"; +import Hex "mo:encoding/Hex"; +import Text "mo:base-0.7.3/Text"; + +import Debug "mo:base-0.7.3/Debug"; + +import SHA3_256 "../src/SHA/SHA3_256"; + +//Debug.print("Testing SHA3_256"); +let shasum = SHA3_256.sum(Blob.toArray(Text.encodeUtf8("hello world\n"))); +//Debug.print(Hex.encode(shasum)); +assert(Hex.encode(shasum) == "a8009a7a528d87778c356da3a55d964719e818666a04e4f960c9e2439e35f138"); + +//Debug.print("Testing SHA3_256 sum"); +let h = SHA3_256.New(); +h.write(Blob.toArray(Text.encodeUtf8("hello world\n"))); +assert(Hex.encode(shasum) == Hex.encode(h.sum([]))); + +//Debug.print("Testing SHA3_256 vectors"); +for (v in [ + ("", "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a"), + ("a", "80084bf2fba02475726feb2cab2d8215eab14bc6bdd8bfb2c8151257032ecd8b"), + ("ab", "5c828b33397f4762922e39a60c35699d2550466a52dd15ed44da37eb0bdc61e6"), + ("abc", "3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532"), + ("abcd", "6f6f129471590d2c91804c812b5750cd44cbdfb7238541c451e1ea2bc0193177"), + ("abcde", "d716ec61e18904a8f58679b71cb065d4d5db72e0e0c3f155a4feff7add0e58eb"), + ("abcdef", "59890c1d183aa279505750422e6384ccb1499c793872d6f31bb3bcaa4bc9f5a5"), + ("abcdefg", "7d55114476dfc6a2fbeaa10e221a8d0f32fc8f2efb69a6e878f4633366917a62"), + ("abcdefgh", "3e2020725a38a48eb3bbf75767f03a22c6b3f41f459c831309b06433ec649779"), + ("abcdefghi", "f74eb337992307c22bc59eb43e59583a683f3b93077e7f2472508e8c464d2657"), + ("123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", "4298644d87cdeed3d444d8514c7830ad12f4bc196d90652a6aa03c885494ae55"), + ].vals()) { + let hv = Hex.encode(SHA3_256.sum(Blob.toArray(Text.encodeUtf8(v.0)))); + // Debug.print(hv); + assert(hv == v.1); +}; + +//Debug.print("Testing SHA3_256 write pieces"); +do { + let h = SHA3_256.New(); + h.write(Blob.toArray(Text.encodeUtf8("hello"))); + h.write(Blob.toArray(Text.encodeUtf8(" "))); + h.write(Blob.toArray(Text.encodeUtf8("world\n"))); + assert(Hex.encode(h.sum([])) == "a8009a7a528d87778c356da3a55d964719e818666a04e4f960c9e2439e35f138"); +}; diff --git a/test/SHA3_384.mo b/test/SHA3_384.mo new file mode 100644 index 0000000..0dc8c15 --- /dev/null +++ b/test/SHA3_384.mo @@ -0,0 +1,45 @@ +import Blob "mo:base-0.7.3/Blob"; +import Hex "mo:encoding/Hex"; +import Text "mo:base-0.7.3/Text"; + +import Debug "mo:base-0.7.3/Debug"; + +import SHA3_384 "../src/SHA/SHA3_384"; + +//Debug.print("Testing SHA3_384"); +let shasum = SHA3_384.sum(Blob.toArray(Text.encodeUtf8("hello world\n"))); +//Debug.print(Hex.encode(shasum)); +assert(Hex.encode(shasum) == "28fc308d4d5c1ef9e60acedb13c3a1fcf7266560602c639000580ae3541dea5ce78a685de897e96b65a0fc15515c3780"); + +//Debug.print("Testing SHA3_384 sum"); +let h = SHA3_384.New(); +h.write(Blob.toArray(Text.encodeUtf8("hello world\n"))); +assert(Hex.encode(shasum) == Hex.encode(h.sum([]))); + +//Debug.print("Testing SHA3_384 vectors"); +for (v in [ + ("", "0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004"), + ("a", "1815f774f320491b48569efec794d249eeb59aae46d22bf77dafe25c5edc28d7ea44f93ee1234aa88f61c91912a4ccd9"), + ("ab", "dc30f83fefe3396fa0bd9709bcad28394386aa4e28ae881dc6617b361b16b969fb6a50a109068f13127b6deffbc82d4b"), + ("abc", "ec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b298d88cea927ac7f539f1edf228376d25"), + ("abcd", "5af1d89732d4d10cc6e92a36756f68ecfbf7ae4d14ed4523f68fc304cccfa5b0bba01c80d0d9b67f9163a5c211cfd65b"), + ("abcde", "348494236b82edda7602c78ba67fc3838e427c63c23e2c9d9aa5ea6354218a3c2ca564679acabf3ac6bf5378047691c4"), + ("abcdef", "d77460b0ce6109168480e279a81af32facb689ab96e22623f0122ff3a10ead263db6607f83876a843d3264dc2a863805"), + ("abcdefg", "49fbbd02884ae664e095edce429aa5b33d85886466de599eff29e1a0367eb16ff7e749d3966c0d4ade9903bd5867d051"), + ("abcdefgh", "f4d9fc5e9f44eb87fe968fc8e4e4691eb1dab6d821fb77550b527f71ccfb1ba043851bb054f281364c44d8541904db5a"), + ("abcdefghi", "36e2a92c181adfd48e897f8041e31bbf3a89fbcf50911e686343aa33c165553b5da8cc2d9b2acc943687e540388d4233"), + ("123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", "f817aec70c33ab0a9435bb6e6cde3682093e9916c21d04e45473f989be87405ee50f43170f816b714e41395eb695dd43"), + ].vals()) { + let hv = Hex.encode(SHA3_384.sum(Blob.toArray(Text.encodeUtf8(v.0)))); + // Debug.print(hv); + assert(hv == v.1); +}; + +//Debug.print("Testing SHA3_384 write pieces"); +do { + let h = SHA3_384.New(); + h.write(Blob.toArray(Text.encodeUtf8("hello"))); + h.write(Blob.toArray(Text.encodeUtf8(" "))); + h.write(Blob.toArray(Text.encodeUtf8("world\n"))); + assert(Hex.encode(h.sum([])) == "28fc308d4d5c1ef9e60acedb13c3a1fcf7266560602c639000580ae3541dea5ce78a685de897e96b65a0fc15515c3780"); +}; diff --git a/test/SHA3_512.mo b/test/SHA3_512.mo new file mode 100644 index 0000000..a3920ff --- /dev/null +++ b/test/SHA3_512.mo @@ -0,0 +1,46 @@ +import Blob "mo:base-0.7.3/Blob"; +import Hex "mo:encoding/Hex"; +import Text "mo:base-0.7.3/Text"; + +import Debug "mo:base-0.7.3/Debug"; + +import SHA3_512 "../src/SHA/SHA3_512"; + +//Debug.print("Testing SHA3_512"); +let shasum = SHA3_512.sum(Blob.toArray(Text.encodeUtf8("hello world\n"))); +//Debug.print(Hex.encode(shasum)); +assert(Hex.encode(shasum) == "4a936cbc1db296bd08d1c0bbf5a66a1897f35ee6d93047e0edff893dfbcba02f1e1570e85d1187ea26bea6d54199e0656f1b7c21b9cc2102b8ed2a12769f4531"); + +//Debug.print("Testing SHA3_512 sum"); +let h = SHA3_512.New(); +h.write(Blob.toArray(Text.encodeUtf8("hello world\n"))); +assert(Hex.encode(shasum) == Hex.encode(h.sum([]))); + +//Debug.print("Testing SHA3_512 vectors"); +for (v in [ + ("", "a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26"), + ("a", "697f2d856172cb8309d6b8b97dac4de344b549d4dee61edfb4962d8698b7fa803f4f93ff24393586e28b5b957ac3d1d369420ce53332712f997bd336d09ab02a"), + ("ab", "01c87b5e8f094d8725ed47be35430de40f6ab6bd7c6641a4ecf0d046c55cb468453796bb61724306a5fb3d90fbe3726a970e5630ae6a9cf9f30d2aa062a0175e"), + ("abc", "b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0"), + ("abcd", "6eb7b86765bf96a8467b72401231539cbb830f6c64120954c4567272f613f1364d6a80084234fa3400d306b9f5e10c341bbdc5894d9b484a8c7deea9cbe4e265"), + ("abcde", "1d7c3aa6ee17da5f4aeb78be968aa38476dbee54842e1ae2856f4c9a5cd04d45dc75c2902182b07c130ed582d476995b502b8777ccf69f60574471600386639b"), + ("abcdef", "01309a45c57cd7faef9ee6bb95fed29e5e2e0312af12a95fffeee340e5e5948b4652d26ae4b75976a53cc1612141af6e24df36517a61f46a1a05f59cf667046a"), + ("abcdefg", "9c93345c31ecffe20a95eca8db169f1b3ee312dd75fb3494cc1dc2f9a2b6092b6cbebf1299ec6d5ba46b08f728f3075109582bc71b97b4deac5122433732234c"), + ("abcdefgh", "c9f25eee75ab4cf9a8cfd44f4992b282079b64d94647edbd88e818e44f701edeb450818f7272cba7a20205b3671ce1991ce9a6d2df8dbad6e0bb3e50493d7fa7"), + ("abcdefghi", "4dbdf4a9fc84c246217a68d5a8f3d2a761766cf78752057d60b730a4a8226ef99bbf580c85468f5e93d8fb7873bbdb0de44314e3adf4b94a4fc37c64ca949c6e"), + ("123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", "42987b893dea6fc14fe56928ddbae6ccae1d3e8afc52e6b19bafe3a34ab35c84ed01cfa9fd18f6edf1c92f04f0666a99b6a067213cf2538ea05716bab570af99"), + ].vals()) { + let hv = Hex.encode(SHA3_512.sum(Blob.toArray(Text.encodeUtf8(v.0)))); + // Debug.print(hv); + assert(hv == v.1); +}; + +//Debug.print("Testing SHA3_512 write pieces"); +do { + let h = SHA3_512.New(); + h.write(Blob.toArray(Text.encodeUtf8("hello"))); + h.write(Blob.toArray(Text.encodeUtf8(" "))); + h.write(Blob.toArray(Text.encodeUtf8("world\n"))); + assert(Hex.encode(h.sum([])) == "4a936cbc1db296bd08d1c0bbf5a66a1897f35ee6d93047e0edff893dfbcba02f1e1570e85d1187ea26bea6d54199e0656f1b7c21b9cc2102b8ed2a12769f4531"); +}; +