From 4c8e5da5dcd9b653f6c6723a6cfb40cdec17a703 Mon Sep 17 00:00:00 2001 From: Kento Sugama Date: Wed, 9 Aug 2023 18:30:32 -0400 Subject: [PATCH 01/12] copy paste in kyles code from examples repo --- src/Cryptography.mo | 526 ++++++++++++++++++++++++++++++++++++++++++++ src/Principal.mo | 40 ++++ 2 files changed, 566 insertions(+) create mode 100644 src/Cryptography.mo diff --git a/src/Cryptography.mo b/src/Cryptography.mo new file mode 100644 index 00000000..4c611df3 --- /dev/null +++ b/src/Cryptography.mo @@ -0,0 +1,526 @@ +import Blob "Blob"; +import Nat "Nat"; +import Nat8 "Nat8"; +import Nat32 "Nat32"; +import Nat64 "Nat64"; +import Array "Array"; +import Iter "Iter"; + +module { + public func crc32OfArray(arr : [Nat8]) : Nat32 { + crc32OfBlob(Blob.fromArray(arr)) + }; + + // Returns CRC-32 checksum of a byte array encoded as big-endian. + public func crc32OfBlob(blob : Blob) : Nat32 { + // See https://en.wikipedia.org/wiki/Cyclic_redundancy_check#CRC-32_algorithm + let seed : Nat32 = 0xffffffff; + let crc32Table : [Nat32] = [ + 0x00000000, + 0x77073096, + 0xee0e612c, + 0x990951ba, + 0x076dc419, + 0x706af48f, + 0xe963a535, + 0x9e6495a3, + 0x0edb8832, + 0x79dcb8a4, + 0xe0d5e91e, + 0x97d2d988, + 0x09b64c2b, + 0x7eb17cbd, + 0xe7b82d07, + 0x90bf1d91, + 0x1db71064, + 0x6ab020f2, + 0xf3b97148, + 0x84be41de, + 0x1adad47d, + 0x6ddde4eb, + 0xf4d4b551, + 0x83d385c7, + 0x136c9856, + 0x646ba8c0, + 0xfd62f97a, + 0x8a65c9ec, + 0x14015c4f, + 0x63066cd9, + 0xfa0f3d63, + 0x8d080df5, + 0x3b6e20c8, + 0x4c69105e, + 0xd56041e4, + 0xa2677172, + 0x3c03e4d1, + 0x4b04d447, + 0xd20d85fd, + 0xa50ab56b, + 0x35b5a8fa, + 0x42b2986c, + 0xdbbbc9d6, + 0xacbcf940, + 0x32d86ce3, + 0x45df5c75, + 0xdcd60dcf, + 0xabd13d59, + 0x26d930ac, + 0x51de003a, + 0xc8d75180, + 0xbfd06116, + 0x21b4f4b5, + 0x56b3c423, + 0xcfba9599, + 0xb8bda50f, + 0x2802b89e, + 0x5f058808, + 0xc60cd9b2, + 0xb10be924, + 0x2f6f7c87, + 0x58684c11, + 0xc1611dab, + 0xb6662d3d, + 0x76dc4190, + 0x01db7106, + 0x98d220bc, + 0xefd5102a, + 0x71b18589, + 0x06b6b51f, + 0x9fbfe4a5, + 0xe8b8d433, + 0x7807c9a2, + 0x0f00f934, + 0x9609a88e, + 0xe10e9818, + 0x7f6a0dbb, + 0x086d3d2d, + 0x91646c97, + 0xe6635c01, + 0x6b6b51f4, + 0x1c6c6162, + 0x856530d8, + 0xf262004e, + 0x6c0695ed, + 0x1b01a57b, + 0x8208f4c1, + 0xf50fc457, + 0x65b0d9c6, + 0x12b7e950, + 0x8bbeb8ea, + 0xfcb9887c, + 0x62dd1ddf, + 0x15da2d49, + 0x8cd37cf3, + 0xfbd44c65, + 0x4db26158, + 0x3ab551ce, + 0xa3bc0074, + 0xd4bb30e2, + 0x4adfa541, + 0x3dd895d7, + 0xa4d1c46d, + 0xd3d6f4fb, + 0x4369e96a, + 0x346ed9fc, + 0xad678846, + 0xda60b8d0, + 0x44042d73, + 0x33031de5, + 0xaa0a4c5f, + 0xdd0d7cc9, + 0x5005713c, + 0x270241aa, + 0xbe0b1010, + 0xc90c2086, + 0x5768b525, + 0x206f85b3, + 0xb966d409, + 0xce61e49f, + 0x5edef90e, + 0x29d9c998, + 0xb0d09822, + 0xc7d7a8b4, + 0x59b33d17, + 0x2eb40d81, + 0xb7bd5c3b, + 0xc0ba6cad, + 0xedb88320, + 0x9abfb3b6, + 0x03b6e20c, + 0x74b1d29a, + 0xead54739, + 0x9dd277af, + 0x04db2615, + 0x73dc1683, + 0xe3630b12, + 0x94643b84, + 0x0d6d6a3e, + 0x7a6a5aa8, + 0xe40ecf0b, + 0x9309ff9d, + 0x0a00ae27, + 0x7d079eb1, + 0xf00f9344, + 0x8708a3d2, + 0x1e01f268, + 0x6906c2fe, + 0xf762575d, + 0x806567cb, + 0x196c3671, + 0x6e6b06e7, + 0xfed41b76, + 0x89d32be0, + 0x10da7a5a, + 0x67dd4acc, + 0xf9b9df6f, + 0x8ebeeff9, + 0x17b7be43, + 0x60b08ed5, + 0xd6d6a3e8, + 0xa1d1937e, + 0x38d8c2c4, + 0x4fdff252, + 0xd1bb67f1, + 0xa6bc5767, + 0x3fb506dd, + 0x48b2364b, + 0xd80d2bda, + 0xaf0a1b4c, + 0x36034af6, + 0x41047a60, + 0xdf60efc3, + 0xa867df55, + 0x316e8eef, + 0x4669be79, + 0xcb61b38c, + 0xbc66831a, + 0x256fd2a0, + 0x5268e236, + 0xcc0c7795, + 0xbb0b4703, + 0x220216b9, + 0x5505262f, + 0xc5ba3bbe, + 0xb2bd0b28, + 0x2bb45a92, + 0x5cb36a04, + 0xc2d7ffa7, + 0xb5d0cf31, + 0x2cd99e8b, + 0x5bdeae1d, + 0x9b64c2b0, + 0xec63f226, + 0x756aa39c, + 0x026d930a, + 0x9c0906a9, + 0xeb0e363f, + 0x72076785, + 0x05005713, + 0x95bf4a82, + 0xe2b87a14, + 0x7bb12bae, + 0x0cb61b38, + 0x92d28e9b, + 0xe5d5be0d, + 0x7cdcefb7, + 0x0bdbdf21, + 0x86d3d2d4, + 0xf1d4e242, + 0x68ddb3f8, + 0x1fda836e, + 0x81be16cd, + 0xf6b9265b, + 0x6fb077e1, + 0x18b74777, + 0x88085ae6, + 0xff0f6a70, + 0x66063bca, + 0x11010b5c, + 0x8f659eff, + 0xf862ae69, + 0x616bffd3, + 0x166ccf45, + 0xa00ae278, + 0xd70dd2ee, + 0x4e048354, + 0x3903b3c2, + 0xa7672661, + 0xd06016f7, + 0x4969474d, + 0x3e6e77db, + 0xaed16a4a, + 0xd9d65adc, + 0x40df0b66, + 0x37d83bf0, + 0xa9bcae53, + 0xdebb9ec5, + 0x47b2cf7f, + 0x30b5ffe9, + 0xbdbdf21c, + 0xcabac28a, + 0x53b39330, + 0x24b4a3a6, + 0xbad03605, + 0xcdd70693, + 0x54de5729, + 0x23d967bf, + 0xb3667a2e, + 0xc4614ab8, + 0x5d681b02, + 0x2a6f2b94, + 0xb40bbe37, + 0xc30c8ea1, + 0x5a05df1b, + 0x2d02ef8d + ]; + var crc = seed; + for (b in blob.vals()) { + crc := crc32Table[Nat32.toNat(crc ^ Nat32.fromNat(Nat8.toNat(b)) & 0xff)] ^ (crc >> 8) + }; + crc ^ seed + }; + + ////////////////////// SHA224 ////// + private let K : [Nat32] = [ + 0x428a2f98, + 0x71374491, + 0xb5c0fbcf, + 0xe9b5dba5, + 0x3956c25b, + 0x59f111f1, + 0x923f82a4, + 0xab1c5ed5, + 0xd807aa98, + 0x12835b01, + 0x243185be, + 0x550c7dc3, + 0x72be5d74, + 0x80deb1fe, + 0x9bdc06a7, + 0xc19bf174, + 0xe49b69c1, + 0xefbe4786, + 0x0fc19dc6, + 0x240ca1cc, + 0x2de92c6f, + 0x4a7484aa, + 0x5cb0a9dc, + 0x76f988da, + 0x983e5152, + 0xa831c66d, + 0xb00327c8, + 0xbf597fc7, + 0xc6e00bf3, + 0xd5a79147, + 0x06ca6351, + 0x14292967, + 0x27b70a85, + 0x2e1b2138, + 0x4d2c6dfc, + 0x53380d13, + 0x650a7354, + 0x766a0abb, + 0x81c2c92e, + 0x92722c85, + 0xa2bfe8a1, + 0xa81a664b, + 0xc24b8b70, + 0xc76c51a3, + 0xd192e819, + 0xd6990624, + 0xf40e3585, + 0x106aa070, + 0x19a4c116, + 0x1e376c08, + 0x2748774c, + 0x34b0bcb5, + 0x391c0cb3, + 0x4ed8aa4a, + 0x5b9cca4f, + 0x682e6ff3, + 0x748f82ee, + 0x78a5636f, + 0x84c87814, + 0x8cc70208, + 0x90befffa, + 0xa4506ceb, + 0xbef9a3f7, + 0xc67178f2 + ]; + + private let S : [Nat32] = [ + 0xc1059ed8, + 0x367cd507, + 0x3070dd17, + 0xf70e5939, + 0xffc00b31, + 0x68581511, + 0x64f98fa7, + 0xbefa4fa4 + ]; + + // Calculate a SHA224 hash. + public func sha224(data : [Nat8]) : [Nat8] { + let digest = SHA224(); + digest.write(data); + return digest.sum() + }; + + public class SHA224() { + + private let s = Array.thaw(S); + + private let x = Array.init(64, 0); + + private var nx = 0; + + private var len : Nat64 = 0; + + public func reset() { + for (i in Iter.range(0, 7)) { + s[i] := S[i] + }; + nx := 0; + len := 0 + }; + + public func write(data : [Nat8]) { + var p = data; + len +%= Nat64.fromIntWrap(p.size()); + if (nx > 0) { + let n = Nat.min(p.size(), 64 - nx); + for (i in Iter.range(0, n - 1)) { + x[nx + i] := p[i] + }; + nx += n; + if (nx == 64) { + let buf = Array.freeze(x); + block(buf); + nx := 0 + }; + p := Array.tabulate( + p.size() - n, + func(i) { + return p[n + i] + } + ) + }; + if (p.size() >= 64) { + let n = Nat64.toNat(Nat64.fromIntWrap(p.size()) & (^ 63)); + let buf = Array.tabulate( + n, + func(i) { + return p[i] + } + ); + block(buf); + p := Array.tabulate( + p.size() - n, + func(i) { + return p[n + i] + } + ) + }; + if (p.size() > 0) { + for (i in Iter.range(0, p.size() - 1)) { + x[i] := p[i] + }; + nx := p.size() + } + }; + + public func sum() : [Nat8] { + var m = 0; + var n = len; + var t = Nat64.toNat(n) % 64; + var buf : [var Nat8] = [var]; + if (56 > t) { + m := 56 - t + } else { + m := 120 - t + }; + n := n << 3; + buf := Array.init(m, 0); + if (m > 0) { + buf[0] := 0x80 + }; + write(Array.freeze(buf)); + buf := Array.init(8, 0); + for (i in Iter.range(0, 7)) { + let j : Nat64 = 56 -% 8 *% Nat64.fromIntWrap(i); + buf[i] := Nat8.fromIntWrap(Nat64.toNat(n >> j)) + }; + write(Array.freeze(buf)); + let hash = Array.init(28, 0); + for (i in Iter.range(0, 6)) { + for (j in Iter.range(0, 3)) { + let k : Nat32 = 24 -% 8 *% Nat32.fromIntWrap(j); + hash[4 * i + j] := Nat8.fromIntWrap(Nat32.toNat(s[i] >> k)) + } + }; + return Array.freeze(hash) + }; + + private func block(data : [Nat8]) { + var p = data; + var w = Array.init(64, 0); + while (p.size() >= 64) { + var j = 0; + for (i in Iter.range(0, 15)) { + j := i * 4; + w[i] := Nat32.fromIntWrap(Nat8.toNat(p[j + 0])) << 24 | Nat32.fromIntWrap(Nat8.toNat(p[j + 1])) << 16 | Nat32.fromIntWrap(Nat8.toNat(p[j + 2])) << 08 | Nat32.fromIntWrap(Nat8.toNat(p[j + 3])) << 00 + }; + var v1 : Nat32 = 0; + var v2 : Nat32 = 0; + var t1 : Nat32 = 0; + var t2 : Nat32 = 0; + for (i in Iter.range(16, 63)) { + v1 := w[i - 02]; + v2 := w[i - 15]; + t1 := rot(v1, 17) ^ rot(v1, 19) ^ (v1 >> 10); + t2 := rot(v2, 07) ^ rot(v2, 18) ^ (v2 >> 03); + w[i] := t1 +% w[i - 07] +% t2 +% w[i - 16] + }; + var a = s[0]; + var b = s[1]; + var c = s[2]; + var d = s[3]; + var e = s[4]; + var f = s[5]; + var g = s[6]; + var h = s[7]; + for (i in Iter.range(0, 63)) { + t1 := rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + t1 +%= (e & f) ^ (^ e & g) +% h +% K[i] +% w[i]; + t2 := rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t2 +%= (a & b) ^ (a & c) ^ (b & c); + h := g; + g := f; + f := e; + e := d +% t1; + d := c; + c := b; + b := a; + a := t1 +% t2 + }; + s[0] +%= a; + s[1] +%= b; + s[2] +%= c; + s[3] +%= d; + s[4] +%= e; + s[5] +%= f; + s[6] +%= g; + s[7] +%= h; + p := Array.tabulate( + p.size() - 64, + func(i) { + return p[i + 64] + } + ) + } + } + }; + + private let rot : (Nat32, Nat32) -> Nat32 = Nat32.bitrotRight; + +} diff --git a/src/Principal.mo b/src/Principal.mo index d157df47..1927eba3 100644 --- a/src/Principal.mo +++ b/src/Principal.mo @@ -27,6 +27,12 @@ import Prim "mo:⛔"; import Blob "Blob"; import Hash "Hash"; +import Cryptography "Cryptography"; +import Array "Array"; +import Nat8 "Nat8"; +import Nat32 "Nat32"; +import Text "Text"; + module { public type Principal = Prim.Types.Principal; @@ -43,6 +49,40 @@ module { /// ``` public func fromActor(a : actor {}) : Principal = Prim.principalOfActor a; + /// Compute the account identifier of a principal. Optionally specify a sub-account. + /// + /// Example: + /// ```motoko include=import + /// let principal = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); + /// let account = Principal.toAccount(principal, null); // => \00\00\00\00\00\30\00\D3\01\01 FIXME check ChatGPT's math + /// ``` + public func toAccount(principal : Principal, subAccount : ?Blob) : Blob { + func beBytes(n : Nat32) : [Nat8] { + func byte(n : Nat32) : Nat8 { + Nat8.fromNat(Nat32.toNat(n & 0xff)) + }; + [byte(n >> 24), byte(n >> 16), byte(n >> 8), byte(n)] + }; + + let sha224 = Cryptography.SHA224(); + sha224.write([0x0A]); + sha224.write(Blob.toArray(Text.encodeUtf8("account-id"))); + sha224.write(Blob.toArray(toBlob(principal))); + switch subAccount { + case (?subAccount) { + sha224.write(Blob.toArray(subAccount)) + }; + case (null) { + let defaultSubAccount = Array.tabulate(32, func _ = 0); + sha224.write(defaultSubAccount) + } + }; + + let hashSum = sha224.sum(); + let crc32Bytes = beBytes(Cryptography.crc32OfArray(hashSum)); + Blob.fromArray(Array.append(crc32Bytes, hashSum)) + }; + /// Convert a `Principal` to its `Blob` (bytes) representation. /// /// Example: From ec36e97eadaeeb0a6d162d52d7a3bc07f0d2b5ee Mon Sep 17 00:00:00 2001 From: Kento Sugama Date: Fri, 1 Sep 2023 15:48:28 -0400 Subject: [PATCH 02/12] Replace sha224 with timos version and use crc32 from RTS --- src/Cryptography.mo | 526 ------------------------- src/Principal.mo | 938 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 929 insertions(+), 535 deletions(-) delete mode 100644 src/Cryptography.mo diff --git a/src/Cryptography.mo b/src/Cryptography.mo deleted file mode 100644 index 4c611df3..00000000 --- a/src/Cryptography.mo +++ /dev/null @@ -1,526 +0,0 @@ -import Blob "Blob"; -import Nat "Nat"; -import Nat8 "Nat8"; -import Nat32 "Nat32"; -import Nat64 "Nat64"; -import Array "Array"; -import Iter "Iter"; - -module { - public func crc32OfArray(arr : [Nat8]) : Nat32 { - crc32OfBlob(Blob.fromArray(arr)) - }; - - // Returns CRC-32 checksum of a byte array encoded as big-endian. - public func crc32OfBlob(blob : Blob) : Nat32 { - // See https://en.wikipedia.org/wiki/Cyclic_redundancy_check#CRC-32_algorithm - let seed : Nat32 = 0xffffffff; - let crc32Table : [Nat32] = [ - 0x00000000, - 0x77073096, - 0xee0e612c, - 0x990951ba, - 0x076dc419, - 0x706af48f, - 0xe963a535, - 0x9e6495a3, - 0x0edb8832, - 0x79dcb8a4, - 0xe0d5e91e, - 0x97d2d988, - 0x09b64c2b, - 0x7eb17cbd, - 0xe7b82d07, - 0x90bf1d91, - 0x1db71064, - 0x6ab020f2, - 0xf3b97148, - 0x84be41de, - 0x1adad47d, - 0x6ddde4eb, - 0xf4d4b551, - 0x83d385c7, - 0x136c9856, - 0x646ba8c0, - 0xfd62f97a, - 0x8a65c9ec, - 0x14015c4f, - 0x63066cd9, - 0xfa0f3d63, - 0x8d080df5, - 0x3b6e20c8, - 0x4c69105e, - 0xd56041e4, - 0xa2677172, - 0x3c03e4d1, - 0x4b04d447, - 0xd20d85fd, - 0xa50ab56b, - 0x35b5a8fa, - 0x42b2986c, - 0xdbbbc9d6, - 0xacbcf940, - 0x32d86ce3, - 0x45df5c75, - 0xdcd60dcf, - 0xabd13d59, - 0x26d930ac, - 0x51de003a, - 0xc8d75180, - 0xbfd06116, - 0x21b4f4b5, - 0x56b3c423, - 0xcfba9599, - 0xb8bda50f, - 0x2802b89e, - 0x5f058808, - 0xc60cd9b2, - 0xb10be924, - 0x2f6f7c87, - 0x58684c11, - 0xc1611dab, - 0xb6662d3d, - 0x76dc4190, - 0x01db7106, - 0x98d220bc, - 0xefd5102a, - 0x71b18589, - 0x06b6b51f, - 0x9fbfe4a5, - 0xe8b8d433, - 0x7807c9a2, - 0x0f00f934, - 0x9609a88e, - 0xe10e9818, - 0x7f6a0dbb, - 0x086d3d2d, - 0x91646c97, - 0xe6635c01, - 0x6b6b51f4, - 0x1c6c6162, - 0x856530d8, - 0xf262004e, - 0x6c0695ed, - 0x1b01a57b, - 0x8208f4c1, - 0xf50fc457, - 0x65b0d9c6, - 0x12b7e950, - 0x8bbeb8ea, - 0xfcb9887c, - 0x62dd1ddf, - 0x15da2d49, - 0x8cd37cf3, - 0xfbd44c65, - 0x4db26158, - 0x3ab551ce, - 0xa3bc0074, - 0xd4bb30e2, - 0x4adfa541, - 0x3dd895d7, - 0xa4d1c46d, - 0xd3d6f4fb, - 0x4369e96a, - 0x346ed9fc, - 0xad678846, - 0xda60b8d0, - 0x44042d73, - 0x33031de5, - 0xaa0a4c5f, - 0xdd0d7cc9, - 0x5005713c, - 0x270241aa, - 0xbe0b1010, - 0xc90c2086, - 0x5768b525, - 0x206f85b3, - 0xb966d409, - 0xce61e49f, - 0x5edef90e, - 0x29d9c998, - 0xb0d09822, - 0xc7d7a8b4, - 0x59b33d17, - 0x2eb40d81, - 0xb7bd5c3b, - 0xc0ba6cad, - 0xedb88320, - 0x9abfb3b6, - 0x03b6e20c, - 0x74b1d29a, - 0xead54739, - 0x9dd277af, - 0x04db2615, - 0x73dc1683, - 0xe3630b12, - 0x94643b84, - 0x0d6d6a3e, - 0x7a6a5aa8, - 0xe40ecf0b, - 0x9309ff9d, - 0x0a00ae27, - 0x7d079eb1, - 0xf00f9344, - 0x8708a3d2, - 0x1e01f268, - 0x6906c2fe, - 0xf762575d, - 0x806567cb, - 0x196c3671, - 0x6e6b06e7, - 0xfed41b76, - 0x89d32be0, - 0x10da7a5a, - 0x67dd4acc, - 0xf9b9df6f, - 0x8ebeeff9, - 0x17b7be43, - 0x60b08ed5, - 0xd6d6a3e8, - 0xa1d1937e, - 0x38d8c2c4, - 0x4fdff252, - 0xd1bb67f1, - 0xa6bc5767, - 0x3fb506dd, - 0x48b2364b, - 0xd80d2bda, - 0xaf0a1b4c, - 0x36034af6, - 0x41047a60, - 0xdf60efc3, - 0xa867df55, - 0x316e8eef, - 0x4669be79, - 0xcb61b38c, - 0xbc66831a, - 0x256fd2a0, - 0x5268e236, - 0xcc0c7795, - 0xbb0b4703, - 0x220216b9, - 0x5505262f, - 0xc5ba3bbe, - 0xb2bd0b28, - 0x2bb45a92, - 0x5cb36a04, - 0xc2d7ffa7, - 0xb5d0cf31, - 0x2cd99e8b, - 0x5bdeae1d, - 0x9b64c2b0, - 0xec63f226, - 0x756aa39c, - 0x026d930a, - 0x9c0906a9, - 0xeb0e363f, - 0x72076785, - 0x05005713, - 0x95bf4a82, - 0xe2b87a14, - 0x7bb12bae, - 0x0cb61b38, - 0x92d28e9b, - 0xe5d5be0d, - 0x7cdcefb7, - 0x0bdbdf21, - 0x86d3d2d4, - 0xf1d4e242, - 0x68ddb3f8, - 0x1fda836e, - 0x81be16cd, - 0xf6b9265b, - 0x6fb077e1, - 0x18b74777, - 0x88085ae6, - 0xff0f6a70, - 0x66063bca, - 0x11010b5c, - 0x8f659eff, - 0xf862ae69, - 0x616bffd3, - 0x166ccf45, - 0xa00ae278, - 0xd70dd2ee, - 0x4e048354, - 0x3903b3c2, - 0xa7672661, - 0xd06016f7, - 0x4969474d, - 0x3e6e77db, - 0xaed16a4a, - 0xd9d65adc, - 0x40df0b66, - 0x37d83bf0, - 0xa9bcae53, - 0xdebb9ec5, - 0x47b2cf7f, - 0x30b5ffe9, - 0xbdbdf21c, - 0xcabac28a, - 0x53b39330, - 0x24b4a3a6, - 0xbad03605, - 0xcdd70693, - 0x54de5729, - 0x23d967bf, - 0xb3667a2e, - 0xc4614ab8, - 0x5d681b02, - 0x2a6f2b94, - 0xb40bbe37, - 0xc30c8ea1, - 0x5a05df1b, - 0x2d02ef8d - ]; - var crc = seed; - for (b in blob.vals()) { - crc := crc32Table[Nat32.toNat(crc ^ Nat32.fromNat(Nat8.toNat(b)) & 0xff)] ^ (crc >> 8) - }; - crc ^ seed - }; - - ////////////////////// SHA224 ////// - private let K : [Nat32] = [ - 0x428a2f98, - 0x71374491, - 0xb5c0fbcf, - 0xe9b5dba5, - 0x3956c25b, - 0x59f111f1, - 0x923f82a4, - 0xab1c5ed5, - 0xd807aa98, - 0x12835b01, - 0x243185be, - 0x550c7dc3, - 0x72be5d74, - 0x80deb1fe, - 0x9bdc06a7, - 0xc19bf174, - 0xe49b69c1, - 0xefbe4786, - 0x0fc19dc6, - 0x240ca1cc, - 0x2de92c6f, - 0x4a7484aa, - 0x5cb0a9dc, - 0x76f988da, - 0x983e5152, - 0xa831c66d, - 0xb00327c8, - 0xbf597fc7, - 0xc6e00bf3, - 0xd5a79147, - 0x06ca6351, - 0x14292967, - 0x27b70a85, - 0x2e1b2138, - 0x4d2c6dfc, - 0x53380d13, - 0x650a7354, - 0x766a0abb, - 0x81c2c92e, - 0x92722c85, - 0xa2bfe8a1, - 0xa81a664b, - 0xc24b8b70, - 0xc76c51a3, - 0xd192e819, - 0xd6990624, - 0xf40e3585, - 0x106aa070, - 0x19a4c116, - 0x1e376c08, - 0x2748774c, - 0x34b0bcb5, - 0x391c0cb3, - 0x4ed8aa4a, - 0x5b9cca4f, - 0x682e6ff3, - 0x748f82ee, - 0x78a5636f, - 0x84c87814, - 0x8cc70208, - 0x90befffa, - 0xa4506ceb, - 0xbef9a3f7, - 0xc67178f2 - ]; - - private let S : [Nat32] = [ - 0xc1059ed8, - 0x367cd507, - 0x3070dd17, - 0xf70e5939, - 0xffc00b31, - 0x68581511, - 0x64f98fa7, - 0xbefa4fa4 - ]; - - // Calculate a SHA224 hash. - public func sha224(data : [Nat8]) : [Nat8] { - let digest = SHA224(); - digest.write(data); - return digest.sum() - }; - - public class SHA224() { - - private let s = Array.thaw(S); - - private let x = Array.init(64, 0); - - private var nx = 0; - - private var len : Nat64 = 0; - - public func reset() { - for (i in Iter.range(0, 7)) { - s[i] := S[i] - }; - nx := 0; - len := 0 - }; - - public func write(data : [Nat8]) { - var p = data; - len +%= Nat64.fromIntWrap(p.size()); - if (nx > 0) { - let n = Nat.min(p.size(), 64 - nx); - for (i in Iter.range(0, n - 1)) { - x[nx + i] := p[i] - }; - nx += n; - if (nx == 64) { - let buf = Array.freeze(x); - block(buf); - nx := 0 - }; - p := Array.tabulate( - p.size() - n, - func(i) { - return p[n + i] - } - ) - }; - if (p.size() >= 64) { - let n = Nat64.toNat(Nat64.fromIntWrap(p.size()) & (^ 63)); - let buf = Array.tabulate( - n, - func(i) { - return p[i] - } - ); - block(buf); - p := Array.tabulate( - p.size() - n, - func(i) { - return p[n + i] - } - ) - }; - if (p.size() > 0) { - for (i in Iter.range(0, p.size() - 1)) { - x[i] := p[i] - }; - nx := p.size() - } - }; - - public func sum() : [Nat8] { - var m = 0; - var n = len; - var t = Nat64.toNat(n) % 64; - var buf : [var Nat8] = [var]; - if (56 > t) { - m := 56 - t - } else { - m := 120 - t - }; - n := n << 3; - buf := Array.init(m, 0); - if (m > 0) { - buf[0] := 0x80 - }; - write(Array.freeze(buf)); - buf := Array.init(8, 0); - for (i in Iter.range(0, 7)) { - let j : Nat64 = 56 -% 8 *% Nat64.fromIntWrap(i); - buf[i] := Nat8.fromIntWrap(Nat64.toNat(n >> j)) - }; - write(Array.freeze(buf)); - let hash = Array.init(28, 0); - for (i in Iter.range(0, 6)) { - for (j in Iter.range(0, 3)) { - let k : Nat32 = 24 -% 8 *% Nat32.fromIntWrap(j); - hash[4 * i + j] := Nat8.fromIntWrap(Nat32.toNat(s[i] >> k)) - } - }; - return Array.freeze(hash) - }; - - private func block(data : [Nat8]) { - var p = data; - var w = Array.init(64, 0); - while (p.size() >= 64) { - var j = 0; - for (i in Iter.range(0, 15)) { - j := i * 4; - w[i] := Nat32.fromIntWrap(Nat8.toNat(p[j + 0])) << 24 | Nat32.fromIntWrap(Nat8.toNat(p[j + 1])) << 16 | Nat32.fromIntWrap(Nat8.toNat(p[j + 2])) << 08 | Nat32.fromIntWrap(Nat8.toNat(p[j + 3])) << 00 - }; - var v1 : Nat32 = 0; - var v2 : Nat32 = 0; - var t1 : Nat32 = 0; - var t2 : Nat32 = 0; - for (i in Iter.range(16, 63)) { - v1 := w[i - 02]; - v2 := w[i - 15]; - t1 := rot(v1, 17) ^ rot(v1, 19) ^ (v1 >> 10); - t2 := rot(v2, 07) ^ rot(v2, 18) ^ (v2 >> 03); - w[i] := t1 +% w[i - 07] +% t2 +% w[i - 16] - }; - var a = s[0]; - var b = s[1]; - var c = s[2]; - var d = s[3]; - var e = s[4]; - var f = s[5]; - var g = s[6]; - var h = s[7]; - for (i in Iter.range(0, 63)) { - t1 := rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); - t1 +%= (e & f) ^ (^ e & g) +% h +% K[i] +% w[i]; - t2 := rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); - t2 +%= (a & b) ^ (a & c) ^ (b & c); - h := g; - g := f; - f := e; - e := d +% t1; - d := c; - c := b; - b := a; - a := t1 +% t2 - }; - s[0] +%= a; - s[1] +%= b; - s[2] +%= c; - s[3] +%= d; - s[4] +%= e; - s[5] +%= f; - s[6] +%= g; - s[7] +%= h; - p := Array.tabulate( - p.size() - 64, - func(i) { - return p[i + 64] - } - ) - } - } - }; - - private let rot : (Nat32, Nat32) -> Nat32 = Nat32.bitrotRight; - -} diff --git a/src/Principal.mo b/src/Principal.mo index 1927eba3..c6f57c9e 100644 --- a/src/Principal.mo +++ b/src/Principal.mo @@ -27,10 +27,10 @@ import Prim "mo:⛔"; import Blob "Blob"; import Hash "Hash"; -import Cryptography "Cryptography"; import Array "Array"; import Nat8 "Nat8"; import Nat32 "Nat32"; +import Nat64 "Nat64"; import Text "Text"; module { @@ -49,6 +49,923 @@ module { /// ``` public func fromActor(a : actor {}) : Principal = Prim.principalOfActor a; + //// PRIVATE SHA 224 UTILITIES //// + //// Taken from https://github.com/research-ag/sha2 //// + let K00 : Nat32 = 0x428a2f98; + let K01 : Nat32 = 0x71374491; + let K02 : Nat32 = 0xb5c0fbcf; + let K03 : Nat32 = 0xe9b5dba5; + let K04 : Nat32 = 0x3956c25b; + let K05 : Nat32 = 0x59f111f1; + let K06 : Nat32 = 0x923f82a4; + let K07 : Nat32 = 0xab1c5ed5; + let K08 : Nat32 = 0xd807aa98; + let K09 : Nat32 = 0x12835b01; + let K10 : Nat32 = 0x243185be; + let K11 : Nat32 = 0x550c7dc3; + let K12 : Nat32 = 0x72be5d74; + let K13 : Nat32 = 0x80deb1fe; + let K14 : Nat32 = 0x9bdc06a7; + let K15 : Nat32 = 0xc19bf174; + let K16 : Nat32 = 0xe49b69c1; + let K17 : Nat32 = 0xefbe4786; + let K18 : Nat32 = 0x0fc19dc6; + let K19 : Nat32 = 0x240ca1cc; + let K20 : Nat32 = 0x2de92c6f; + let K21 : Nat32 = 0x4a7484aa; + let K22 : Nat32 = 0x5cb0a9dc; + let K23 : Nat32 = 0x76f988da; + let K24 : Nat32 = 0x983e5152; + let K25 : Nat32 = 0xa831c66d; + let K26 : Nat32 = 0xb00327c8; + let K27 : Nat32 = 0xbf597fc7; + let K28 : Nat32 = 0xc6e00bf3; + let K29 : Nat32 = 0xd5a79147; + let K30 : Nat32 = 0x06ca6351; + let K31 : Nat32 = 0x14292967; + let K32 : Nat32 = 0x27b70a85; + let K33 : Nat32 = 0x2e1b2138; + let K34 : Nat32 = 0x4d2c6dfc; + let K35 : Nat32 = 0x53380d13; + let K36 : Nat32 = 0x650a7354; + let K37 : Nat32 = 0x766a0abb; + let K38 : Nat32 = 0x81c2c92e; + let K39 : Nat32 = 0x92722c85; + let K40 : Nat32 = 0xa2bfe8a1; + let K41 : Nat32 = 0xa81a664b; + let K42 : Nat32 = 0xc24b8b70; + let K43 : Nat32 = 0xc76c51a3; + let K44 : Nat32 = 0xd192e819; + let K45 : Nat32 = 0xd6990624; + let K46 : Nat32 = 0xf40e3585; + let K47 : Nat32 = 0x106aa070; + let K48 : Nat32 = 0x19a4c116; + let K49 : Nat32 = 0x1e376c08; + let K50 : Nat32 = 0x2748774c; + let K51 : Nat32 = 0x34b0bcb5; + let K52 : Nat32 = 0x391c0cb3; + let K53 : Nat32 = 0x4ed8aa4a; + let K54 : Nat32 = 0x5b9cca4f; + let K55 : Nat32 = 0x682e6ff3; + let K56 : Nat32 = 0x748f82ee; + let K57 : Nat32 = 0x78a5636f; + let K58 : Nat32 = 0x84c87814; + let K59 : Nat32 = 0x8cc70208; + let K60 : Nat32 = 0x90befffa; + let K61 : Nat32 = 0xa4506ceb; + let K62 : Nat32 = 0xbef9a3f7; + let K63 : Nat32 = 0xc67178f2; + + let ivs : [[Nat32]] = [ + [ + // 224 + 0xc1059ed8, + 0x367cd507, + 0x3070dd17, + 0xf70e5939, + 0xffc00b31, + 0x68581511, + 0x64f98fa7, + 0xbefa4fa4 + ], + [ + // 256 + 0x6a09e667, + 0xbb67ae85, + 0x3c6ef372, + 0xa54ff53a, + 0x510e527f, + 0x9b05688c, + 0x1f83d9ab, + 0x5be0cd19 + ] + ]; + + let rot = Nat32.bitrotRight; + + class SHA224() { + let (sum_bytes, iv) = (28, 0); + + var s0 : Nat32 = 0; + var s1 : Nat32 = 0; + var s2 : Nat32 = 0; + var s3 : Nat32 = 0; + var s4 : Nat32 = 0; + var s5 : Nat32 = 0; + var s6 : Nat32 = 0; + var s7 : Nat32 = 0; + + let msg : [var Nat32] = Array.init(16, 0); + let digest = Array.init(sum_bytes, 0); + var word : Nat32 = 0; + + var i_msg : Nat8 = 0; + var i_byte : Nat8 = 4; + var i_block : Nat64 = 0; + + public func reset() { + i_msg := 0; + i_byte := 4; + i_block := 0; + s0 := ivs[iv][0]; + s1 := ivs[iv][1]; + s2 := ivs[iv][2]; + s3 := ivs[iv][3]; + s4 := ivs[iv][4]; + s5 := ivs[iv][5]; + s6 := ivs[iv][6]; + s7 := ivs[iv][7] + }; + + reset(); + + private func writeByte(val : Nat8) : () { + word := (word << 8) ^ Nat32.fromIntWrap(Nat8.toNat(val)); + i_byte -%= 1; + if (i_byte == 0) { + msg[Nat8.toNat(i_msg)] := word; + word := 0; + i_byte := 4; + i_msg +%= 1; + if (i_msg == 16) { + process_block(); + i_msg := 0; + i_block +%= 1 + } + } + }; + + private func process_block() : () { + let w00 = msg[0]; + let w01 = msg[1]; + let w02 = msg[2]; + let w03 = msg[3]; + let w04 = msg[4]; + let w05 = msg[5]; + let w06 = msg[6]; + let w07 = msg[7]; + let w08 = msg[8]; + let w09 = msg[9]; + let w10 = msg[10]; + let w11 = msg[11]; + let w12 = msg[12]; + let w13 = msg[13]; + let w14 = msg[14]; + let w15 = msg[15]; + let w16 = w00 +% rot(w01, 07) ^ rot(w01, 18) ^ (w01 >> 03) +% w09 +% rot(w14, 17) ^ rot(w14, 19) ^ (w14 >> 10); + let w17 = w01 +% rot(w02, 07) ^ rot(w02, 18) ^ (w02 >> 03) +% w10 +% rot(w15, 17) ^ rot(w15, 19) ^ (w15 >> 10); + let w18 = w02 +% rot(w03, 07) ^ rot(w03, 18) ^ (w03 >> 03) +% w11 +% rot(w16, 17) ^ rot(w16, 19) ^ (w16 >> 10); + let w19 = w03 +% rot(w04, 07) ^ rot(w04, 18) ^ (w04 >> 03) +% w12 +% rot(w17, 17) ^ rot(w17, 19) ^ (w17 >> 10); + let w20 = w04 +% rot(w05, 07) ^ rot(w05, 18) ^ (w05 >> 03) +% w13 +% rot(w18, 17) ^ rot(w18, 19) ^ (w18 >> 10); + let w21 = w05 +% rot(w06, 07) ^ rot(w06, 18) ^ (w06 >> 03) +% w14 +% rot(w19, 17) ^ rot(w19, 19) ^ (w19 >> 10); + let w22 = w06 +% rot(w07, 07) ^ rot(w07, 18) ^ (w07 >> 03) +% w15 +% rot(w20, 17) ^ rot(w20, 19) ^ (w20 >> 10); + let w23 = w07 +% rot(w08, 07) ^ rot(w08, 18) ^ (w08 >> 03) +% w16 +% rot(w21, 17) ^ rot(w21, 19) ^ (w21 >> 10); + let w24 = w08 +% rot(w09, 07) ^ rot(w09, 18) ^ (w09 >> 03) +% w17 +% rot(w22, 17) ^ rot(w22, 19) ^ (w22 >> 10); + let w25 = w09 +% rot(w10, 07) ^ rot(w10, 18) ^ (w10 >> 03) +% w18 +% rot(w23, 17) ^ rot(w23, 19) ^ (w23 >> 10); + let w26 = w10 +% rot(w11, 07) ^ rot(w11, 18) ^ (w11 >> 03) +% w19 +% rot(w24, 17) ^ rot(w24, 19) ^ (w24 >> 10); + let w27 = w11 +% rot(w12, 07) ^ rot(w12, 18) ^ (w12 >> 03) +% w20 +% rot(w25, 17) ^ rot(w25, 19) ^ (w25 >> 10); + let w28 = w12 +% rot(w13, 07) ^ rot(w13, 18) ^ (w13 >> 03) +% w21 +% rot(w26, 17) ^ rot(w26, 19) ^ (w26 >> 10); + let w29 = w13 +% rot(w14, 07) ^ rot(w14, 18) ^ (w14 >> 03) +% w22 +% rot(w27, 17) ^ rot(w27, 19) ^ (w27 >> 10); + let w30 = w14 +% rot(w15, 07) ^ rot(w15, 18) ^ (w15 >> 03) +% w23 +% rot(w28, 17) ^ rot(w28, 19) ^ (w28 >> 10); + let w31 = w15 +% rot(w16, 07) ^ rot(w16, 18) ^ (w16 >> 03) +% w24 +% rot(w29, 17) ^ rot(w29, 19) ^ (w29 >> 10); + let w32 = w16 +% rot(w17, 07) ^ rot(w17, 18) ^ (w17 >> 03) +% w25 +% rot(w30, 17) ^ rot(w30, 19) ^ (w30 >> 10); + let w33 = w17 +% rot(w18, 07) ^ rot(w18, 18) ^ (w18 >> 03) +% w26 +% rot(w31, 17) ^ rot(w31, 19) ^ (w31 >> 10); + let w34 = w18 +% rot(w19, 07) ^ rot(w19, 18) ^ (w19 >> 03) +% w27 +% rot(w32, 17) ^ rot(w32, 19) ^ (w32 >> 10); + let w35 = w19 +% rot(w20, 07) ^ rot(w20, 18) ^ (w20 >> 03) +% w28 +% rot(w33, 17) ^ rot(w33, 19) ^ (w33 >> 10); + let w36 = w20 +% rot(w21, 07) ^ rot(w21, 18) ^ (w21 >> 03) +% w29 +% rot(w34, 17) ^ rot(w34, 19) ^ (w34 >> 10); + let w37 = w21 +% rot(w22, 07) ^ rot(w22, 18) ^ (w22 >> 03) +% w30 +% rot(w35, 17) ^ rot(w35, 19) ^ (w35 >> 10); + let w38 = w22 +% rot(w23, 07) ^ rot(w23, 18) ^ (w23 >> 03) +% w31 +% rot(w36, 17) ^ rot(w36, 19) ^ (w36 >> 10); + let w39 = w23 +% rot(w24, 07) ^ rot(w24, 18) ^ (w24 >> 03) +% w32 +% rot(w37, 17) ^ rot(w37, 19) ^ (w37 >> 10); + let w40 = w24 +% rot(w25, 07) ^ rot(w25, 18) ^ (w25 >> 03) +% w33 +% rot(w38, 17) ^ rot(w38, 19) ^ (w38 >> 10); + let w41 = w25 +% rot(w26, 07) ^ rot(w26, 18) ^ (w26 >> 03) +% w34 +% rot(w39, 17) ^ rot(w39, 19) ^ (w39 >> 10); + let w42 = w26 +% rot(w27, 07) ^ rot(w27, 18) ^ (w27 >> 03) +% w35 +% rot(w40, 17) ^ rot(w40, 19) ^ (w40 >> 10); + let w43 = w27 +% rot(w28, 07) ^ rot(w28, 18) ^ (w28 >> 03) +% w36 +% rot(w41, 17) ^ rot(w41, 19) ^ (w41 >> 10); + let w44 = w28 +% rot(w29, 07) ^ rot(w29, 18) ^ (w29 >> 03) +% w37 +% rot(w42, 17) ^ rot(w42, 19) ^ (w42 >> 10); + let w45 = w29 +% rot(w30, 07) ^ rot(w30, 18) ^ (w30 >> 03) +% w38 +% rot(w43, 17) ^ rot(w43, 19) ^ (w43 >> 10); + let w46 = w30 +% rot(w31, 07) ^ rot(w31, 18) ^ (w31 >> 03) +% w39 +% rot(w44, 17) ^ rot(w44, 19) ^ (w44 >> 10); + let w47 = w31 +% rot(w32, 07) ^ rot(w32, 18) ^ (w32 >> 03) +% w40 +% rot(w45, 17) ^ rot(w45, 19) ^ (w45 >> 10); + let w48 = w32 +% rot(w33, 07) ^ rot(w33, 18) ^ (w33 >> 03) +% w41 +% rot(w46, 17) ^ rot(w46, 19) ^ (w46 >> 10); + let w49 = w33 +% rot(w34, 07) ^ rot(w34, 18) ^ (w34 >> 03) +% w42 +% rot(w47, 17) ^ rot(w47, 19) ^ (w47 >> 10); + let w50 = w34 +% rot(w35, 07) ^ rot(w35, 18) ^ (w35 >> 03) +% w43 +% rot(w48, 17) ^ rot(w48, 19) ^ (w48 >> 10); + let w51 = w35 +% rot(w36, 07) ^ rot(w36, 18) ^ (w36 >> 03) +% w44 +% rot(w49, 17) ^ rot(w49, 19) ^ (w49 >> 10); + let w52 = w36 +% rot(w37, 07) ^ rot(w37, 18) ^ (w37 >> 03) +% w45 +% rot(w50, 17) ^ rot(w50, 19) ^ (w50 >> 10); + let w53 = w37 +% rot(w38, 07) ^ rot(w38, 18) ^ (w38 >> 03) +% w46 +% rot(w51, 17) ^ rot(w51, 19) ^ (w51 >> 10); + let w54 = w38 +% rot(w39, 07) ^ rot(w39, 18) ^ (w39 >> 03) +% w47 +% rot(w52, 17) ^ rot(w52, 19) ^ (w52 >> 10); + let w55 = w39 +% rot(w40, 07) ^ rot(w40, 18) ^ (w40 >> 03) +% w48 +% rot(w53, 17) ^ rot(w53, 19) ^ (w53 >> 10); + let w56 = w40 +% rot(w41, 07) ^ rot(w41, 18) ^ (w41 >> 03) +% w49 +% rot(w54, 17) ^ rot(w54, 19) ^ (w54 >> 10); + let w57 = w41 +% rot(w42, 07) ^ rot(w42, 18) ^ (w42 >> 03) +% w50 +% rot(w55, 17) ^ rot(w55, 19) ^ (w55 >> 10); + let w58 = w42 +% rot(w43, 07) ^ rot(w43, 18) ^ (w43 >> 03) +% w51 +% rot(w56, 17) ^ rot(w56, 19) ^ (w56 >> 10); + let w59 = w43 +% rot(w44, 07) ^ rot(w44, 18) ^ (w44 >> 03) +% w52 +% rot(w57, 17) ^ rot(w57, 19) ^ (w57 >> 10); + let w60 = w44 +% rot(w45, 07) ^ rot(w45, 18) ^ (w45 >> 03) +% w53 +% rot(w58, 17) ^ rot(w58, 19) ^ (w58 >> 10); + let w61 = w45 +% rot(w46, 07) ^ rot(w46, 18) ^ (w46 >> 03) +% w54 +% rot(w59, 17) ^ rot(w59, 19) ^ (w59 >> 10); + let w62 = w46 +% rot(w47, 07) ^ rot(w47, 18) ^ (w47 >> 03) +% w55 +% rot(w60, 17) ^ rot(w60, 19) ^ (w60 >> 10); + let w63 = w47 +% rot(w48, 07) ^ rot(w48, 18) ^ (w48 >> 03) +% w56 +% rot(w61, 17) ^ rot(w61, 19) ^ (w61 >> 10); + + /* + for ((i, j, k, l, m) in expansion_rounds.vals()) { + // (j,k,l,m) = (i+1,i+9,i+14,i+16) + let (v0, v1) = (msg[j], msg[l]); + let s0 = rot(v0, 07) ^ rot(v0, 18) ^ (v0 >> 03); + let s1 = rot(v1, 17) ^ rot(v1, 19) ^ (v1 >> 10); + msg[m] := msg[i] +% s0 +% msg[k] +% s1; + }; +*/ + // compress + var a = s0; + var b = s1; + var c = s2; + var d = s3; + var e = s4; + var f = s5; + var g = s6; + var h = s7; + var t = 0 : Nat32; + + t := h +% K00 +% w00 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K01 +% w01 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K02 +% w02 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K03 +% w03 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K04 +% w04 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K05 +% w05 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K06 +% w06 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K07 +% w07 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K08 +% w08 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K09 +% w09 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K10 +% w10 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K11 +% w11 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K12 +% w12 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K13 +% w13 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K14 +% w14 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K15 +% w15 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K16 +% w16 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K17 +% w17 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K18 +% w18 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K19 +% w19 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K20 +% w20 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K21 +% w21 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K22 +% w22 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K23 +% w23 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K24 +% w24 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K25 +% w25 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K26 +% w26 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K27 +% w27 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K28 +% w28 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K29 +% w29 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K30 +% w30 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K31 +% w31 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K32 +% w32 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K33 +% w33 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K34 +% w34 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K35 +% w35 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K36 +% w36 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K37 +% w37 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K38 +% w38 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K39 +% w39 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K40 +% w40 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K41 +% w41 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K42 +% w42 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K43 +% w43 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K44 +% w44 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K45 +% w45 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K46 +% w46 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K47 +% w47 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K48 +% w48 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K49 +% w49 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K50 +% w50 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K51 +% w51 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K52 +% w52 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K53 +% w53 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K54 +% w54 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K55 +% w55 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K56 +% w56 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K57 +% w57 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K58 +% w58 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K59 +% w59 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K60 +% w60 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K61 +% w61 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K62 +% w62 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + t := h +% K63 +% w63 +% (e & f) ^ (^ e & g) +% rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% (b & c) ^ (b & d) ^ (c & d) +% rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + + /* + for (i in compression_rounds.keys()) { + let ch = (e & f) ^ (^ e & g); + let maj = (a & b) ^ (a & c) ^ (b & c); + let sigma0 = rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); + let sigma1 = rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); + let t = h +% K[i] +% msg[i] +% ch +% sigma1; + h := g; + g := f; + f := e; + e := d +% t; + d := c; + c := b; + b := a; + a := t +% maj +% sigma0; + }; +*/ + // final addition + s0 +%= a; + s1 +%= b; + s2 +%= c; + s3 +%= d; + s4 +%= e; + s5 +%= f; + s6 +%= g; + s7 +%= h + }; + + public func writeIter(iter : { next() : ?Nat8 }) : () { + label reading loop { + switch (iter.next()) { + case (?val) { + writeByte(val); + continue reading + }; + case (null) { + break reading + } + } + } + }; + + public func writeArray(arr : [Nat8]) : () = writeIter(arr.vals()); + public func writeBlob(blob : Blob) : () = writeIter(blob.vals()); + + public func sum() : Blob { + // calculate padding + // t = bytes in the last incomplete block (0-63) + let t : Nat8 = (i_msg << 2) +% 4 -% i_byte; + // p = length of padding (1-64) + var p : Nat8 = if (t < 56) (56 -% t) else (120 -% t); + // n_bits = length of message in bits + let n_bits : Nat64 = ((i_block << 6) +% Nat64.fromIntWrap(Nat8.toNat(t))) << 3; + + // write padding + writeByte(0x80); + p -%= 1; + while (p != 0) { + writeByte(0x00); + p -%= 1 + }; + + // write length (8 bytes) + // Note: this exactly fills the block buffer, hence process_block will get + // triggered by the last writeByte + writeByte(Nat8.fromIntWrap(Nat64.toNat((n_bits >> 56) & 0xff))); + writeByte(Nat8.fromIntWrap(Nat64.toNat((n_bits >> 48) & 0xff))); + writeByte(Nat8.fromIntWrap(Nat64.toNat((n_bits >> 40) & 0xff))); + writeByte(Nat8.fromIntWrap(Nat64.toNat((n_bits >> 32) & 0xff))); + writeByte(Nat8.fromIntWrap(Nat64.toNat((n_bits >> 24) & 0xff))); + writeByte(Nat8.fromIntWrap(Nat64.toNat((n_bits >> 16) & 0xff))); + writeByte(Nat8.fromIntWrap(Nat64.toNat((n_bits >> 8) & 0xff))); + writeByte(Nat8.fromIntWrap(Nat64.toNat(n_bits & 0xff))); + + // retrieve sum + digest[0] := Nat8.fromIntWrap(Nat32.toNat((s0 >> 24) & 0xff)); + digest[1] := Nat8.fromIntWrap(Nat32.toNat((s0 >> 16) & 0xff)); + digest[2] := Nat8.fromIntWrap(Nat32.toNat((s0 >> 8) & 0xff)); + digest[3] := Nat8.fromIntWrap(Nat32.toNat(s0 & 0xff)); + digest[4] := Nat8.fromIntWrap(Nat32.toNat((s1 >> 24) & 0xff)); + digest[5] := Nat8.fromIntWrap(Nat32.toNat((s1 >> 16) & 0xff)); + digest[6] := Nat8.fromIntWrap(Nat32.toNat((s1 >> 8) & 0xff)); + digest[7] := Nat8.fromIntWrap(Nat32.toNat(s1 & 0xff)); + digest[8] := Nat8.fromIntWrap(Nat32.toNat((s2 >> 24) & 0xff)); + digest[9] := Nat8.fromIntWrap(Nat32.toNat((s2 >> 16) & 0xff)); + digest[10] := Nat8.fromIntWrap(Nat32.toNat((s2 >> 8) & 0xff)); + digest[11] := Nat8.fromIntWrap(Nat32.toNat(s2 & 0xff)); + digest[12] := Nat8.fromIntWrap(Nat32.toNat((s3 >> 24) & 0xff)); + digest[13] := Nat8.fromIntWrap(Nat32.toNat((s3 >> 16) & 0xff)); + digest[14] := Nat8.fromIntWrap(Nat32.toNat((s3 >> 8) & 0xff)); + digest[15] := Nat8.fromIntWrap(Nat32.toNat(s3 & 0xff)); + digest[16] := Nat8.fromIntWrap(Nat32.toNat((s4 >> 24) & 0xff)); + digest[17] := Nat8.fromIntWrap(Nat32.toNat((s4 >> 16) & 0xff)); + digest[18] := Nat8.fromIntWrap(Nat32.toNat((s4 >> 8) & 0xff)); + digest[19] := Nat8.fromIntWrap(Nat32.toNat(s4 & 0xff)); + digest[20] := Nat8.fromIntWrap(Nat32.toNat((s5 >> 24) & 0xff)); + digest[21] := Nat8.fromIntWrap(Nat32.toNat((s5 >> 16) & 0xff)); + digest[22] := Nat8.fromIntWrap(Nat32.toNat((s5 >> 8) & 0xff)); + digest[23] := Nat8.fromIntWrap(Nat32.toNat(s5 & 0xff)); + digest[24] := Nat8.fromIntWrap(Nat32.toNat((s6 >> 24) & 0xff)); + digest[25] := Nat8.fromIntWrap(Nat32.toNat((s6 >> 16) & 0xff)); + digest[26] := Nat8.fromIntWrap(Nat32.toNat((s6 >> 8) & 0xff)); + digest[27] := Nat8.fromIntWrap(Nat32.toNat(s6 & 0xff)); + + return Blob.fromArrayMut(digest) + } + }; // class Digest + /// Compute the account identifier of a principal. Optionally specify a sub-account. /// /// Example: @@ -64,23 +981,26 @@ module { [byte(n >> 24), byte(n >> 16), byte(n >> 8), byte(n)] }; - let sha224 = Cryptography.SHA224(); - sha224.write([0x0A]); - sha224.write(Blob.toArray(Text.encodeUtf8("account-id"))); - sha224.write(Blob.toArray(toBlob(principal))); + let sha224 = SHA224(); + sha224.writeArray([0x0A]); + sha224.writeBlob(Text.encodeUtf8("account-id")); + sha224.writeBlob(toBlob(principal)); switch subAccount { case (?subAccount) { - sha224.write(Blob.toArray(subAccount)) + sha224.writeBlob(subAccount) }; case (null) { let defaultSubAccount = Array.tabulate(32, func _ = 0); - sha224.write(defaultSubAccount) + sha224.writeArray(defaultSubAccount) } }; let hashSum = sha224.sum(); - let crc32Bytes = beBytes(Cryptography.crc32OfArray(hashSum)); - Blob.fromArray(Array.append(crc32Bytes, hashSum)) + + // hashBlob is a CRC32 implementation + let crc32Bytes = beBytes(Prim.hashBlob hashSum); + + Blob.fromArray(Array.append(crc32Bytes, Blob.toArray(hashSum))) }; /// Convert a `Principal` to its `Blob` (bytes) representation. From 1e02e23634da34f91f143473dfaea0c32717fcf9 Mon Sep 17 00:00:00 2001 From: Kento Sugama Date: Fri, 1 Sep 2023 15:52:59 -0400 Subject: [PATCH 03/12] bump node version. causing incompatibility error --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6a331a68..fd86dbc3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 20. - run: npm ci - name: "initial checks" run: npm run validate From 164d0a0f69a45297f8b797a49268a9fafc6ca546 Mon Sep 17 00:00:00 2001 From: Kento Sugama Date: Fri, 1 Sep 2023 15:54:59 -0400 Subject: [PATCH 04/12] dont specify node version --- .github/workflows/ci.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0a132ef2..1fb4499e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,8 +18,6 @@ jobs: steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 - with: - node-version: 20. - run: npm ci - name: "initial checks" run: npm run validate From e04cd07a19cd0d3fdeea46865a685174456f16e3 Mon Sep 17 00:00:00 2001 From: Kento Sugama Date: Fri, 1 Sep 2023 15:57:34 -0400 Subject: [PATCH 05/12] try 20.5.0 --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1fb4499e..a451ff41 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,6 +18,8 @@ jobs: steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 + with: + node-version: 20.5.0 - run: npm ci - name: "initial checks" run: npm run validate From 7a457d3510b5be72b1e65313d7789f696b411d8e Mon Sep 17 00:00:00 2001 From: Kento Sugama Date: Fri, 1 Sep 2023 15:59:16 -0400 Subject: [PATCH 06/12] bump other node --- .github/workflows/prettier.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/prettier.yml b/.github/workflows/prettier.yml index e3ff0c2d..45ae84f6 100644 --- a/.github/workflows/prettier.yml +++ b/.github/workflows/prettier.yml @@ -14,7 +14,7 @@ jobs: fail-fast: true matrix: os: [ubuntu-22.04] - node: [16] + node: [20.5.0] steps: - uses: actions/checkout@v3 - name: Use Node.js ${{ matrix.node }} From 5ff1e4570b732414d8c58b96ec3e5be6710a9d71 Mon Sep 17 00:00:00 2001 From: Kento Sugama Date: Fri, 1 Sep 2023 16:05:38 -0400 Subject: [PATCH 07/12] cleanup --- src/Principal.mo | 507 ++++++++++++++++++++++++----------------------- 1 file changed, 255 insertions(+), 252 deletions(-) diff --git a/src/Principal.mo b/src/Principal.mo index c6f57c9e..8d7d51d6 100644 --- a/src/Principal.mo +++ b/src/Principal.mo @@ -49,8 +49,254 @@ module { /// ``` public func fromActor(a : actor {}) : Principal = Prim.principalOfActor a; - //// PRIVATE SHA 224 UTILITIES //// - //// Taken from https://github.com/research-ag/sha2 //// + /// Compute the account identifier of a principal. Optionally specify a sub-account. + /// + /// Example: + /// ```motoko include=import + /// let principal = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); + /// let account = Principal.toAccount(principal, null); // => \00\00\00\00\00\30\00\D3\01\01 FIXME check ChatGPT's math + /// ``` + public func toAccount(principal : Principal, subAccount : ?Blob) : Blob { + let sha224 = SHA224(); + sha224.writeArray([0x0A]); + sha224.writeBlob(Text.encodeUtf8("account-id")); + sha224.writeBlob(toBlob(principal)); + switch subAccount { + case (?subAccount) { + sha224.writeBlob(subAccount) + }; + case (null) { + let defaultSubAccount = Array.tabulate(32, func _ = 0); + sha224.writeArray(defaultSubAccount) + } + }; + + let hashSum = sha224.sum(); + + // hashBlob is a CRC32 implementation + let crc32Bytes = nat32ToByteArray(Prim.hashBlob hashSum); + + Blob.fromArray(Array.append(crc32Bytes, Blob.toArray(hashSum))) + }; + + /// Convert a `Principal` to its `Blob` (bytes) representation. + /// + /// Example: + /// ```motoko include=import + /// let principal = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); + /// let blob = Principal.toBlob(principal); // => \00\00\00\00\00\30\00\D3\01\01 + /// ``` + public func toBlob(p : Principal) : Blob = Prim.blobOfPrincipal p; + + /// Converts a `Blob` (bytes) representation of a `Principal` to a `Principal` value. + /// + /// Example: + /// ```motoko include=import + /// let blob = "\00\00\00\00\00\30\00\D3\01\01" : Blob; + /// let principal = Principal.fromBlob(blob); + /// Principal.toText(principal) // => "un4fu-tqaaa-aaaab-qadjq-cai" + /// ``` + public func fromBlob(b : Blob) : Principal = Prim.principalOfBlob b; + + /// Converts a `Principal` to its `Text` representation. + /// + /// Example: + /// ```motoko include=import + /// let principal = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); + /// Principal.toText(principal) // => "un4fu-tqaaa-aaaab-qadjq-cai" + /// ``` + public func toText(p : Principal) : Text = debug_show (p); + + /// Converts a `Text` representation of a `Principal` to a `Principal` value. + /// + /// Example: + /// ```motoko include=import + /// let principal = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); + /// Principal.toText(principal) // => "un4fu-tqaaa-aaaab-qadjq-cai" + /// ``` + public func fromText(t : Text) : Principal = fromActor(actor (t)); + + private let anonymousPrincipal : Blob = "\04"; + + /// Checks if the given principal represents an anonymous user. + /// + /// Example: + /// ```motoko include=import + /// let principal = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); + /// Principal.isAnonymous(principal) // => false + /// ``` + public func isAnonymous(p : Principal) : Bool = Prim.blobOfPrincipal p == anonymousPrincipal; + + /// Checks if the given principal can control this canister. + /// + /// Example: + /// ```motoko include=import + /// let principal = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); + /// Principal.isController(principal) // => false + /// ``` + public func isController(p : Principal) : Bool = Prim.isController p; + + /// Hashes the given principal by hashing its `Blob` representation. + /// + /// Example: + /// ```motoko include=import + /// let principal = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); + /// Principal.hash(principal) // => 2_742_573_646 + /// ``` + public func hash(principal : Principal) : Hash.Hash = Blob.hash(Prim.blobOfPrincipal(principal)); + + /// General purpose comparison function for `Principal`. Returns the `Order` ( + /// either `#less`, `#equal`, or `#greater`) of comparing `principal1` with + /// `principal2`. + /// + /// Example: + /// ```motoko include=import + /// let principal1 = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); + /// let principal2 = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); + /// Principal.compare(principal1, principal2) // => #equal + /// ``` + public func compare(principal1 : Principal, principal2 : Principal) : { + #less; + #equal; + #greater + } { + if (principal1 < principal2) { + #less + } else if (principal1 == principal2) { + #equal + } else { + #greater + } + }; + + /// Equality function for Principal types. + /// This is equivalent to `principal1 == principal2`. + /// + /// Example: + /// ```motoko include=import + /// let principal1 = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); + /// let principal2 = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); + /// ignore Principal.equal(principal1, principal2); + /// principal1 == principal2 // => true + /// ``` + /// + /// Note: The reason why this function is defined in this library (in addition + /// to the existing `==` operator) is so that you can use it as a function + /// value to pass to a higher order function. It is not possible to use `==` + /// as a function value at the moment. + /// + /// Example: + /// ```motoko include=import + /// import Buffer "mo:base/Buffer"; + /// + /// let buffer1 = Buffer.Buffer(3); + /// let buffer2 = Buffer.Buffer(3); + /// Buffer.equal(buffer1, buffer2, Principal.equal) // => true + /// ``` + public func equal(principal1 : Principal, principal2 : Principal) : Bool { + principal1 == principal2 + }; + + /// Inequality function for Principal types. + /// This is equivalent to `principal1 != principal2`. + /// + /// Example: + /// ```motoko include=import + /// let principal1 = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); + /// let principal2 = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); + /// ignore Principal.notEqual(principal1, principal2); + /// principal1 != principal2 // => false + /// ``` + /// + /// Note: The reason why this function is defined in this library (in addition + /// to the existing `!=` operator) is so that you can use it as a function + /// value to pass to a higher order function. It is not possible to use `!=` + /// as a function value at the moment. + public func notEqual(principal1 : Principal, principal2 : Principal) : Bool { + principal1 != principal2 + }; + + /// "Less than" function for Principal types. + /// This is equivalent to `principal1 < principal2`. + /// + /// Example: + /// ```motoko include=import + /// let principal1 = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); + /// let principal2 = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); + /// ignore Principal.less(principal1, principal2); + /// principal1 < principal2 // => false + /// ``` + /// + /// Note: The reason why this function is defined in this library (in addition + /// to the existing `<` operator) is so that you can use it as a function + /// value to pass to a higher order function. It is not possible to use `<` + /// as a function value at the moment. + public func less(principal1 : Principal, principal2 : Principal) : Bool { + principal1 < principal2 + }; + + /// "Less than or equal to" function for Principal types. + /// This is equivalent to `principal1 <= principal2`. + /// + /// Example: + /// ```motoko include=import + /// let principal1 = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); + /// let principal2 = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); + /// ignore Principal.lessOrEqual(principal1, principal2); + /// principal1 <= principal2 // => true + /// ``` + /// + /// Note: The reason why this function is defined in this library (in addition + /// to the existing `<=` operator) is so that you can use it as a function + /// value to pass to a higher order function. It is not possible to use `<=` + /// as a function value at the moment. + public func lessOrEqual(principal1 : Principal, principal2 : Principal) : Bool { + principal1 <= principal2 + }; + + /// "Greater than" function for Principal types. + /// This is equivalent to `principal1 > principal2`. + /// + /// Example: + /// ```motoko include=import + /// let principal1 = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); + /// let principal2 = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); + /// ignore Principal.greater(principal1, principal2); + /// principal1 > principal2 // => false + /// ``` + /// + /// Note: The reason why this function is defined in this library (in addition + /// to the existing `>` operator) is so that you can use it as a function + /// value to pass to a higher order function. It is not possible to use `>` + /// as a function value at the moment. + public func greater(principal1 : Principal, principal2 : Principal) : Bool { + principal1 > principal2 + }; + + /// "Greater than or equal to" function for Principal types. + /// This is equivalent to `principal1 >= principal2`. + /// + /// Example: + /// ```motoko include=import + /// let principal1 = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); + /// let principal2 = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); + /// ignore Principal.greaterOrEqual(principal1, principal2); + /// principal1 >= principal2 // => true + /// ``` + /// + /// Note: The reason why this function is defined in this library (in addition + /// to the existing `>=` operator) is so that you can use it as a function + /// value to pass to a higher order function. It is not possible to use `>=` + /// as a function value at the moment. + public func greaterOrEqual(principal1 : Principal, principal2 : Principal) : Bool { + principal1 >= principal2 + }; + + /** + * SHA224 Utilities used in toAccount(). + * Utilities are not exposed as public functions. + * Taken from https://github.com/research-ag/sha2 + **/ let K00 : Nat32 = 0x428a2f98; let K01 : Nat32 = 0x71374491; let K02 : Nat32 = 0xb5c0fbcf; @@ -269,7 +515,7 @@ module { let s1 = rot(v1, 17) ^ rot(v1, 19) ^ (v1 >> 10); msg[m] := msg[i] +% s0 +% msg[k] +% s1; }; -*/ + */ // compress var a = s0; var b = s1; @@ -874,7 +1120,7 @@ module { b := a; a := t +% maj +% sigma0; }; -*/ + */ // final addition s0 +%= a; s1 +%= b; @@ -964,255 +1210,12 @@ module { return Blob.fromArrayMut(digest) } - }; // class Digest + }; // class SHA224 - /// Compute the account identifier of a principal. Optionally specify a sub-account. - /// - /// Example: - /// ```motoko include=import - /// let principal = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); - /// let account = Principal.toAccount(principal, null); // => \00\00\00\00\00\30\00\D3\01\01 FIXME check ChatGPT's math - /// ``` - public func toAccount(principal : Principal, subAccount : ?Blob) : Blob { - func beBytes(n : Nat32) : [Nat8] { - func byte(n : Nat32) : Nat8 { - Nat8.fromNat(Nat32.toNat(n & 0xff)) - }; - [byte(n >> 24), byte(n >> 16), byte(n >> 8), byte(n)] + func nat32ToByteArray(n : Nat32) : [Nat8] { + func byte(n : Nat32) : Nat8 { + Nat8.fromNat(Nat32.toNat(n & 0xff)) }; - - let sha224 = SHA224(); - sha224.writeArray([0x0A]); - sha224.writeBlob(Text.encodeUtf8("account-id")); - sha224.writeBlob(toBlob(principal)); - switch subAccount { - case (?subAccount) { - sha224.writeBlob(subAccount) - }; - case (null) { - let defaultSubAccount = Array.tabulate(32, func _ = 0); - sha224.writeArray(defaultSubAccount) - } - }; - - let hashSum = sha224.sum(); - - // hashBlob is a CRC32 implementation - let crc32Bytes = beBytes(Prim.hashBlob hashSum); - - Blob.fromArray(Array.append(crc32Bytes, Blob.toArray(hashSum))) - }; - - /// Convert a `Principal` to its `Blob` (bytes) representation. - /// - /// Example: - /// ```motoko include=import - /// let principal = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); - /// let blob = Principal.toBlob(principal); // => \00\00\00\00\00\30\00\D3\01\01 - /// ``` - public func toBlob(p : Principal) : Blob = Prim.blobOfPrincipal p; - - /// Converts a `Blob` (bytes) representation of a `Principal` to a `Principal` value. - /// - /// Example: - /// ```motoko include=import - /// let blob = "\00\00\00\00\00\30\00\D3\01\01" : Blob; - /// let principal = Principal.fromBlob(blob); - /// Principal.toText(principal) // => "un4fu-tqaaa-aaaab-qadjq-cai" - /// ``` - public func fromBlob(b : Blob) : Principal = Prim.principalOfBlob b; - - /// Converts a `Principal` to its `Text` representation. - /// - /// Example: - /// ```motoko include=import - /// let principal = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); - /// Principal.toText(principal) // => "un4fu-tqaaa-aaaab-qadjq-cai" - /// ``` - public func toText(p : Principal) : Text = debug_show (p); - - /// Converts a `Text` representation of a `Principal` to a `Principal` value. - /// - /// Example: - /// ```motoko include=import - /// let principal = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); - /// Principal.toText(principal) // => "un4fu-tqaaa-aaaab-qadjq-cai" - /// ``` - public func fromText(t : Text) : Principal = fromActor(actor (t)); - - private let anonymousPrincipal : Blob = "\04"; - - /// Checks if the given principal represents an anonymous user. - /// - /// Example: - /// ```motoko include=import - /// let principal = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); - /// Principal.isAnonymous(principal) // => false - /// ``` - public func isAnonymous(p : Principal) : Bool = Prim.blobOfPrincipal p == anonymousPrincipal; - - /// Checks if the given principal can control this canister. - /// - /// Example: - /// ```motoko include=import - /// let principal = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); - /// Principal.isController(principal) // => false - /// ``` - public func isController(p : Principal) : Bool = Prim.isController p; - - /// Hashes the given principal by hashing its `Blob` representation. - /// - /// Example: - /// ```motoko include=import - /// let principal = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); - /// Principal.hash(principal) // => 2_742_573_646 - /// ``` - public func hash(principal : Principal) : Hash.Hash = Blob.hash(Prim.blobOfPrincipal(principal)); - - /// General purpose comparison function for `Principal`. Returns the `Order` ( - /// either `#less`, `#equal`, or `#greater`) of comparing `principal1` with - /// `principal2`. - /// - /// Example: - /// ```motoko include=import - /// let principal1 = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); - /// let principal2 = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); - /// Principal.compare(principal1, principal2) // => #equal - /// ``` - public func compare(principal1 : Principal, principal2 : Principal) : { - #less; - #equal; - #greater - } { - if (principal1 < principal2) { - #less - } else if (principal1 == principal2) { - #equal - } else { - #greater - } - }; - - /// Equality function for Principal types. - /// This is equivalent to `principal1 == principal2`. - /// - /// Example: - /// ```motoko include=import - /// let principal1 = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); - /// let principal2 = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); - /// ignore Principal.equal(principal1, principal2); - /// principal1 == principal2 // => true - /// ``` - /// - /// Note: The reason why this function is defined in this library (in addition - /// to the existing `==` operator) is so that you can use it as a function - /// value to pass to a higher order function. It is not possible to use `==` - /// as a function value at the moment. - /// - /// Example: - /// ```motoko include=import - /// import Buffer "mo:base/Buffer"; - /// - /// let buffer1 = Buffer.Buffer(3); - /// let buffer2 = Buffer.Buffer(3); - /// Buffer.equal(buffer1, buffer2, Principal.equal) // => true - /// ``` - public func equal(principal1 : Principal, principal2 : Principal) : Bool { - principal1 == principal2 - }; - - /// Inequality function for Principal types. - /// This is equivalent to `principal1 != principal2`. - /// - /// Example: - /// ```motoko include=import - /// let principal1 = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); - /// let principal2 = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); - /// ignore Principal.notEqual(principal1, principal2); - /// principal1 != principal2 // => false - /// ``` - /// - /// Note: The reason why this function is defined in this library (in addition - /// to the existing `!=` operator) is so that you can use it as a function - /// value to pass to a higher order function. It is not possible to use `!=` - /// as a function value at the moment. - public func notEqual(principal1 : Principal, principal2 : Principal) : Bool { - principal1 != principal2 - }; - - /// "Less than" function for Principal types. - /// This is equivalent to `principal1 < principal2`. - /// - /// Example: - /// ```motoko include=import - /// let principal1 = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); - /// let principal2 = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); - /// ignore Principal.less(principal1, principal2); - /// principal1 < principal2 // => false - /// ``` - /// - /// Note: The reason why this function is defined in this library (in addition - /// to the existing `<` operator) is so that you can use it as a function - /// value to pass to a higher order function. It is not possible to use `<` - /// as a function value at the moment. - public func less(principal1 : Principal, principal2 : Principal) : Bool { - principal1 < principal2 - }; - - /// "Less than or equal to" function for Principal types. - /// This is equivalent to `principal1 <= principal2`. - /// - /// Example: - /// ```motoko include=import - /// let principal1 = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); - /// let principal2 = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); - /// ignore Principal.lessOrEqual(principal1, principal2); - /// principal1 <= principal2 // => true - /// ``` - /// - /// Note: The reason why this function is defined in this library (in addition - /// to the existing `<=` operator) is so that you can use it as a function - /// value to pass to a higher order function. It is not possible to use `<=` - /// as a function value at the moment. - public func lessOrEqual(principal1 : Principal, principal2 : Principal) : Bool { - principal1 <= principal2 - }; - - /// "Greater than" function for Principal types. - /// This is equivalent to `principal1 > principal2`. - /// - /// Example: - /// ```motoko include=import - /// let principal1 = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); - /// let principal2 = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); - /// ignore Principal.greater(principal1, principal2); - /// principal1 > principal2 // => false - /// ``` - /// - /// Note: The reason why this function is defined in this library (in addition - /// to the existing `>` operator) is so that you can use it as a function - /// value to pass to a higher order function. It is not possible to use `>` - /// as a function value at the moment. - public func greater(principal1 : Principal, principal2 : Principal) : Bool { - principal1 > principal2 - }; - - /// "Greater than or equal to" function for Principal types. - /// This is equivalent to `principal1 >= principal2`. - /// - /// Example: - /// ```motoko include=import - /// let principal1 = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); - /// let principal2 = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); - /// ignore Principal.greaterOrEqual(principal1, principal2); - /// principal1 >= principal2 // => true - /// ``` - /// - /// Note: The reason why this function is defined in this library (in addition - /// to the existing `>=` operator) is so that you can use it as a function - /// value to pass to a higher order function. It is not possible to use `>=` - /// as a function value at the moment. - public func greaterOrEqual(principal1 : Principal, principal2 : Principal) : Bool { - principal1 >= principal2 + [byte(n >> 24), byte(n >> 16), byte(n >> 8), byte(n)] } } From 9bd25e9fa866a4db67e8e1789443b87de830dfe8 Mon Sep 17 00:00:00 2001 From: Kento Sugama Date: Mon, 11 Sep 2023 14:41:50 -0400 Subject: [PATCH 08/12] add unit tests --- src/Principal.mo | 2 +- test/Principal.test.mo | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 test/Principal.test.mo diff --git a/src/Principal.mo b/src/Principal.mo index 8d7d51d6..2330274c 100644 --- a/src/Principal.mo +++ b/src/Principal.mo @@ -54,7 +54,7 @@ module { /// Example: /// ```motoko include=import /// let principal = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); - /// let account = Principal.toAccount(principal, null); // => \00\00\00\00\00\30\00\D3\01\01 FIXME check ChatGPT's math + /// let account = Principal.toAccount(principal, null); // => \57\4E\66\E1\B5\DD\EF\EA\78\73\6B\E4\6C\4F\61\21\31\98\88\90\08\2E\E8\0F\97\F6\B6\DB\ED\72\84\1E /// ``` public func toAccount(principal : Principal, subAccount : ?Blob) : Blob { let sha224 = SHA224(); diff --git a/test/Principal.test.mo b/test/Principal.test.mo new file mode 100644 index 00000000..b5a51bde --- /dev/null +++ b/test/Principal.test.mo @@ -0,0 +1,38 @@ +import Principal "mo:base/Principal"; +import Text "mo:base/Text"; +import Blob "mo:base/Blob"; +import Suite "mo:matchers/Suite"; +import T "mo:matchers/Testable"; +import M "mo:matchers/Matchers"; + +let BlobTestable : T.Testable = object { + public func display(blob : Blob) : Text { + debug_show blob + }; + public func equals(blob1 : Blob, blob2 : Blob) : Bool { + blob1 == blob2 + } +}; + +let principal = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); +let defaultAccount : Blob = "\57\4E\66\E1\B5\DD\EF\EA\78\73\6B\E4\6C\4F\61\21\31\98\88\90\08\2E\E8\0F\97\F6\B6\DB\ED\72\84\1E"; +let subAccount : Blob = "\4A\8D\3F\2B\6E\01\C8\7D\9E\03\B4\56\7C\F8\9A\01\D2\34\56\78\9A\BC\DE\F0\12\34\56\78\9A\BC\DE\F0"; +let accountWithSubAccount : Blob = "\8C\5C\20\C6\15\3F\7F\51\E2\0D\0F\0F\B5\08\51\5B\47\65\63\A9\62\B4\A9\91\5F\4F\02\70\8A\ED\4F\82"; + +let suite = Suite.suite( + "Principal", + [ + Suite.test( + "toAccount, default sub-account", + Principal.toAccount(principal, null), + M.equals({ BlobTestable and { item = defaultAccount } }) + ), + Suite.test( + "toAccount, with sub-account", + Principal.toAccount(principal, ?subAccount), + M.equals({ BlobTestable and { item = accountWithSubAccount } }) + ) + ] +); + +Suite.run(suite) From 274c66b1a5065a581a00b8b809f3aec81d27ea50 Mon Sep 17 00:00:00 2001 From: Kento Sugama Date: Tue, 12 Sep 2023 10:18:43 -0400 Subject: [PATCH 09/12] update function name --- src/Principal.mo | 7 ++++--- test/Principal.test.mo | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Principal.mo b/src/Principal.mo index 2330274c..3e5a76f6 100644 --- a/src/Principal.mo +++ b/src/Principal.mo @@ -49,14 +49,15 @@ module { /// ``` public func fromActor(a : actor {}) : Principal = Prim.principalOfActor a; - /// Compute the account identifier of a principal. Optionally specify a sub-account. + /// Compute the Ledger account identifier of a principal. Optionally specify a sub-account. /// /// Example: /// ```motoko include=import /// let principal = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); - /// let account = Principal.toAccount(principal, null); // => \57\4E\66\E1\B5\DD\EF\EA\78\73\6B\E4\6C\4F\61\21\31\98\88\90\08\2E\E8\0F\97\F6\B6\DB\ED\72\84\1E + /// let subAccount : Blob = "\4A\8D\3F\2B\6E\01\C8\7D\9E\03\B4\56\7C\F8\9A\01\D2\34\56\78\9A\BC\DE\F0\12\34\56\78\9A\BC\DE\F0"; + /// let account = Principal.toLedgerAccount(principal, ?subAccount); // => \8C\5C\20\C6\15\3F\7F\51\E2\0D\0F\0F\B5\08\51\5B\47\65\63\A9\62\B4\A9\91\5F\4F\02\70\8A\ED\4F\82 /// ``` - public func toAccount(principal : Principal, subAccount : ?Blob) : Blob { + public func toLedgerAccount(principal : Principal, subAccount : ?Blob) : Blob { let sha224 = SHA224(); sha224.writeArray([0x0A]); sha224.writeBlob(Text.encodeUtf8("account-id")); diff --git a/test/Principal.test.mo b/test/Principal.test.mo index b5a51bde..d918e060 100644 --- a/test/Principal.test.mo +++ b/test/Principal.test.mo @@ -24,12 +24,12 @@ let suite = Suite.suite( [ Suite.test( "toAccount, default sub-account", - Principal.toAccount(principal, null), + Principal.toLedgerAccount(principal, null), M.equals({ BlobTestable and { item = defaultAccount } }) ), Suite.test( "toAccount, with sub-account", - Principal.toAccount(principal, ?subAccount), + Principal.toLedgerAccount(principal, ?subAccount), M.equals({ BlobTestable and { item = accountWithSubAccount } }) ) ] From f2a8cb20141c31b92b2cabbdae61534cd03b5458 Mon Sep 17 00:00:00 2001 From: Kento Sugama Date: Tue, 12 Sep 2023 12:21:19 -0400 Subject: [PATCH 10/12] add second test --- test/Principal.test.mo | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/test/Principal.test.mo b/test/Principal.test.mo index d918e060..b88ee6e9 100644 --- a/test/Principal.test.mo +++ b/test/Principal.test.mo @@ -14,23 +14,38 @@ let BlobTestable : T.Testable = object { } }; -let principal = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); -let defaultAccount : Blob = "\57\4E\66\E1\B5\DD\EF\EA\78\73\6B\E4\6C\4F\61\21\31\98\88\90\08\2E\E8\0F\97\F6\B6\DB\ED\72\84\1E"; -let subAccount : Blob = "\4A\8D\3F\2B\6E\01\C8\7D\9E\03\B4\56\7C\F8\9A\01\D2\34\56\78\9A\BC\DE\F0\12\34\56\78\9A\BC\DE\F0"; -let accountWithSubAccount : Blob = "\8C\5C\20\C6\15\3F\7F\51\E2\0D\0F\0F\B5\08\51\5B\47\65\63\A9\62\B4\A9\91\5F\4F\02\70\8A\ED\4F\82"; +let principal1 = Principal.fromText("un4fu-tqaaa-aaaab-qadjq-cai"); +let defaultAccount1 : Blob = "\57\4E\66\E1\B5\DD\EF\EA\78\73\6B\E4\6C\4F\61\21\31\98\88\90\08\2E\E8\0F\97\F6\B6\DB\ED\72\84\1E"; +let subAccount1 : Blob = "\4A\8D\3F\2B\6E\01\C8\7D\9E\03\B4\56\7C\F8\9A\01\D2\34\56\78\9A\BC\DE\F0\12\34\56\78\9A\BC\DE\F0"; +let accountWithSubAccount1 : Blob = "\8C\5C\20\C6\15\3F\7F\51\E2\0D\0F\0F\B5\08\51\5B\47\65\63\A9\62\B4\A9\91\5F\4F\02\70\8A\ED\4F\82"; + +let principal2 = Principal.fromText("ylia2-w3sds-lgwx6-swrzr-xctdp-2rukx-uothy-yh5te-i5rt6-fqg62-iae"); +let defaultAccount2 : Blob = "\CA\04\B1\21\82\A1\6F\55\59\D0\63\BB\F4\46\CB\A2\F8\49\51\FE\1D\13\7C\E7\D7\45\85\1B\B2\96\6E\08"; +let subAccount2 : Blob = "\4F\8B\12\A5\C3\E6\07\D9\1F\A2\B0\C4\67\E8\90\23\4A\B6\5D\C8\91\0E\F2\47\8A\CD\56\B3\9E\01\2F\84"; +let accountWithSubAccount2 : Blob = "\D4\40\35\AF\5D\1D\6A\37\5F\F6\26\E6\9E\17\FA\44\B3\9C\31\FE\17\D3\3A\54\FF\4C\E4\C6\F0\FA\DA\EC"; let suite = Suite.suite( "Principal", [ Suite.test( - "toAccount, default sub-account", - Principal.toLedgerAccount(principal, null), - M.equals({ BlobTestable and { item = defaultAccount } }) + "toLedgerAccount, default sub-account 1", + Principal.toLedgerAccount(principal1, null), + M.equals({ BlobTestable and { item = defaultAccount1 } }) + ), + Suite.test( + "toLedgerAccount, with sub-account 1", + Principal.toLedgerAccount(principal1, ?subAccount1), + M.equals({ BlobTestable and { item = accountWithSubAccount1 } }) + ), + Suite.test( + "toAccount, default sub-account 2", + Principal.toLedgerAccount(principal2, null), + M.equals({ BlobTestable and { item = defaultAccount2 } }) ), Suite.test( - "toAccount, with sub-account", - Principal.toLedgerAccount(principal, ?subAccount), - M.equals({ BlobTestable and { item = accountWithSubAccount } }) + "toLedgerAccount, with sub-account 2", + Principal.toLedgerAccount(principal2, ?subAccount2), + M.equals({ BlobTestable and { item = accountWithSubAccount2 } }) ) ] ); From 70e8fab8f1b4c88db0a19b9cd80e141fe74be155 Mon Sep 17 00:00:00 2001 From: Kento Sugama Date: Tue, 26 Sep 2023 14:52:26 -0400 Subject: [PATCH 11/12] factor out separator --- src/Principal.mo | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Principal.mo b/src/Principal.mo index 3e5a76f6..7fa82f51 100644 --- a/src/Principal.mo +++ b/src/Principal.mo @@ -59,8 +59,8 @@ module { /// ``` public func toLedgerAccount(principal : Principal, subAccount : ?Blob) : Blob { let sha224 = SHA224(); - sha224.writeArray([0x0A]); - sha224.writeBlob(Text.encodeUtf8("account-id")); + let accountSeparator : Blob = "\0Aaccount-id"; + sha224.writeBlob(accountSeparator); sha224.writeBlob(toBlob(principal)); switch subAccount { case (?subAccount) { From 2f70dee905cd36fb20a9b30ba37f2d1f55e8214e Mon Sep 17 00:00:00 2001 From: Kento Sugama <107421898+kentosugama@users.noreply.github.com> Date: Tue, 26 Sep 2023 14:54:10 -0400 Subject: [PATCH 12/12] Update comment --- src/Principal.mo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Principal.mo b/src/Principal.mo index 7fa82f51..d1f1d2db 100644 --- a/src/Principal.mo +++ b/src/Principal.mo @@ -296,7 +296,7 @@ module { /** * SHA224 Utilities used in toAccount(). * Utilities are not exposed as public functions. - * Taken from https://github.com/research-ag/sha2 + * Taken with permission from https://github.com/research-ag/sha2 **/ let K00 : Nat32 = 0x428a2f98; let K01 : Nat32 = 0x71374491;