diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f10761d..9c5018f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,7 +12,7 @@ jobs: - uses: actions/setup-go@v1 with: - go-version: 1.17 + go-version: 1.21 - name: Run Tests run: | diff --git a/README.md b/README.md index 11ff0da..e24ff2f 100644 --- a/README.md +++ b/README.md @@ -8,12 +8,7 @@ It contains the following general packages: - `bip39` implements the [BIP-39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) specification and mnemonic [word lists](https://github.com/bitcoin/bips/blob/master/bip-0039/bip-0039-wordlists.md). - `bech32` implements Bech32 addresses based on the format described in [BIP-173](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki). - `ed25519` implements Ed25519 signatures with particular validation rules around edge cases as described in [ZIP-215](https://zips.z.cash/zip-0215). -- `curl` implements the Curl ternary hash function in its batched mode. It relies on [`avo`](https://github.com/mmcloughlin/avo) to generate high-performance x86 assembly. - `merkle` implements a simple Merkle tree hash. -- `pow` implements the Curl-based proof of work for arbitrary binary data as mentioned in [TIP-12](https://iotaledger.github.io/tips/tips/TIP-0012/tip-0012.html). -- `encoding/b1t6` implements the binary-to-ternary encoding which uses 6 trits to represent each byte. -- `encoding/b1t8` implements the binary-to-ternary encoding which uses 8 trits to represent each byte. -- `migration` implements the migration address computation as described in this document: https://hackmd.io/@wollac/H1tZoCK0w All these packages are tested against the full test vectors provided in the corresponding specifications. @@ -21,9 +16,7 @@ All these packages are tested against the full test vectors provided in the corr - `bech32` encode and decode addresses using the bech32 address scheme.
Run the example with `go run examples/bech32/main.go` and use `-help` to see the available commands. - `kdf` shows the private and public key derivation using SLIP-10 and BIP-39 mnemonics + passphrase.
-It performs the legacy IOTA seed derivation (as implemented in the Ledger App) based on BIP-32 and the Ed25519 key derivation following SLIP-10.
+It performs the Ed25519 key derivation following SLIP-10.
Run with `go run examples/kdf/main.go` and use `-help` to see the available command-line flags. - `merkle` prints the Merkle tree of several random transaction hashes on the console.
Run with `go run examples/merkle/main.go` and use `-help` to see the available command-line flags. -- `mnemseed` presents the extension of BIP-0039 to decode and encode 81-tryte legacy IOTA seeds using mnemonics.
-Run with `go run examples/mnemseed/main.go` and use `-help` to see the available command-line flags. diff --git a/examples/bech32/main.go b/examples/bech32/main.go index a20fca3..64c70e0 100644 --- a/examples/bech32/main.go +++ b/examples/bech32/main.go @@ -8,10 +8,10 @@ import ( "os" "strings" - "github.com/wollac/iota-crypto-demo/internal/rand" - "github.com/wollac/iota-crypto-demo/pkg/bech32" - "github.com/wollac/iota-crypto-demo/pkg/bech32/address" - "github.com/wollac/iota-crypto-demo/pkg/ed25519" + "github.com/iotaledger/iota-crypto-demo/internal/rand" + "github.com/iotaledger/iota-crypto-demo/pkg/bech32" + "github.com/iotaledger/iota-crypto-demo/pkg/bech32/address" + "github.com/iotaledger/iota-crypto-demo/pkg/ed25519" ) // default values diff --git a/examples/kdf/main.go b/examples/kdf/main.go index d4d53b7..dd71291 100644 --- a/examples/kdf/main.go +++ b/examples/kdf/main.go @@ -7,16 +7,11 @@ import ( "os" "strings" - "github.com/iotaledger/iota.go/consts" - "github.com/iotaledger/iota.go/kerl" - "github.com/iotaledger/iota.go/kerl/sha3" - "github.com/iotaledger/iota.go/trinary" - "github.com/wollac/iota-crypto-demo/pkg/bech32/address" - "github.com/wollac/iota-crypto-demo/pkg/bip32path" - "github.com/wollac/iota-crypto-demo/pkg/bip39" - "github.com/wollac/iota-crypto-demo/pkg/slip10" - "github.com/wollac/iota-crypto-demo/pkg/slip10/eddsa" - "github.com/wollac/iota-crypto-demo/pkg/slip10/elliptic" + "github.com/iotaledger/iota-crypto-demo/pkg/bech32/address" + "github.com/iotaledger/iota-crypto-demo/pkg/bip32path" + "github.com/iotaledger/iota-crypto-demo/pkg/bip39" + "github.com/iotaledger/iota-crypto-demo/pkg/slip10" + "github.com/iotaledger/iota-crypto-demo/pkg/slip10/eddsa" ) var ( @@ -94,25 +89,10 @@ func run() error { fmt.Printf(" optional passphrase:\t\"%s\"\n", *passphrase) fmt.Printf(" master seed (%d-byte):\t%x\n", len(seed), seed) - fmt.Println("\n==> Legacy IOTA Seed Derivation (Ledger App)") - - curve := elliptic.Secp256k1() - key, err := slip10.DeriveKeyFromPath(seed, curve, path) - if err != nil { - return fmt.Errorf("failed deriving %s key: %w", curve.Name(), err) - } - - fmt.Printf(" SLIP-10 curve seed:\t%s\n", curve.HmacKey()) - fmt.Printf(" SLIP-10 address path:\t%s\n", path) - - fmt.Printf(" private key (%d-byte):\t%x\n", slip10.PrivateKeySize, key.Key) - fmt.Printf(" chain code (%d-byte):\t%x\n", slip10.ChainCodeSize, key.ChainCode) - fmt.Printf(" IOTA seed (%d-tryte):\t%s\n", consts.HashTrytesSize, iotaSeedFromKey(key)) - fmt.Println("\n==> Ed25519 Private Key Derivation") - curve = eddsa.Ed25519() - key, err = slip10.DeriveKeyFromPath(seed, curve, path) + curve := eddsa.Ed25519() + key, err := slip10.DeriveKeyFromPath(seed, curve, path) if err != nil { return fmt.Errorf("failed deriving %s key: %w", curve.Name(), err) } @@ -143,27 +123,3 @@ func generateEntropy(size int) ([]byte, error) { } return entropy, nil } - -// Legacy IOTA seed derivation as implemented in the blue-app-iota: -// https://github.com/IOTA-Ledger/blue-app-iota/blob/master/docs/specification.md#iota-seed -func iotaSeedFromKey(key *slip10.ExtendedKey) trinary.Hash { - // the 512 bits extended private key (k, c) of the provided address path is then hashed using Keccak-384. - hash := sha3.NewLegacyKeccak384() - - k := key.Key.Bytes() - c := key.ChainCode - - // as Kerl usually expects multiples of 48 bytes as input, the following 98 bytes are absorbed: - // k[0:32] + c[0:16] + k[16:32] + c[0:32] - hash.Write(k[0:32]) - hash.Write(c[0:16]) - hash.Write(k[16:32]) - hash.Write(c[0:32]) - - // derive the final 243 trit IOTA seed from the resulting hash - seed, err := kerl.KerlBytesToTrytes(hash.Sum(nil)) - if err != nil { - panic(err) - } - return seed -} diff --git a/examples/merkle/README.md b/examples/merkle/README.md index 658624a..6501c19 100644 --- a/examples/merkle/README.md +++ b/examples/merkle/README.md @@ -1,37 +1,34 @@ -Print the Merkle tree (as described in the IOTA protocol RFC-0012) of several random transaction hashes on the console. +Print the Merkle tree (as described in the IOTA protocol RFC-0012 for Chrysalis part 2) of several random message IDs on the console. ``` -go run examples/merkle/main.go -hashes 7 - -==> input tx hashes - d[0]: NOBKDFGZMOWYUKDZITTWBRWA9YPSXCVFENCQFPC9GMJIAIPSSURYIOMYZLGNZXLUAQHHNBSRHNOIJDYZO - d[1]: IPATPTEZSBMFJRDCRPTCVUQWBAVCAXAVZIDEDL9TSILDFWDMIIFPZIYHKRFFZDYQNKBQBVGYSKMLCYBMR - d[2]: MXOIOFOGLIHCHMDRCWAIYCWIUCMGEZWXFJZFWBRCNSNBWIGFJXBCACPKMLLANYNXSGYKANYFTVGTLFXXX - d[3]: EXZTJAXJMZJBBIZGUTMBOEUQDNVHJPXCLFUXNLPLSBATDMKYUZOFMHCOBWUABYDMNGMKIXLIUFXNVY9PN - d[4]: SJXYVFUDCDPPAOALVXDQUKAWLLOQO99OSJQT9TUNILQ9VLFLCZMLZAKUTIZFHOLPMGPYHKMMUUSURIOCF - d[5]: Q9GHMAITEZCWKFIESJARYQYMF9XWFPQTTFRXULLHQDWEZLYBSFYHSLPXEHBORDDFYZRFYFGDCM9VJKEFR - d[6]: GMNECTSPSLSPPEITCHBXSN9KZD9OZPVPOET9TVQJDZMFGN9SGPRPMUQARNXUVKMWAFAKLKWBZLWZCTPCP +==> input message ids + d[0]: 52fdfc072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c649 + d[1]: 81855ad8681d0d86d1e91e00167939cb6694d2c422acd208a0072939487f6999 + d[2]: eb9d18a44784045d87f3c67cf22746e995af5a25367951baa2ff6cd471c483f1 + d[3]: 5fb90badb37c5821b6d95526a41a9504680b4e7c8b763a1b1d49d4955c848621 + d[4]: 6325253fec738dd7a9e28bf921119c160f0702448615bbda08313f6a8eb668d2 + d[5]: 0bf5059875921e668a5bdf2c7fc4844592d2572bcd0668d2d6c52f5054e2d083 + d[6]: 6bf84c7174cb7476364cc3dbd968b0f7172ed85794bb358b0c3b525da1786f9f ==> Merkle tree with 7 leafs - Htri: FYEDPDNYFXZB9XHXQZDXP9CXV9YAUWEYEDKCNYIWW9MWXBHYEXTWVDBXWZQAGDWYT9PBHZTBWC9YYWTYBDTWCAMZMDLWRYHWUXZZJ9QAHBKWDCKAI9C9LBDWVWMV9ZDB - root: d07161bdb535afb7dbb3f5b2fb198ecf715cbd9dfca133d2b48d67b1e11173c6f92bed2f4dca92c36e8d1ef279a0c19ca9e40a113e9f5526090342988f86e53a - ├─ node: 1448659e74c870013900a3012842b1e5fb2cfecde299d7bbe272ce0968b95546f7bbce242ebd39cd7ea965bd25c51e007212ecd999af17530ef68843311ef403 - │ ├─ node: ea4f73b420757c426e5f166066d9207ca4a49f878a1ba6d420367c7f9b946b6dcb35121b619c374a0a8b647623b391c54087b29401d2a9bc864b9816a53cdf27 - │ │ │ ┌ tx hash: NOBKDFGZMOWYUKDZITTWBRWA9YPSXCVFENCQFPC9GMJIAIPSSURYIOMYZLGNZXLUAQHHNBSRHNOIJDYZO - │ │ ├──┴ leaf: 470afd417b1b3cdd4d876f1e636cb41e5a0f2c38d2160348cf0b8971144e5d20b118c08c3f65956f8d98949bf89bea8da3b34fa2cab1fba299512a9e573c0854 - │ │ │ ┌ tx hash: IPATPTEZSBMFJRDCRPTCVUQWBAVCAXAVZIDEDL9TSILDFWDMIIFPZIYHKRFFZDYQNKBQBVGYSKMLCYBMR - │ │ └──┴ leaf: efefcba97952a5cad857b53f015c3d95c6c38ef9cc97b4b622a9f9f56b396627a6c3fd6f737428ed9c1487e834abedf83561f58c356071279068bdd53b85ffa8 - │ └─ node: 183cc0b9a79965986a12003af8b0be0ee3c3980853a99fb571a39fa394f56cb071db6487029b4d7c6ecdb72ae65fafa9e446c0bdca0f18c7f1eeea5170f5aca4 - │ │ ┌ tx hash: MXOIOFOGLIHCHMDRCWAIYCWIUCMGEZWXFJZFWBRCNSNBWIGFJXBCACPKMLLANYNXSGYKANYFTVGTLFXXX - │ ├──┴ leaf: 95200ea45cebbe7b582cf23caf53224be98be9a553d4801ed804715afeb9b4b0db4c6a4b3de9852d2cef0712144196c18a7290936fea48208fb417b8d6fe56d0 - │ │ ┌ tx hash: EXZTJAXJMZJBBIZGUTMBOEUQDNVHJPXCLFUXNLPLSBATDMKYUZOFMHCOBWUABYDMNGMKIXLIUFXNVY9PN - │ └──┴ leaf: b162e61d41a83ec238871d2a3ed2fbcfea5001b04b363c704bd3a29923ccfc701850ed9911bad3cf9bcb11c510955f8a16ff06f6cbe8d8c887275a83e9232483 - └─ node: 7ee54d71bd7958241bfba8a7817fe8eff006d5d7a84edc7358d0ce5639fc9a6cbf38e77bb96656e37189be922fc04090a5a306988f4d1060c2e4f011ff0b7470 - ├─ node: f2a80742a2b9f03cbf54878c50c6d79df79fe53809de55f236e9ce45f82a2ed9d4bb3a41f6254e2a24955bd6ce7cde5ff6178836029902819de20d0fce3add87 - │ │ ┌ tx hash: SJXYVFUDCDPPAOALVXDQUKAWLLOQO99OSJQT9TUNILQ9VLFLCZMLZAKUTIZFHOLPMGPYHKMMUUSURIOCF - │ ├──┴ leaf: a32b588ed56c6823ab9677c5c910b274886b8bd49db9e3a5af24bddbad83dd2b801c744c3b690c99dab3d33a156bb076b4c047163010064235b9268568121e78 - │ │ ┌ tx hash: Q9GHMAITEZCWKFIESJARYQYMF9XWFPQTTFRXULLHQDWEZLYBSFYHSLPXEHBORDDFYZRFYFGDCM9VJKEFR - │ └──┴ leaf: 7405aa17eaec13f23b9dc2faf635bf2688bdb7582296880453a930b0716265c93a12b823d5b2ed0a62459f80df3f347b44e7a8d290ff6c1051f34afe63d3827d - │ ┌ tx hash: GMNECTSPSLSPPEITCHBXSN9KZD9OZPVPOET9TVQJDZMFGN9SGPRPMUQARNXUVKMWAFAKLKWBZLWZCTPCP - └──┴ leaf: 282f3dc49046480e118f697bc90d37f19efb633d6e92cb27e53c4a3c69735e6e66e698b810c20e8e7c4d5b5f0b04946fc779a0c817ee587c01f80e44d3e69f84 + root: bf67ce7ba23e8c0951b5abaec4f5524360d2c26d971ff226d3359fa70cdb0beb + ├─ node: 03bcbb3cf4314eab2f5ae68c767ff0a5fec4573c865728231f71d596fd867b56 + │ ├─ node: ae4505f4cfae93586e23958ca88d35d2f34d43def49786b6d0d4224b819f4cda + │ │ │ ┌ msg id: 52fdfc072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c649 + │ │ ├──┴ leaf: 3d1399c64ff0ae6a074afa4cd2ce4eab8d5c499c1da6afdd1d84b7447cc00544 + │ │ │ ┌ msg id: 81855ad8681d0d86d1e91e00167939cb6694d2c422acd208a0072939487f6999 + │ │ └──┴ leaf: 83b0b255014e9a3656f0004a3f17943a20b715ef9c3e7cb85a6b2abac15e00d0 + │ └─ node: 54d51291aca22ce5b04cd3e6584fa3026ebe86ef86f0a6dfb47ab843801d4b38 + │ │ ┌ msg id: eb9d18a44784045d87f3c67cf22746e995af5a25367951baa2ff6cd471c483f1 + │ ├──┴ leaf: ad4bc0a34b27f37810f2ff3a8177ecc98402f8f59a06270f9d285fdf764e45fe + │ │ ┌ msg id: 5fb90badb37c5821b6d95526a41a9504680b4e7c8b763a1b1d49d4955c848621 + │ └──┴ leaf: ffb3a7c6bea8f9fdcfb26f4701ad6e912a6076e1a40663607dbe110ebfc9a571 + └─ node: ce22d5bc728023e7ab6a9eb8f58baf62b9565fc8baeef4b377daa6709dbe598c + ├─ node: e14c8af1258005cd0dbed88f0c5885c6988f319bb8f24272a7495592b873c169 + │ │ ┌ msg id: 6325253fec738dd7a9e28bf921119c160f0702448615bbda08313f6a8eb668d2 + │ ├──┴ leaf: 1c062628a7a147cc6a4defa655ce6c4ae5b838b4b4cd81b12e8924b5b4b5cca6 + │ │ ┌ msg id: 0bf5059875921e668a5bdf2c7fc4844592d2572bcd0668d2d6c52f5054e2d083 + │ └──┴ leaf: 2ef4e2ad06b8c8ae1fd4b28b5ed166829533fbfff1f6c14218358537da277fa3 + │ ┌ msg id: 6bf84c7174cb7476364cc3dbd968b0f7172ed85794bb358b0c3b525da1786f9f + └──┴ leaf: 7ec774ebc33ed4ca298e8a1cf1f569e36c6784467d63b055efd7612abe2858a4 ``` \ No newline at end of file diff --git a/examples/merkle/main.go b/examples/merkle/main.go index 0fb2c29..423e95c 100644 --- a/examples/merkle/main.go +++ b/examples/merkle/main.go @@ -3,18 +3,16 @@ package main import ( "crypto" "encoding" + "encoding/hex" "flag" "fmt" "math/bits" "math/rand" "strings" - "github.com/iotaledger/iota.go/consts" - "github.com/iotaledger/iota.go/encoding/t5b1" - "github.com/iotaledger/iota.go/trinary" - "github.com/wollac/iota-crypto-demo/pkg/merkle" + "github.com/iotaledger/iota-crypto-demo/pkg/merkle" - _ "golang.org/x/crypto/blake2b" // BLAKE2b_512 is the default hashing algorithm + _ "golang.org/x/crypto/blake2b" // BLAKE2b_256 is the default hashing algorithm ) var ( @@ -25,34 +23,35 @@ var ( ) ) -type Hash trinary.Hash +type ID [32]byte -func (h Hash) MarshalBinary() ([]byte, error) { return t5b1.EncodeTrytes(trinary.Trytes(h)), nil } -func (h Hash) String() string { return string(h) } +func (i ID) MarshalBinary() ([]byte, error) { + return i[:], nil +} + +func (i ID) String() string { + return hex.EncodeToString(i[:]) +} func main() { flag.Parse() - var hashes []encoding.BinaryMarshaler + var data []encoding.BinaryMarshaler for i := 0; i < *numHashes; i++ { - hashes = append(hashes, randomHash(consts.HashTrytesSize)) + data = append(data, randomID()) } - fmt.Println("==> input tx hashes") - for i := range hashes { - fmt.Printf(" d[%d]: %s\n", i, hashes[i]) + fmt.Println("==> input message ids") + for i := range data { + fmt.Printf(" d[%d]: %s\n", i, data[i]) } - fmt.Printf("\n==> Merkle tree with %d leafs\n", len(hashes)) - printTree(merkle.NewHasher(crypto.BLAKE2b_512), hashes) + fmt.Printf("\n==> Merkle tree with %d leafs\n", len(data)) + printTree(merkle.NewHasher(crypto.BLAKE2b_256), data) } -func randomHash(n int) Hash { - var trytes strings.Builder - trytes.Grow(n) - for i := 0; i < n; i++ { - trytes.WriteByte(consts.TryteAlphabet[rand.Intn(len(consts.TryteAlphabet))]) - } - return Hash(trytes.String()) +func randomID() (id ID) { + rand.Read(id[:]) + return id } // printTree pretty prints the Merkle tree. diff --git a/examples/merkle/pt2/README.md b/examples/merkle/pt2/README.md deleted file mode 100644 index 6501c19..0000000 --- a/examples/merkle/pt2/README.md +++ /dev/null @@ -1,34 +0,0 @@ -Print the Merkle tree (as described in the IOTA protocol RFC-0012 for Chrysalis part 2) of several random message IDs on the console. - -``` -==> input message ids - d[0]: 52fdfc072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c649 - d[1]: 81855ad8681d0d86d1e91e00167939cb6694d2c422acd208a0072939487f6999 - d[2]: eb9d18a44784045d87f3c67cf22746e995af5a25367951baa2ff6cd471c483f1 - d[3]: 5fb90badb37c5821b6d95526a41a9504680b4e7c8b763a1b1d49d4955c848621 - d[4]: 6325253fec738dd7a9e28bf921119c160f0702448615bbda08313f6a8eb668d2 - d[5]: 0bf5059875921e668a5bdf2c7fc4844592d2572bcd0668d2d6c52f5054e2d083 - d[6]: 6bf84c7174cb7476364cc3dbd968b0f7172ed85794bb358b0c3b525da1786f9f - -==> Merkle tree with 7 leafs - root: bf67ce7ba23e8c0951b5abaec4f5524360d2c26d971ff226d3359fa70cdb0beb - ├─ node: 03bcbb3cf4314eab2f5ae68c767ff0a5fec4573c865728231f71d596fd867b56 - │ ├─ node: ae4505f4cfae93586e23958ca88d35d2f34d43def49786b6d0d4224b819f4cda - │ │ │ ┌ msg id: 52fdfc072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c649 - │ │ ├──┴ leaf: 3d1399c64ff0ae6a074afa4cd2ce4eab8d5c499c1da6afdd1d84b7447cc00544 - │ │ │ ┌ msg id: 81855ad8681d0d86d1e91e00167939cb6694d2c422acd208a0072939487f6999 - │ │ └──┴ leaf: 83b0b255014e9a3656f0004a3f17943a20b715ef9c3e7cb85a6b2abac15e00d0 - │ └─ node: 54d51291aca22ce5b04cd3e6584fa3026ebe86ef86f0a6dfb47ab843801d4b38 - │ │ ┌ msg id: eb9d18a44784045d87f3c67cf22746e995af5a25367951baa2ff6cd471c483f1 - │ ├──┴ leaf: ad4bc0a34b27f37810f2ff3a8177ecc98402f8f59a06270f9d285fdf764e45fe - │ │ ┌ msg id: 5fb90badb37c5821b6d95526a41a9504680b4e7c8b763a1b1d49d4955c848621 - │ └──┴ leaf: ffb3a7c6bea8f9fdcfb26f4701ad6e912a6076e1a40663607dbe110ebfc9a571 - └─ node: ce22d5bc728023e7ab6a9eb8f58baf62b9565fc8baeef4b377daa6709dbe598c - ├─ node: e14c8af1258005cd0dbed88f0c5885c6988f319bb8f24272a7495592b873c169 - │ │ ┌ msg id: 6325253fec738dd7a9e28bf921119c160f0702448615bbda08313f6a8eb668d2 - │ ├──┴ leaf: 1c062628a7a147cc6a4defa655ce6c4ae5b838b4b4cd81b12e8924b5b4b5cca6 - │ │ ┌ msg id: 0bf5059875921e668a5bdf2c7fc4844592d2572bcd0668d2d6c52f5054e2d083 - │ └──┴ leaf: 2ef4e2ad06b8c8ae1fd4b28b5ed166829533fbfff1f6c14218358537da277fa3 - │ ┌ msg id: 6bf84c7174cb7476364cc3dbd968b0f7172ed85794bb358b0c3b525da1786f9f - └──┴ leaf: 7ec774ebc33ed4ca298e8a1cf1f569e36c6784467d63b055efd7612abe2858a4 -``` \ No newline at end of file diff --git a/examples/merkle/pt2/main.go b/examples/merkle/pt2/main.go deleted file mode 100644 index 1bbaeeb..0000000 --- a/examples/merkle/pt2/main.go +++ /dev/null @@ -1,107 +0,0 @@ -package main - -import ( - "crypto" - "encoding" - "encoding/hex" - "flag" - "fmt" - "math/bits" - "math/rand" - "strings" - - "github.com/wollac/iota-crypto-demo/pkg/merkle" - - _ "golang.org/x/crypto/blake2b" // BLAKE2b_256 is the default hashing algorithm -) - -var ( - numHashes = flag.Int( - "hashes", - 7, - "number of random bundle hashes to be combined", - ) -) - -type ID [32]byte - -func (i ID) MarshalBinary() ([]byte, error) { - return i[:], nil -} - -func (i ID) String() string { - return hex.EncodeToString(i[:]) -} - -func main() { - flag.Parse() - - var data []encoding.BinaryMarshaler - for i := 0; i < *numHashes; i++ { - data = append(data, randomID()) - } - - fmt.Println("==> input message ids") - for i := range data { - fmt.Printf(" d[%d]: %s\n", i, data[i]) - } - fmt.Printf("\n==> Merkle tree with %d leafs\n", len(data)) - printTree(merkle.NewHasher(crypto.BLAKE2b_256), data) -} - -func randomID() (id ID) { - rand.Read(id[:]) - return id -} - -// printTree pretty prints the Merkle tree. -func printTree(h *merkle.Hasher, leafs []encoding.BinaryMarshaler) { - root, _ := h.Hash(leafs) - fmt.Printf(" root: %x\n", root) - printNode(buildTree(h, leafs), "") -} - -type node struct { - text string - children []*node -} - -func buildTree(h *merkle.Hasher, leafs []encoding.BinaryMarshaler) *node { - if len(leafs) == 0 { - return &node{text: fmt.Sprintf(" %x", h.EmptyRoot())} - } - if len(leafs) == 1 { - leafHash, _ := h.Hash([]encoding.BinaryMarshaler{leafs[0]}) - return &node{text: fmt.Sprintf(" ┌ msg id: %s\n─┴ leaf: %x", leafs[0], leafHash)} - } - // largest power of two less than n, i.e. k < n <= 2k - k := 1 << (bits.Len(uint(len(leafs)-1)) - 1) - l, r := leafs[:k], leafs[k:] - nodeHash, _ := h.Hash(leafs) - return &node{ - text: fmt.Sprintf(" node: %x", nodeHash), - children: []*node{buildTree(h, l), buildTree(h, r)}, - } -} - -func printNode(n *node, parentPrefix string) { - var prefixes = [][]string{{" ├─", " │ "}, {" └─", " "}} - - for i := range n.children { - var p []string - if i < len(n.children)-1 { - p = prefixes[0] - } else { - p = prefixes[1] - } - lines := strings.Split(n.children[i].text, "\n") - for j, line := range lines { - if j < len(lines)-1 { - fmt.Println(" " + parentPrefix + prefixes[0][1] + line) - } else { - fmt.Println(" " + parentPrefix + p[0] + line) - } - } - printNode(n.children[i], parentPrefix+p[1]) - } -} diff --git a/examples/migration/main.go b/examples/migration/main.go deleted file mode 100644 index e068520..0000000 --- a/examples/migration/main.go +++ /dev/null @@ -1,67 +0,0 @@ -package main - -import ( - "encoding/hex" - "flag" - "fmt" - "os" - - "github.com/iotaledger/iota.go/checksum" - "github.com/iotaledger/iota.go/consts" - "github.com/wollac/iota-crypto-demo/internal/rand" - "github.com/wollac/iota-crypto-demo/pkg/ed25519" - "github.com/wollac/iota-crypto-demo/pkg/migration" - "golang.org/x/crypto/blake2b" -) - -var ( - ed25519Address = flag.String( - "address", - "", - "Ed25519 address as hex; if empty a new random address is generated", - ) -) - -func main() { - flag.Parse() - - if err := run(); err != nil { - fmt.Fprintf(os.Stderr, "Error: %s\n", err) - os.Exit(1) - } -} - -func run() (err error) { - if len(*ed25519Address) == 0 { - *ed25519Address, err = randomAddress() - if err != nil { - return err - } - } - addressBytes, err := hex.DecodeString(*ed25519Address) - if err != nil { - return fmt.Errorf("failed to decode address: %w", err) - } - - var addr [32]byte - copy(addr[:], addressBytes) - migAddr, err := checksum.AddChecksum(migration.Encode(addr), true, consts.AddressChecksumTrytesSize) - if err != nil { - return fmt.Errorf("failed to compute address checksum: %w", err) - } - - fmt.Println("==> Migration Address Encoder") - fmt.Printf(" Ed25519 address (%d-byte):\t%s\n", len(addr), hex.EncodeToString(addr[:])) - fmt.Printf(" Migration address (%d-tryte):\t%s\n", len(migAddr), migAddr) - - return nil -} - -func randomAddress() (string, error) { - pub, _, err := ed25519.GenerateKey(rand.Reader) - if err != nil { - return "", err - } - hash := blake2b.Sum256(pub) - return hex.EncodeToString(hash[:]), nil -} diff --git a/examples/mnemseed/README.md b/examples/mnemseed/README.md deleted file mode 100644 index 98c4924..0000000 --- a/examples/mnemseed/README.md +++ /dev/null @@ -1,10 +0,0 @@ -Represent 81-tryte legacy IOTA seeds using BIP-39 mnemonics. - -``` -go run examples/mnemseed/main.go -language japanese - -==> IOTA Seed Mnemonics - input seed (81-tryte): XRUVXMOQVOFJASPMGMKJID9DASLCCIAPLBKFKHWBGXIOCJLLEJUTEEMKZRJDCTRSBTKHMHDNUYDYEYDZZ - mnemonic (36-word): むらさき ふんしつ もくし みがく はかる てんぷら すごい けんすう いだい なわとび みつける うるさい けおりもの ほかん ねもと かわら ていたい りよう ぎしき こせい げんき にりんしゃ ひつぜん きぞん かいすいよく げぼく ばかり じゃま いこう たいせつ けんげん ふるい いわう たきび こうこう よけい - decoded seed (81-tryte): XRUVXMOQVOFJASPMGMKJID9DASLCCIAPLBKFKHWBGXIOCJLLEJUTEEMKZRJDCTRSBTKHMHDNUYDYEYDZZ -``` diff --git a/examples/mnemseed/main.go b/examples/mnemseed/main.go deleted file mode 100644 index c40e661..0000000 --- a/examples/mnemseed/main.go +++ /dev/null @@ -1,118 +0,0 @@ -package main - -import ( - "crypto/rand" - "flag" - "fmt" - "os" - "strings" - - "github.com/iotaledger/iota.go/consts" - "github.com/iotaledger/iota.go/kerl" - "github.com/iotaledger/iota.go/trinary" - "github.com/wollac/iota-crypto-demo/pkg/bip39" -) - -var ( - seed = flag.String( - "seed", - "", - "IOTA seed; if empty a new random seed is generated", - ) - language = flag.String( - "language", - "english", - "language of the mnemonics", - ) -) - -func main() { - flag.Parse() - - if err := run(); err != nil { - fmt.Fprintf(os.Stderr, "Error: %s\n", err) - os.Exit(1) - } -} - -func run() error { - var err error - - if len(*seed) == 0 { - *seed, err = generateSeed() - if err != nil { - return err - } - } - if err := bip39.SetWordList(strings.ToLower(*language)); err != nil { - return err - } - - mnemonic, err := seedToMnemonic(*seed) - if err != nil { - return fmt.Errorf("failed encoding seed: %w", err) - } - decoded, err := mnemonicToSeed(mnemonic) - if err != nil { - return fmt.Errorf("failed decoding mnemonic: %w", err) - } - - fmt.Println("==> IOTA Seed Mnemonics") - - fmt.Printf(" input seed (%d-tryte):\t\t%s\n", len(*seed), *seed) - fmt.Printf(" mnemonic (%d-word):\t\t%s\n", len(mnemonic), mnemonic) - fmt.Printf(" decoded seed (%d-tryte):\t%s\n", len(decoded), decoded) - - return nil -} - -func seedToMnemonic(seed trinary.Hash) (bip39.Mnemonic, error) { - err := validateSeed(seed) - if err != nil { - return nil, err - } - seedBytes, err := kerl.KerlTrytesToBytes(seed) - if err != nil { - return nil, err - } - mnemonic, err := bip39.EntropyToMnemonic(seedBytes) - if err != nil { - return nil, err - } - return mnemonic, nil -} - -func mnemonicToSeed(mnemonic bip39.Mnemonic) (trinary.Hash, error) { - seedBytes, err := bip39.MnemonicToEntropy(mnemonic) - if err != nil { - return "", err - } - return kerl.KerlBytesToTrytes(seedBytes) -} - -func generateSeed() (trinary.Hash, error) { - entropy := make([]byte, consts.HashBytesSize) - if _, err := rand.Read(entropy); err != nil { - return "", fmt.Errorf("error generating entropy: %s", err) - } - trytes, err := kerl.KerlBytesToTrytes(entropy) - if err != nil { - return "", fmt.Errorf("error converting seed: %s", err) - } - return trytes, nil -} - -func validateSeed(seed trinary.Hash) error { - if len(seed) != consts.HashTrytesSize { - return consts.ErrInvalidTrytesLength - } - if err := trinary.ValidTrytes(seed); err != nil { - return err - } - // a valid hash must have the last trit set to zero - lastTrits := trinary.MustTrytesToTrits(string(seed[consts.HashTrytesSize-1])) - if lastTrits[consts.TritsPerTryte-1] != 0 { - return consts.ErrInvalidHash - } - return nil -} diff --git a/go.mod b/go.mod index 169eee5..9c44655 100644 --- a/go.mod +++ b/go.mod @@ -1,19 +1,17 @@ -module github.com/wollac/iota-crypto-demo +module github.com/iotaledger/iota-crypto-demo -go 1.17 +go 1.21 require ( filippo.io/edwards25519 v1.0.0 - github.com/iotaledger/iota.go v1.0.0 - github.com/stretchr/testify v1.8.1 - golang.org/x/crypto v0.2.0 - golang.org/x/text v0.4.0 + github.com/stretchr/testify v1.8.4 + golang.org/x/crypto v0.16.0 + golang.org/x/text v0.14.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect - github.com/pkg/errors v0.8.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - golang.org/x/sys v0.2.0 // indirect + golang.org/x/sys v0.15.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 67f85eb..74fda07 100644 --- a/go.sum +++ b/go.sum @@ -1,125 +1,18 @@ filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek= filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= -github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dgraph-io/badger v1.5.4/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ= -github.com/dgryski/go-farm v0.0.0-20190323231341-8198c7b169ec/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/iotaledger/iota.go v1.0.0 h1:tqm1FxJ/zOdzbrAaQ5BQpVF8dUy2eeGlSeWlNG8GoXY= -github.com/iotaledger/iota.go v1.0.0/go.mod h1:RiKYwDyY7aCD1L0YRzHSjOsJ5mUR9yvQpvhZncNcGQI= -github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= -github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.2 h1:8mVmC9kjFFmA8H4pKMUhcblgifdkOIXPvbhN1T36q1M= -github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.10.4 h1:NiTx7EEvBzu9sFOD1zORteLSt3o8gnlvZZwSE9TnY9U= -github.com/onsi/gomega v1.10.4/go.mod h1:g/HbgYopi++010VEqkFgJHKC09uJiW9UkXvMUuKHUCQ= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= -github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= -github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.mongodb.org/mongo-driver v1.0.0/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.2.0 h1:BRXPfhNivWL5Yq0BGQ39a2sW6t44aODpfxkWjYdzewE= -golang.org/x/crypto v0.2.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU= -golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= +golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/h2non/gock.v1 v1.0.14/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/pkg/bech32/address/address.go b/pkg/bech32/address/address.go index 45ab11d..3287415 100644 --- a/pkg/bech32/address/address.go +++ b/pkg/bech32/address/address.go @@ -6,8 +6,8 @@ import ( "errors" "fmt" - "github.com/wollac/iota-crypto-demo/pkg/bech32" - "github.com/wollac/iota-crypto-demo/pkg/ed25519" + "github.com/iotaledger/iota-crypto-demo/pkg/bech32" + "github.com/iotaledger/iota-crypto-demo/pkg/ed25519" "golang.org/x/crypto/blake2b" ) diff --git a/pkg/bech32/bech32.go b/pkg/bech32/bech32.go index 3655a86..d778e84 100644 --- a/pkg/bech32/bech32.go +++ b/pkg/bech32/bech32.go @@ -6,7 +6,7 @@ import ( "fmt" "strings" - "github.com/wollac/iota-crypto-demo/pkg/bech32/internal/base32" + "github.com/iotaledger/iota-crypto-demo/pkg/bech32/internal/base32" ) const ( diff --git a/pkg/bech32/bech32_test.go b/pkg/bech32/bech32_test.go index 967a4e1..82e972a 100644 --- a/pkg/bech32/bech32_test.go +++ b/pkg/bech32/bech32_test.go @@ -6,8 +6,8 @@ import ( "fmt" "testing" + "github.com/iotaledger/iota-crypto-demo/pkg/bech32/internal/base32" "github.com/stretchr/testify/assert" - "github.com/wollac/iota-crypto-demo/pkg/bech32/internal/base32" ) func TestEncode(t *testing.T) { diff --git a/pkg/bip39/bip39.go b/pkg/bip39/bip39.go index 4cc098c..7fcbd9c 100644 --- a/pkg/bip39/bip39.go +++ b/pkg/bip39/bip39.go @@ -22,8 +22,8 @@ import ( "log" "math/big" - "github.com/wollac/iota-crypto-demo/pkg/bip39/internal/wordlists" - "github.com/wollac/iota-crypto-demo/pkg/bip39/wordlist" + "github.com/iotaledger/iota-crypto-demo/pkg/bip39/internal/wordlists" + "github.com/iotaledger/iota-crypto-demo/pkg/bip39/wordlist" "golang.org/x/crypto/pbkdf2" "golang.org/x/text/unicode/norm" ) diff --git a/pkg/bip39/bip39_test.go b/pkg/bip39/bip39_test.go index cb1ec7d..8ff2d29 100644 --- a/pkg/bip39/bip39_test.go +++ b/pkg/bip39/bip39_test.go @@ -9,9 +9,9 @@ import ( "strings" "testing" + "github.com/iotaledger/iota-crypto-demo/internal/hexutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/wollac/iota-crypto-demo/internal/hexutil" ) type Test struct { diff --git a/pkg/bip39/internal/wordlists/english.go b/pkg/bip39/internal/wordlists/english.go index b49a551..d753461 100644 --- a/pkg/bip39/internal/wordlists/english.go +++ b/pkg/bip39/internal/wordlists/english.go @@ -1,7 +1,7 @@ package wordlists import ( - "github.com/wollac/iota-crypto-demo/pkg/bip39/wordlist" + "github.com/iotaledger/iota-crypto-demo/pkg/bip39/wordlist" ) // English returns the mnemonic word list for the English language taken from the BIP-39 specification. diff --git a/pkg/bip39/internal/wordlists/japanese.go b/pkg/bip39/internal/wordlists/japanese.go index 71fbe3c..0d4ac64 100644 --- a/pkg/bip39/internal/wordlists/japanese.go +++ b/pkg/bip39/internal/wordlists/japanese.go @@ -1,7 +1,7 @@ package wordlists import ( - "github.com/wollac/iota-crypto-demo/pkg/bip39/wordlist" + "github.com/iotaledger/iota-crypto-demo/pkg/bip39/wordlist" ) // Japanese returns the mnemonic word list for the Japanese language taken from the BIP-39 specification. diff --git a/pkg/bip39/internal/wordlists/wordlist.go b/pkg/bip39/internal/wordlists/wordlist.go index a00fffe..4b83a5e 100644 --- a/pkg/bip39/internal/wordlists/wordlist.go +++ b/pkg/bip39/internal/wordlists/wordlist.go @@ -4,7 +4,7 @@ import ( "fmt" "strings" - "github.com/wollac/iota-crypto-demo/pkg/bip39/wordlist" + "github.com/iotaledger/iota-crypto-demo/pkg/bip39/wordlist" ) type wordList struct { diff --git a/pkg/bip39/register.go b/pkg/bip39/register.go index 18afbaa..24bd00a 100644 --- a/pkg/bip39/register.go +++ b/pkg/bip39/register.go @@ -3,7 +3,7 @@ package bip39 import ( "fmt" - "github.com/wollac/iota-crypto-demo/pkg/bip39/wordlist" + "github.com/iotaledger/iota-crypto-demo/pkg/bip39/wordlist" ) var wordLists = make(map[string]func() wordlist.List) diff --git a/pkg/curl/asm/go.mod b/pkg/curl/asm/go.mod deleted file mode 100644 index b6e4265..0000000 --- a/pkg/curl/asm/go.mod +++ /dev/null @@ -1,10 +0,0 @@ -module github.com/wollac/iota-crypto-demo/pkg/curl/asm - -go 1.17 - -require ( - github.com/mmcloughlin/avo v0.4.0 - github.com/wollac/iota-crypto-demo v0.0.0 -) - -replace github.com/wollac/iota-crypto-demo => ../../../ diff --git a/pkg/curl/asm/go.sum b/pkg/curl/asm/go.sum deleted file mode 100644 index 768e04a..0000000 --- a/pkg/curl/asm/go.sum +++ /dev/null @@ -1,125 +0,0 @@ -filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= -github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dgraph-io/badger v1.5.4/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ= -github.com/dgryski/go-farm v0.0.0-20190323231341-8198c7b169ec/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/iotaledger/iota.go v1.0.0 h1:tqm1FxJ/zOdzbrAaQ5BQpVF8dUy2eeGlSeWlNG8GoXY= -github.com/iotaledger/iota.go v1.0.0/go.mod h1:RiKYwDyY7aCD1L0YRzHSjOsJ5mUR9yvQpvhZncNcGQI= -github.com/mmcloughlin/avo v0.4.0 h1:jeHDRktVD+578ULxWpQHkilor6pkdLF7u7EiTzDbfcU= -github.com/mmcloughlin/avo v0.4.0/go.mod h1:RW9BfYA3TgO9uCdNrKU2h6J8cPD8ZLznvfgHAeszb1s= -github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= -github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.2 h1:8mVmC9kjFFmA8H4pKMUhcblgifdkOIXPvbhN1T36q1M= -github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.10.4 h1:NiTx7EEvBzu9sFOD1zORteLSt3o8gnlvZZwSE9TnY9U= -github.com/onsi/gomega v1.10.4/go.mod h1:g/HbgYopi++010VEqkFgJHKC09uJiW9UkXvMUuKHUCQ= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= -github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= -github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= -github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -go.mongodb.org/mongo-driver v1.0.0/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= -golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20220824171710-5757bc0c5503/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211030160813-b3129d9d1021 h1:giLT+HuUP/gXYrG2Plg9WTjj4qhfgaW424ZIFog3rlk= -golang.org/x/sys v0.0.0-20211030160813-b3129d9d1021/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= -golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/h2non/gock.v1 v1.0.14/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/pkg/curl/asm/transform_amd64_asm.go b/pkg/curl/asm/transform_amd64_asm.go deleted file mode 100644 index d855e42..0000000 --- a/pkg/curl/asm/transform_amd64_asm.go +++ /dev/null @@ -1,154 +0,0 @@ -package main - -import ( - . "github.com/mmcloughlin/avo/build" - . "github.com/mmcloughlin/avo/operand" - . "github.com/mmcloughlin/avo/reg" - "github.com/wollac/iota-crypto-demo/pkg/curl" -) - -const unroll = 2 - -//go:generate go run transform_amd64_asm.go -out ../transform_amd64.s -stubs ../transform_amd64.go -pkg curl - -func main() { - Package("github.com/wollac/iota-crypto-demo/pkg/curl") - ConstraintExpr("amd64,gc,!purego") - transform() - Generate() -} - -func transform() { - TEXT("transform", NOSPLIT, "func(lto, hto, lfrom, hfrom *[StateSize]uint)") - Doc("transform transforms the sponge state. It works like transformGeneric.") - Pragma("noescape") - - to := bctMem{ - name: "to", - l: Mem{Base: Load(Param("lto"), GP64())}, - h: Mem{Base: Load(Param("hto"), GP64())}, - } - from := bctMem{ - name: "from", - l: Mem{Base: Load(Param("lfrom"), GP64())}, - h: Mem{Base: Load(Param("hfrom"), GP64())}, - } - - r := GP64() - MOVQ(U32(curl.NumRounds), r) - - Label("RoundLoop") - - stateLoop(from, to) - - Comment("swap buffers") - XCHGQ(from.l.Base, to.l.Base) - XCHGQ(from.h.Base, to.h.Base) - - DECQ(r) - JNZ(LabelRef("RoundLoop")) - - RET() -} - -func stateLoop(src, dst bctMem) { - blockSize := 2 * unroll - // the number of unrolled iterations must be even (as sBox swaps high and low) - // and the state size must be divisible by the unrolled block - if (curl.StateSize-1)%blockSize != 0 { - panic("invalid unroll") - } - - a := bct{"a", GP64(), GP64()} - src.Load(0, a) - b := bct{"b", GP64(), GP64()} - src.Load(364, b) - dst.Store(sBox(a, b), 0) - - t := namedRegister{GP64(), "t"} - MOVQ(U32(364), t) - - i := namedRegister{GP64(), "i"} - MOVQ(U32(1), i) - - Label("StateLoop") - offset := 0 - for u := 0; u < blockSize; u += 2 { - offset += 364 - src.LoadIdx(t, offset, a) - dst.StoreIdx(sBox(b, a), i, u) - - offset -= 365 - src.LoadIdx(t, offset, b) - dst.StoreIdx(sBox(a, b), i, u+1) - } - SUBQ(U32(-offset), t) - - // loop through the entire state - ADDQ(U32(blockSize), i) - CMPQ(i, U32(curl.StateSize)) - JL(LabelRef("StateLoop")) -} - -// sBox returns sBox(a, b). -// The content of a and b is not modified. -func sBox(a bct, b bct) bct { - s := bct{"s", GP64(), GP64()} - Commentf("%s = sBox(%s, %s)", s, a, b) - // s.l = (b.l ^ a.h) & a.l - MOVQ(b.l, s.l) - XORQ(a.h, s.l) - ANDQ(a.l, s.l) - // s.h = (a.l ^ b.h) | s.l - MOVQ(a.l, s.h) - XORQ(b.h, s.h) - ORQ(s.l, s.h) - // s.l = ^s.l - NOTQ(s.l) - return s -} - -type namedRegister struct { - Register - name string -} - -func (r namedRegister) String() string { return r.name } - -type bct struct { - name string - l, h GPVirtual -} - -func (b bct) String() string { return b.name } - -type bctMem struct { - name string - l, h Mem -} - -func (m bctMem) String() string { return m.name } - -func (m bctMem) Load(offset int, dst bct) { - Commentf("%s = %s[%d]", dst, m, offset) - MOVQ(m.l.Offset(offset*8), dst.l) - MOVQ(m.h.Offset(offset*8), dst.h) -} - -func (m bctMem) LoadIdx(index namedRegister, offset int, dst bct) { - Commentf("%s = %s[%d+%s]", dst, m, offset, index) - MOVQ(m.l.Idx(index, 8).Offset(offset*8), dst.l) - MOVQ(m.h.Idx(index, 8).Offset(offset*8), dst.h) -} - -func (m bctMem) Store(src bct, offset int) { - Commentf("%s[%d] = %s", m, offset, src) - MOVQ(src.l, m.l.Offset(offset*8)) - MOVQ(src.h, m.h.Offset(offset*8)) -} - -func (m bctMem) StoreIdx(src bct, index namedRegister, offset int) { - Commentf("%s[%d+%s] = %s", m, offset, index, src) - MOVQ(src.l, m.l.Idx(index, 8).Offset(offset*8)) - MOVQ(src.h, m.h.Idx(index, 8).Offset(offset*8)) -} diff --git a/pkg/curl/common.go b/pkg/curl/common.go deleted file mode 100644 index bf51609..0000000 --- a/pkg/curl/common.go +++ /dev/null @@ -1,23 +0,0 @@ -package curl - -import ( - "github.com/iotaledger/iota.go/consts" -) - -const ( - // StateSize is the size of the Curl hash function. - StateSize = consts.HashTrinarySize * 3 - - // NumRounds is the number of rounds in a Curl transform. - NumRounds = 81 -) - -// SpongeDirection indicates the direction trits are flowing through the sponge. -type SpongeDirection int - -const ( - // SpongeAbsorbing indicates that the sponge is absorbing input. - SpongeAbsorbing SpongeDirection = iota - // SpongeSqueezing indicates that the sponge is being squeezed. - SpongeSqueezing -) diff --git a/pkg/curl/curl.go b/pkg/curl/curl.go deleted file mode 100644 index 625000f..0000000 --- a/pkg/curl/curl.go +++ /dev/null @@ -1,137 +0,0 @@ -// Package curl implements the BCT Curl hashing function computing multiple Curl hashes in parallel. -package curl - -import ( - "math/bits" - - "github.com/iotaledger/iota.go/consts" - "github.com/iotaledger/iota.go/trinary" -) - -// MaxBatchSize is the maximum number of Curl hashes that can be computed in one batch. -const MaxBatchSize = bits.UintSize - -// Curl is the BCT version of the Curl hashing function. -type Curl struct { - l, h [StateSize]uint // main batched state of the hash - direction SpongeDirection // whether the sponge is absorbing or squeezing -} - -// NewCurlP81 returns a new BCT Curl-P-81. -func NewCurlP81() *Curl { - c := &Curl{} - c.Reset() - return c -} - -// Reset the internal state of the BCT Curl instance. -func (c *Curl) Reset() { - for i := 0; i < StateSize; i++ { - c.l[i], c.h[i] = ^uint(0), ^uint(0) - } - c.direction = SpongeAbsorbing -} - -// Clone returns a deep copy of the current BCT Curl instance. -func (c *Curl) Clone() *Curl { - return &Curl{ - l: c.l, - h: c.h, - direction: c.direction, - } -} - -// CopyState copies the content of the Curl state buffer into l and h. -func (c *Curl) CopyState(l, h []uint) { - copy(l, c.l[:]) - copy(h, c.h[:]) -} - -// Absorb fills the states of the sponge with src; each element of src must have the length tritsCount. -// The value tritsCount has to be a multiple of HashTrinarySize. -func (c *Curl) Absorb(src []trinary.Trits, tritsCount int) error { - if len(src) < 1 || len(src) > MaxBatchSize { - return consts.ErrInvalidBatchSize - } - if tritsCount%consts.HashTrinarySize != 0 { - return consts.ErrInvalidTritsLength - } - - if c.direction != SpongeAbsorbing { - panic("absorb after squeeze") - } - for i := 0; i < tritsCount; i += consts.HashTrinarySize { - // reset the first 243 trits of the state, since they will be overridden by c.in - for j := 0; j < consts.HashTrinarySize; j++ { - c.l[j], c.h[j] = ^uint(0), ^uint(0) - } - for j := range src { - c.in(src[j][i:], uint(j)) - } - c.transform() - } - return nil -} - -// Squeeze squeezes out trits of the given length. -// The value tritsCount has to be a multiple of HashTrinarySize. -func (c *Curl) Squeeze(dst []trinary.Trits, tritsCount int) error { - if len(dst) < 1 || len(dst) > MaxBatchSize { - return consts.ErrInvalidBatchSize - } - if tritsCount%consts.HashTrinarySize != 0 { - return consts.ErrInvalidSqueezeLength - } - - for j := range dst { - dst[j] = make(trinary.Trits, tritsCount) - } - for i := 0; i < tritsCount; i += consts.HashTrinarySize { - // during squeezing, we only transform before each squeeze to avoid unnecessary transforms - if c.direction == SpongeSqueezing { - c.transform() - } - c.direction = SpongeSqueezing - for j := range dst { - c.out(dst[j][i:], uint(j)) - } - } - return nil -} - -// in sets the idx-th entry of the internal state to src. -func (c *Curl) in(src trinary.Trits, idx uint) { - src = src[:consts.HashTrinarySize] // bounds check hint to compiler - idx &= bits.UintSize - 1 // hint to the compiler that shifts don't need guard code - m := ^(uint(1) << idx) - for i := 0; i < consts.HashTrinarySize; i++ { - s := src[i] // avoid branching - c.l[i] &= bool2int(s <= 0) | m // if s > 0, clear the l-bit - c.h[i] &= bool2int(s >= 0) | m // if s < 0, clear the h-bit - } -} - -// out extracts the idx-th entry of the internal state to dst. -func (c *Curl) out(dst trinary.Trits, idx uint) { - dst = dst[:consts.HashTrinarySize] // bounds check hint to compiler - idx &= bits.UintSize - 1 // hint to the compiler that shifts don't need guard code - for i := 0; i < consts.HashTrinarySize; i++ { - dst[i] = int8((c.h[i]>>idx)&1) - int8((c.l[i]>>idx)&1) // avoid branching - } -} - -// transform transforms the sponge. -func (c *Curl) transform() { - var ltmp, htmp [StateSize]uint - transform(<mp, &htmp, &c.l, &c.h) - c.l, c.h = ltmp, htmp -} - -// bool2int returns 0 when b is false and -1 otherwise. -// bool2int can be optimized by the compiler to not use conditional branching. -func bool2int(b bool) uint { - if b { - return ^uint(0) - } - return 0 -} diff --git a/pkg/curl/curl_bench_test.go b/pkg/curl/curl_bench_test.go deleted file mode 100644 index d9f6a42..0000000 --- a/pkg/curl/curl_bench_test.go +++ /dev/null @@ -1,61 +0,0 @@ -package curl_test - -import ( - "math/rand" - "strings" - "testing" - - "github.com/iotaledger/iota.go/consts" - "github.com/iotaledger/iota.go/trinary" - "github.com/wollac/iota-crypto-demo/pkg/curl" -) - -func BenchmarkCurlTransaction(b *testing.B) { - src := make([][]trinary.Trits, b.N) - for i := range src { - src[i] = make([]trinary.Trits, curl.MaxBatchSize) - for j := range src[i] { - src[i][j] = randomTrits(consts.TransactionTrinarySize) - } - } - dst := make([]trinary.Trits, curl.MaxBatchSize) - b.ResetTimer() - - for i := range src { - c := curl.NewCurlP81() - c.Absorb(src[i], consts.TransactionTrinarySize) - c.Squeeze(dst, consts.HashTrinarySize) - } -} - -func BenchmarkCurlHash(b *testing.B) { - src := make([][]trinary.Trits, b.N) - for i := range src { - src[i] = make([]trinary.Trits, curl.MaxBatchSize) - for j := range src[i] { - src[i][j] = randomTrits(consts.HashTrinarySize) - } - } - dst := make([]trinary.Trits, curl.MaxBatchSize) - b.ResetTimer() - - for i := range src { - c := curl.NewCurlP81() - c.Absorb(src[i], consts.HashTrinarySize) - c.Squeeze(dst, consts.HashTrinarySize) - } -} - -func randomTrits(n int) trinary.Trits { - trytes := randomTrytes((n + 2) / 3) - return trinary.MustTrytesToTrits(trytes)[:n] -} - -func randomTrytes(n int) trinary.Trytes { - var result strings.Builder - result.Grow(n) - for i := 0; i < n; i++ { - result.WriteByte(consts.TryteAlphabet[rand.Intn(len(consts.TryteAlphabet))]) - } - return result.String() -} diff --git a/pkg/curl/curl_test.go b/pkg/curl/curl_test.go deleted file mode 100644 index 79371f5..0000000 --- a/pkg/curl/curl_test.go +++ /dev/null @@ -1,115 +0,0 @@ -package curl - -import ( - "encoding/json" - "fmt" - "math/rand" - "os" - "path/filepath" - "strings" - "testing" - - "github.com/iotaledger/iota.go/consts" - iotagocurl "github.com/iotaledger/iota.go/curl" - "github.com/iotaledger/iota.go/curl/bct" - "github.com/iotaledger/iota.go/trinary" - "github.com/stretchr/testify/require" -) - -type Test struct { - In trinary.Trytes `json:"in"` - Hash trinary.Trytes `json:"hash"` -} - -func TestSingleGolden(t *testing.T) { - var tests []Test - b, err := os.ReadFile(filepath.Join("testdata", "curlp81.json")) - require.NoError(t, err) - require.NoError(t, json.Unmarshal(b, &tests)) - - for i, tt := range tests { - t.Run(fmt.Sprintf("test vector#%d", i), func(t *testing.T) { - inTrits := trinary.MustTrytesToTrits(tt.In) - hashTrits := trinary.MustTrytesToTrits(tt.Hash) - - c := NewCurlP81() - require.NoError(t, c.Absorb([]trinary.Trits{inTrits}, len(inTrits))) - - dst := make([]trinary.Trits, 1) - require.NoError(t, c.Squeeze(dst, len(hashTrits))) - require.Equal(t, []trinary.Trits{hashTrits}, dst) - }) - } -} - -func TestCurl(t *testing.T) { - tests := []struct { - name string - src []trinary.Trits - hashLen int - }{ - {"trits and hash", Trits(bct.MaxBatchSize, consts.HashTrinarySize), consts.HashTrinarySize}, - {"multi trits and hash", Trits(bct.MaxBatchSize, consts.TransactionTrinarySize), consts.HashTrinarySize}, - {"trits and multi squeeze", Trits(bct.MaxBatchSize, consts.HashTrinarySize), 3 * consts.HashTrinarySize}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - c := NewCurlP81() - require.NoError(t, c.Absorb(tt.src, len(tt.src[0]))) - - dst := make([]trinary.Trits, len(tt.src)) - require.NoError(t, c.Squeeze(dst, tt.hashLen)) - - for i := range dst { - // compare against the non batched Curl implementation from iota.go - require.Equal(t, CurlSum(tt.src[i], tt.hashLen), dst[i]) - } - }) - } -} - -func TestTransformCompare(t *testing.T) { - // use local deterministic RNG - r := rand.New(rand.NewSource(0)) - - var srcL, srcH, tmpL, tmpH [StateSize]uint - for i := 0; i < 1000; i++ { - for j := 0; j < StateSize; j++ { - srcL[j] = uint(r.Uint64()) - srcH[j] = uint(r.Uint64()) - } - - var dstGenericL, dstGenericH [StateSize]uint - tmpL, tmpH = srcL, srcH - transformGeneric(&dstGenericL, &dstGenericH, &tmpL, &tmpH) - - var dstL, dstH [StateSize]uint - tmpL, tmpH = srcL, srcH - transform(&dstL, &dstH, &tmpL, &tmpH) - - require.Equal(t, dstGenericL, dstL) - require.Equal(t, dstGenericH, dstH) - } -} - -func Trits(size int, tritsCount int) []trinary.Trits { - trytesCount := tritsCount / consts.TritsPerTryte - src := make([]trinary.Trits, size) - for i := range src { - trytes := strings.Repeat("ABC", trytesCount/3+1)[:trytesCount-2] + trinary.IntToTrytes(int64(i), 2) - src[i] = trinary.MustTrytesToTrits(trytes) - } - return src -} - -func CurlSum(data trinary.Trits, tritsCount int) trinary.Trits { - c := iotagocurl.NewCurlP81() - if err := c.Absorb(data); err != nil { - panic(err) - } - out, err := c.Squeeze(tritsCount) - if err != nil { - panic(err) - } - return out -} diff --git a/pkg/curl/testdata/curlp81.json b/pkg/curl/testdata/curlp81.json deleted file mode 100644 index 018edbe..0000000 --- a/pkg/curl/testdata/curlp81.json +++ /dev/null @@ -1 +0,0 @@ -[{"in":"QZELVPOZTGSBCMEIZWZBGFSRPQNSMBREV9QD9JINWPNHHVCIFFGMHUH99OLWPXUZ9AWKJVYEC9JDTKRZO","hash":"9MMGDFTUNMXVFRWTMVYWHKIUMJRWZPYVYDYHNATZWSLWPUSULDZVSJJXQPKXENXJFLTSEEMBJIWZLLXBX"},{"in":"ZYMHMWWBGGZYFLBGVBIUIRBWBIZOJEVOBUSIVUEIHI9S9EHIVZPZWGHG9THDDPBNIXDLCPYIAVQELZEFD","hash":"KMNWODCXRXYVGKSTRTAOV9SQDHIVKACSHGQQINUNVFITWFHOCEWEZDVVUBDVJJLTESKTOUAXBSBICGL9K"},{"in":"IBCOIDJ9TCZZSDRD9XCILKQIFOZWQPDEGPXSBOTZPZROFJVCVOECEDNBOCMJIDWQSUKDVIIQDEU9CNDVH","hash":"KNLJDCZEXQZOSUIZWTJIQPEUOKERQXUNAEHRGQHIJUUSIRKRJYRFUHG9KKCPTAZTHPC9PEHIIUFWYKBFV"},{"in":"DW9CCXYXELKVWZBC9SRAXXZF9GZB9CPEOGCNZUHJOKVZVOMITPCVQVPN9HSVX9YGUOGXGVNAEYXWMNXYX","hash":"FDKAZRWMHEL9GQY9RQVGKHCZSXVJJMFHVAJMMGWGDUZQC9WVMNISPKY9VZBHNHODWXHDTWGOHODLIRYJG"},{"in":"REHTYFYFKGJOVXKSBCENUNPIDONAVVAVSXPRCDEASVJTBTOJCZPUJRGNEYAGVLXEGAESFHMRBBYAHKIXI","hash":"GAJLUCMLPWLGOZLNBS9RC9ILYAUQZXNWKUEZXFUYSPROCIRLNKKNIUV9GGVJSQFWRIMXNEEMRDSCBEBDJ"},{"in":"WNVUFAIPVTXMEYOL9PAHTKUJBIGWNJFOOTJVULJHGPINPOPTRCIOYHYA9YWGOAKBKCFKUWZUVPUSMQKXU","hash":"YIUDGTODCJDXEJLXIWUSX99GSZSWDJCWONDXQCCBDXFKWJZPOLIDRPUSLCVAQJZDGUCZULCENHJXAVEEN"},{"in":"HMSZBEILNZILUDKHKKOQQIDPITNTPT9GH9CXXYNTQECJAGMRDO9JRZIDXEUBSYSIFIC9VURLTDXXQEETS","hash":"QKEHJWVGIAWBZODRIOFMNUOBEBPVNJYCBDEQI9WFRFYGZPNQLGBWVGISORSJEQABCKNZEGYUI9GVDUJ9G"},{"in":"BRIAQFTYXZOZWBVAMPZRUNQGSAR9JFJTVGEZHHL9POPIFXRBYKNPIWYXMXJMIQLDUHFWSDZPVJSNEJABA","hash":"ARHADPO9ALXLWSQTYF9QULPBOHREUZLOJMPYJYQUWOPJLWECTNEFECQTV9PLLBZEQDFDTMOROIJTDJHSY"},{"in":"KX9OYYWHMSZVZDBUHSURDXQZBDKHIGAQVU9VTHKYLKGVRYMSXPIY9VDERZLEEFQEAUTAICCD9XYYLDMLQ","hash":"VWVLOMWYMJLORUAQGCFTERTXPYUYSWQFLPDMGRZBTKBBYRKVYLKGMNMOOPKMWPAKOTVHOHXHDZQVWFBUB"},{"in":"MOPNFIHHGTAHYSJGTRPTZYCSEGCOBIROOEHQXRUTRCMITBUAHTPXLIPXCGTBBHOYJLXUEIKKJOOZDVYDQ","hash":"WDWDVECYS9NFPWXDDSUYHJIQGHPNGILGICQJJOKEAIRLRDDDXXJVOSNSKQITDFKYLGKWEAHDACOBXAJ9S"},{"in":"ZZCPOSYPRNQYNI9STHUQFFUEGAJPRRIVOWGZGCIGHKLVOOANUSVZMGJDHHAHHQJMVFWKMCUTDEYLFXWKR","hash":"BQYDHNL9PNUZTDIZAOCJKZLJCFOPPNZXEEXHUYVBHJNTJMCE9JMGPPGDTSZX9XGMMQQGUMQSFGUMHNNOB"},{"in":"9EKTMPWDBLLB9JLGUKZWQTQCCLGINEACNBVLKUAPFQWNPAGNFZCMLLCMNLNKVTACTJGIGTCW9IGPPWCGQ","hash":"REXCCQDZOYIGXX9GYCTQMYP9ESLILCYOEIXOSQXTYJBEE9PUYBVLWKBQUIFZBQUJXIEHBNTSICFE9CMYU"},{"in":"UKEWZWIDUJQ9XHYOOKJOFNBEORWIIDDRSMHFHQDCXVJNFHBH9NLKXFUSTESR9ZZOJOTNYDNSABTMEMGQX","hash":"XXJHHJWHRWXXRONLEGKX9WBUU9REEX9HHUZ9SMPQRTSPFRNMPHJYAKDOGTHMSHGROQFEECVCGKBYJXBII"},{"in":"BKLFBTP9EKWMWYMMTAQZBVG9SKFHPFTKIKGVEQDXZLGXCMBIHPPSOZSYUAFHZDHAPSJMZAYSJKGLNAHMM","hash":"UJKUOWSOYBXCT9QFHRNSQRFZZUFVGSKAHSUJMNXUSXD9JPNDFHVHHJPGVKIBGVTTXGCUAZGCEIPAQCCYR"},{"in":"EEFL9JPVLHPQADKTEGVNGWOUUJNREZBNOGZFAYVTCTZ9CCNJMLUIBFZCIOMXVGDINMRKKLQJGUJ9DWGOT","hash":"RXLWLFAEZSZIIZHPKHCMIUFYZUVJQGIYKQZPGK9MMCRALIZYRLTITQGEJIYFIBLJQCSJIIJBPHDJFKPOB"},{"in":"QAJY9VDMWYJJZSXJWRVLMANQNWTKKQJWOOCRHFXAAYMMWMAHLHUIRZGAEQCWYDIAJ9TZNKOBEHVTWELAN","hash":"KXEUFMNTKBSNVNFBBELPXSOLXNNSNZNGYEAUJNRVJKOYJMMJEURAET9WKUHMMCEHAYCDUEPQRGGPDGDHR"},{"in":"LUBLGFMQWZNP9DULBJYHOSHJWYCFJQWLZEQETNGRIRMBIKQZMTDTUISG9ZEZHILSMBHEWGFPKCAD9ASZW","hash":"FTIWKGFP9NASDJZCCOSGHJPPDGACFKJNDEZV9HKECBGHTMHEGUECYIQXNVMXDN9EVLBTRVQKKDJOAHEBU"},{"in":"KRIAAEBDRERUZVFNTHCAPNJFMKWBLXPEVQ9O9TPOPQEJOBTMMQYKBSKRGOOPYUJAWGKONLLECMJBVBVSC","hash":"HYVF9ZWKGZTMDCJFMNETKZTWSTEGWHMDUMJUJRQDWVMFZCCGE9JJMWWOTS9WIXV9MXBZIH9DCQMIOOQYC"},{"in":"TDQNRZBWERFGFMG9IBTNPRHUWPWISO9UPXLABIGF9DKBZZSKYMNDNAZSCV9BQPUSFCOEKGRRADROLBBN9","hash":"NRYEPOPYPHGZOZJJGHWEAPMSEKMOZIPBTNNVLKZMJKJXQGBCDFEYOWUKOMKQGNYBOEXKIIROOKIATNUQF"},{"in":"OCMWBAEYLAFJMNMXAQWZVWLPTDDHJQHKKHMWIIDEHQF9JY9OHHEIUHUMRQTUCZQZFLQXEVCIUDQROQGWR","hash":"GPWSZX9BIOFPERYDUNNEBOAZXEU9FOHAP9VMKI9TJAIMYNCECSCLZKWWIHOSNGDWTVGCKJJYUPXQAJL9Y"},{"in":"PDXOECGFCTIZZWKQZPNWEKRAITDQC9DTLKCJD9YRTELAHXYIYMMQVDPYETRMSPBFHOGBVUYAOJVMYCGOM","hash":"SZTUHIZVBSKCSRZYSWSVLUVECYDPLQ9AINJHBXE9IFBSRLINOPVCAP9IDJZZZUDMHBKVDTODTCWPA9COP"},{"in":"WYQOUZYXFNBOAOFVEIJAJLNPKFPJIRBDBVDNCEHTKAMYHJNXVLFHJOWYBQCRGRTGV9EQAESS9YOFJJJGR","hash":"ZUJMYZMCQECOCVFYZNCSTHQTNPZGMTIISKELEGQPZL9KQYOXXFKXVOHPCWNAZSNCTXGWDQGAST9ZP9O9D"},{"in":"NCBSVQVBO9ZMNUGYTNTCYFCURDNCZFZ9XVSVQVPVXLXAMSESHNVWAYFNAOFCJLNZAHSTDWHMJEMPIKEJW","hash":"EOSYKZMSLFDPAZYHTPZCOHGZLRNQQDRPBOGYCICGZWNEVDDTISFBMYCKAMZDLENOUYZEUMPKSBOWNKHFQ"},{"in":"GHKRPSNUSXYXYBNLNYHABCEQRIEJWVGZVJYPBGEHJURXSMMV9KT9HFSVGQQHHBIV9YGGHIQQ9VZRSWUDW","hash":"JVFHLTDXRJVYXTRNVGOEM9GVHSFDQINUSCKSFWMGGCEOCMSOYUSFBYAJTVEAOZNHYLTAUWYSOHYNBKSPU"},{"in":"HYVZJWSDVLJXOAVXQ9UFZPCXPVYCKSMJTENZZPU9NGKFWAGCBFQGNKRJYRBSRSABGOPGTFQGXDXNOGL9K","hash":"GNRUFSAOLPNQQE9AZVACOM9FYABHRRAXXNIIZBSQH9OGGARRLNNKPILWXFBWU9FSDVJXKVEPEZHUNNSTW"},{"in":"OEYLAVSFHECW9FHMFQVRCZ9KCVYMISSFORNMNXWCSRDYNYKKZUDBIXYTLEIUEGEPPKMDYJXGCZOUWBOTK","hash":"VOTHQIMOEEGPTF9W9JXOLIHCCACDFERVGQQSQFGPTLWJUBLITTWLKREXTHSHIMLRTAZDRNLZGIRIUARAG"},{"in":"AM9FCJ9UPYFBPQAVETNNCEXTTXPEFONJOZETQXVMNA9NFBHLICINHTUFF9TVSVWPHIGPPYSERFUZLETQB","hash":"WTGUIYGYLMFQIFIEGEBDYZKY9NA9BZAPPVAKWCEOXVBQNILVRBTUCHHXJCGYAPAJRCVNMAYQWHLLSCAJL"},{"in":"QNWCTHFZFNKDSV9ONQTTQRVUTZI9POGS9PQKILHTOAAEAPNWX9YDSJQMNINDSUAGWIDWN9RPLQPLLC9YK","hash":"RBGKYBOJDEOHVPWQSUTPOAMAZSMYKZUYFHHVWSAOGFZM9KACBSWUBUSLGBEVUEBJHPRJEJPSLEJBIQKZW"},{"in":"MOAPGXPAUEJMVWMU9KIZX9KFBWIWJIEIIXOTLMMSOVQJBADCQVFDRPZRDWTTSSRGOHCXVJJLVIGADEWDE","hash":"YPWNYMMRPNFUISIQLFHRNGPZPUXZ9FT9JZQOYSSAKHP9YMNVTMCTFLECWIXBFEDBQCAESOPKDCXEQBZTW"},{"in":"CLWVT9SEV9EEDAJDJARDOXWJVBHFOCIBOKITJDMETUHILMAWSORSADPLII9SMESJWNU9VTBRXIZYNGZNV","hash":"XFJNKWFPRFKTBJAXZQDNQWQAVOZWVKLQXHVKWQAREWGEECCOQ9TVKVDOPQWXYHZD9CGW9ILMLFCMYF9NQ"},{"in":"OEVXOLTAINGNONMHEVQSREUVHTOMB9DNQQIFFTE9GBDCQHRLAGOOJWH9MNMQIWUGIIDVEOVAXEOEQCRXI","hash":"YGYBLSC9JJLAMQKDUGMNMXEGGLVITNGZKJYMZMW9JGWCIKHXCRLBFRWGDQGIASBFSDRTCZTLAANOGKMOJ"},{"in":"OJGZPPDNOLKJBPTANEYOGUAQZI9XWBSEXDZFBKOQGKRVLGIEELWMZWYIPXTEUOBJUEZEM9RU9PQATTLVT","hash":"KVKZXQHFTKZZWAMCCEWTDYCNUGDVAPASWWFZYCDVHIRKSHYMJOJSWODOSERPA9JYOAMNBRPNKGYMPJDCP"},{"in":"KBVVH9OK9IOVHVRRPYCBTM9NQTBP9VJIPTHO9GVLIZCCAOCGZZGIWFCDNWZJMROVLEYGVYB9L9POOIOHZ","hash":"VHXAOBS9UJBXCCMWUTOOEOMMIBGUMPBEDTAYQBXDCGYL9HEZQKHPIA9DFCNKVTBVWQNDKZEBEDURNQBIH"},{"in":"9UBTZUIOCFGBGUGFVENGYSZDJPLXYHKXJLYIKFSNHQDJPGUEGQMHKLIDTGQOWSDZRDWOLOKLTRVRIJXTR","hash":"OACTTHJAIJIIJKFSPXEEZPKLHGKRYKCD9X9QFYDZRSFXAULYDD9GKJFJBDMTKAFCDJEEDITYWSXDQWDPG"},{"in":"F9JCCUZKUSZB9SEKLNZNMJVWOXHGWQTBCTOQZHVDRMYSMZTTECGNJA9XCOPLZWHNTELKDFODGACGSFMUK","hash":"TAA9DAYPVJYMOEGZILVQBXBGMUNEIPGR99RZWUAQROK9PQRO9SXLKNAVQGDSTSAAKERMJWGU9ISDIFKOI"},{"in":"OABOZCIRESSVUKRNOAEZEBWMZNQZWAQCAAIBS9NUQZI9YEEOYXCPWKTORQIVWYAPJAYDUKOIB9PXDTBGW","hash":"PPATJFBHCXQKUQOHMCICQYUNYLBLKQVXUVRXHRWCMOH9CDEIDZOCVXOSMSKDUQHSBERDPJUSYKGXJTEJN"},{"in":"TCFVFSPFFSVV9KLRCEHJIDXDWGGKSJAFKAANNKWK9CTQ9GNJJXDMTVJUWZEBZUGLIATLWGRSIUYQUZUVG","hash":"VIFILLHIKBTXMLOGQGSPECUSA9ILDHOTHBVUWVXITFHOHRAPMTSNQLGNKILGLDYSODFLTFUZUFDBGFAXL"},{"in":"BTUKRKCICCAFDXEUMAXXFARRUS9TNUXXIRQIGJXDOXVQIMEDYQUXZKAVCSMIAHXPLKNVXDK9PZLFPCJSD","hash":"OQATTQAE9QNXJGVCMLHWBRNACZOOVTFSFXKDGUJOWMNKWWSJJFNHDXOPUYFIFZOGUYXSU9X9EWBABFDLZ"},{"in":"PNUQUVARSN9R9QFZNFLXPBXAQWBSZWENGDEUBZCRHUQJHSHPJKQAYRSOTTVPMXSGHKIYKLJDWDNKHZMNK","hash":"YXYPVBYWHMUGTGBPWNNGDG9LFMVUOQQIOYKSIRGJ9WMDXCOQSYZTUCSBTETWWPLRZGTQEZLZBFQBZOBRW"},{"in":"9DVVVALNWTAPMYKOQOPJXT9ZCCOOHCODWLWLJGAAWYLWUSHEXHXOU9ONLYVMVSKOGHFQWGKBJ9YLNRUIC","hash":"FMCLCQNCQYODQUKBJPQ9KBZHYHNCQBQOJGZITVHUVJVSLEBICEVNRITCWEWOIZWMZPAVRFYSEIKLSQETA"},{"in":"MWYKIOVEBGDTHLEGYLRTKXQ9WTFEIYRVK9WOMM9CQ9VQUEWE9DMTOBBOVNRQLFIWPZIWLLOUFBGKQKFEC","hash":"ZRZGTWVXUEACHK9UOCTBPFXBZMEKV9ZZIWYVJNIDVACTV9QADMRXFDI9ILUUQQFANVAFBKJLVXXMRZZXM"},{"in":"NSVQCXYJPNEYBKPHBCHHIUZTZLHKHPQWABLT9PBFVR9UYJNRVFDDXULWCFYZSXRAIR9GOYQWUDLJGXEDI","hash":"COJZATSNM9SPYYYYSPLUITGE9RPNXIHXALZNMBJTCVJQSLU9BFV9VBLWAJL9KYUCKBPSIUIGBXHVVWIRL"},{"in":"CM9UOCCPIUABYIXMMQXIPEHGFJ9FJOTKXYCISQQTERDCJS9VKSEDUKJFSQBBTVINV9PWNBMQNNDJAEKSC","hash":"OQWMQZTLM9SOOKVZDDHTWRZCDBBQQKBGDDRTEKTRJKQUTTHGHDJOTORM99N9RYAOKTYLDEZSCYVAKZR9F"},{"in":"DDPCSGMIJNHX99LXXURXA9PHMMKEJSVNNPWSEGJSMXOXKPORXMVTR9YKZ9QHPZYEILJNSNRGFRVT9QLPB","hash":"KKIUMTKSVYDZUSWMFUAUYJNFJYGJEZR9BCFVNDKSHDDMZOYCWGCWKTU9KJDJBBYXBJAOHXWFMYOCVHKZA"},{"in":"WHTSKZNQNETBRZIUKQOOECDQL9LCLJWAPEISXT9JWGLVWHVL99ZPSQEGVMUCXYTUGLQYP9TEIMOHKQTJH","hash":"SEHQDIAUAIUYNTAALSATS9WQGSDMMCOJEPWAFVTJOPSXPDFHYEGNQTBSNGMVQCAKCWWAXJVQRLTPCRMAE"},{"in":"AI9UZIKMFMKQAJNCORWGTGJYUVHBYJDR9WUSFOAOGFSOSHDHPMQWHMAYNBWMYNUPIVJIPPKVAGEMRVNZN","hash":"SWI9MRNHRNPXKYHPV9SJSVMIJVUBNCLIPZJPWJWCZAYSAWIZDCCODZYWRWBTZRQEEQFAJQOEMIXQSEDYF"},{"in":"ZAKHZAFACZMXFCEIEIHODVUBJZCKDCIPJQTEAKNZYQWWGOIINQBQCWXQAT9RHHNOZLUKGVAQKIXRNZODR","hash":"DQOFRKNCRZMEHVCTTKY9MLHU9LIMDBGHHEUFMJXHKEGBOPZDWZWJHGEBIGKFLSJERYFPNFK9EVLKUSPJH"},{"in":"GSMTTHENQCDTUM9VLDPMPGGSAFXHLMZGUQWBUAXHFNEJHYGVQKYWMRGHKOTTWOVUVADZJYDBMLSWIOADP","hash":"BJXVCQWANKGVSRHOXBYOMHJZBSNEYHGQQTUMPJWTM9VWEEBEDGZWHNLSBRILICOLSTWQVMWNSJLERQJVE"},{"in":"QNWZLRSJGZSHWY9LLXGULGYTWICELXLESBJPKSKEZZXQFACABVYVAZJS9FFRBBOPIDD9YENSJQEQDMHIM","hash":"SGQUGPRKLLXHVLMYZIQNTXECERLBZKWGSVFKOKEPPKDKEYSPHAUYPHAGGRPPWGJGEUQCBLQJRQIYSJPUC"},{"in":"DXXZXRISICHHZJSMEDESTSXNERRRMTLKDTIISFHXQJGNIBINFJEMT9HMQABMOUSNZOBGXCSBIJ9YQOU9W","hash":"MGUKGVBCX9YAJEGVXNAXGVSWWNEBKDAI9WOKMQFCQGNHUDPXIFVJABZALGKPDMNDAWCCWLE9IKRZEFSAR"},{"in":"XWZXIAEKJNMXOJRNAJNKBIWHGSKBVUNV9MTYJOIGIMKPICYNPANTWTMTJSDZPW9OJEEVW9QRSZEFBSQTL","hash":"FNODYPWRPFAIMVPHMMYLG9LQSYZRT9REVLLRTPXYIJZELNXRR9RRRG9PHFZBWABHHYWIDMDKRYVKXXPZM"},{"in":"IAOHXZWFWSYBKTBSZ9FTRLQQIHCJGHMJOKEGZWLBDEFFK99DVZEYETFCDWABFXWHLPXLMEKABLPI9UBVJ","hash":"PUZHCVKUWXOCXEWATLEFHBUPIIJQBJGXCTDY9LDFSLSJ9YYBUKPFM9XBWHUA9XURVMTCKCVAUGSDCZMTO"},{"in":"CCUW9WHWSARXVOAZCTHKQCAABULYZVJGZCFB9LSAZFZERWFQLUTZZYHUFYJAEHDHTTQYVGJBWJCUESHZL","hash":"PZIWFG9BDDRHZZOVXLDGRWPQNLLWOFGBAAUWUWBPRZQNGWVYYGSKNPPYMRHSJGCESQMZULYMMVCGBKNZZ"},{"in":"HAO9JJZHOERQQ9CFJIQGECOZT9Y9EGTXGBKT9NYQBYZRGPXKRJPFSALRQADJRQVODYN9CJGCKWBXPNSPL","hash":"UDYOFLZOOH9WFORHOWJVADYWCJQKKW9EZBJZWGCPMQLINDSLJAUDWLGCZLRTKTBFLHPSFGLFN9HWZALPC"},{"in":"ZTEJHTBHFGBC9WVGPWHNPGOERWCXEMPBYEDBKU99VVYBKADDLXWU9DIDOOXURFLDWNLUNDSBPLXCVVHX9","hash":"WG9LPSDQMJUXQIAMKMQYJNJUNWXXREVSWLPBKVCEULAQGBJQTZVUE99ZWSEAHGYCRPWGKNCDL9IOJPSQW"},{"in":"MKSOBKSGNEUI9TMXPVYWQNV9JUJLTNFQFDMVWXLRX9HDNGKDEZY9NOSWNKFELOMXCLTREY9LSXRAGZMOT","hash":"BVFJN9TEYQDJDJLP9JSRNXHKNHLHZPPEVGRNKBRLGJXFQXPWYULPCYSZBIATHOWUOSKHEJKKCWDXMDGZN"},{"in":"YMECKI9AXTCEGSBRTAOMD9PAZITWTZ9KVVQDMPXGLONP9XTAZJB9OJANTDK9BQEPE9RVKKNITAQNQGZHV","hash":"VBJMNMAOKRZWSEVVMRDKYZJDBPJKIGXFEARMPIHVQTWHZZBYUCYFSPWCCGMGXKHXPKXNNNUJZNLYKGIYW"},{"in":"QOOUTZPKTWTDOAAUBVLVYCZBLGVPTUQREZFJRBFC9O9IEYKXGASDTDZKEWSMSLKNKVWXVUIQNPE9DSKDU","hash":"URZWHYFJRJOGHRUFRRIQOTDPTNNDSXEDIMWCUEFMRA9PPVWPCRBNRQOABDXIHR9DBXIOXJQYQX9CP9DNI"},{"in":"HAJRWCRBLEOHMIWWNHDYYP9WHQQENGUSSIXN9YWQT9PBZLMBUPOFGJAMYBPHMRMVVCZXSO9JWDIOZ9FQC","hash":"YIUCDQCMXSAEWYWGBERZUVXNEKILZNUBWSQPZWSILMQUWMRZCLPVDLAFGOULYMNWNWLWXVDWIW9KHLQEK"},{"in":"VIKTXCEADFNSFIDXOVAGYOFDQD9PTT9DQHJZKCIDFXRPSCAMGDKN9Q9ILQRZGDMLSOOCWSWVBHFPJNH9B","hash":"FEZIWJBETRIEWPHEGGXVEHUMSTRLTQHILSVAWNAFQLJT9GYKAGJORIFWXZZDQGJSEUDVSFBWGKDXMJWCJ"},{"in":"GOOS99KXJWEUDNVNUJLTFXJZXXFUPFHKONOTIIIYBFTR9EACAQFTQSDNEYZAWVTY99FCL9IMWKQGKLEGU","hash":"COLCCWUUTCGOXJXVBBIBQCUSGEQOMWTUXEYLNLAJISTNWUSPROQQCHPSZGPWKO9ERFAROOGOASGUQNPEO"},{"in":"STWFPSXKXYSCOXMMO9D9XZDYZHSNDALLFJTTEUARORHTDEEPJEPHQTDYWBVUKZXNP9DKBSJRDGDONXUPJ","hash":"CBAALEBROKRABLYD9ZQBLQUJGOYKZWYNDPOMLGYUZ9UMYXUEIMSDEPAXWSMCPZLMQGXEXWNMTKFQYHCEN"},{"in":"QULMDSVBFYMC9UHDLEZRFXXERAJJKLXZXFPO9JRGQSZMVYWCDLTNGXTRQLHQFSMHIIJECHBCNTFYN9HKI","hash":"FBYA9MAPOGSMGOHRIOCUPBKGMUORZEZFSPLVDMQMOGSYUHA9P9TDMPVHCDHSSPIAJC9IKTZRBQJODMEDA"},{"in":"NYJDEMJWOFT9QALRDCXY9PVYACUBZBHGB9QWJZZEDGIQWXKLZBJSGS9OOLTIBATPNCSERNCGPMRJDINNS","hash":"E9WZQHXBCOBNRYXEQSAFFCHI9QCHFNKJGQOPBFQNAAX9SZYEWVKVILUWTOTGPSIZMVMOCBGKASDOBQZXO"},{"in":"XTHE9OPYANWIIQOOWXPLSQQWHSGQHHQCXMTIEZVTIRSHGBT9NMQCIZPCKJPM9EVLVQA9JAEJBTKELHFYQ","hash":"FMFHFUMOUSXZMZTZJZW9ASPHOKJGXCQWYZXDCYAJIDWLNLITGRRSFSIFOSXNQVU99LWXQFEQDRVZWAPUB"},{"in":"XQBYWGZBWCTQSE9ZHUFSDOKOZJKFZTHIBRDXOBJTJTJLTGCWKXVF9ONYYSEJKDMCYEROECKLGWTALQARB","hash":"CVBOMKIHYHISZKPAJI9QAITLRXLVIYVUCTGCSVVHFFWXMUBIZGKPHMNPUMVWKYFPRPLIT9SOYXPAPIRIX"},{"in":"DMZSDTNSVKYIRKWYWHPDVPPBRCYA9YNUDMTMZSVZPIBJYVITRDCYBXVPYNPZGLHDX9KOIZUKPNGXKPYVF","hash":"JSJKUFTUAWHLQARYQTLGBLKETZ9UBQW9VAYGLGXNREJKXUTK9EOKOY9WNQOQUKGJZYROECPFEYDASXDKN"},{"in":"QNHHHFOPMMDIVDATKJCKKROZYSB9FDIWFAPYSVBPSMMJDOHJ9XYLUZDFRQTQXQXLRV9J9PGSHVKWSJLKI","hash":"VEJZULMZX9RHA9BNOUZJBVMUXTJRVKHXZQIHUHHCPAQFDXMGHDVYSWYMKPDTOJWPIY9JTBQAGTXEBENAK"},{"in":"ZCQQXMCFCFOAD9DWNICQUWHAER9RZOZCCEDRAHTXL9DLFRFFTFWROBMMOGCIUYVESFXQNJWUELNQYRADJ","hash":"PLRMQORECVMTRWCHSCGTIWPUTVTJMPAJNTJDNWTZMTONWWYPSXHNMEXBSRWKSRXHBZGGYVUTWGB9BFTFL"},{"in":"NXXHCCXEEAMDWCCNG9YVAEZJBPRSKMVQWWHGACAKPDTYARS9WCXHEWOHJWZQIHAR9NJCFKBXZPDJZCIAT","hash":"MQVZNCOCPSWNLIXSBCHJDDXGTUEBUFBKNTWPYHYAALAKAMBYUNFLZOMYQOECMLTKOCZH9KWKHOMEFARMM"},{"in":"QQKROVGJLP9DQQHR9QEPTRWPGVJQCXTARNGUPYYLHHEHGGUVGFEGEAZJGDSBIBA9GQNNQHATPKULHIZBR","hash":"ACCXUGTUAEHLLWRUFBA9XTMUDQCWRRSUENQHOL9QUCMELGFCNWVZTGKWU9MUZPRXIYVKAXKOOPCSUNRWM"},{"in":"HTEQTBBITGIDUGKPWTYIUAKOZ9DDNAFITHXFAUQNLVBVTKDXTEGUQSUGXDE9SUUAM9XNAVCCBNZQ9UDZV","hash":"GPQPMVYXRHKLOUWFMWPKPDAZKVKDBULFDXEROOX9UIOZGXSFCOZPRZNMFWIUXAPO9VBYFNDWRBIDGCVTV"},{"in":"JHJIOIXRVABUUHYHPTXLPAXJGZGLEEXZGIIPFKCH9JORPUGSKOUKROBEPNGU9EWAHGLI9TMCVFUDXBWWH","hash":"AWUIQ9IIBWKCQASRWEWTXEKZWOEKDCGQJOAGBJHXINRBGAMHLCFTTKYVQDPWXBKYJBCQPXEUVNNUWFWZC"},{"in":"BOYIEBTZCEDRVOAHV9KCBLTBOFHOEURYWKQGY9DSDQFIL9OJQASADASTGZTBEGXEZMNOZJWSYVQIUNBEK","hash":"YVTWYZQXDDCWTIHJMUZHFPTQYFFNWPOMSFLNFGSFMFJMBLLQSRRKXRMFJBHZMWABGOKX9QNWWAUCHCCSN"},{"in":"FG9MVEMKGM9SMBGBAWHXFMDSBHXHRATITXQMGWECOGCPSV9ILLO9VSQUPNFBG9HXKZDVLSVGXLZIWSVK9","hash":"IA9WRACQRBFKCZPFYNGUJRHFNYOGYVZXVXEIYDQGWSMVGFIZJSRGYHCMJO9HNOUUHSUZJHFXXETLYHJFD"},{"in":"GTSNLVNEYFVDPFGPTKMAIZOGBAETPRCEEJKAWCWJQYAZLJH99HDBR99WVVYWRVOJNHGBSWONGWIBXPDMG","hash":"OMBNWUJQZILIQUVWBDQILID9PINYNHIVPVWDMGG9VGYORBZD9BMXGOARGRZTCGHTWVLHTVESKYOSCBRSS"},{"in":"9WPYLKIQ9LXKDJT9FDCXAGLMJUH9WTMJZXKQ9AGDRPTWULSEPUEEEUHTPEDFSSWUHMESDUPWCVUHPMRLX","hash":"PFCWLAGRCOUJERZHJBODEXYHLGTWQYHDW9RASGXMLKJJYVOULKVMXPI9GFMLBVTCOQPO9ZDIFBAHGGEPY"},{"in":"UXPIAPZFEBOCRCJNKNPU99CQLEFYFBDFQQEEQJYGFJYTKMIFINVGVIZPYOWGM9PCMXGNH9YYJTPEQWKYX","hash":"CAAFTGOSRDVMOHTSJLWKXEPMCVIPHNDAUJQK9JX9HXUYAPVWQXBHRGSU9LXB9YIEDYBYMBLS9XSOMDHAA"},{"in":"HQAXQ9INHBXBY9Z9OEKUZZAGPZWBIQAISIMSWUQMSYVLPRLJVYRTJOMFQMNANFFYKA9XZAXWUWIQJKGWF","hash":"UJNUNJQFCEDTKY9ETJBYBXHFPQQFLFDZMHAS9XKPUARIAICIGWTZERMQ9OQYEJJEZLCDWNCFLMEEZRHGX"},{"in":"NIKJGZSRBNEERYDEGXMXXAMKBVTFXKSNCYSLTUPWGIDTHZCKNYSRFVXSNITFBKWWGQHCBJEO9ESAOQTRU","hash":"AMIAKJDU9JIV9YHFFGTHVYTDA9ZLE9PKVTPZYWQAPOTKZCPPGILHFNWLYCPU9RGDDHOQQXAKYVCFVHLWT"},{"in":"PJMXCLXOUCDCZ9GVVLOPBOXROQWHU9YIVDEMBRRKFHEMPFTCTZESYVCNAYRFWHJIJKZNCANXJEAJWFMVO","hash":"CQAUUKGFGABCYGSFOTWJQOAWMOVGDLNACKBLGMUNOSLYFQSAPGCFVAFQISZDARZNGPPQMWXDAEORZYSOT"},{"in":"MAHAQBYCXUQJTVGOMBRCEHODSULZXI9PMCOVMPCMDJNCUVBFSGZHOYWAXZGOWKLQDQJCHDMHDJGUTF9AW","hash":"JIAVVCGSQUTVFQTSCLLHFSMGWMQVPDJM9FJCQZGWRIEGTVSEOBSXTBJXIHRLVTNHJKHZWAOLQPNHLBT9M"},{"in":"QBUVARLPMBWBRALFKFDTXRTJENVSOAVGXJFVACNOMZZAFPJCACIFCRYKNFKLBCHEUBYOUNKNIST9ODJYJ","hash":"ZWFKRCWTLJSLNYBWSJLWMNFQJYIMLDQ9B9MFPKO9XJDLLARHNABQMFUTNTD9DSC9OUAISIZYPEQFBWBKO"},{"in":"PGUJSWJINFCDLXBCYPFL9DEWYVHBDJCRIVUJCHXKDPDYIFUBPQZ9RBXGRAXXOFGREX9GNTSRDZPWUEPTX","hash":"YYNKCTFXLTHWSNANIAISXCDHIVUXHUIGHAAQNLPJTBWJJRR9YICYMOHIRIHGEPTOQTNKUPCIXXYNYABHN"},{"in":"HGSYOJTXQQNEDRTOSWHGPFPJMBZRQDJTDKYG9JJHLHJEHDAXMVJ9FHCXLNNDAEEUQPSCZPHFDUO9HPGCU","hash":"LQAIUFQWAJIVPKZTGTOGQTUJLYWZBBZAGWGDMLNXDRRTKQMZVZPJZZPVEGRMVKOWQUTGANSUIBBDZGJOE"},{"in":"GBHGNWEPRRSGODFXGTLOYJBIS9UYRVOMC9WHI999ESIOBFJTBWVUGJTDKNPLUVYFVJXFWUCXG9HHWXRFB","hash":"YNAGMEWBZAVPBDYYUIFICWTVQAMGZKBSAPTKTDL9JBFMSMQH9VRGYFBROZIYSAZQCHMLPQDABETGG9YCE"},{"in":"UNDDSZPVZJLSJXHPQYPYJERTRDAJ9WLRFSYFJPJLRMXGZRGHX9FZLUSPEZRGAHLGLUWNUKXSXWQRNMUNV","hash":"HIPDBTPLOKTTHPLCSFANAXTSYCVTZDGDKTIHONKZZOHOMOQBIYASMVOBODDGFVYBOIGRRYTCUGNUM9VRL"},{"in":"JVKFVUBLKHXCBCPNPW9VSQKXBRYHCRLXMQFYJRHACOFDM9FLSZUZDJUXVSFJMIRBBMMSUXKQUYCFTOTVP","hash":"SUBEWBHEWQBYMGGEULSUSOUNBSANDYGAEIEPXIPEBGSKBLRHXLZLHGPPCZZWYQZBSWTNMYRLOKYNBNKMC"},{"in":"H9JHSFFXSWXTQUSJBFKUNDTY9GDKUIEMBYXSLSNWFYWEWOFXIZPTWEPEWAYOJJRUORJPNIEXKSGQWZUIO","hash":"NKVYPRFMQQLEUSZYWNIXEGKDHDMAIKHZBHXSHXUQTYQFRCULLQVGWYKOZGBIDODIIKBTVNOLCKSDGVBNB"},{"in":"UUCCZBUYSIDNTGLKECYOYTQMYGPOKOSRCKCIWLAGBUTHYGSORAGWJKDKBFTQZY9RCIFYOCBJUQUCXLLDI","hash":"MWMXHQLLGYTZFTOSMMHYBOAILOWLWONQZ99UZNNSPSUBLRAHR9MKBNRHQHL9NSMKRAYUKKGIFSAEXTHC9"},{"in":"YAKYFERH9KOOO9VJJUM9WFQATMQPRGMUDOLIFLZGCZMMXJOFDQLUXUUULYZDMAHMEJHIM9WFE9G9YUPJN","hash":"UEMKBFUINOVRHRKJZQNCYPOVRYLVPUUCR9BGDVXRQMVYASJAZNTWHW9CZTFOOIEJUMTRJWRTFDGEMQRYI"},{"in":"OHXSSPKKPLZYDOTDTRJZXREHCTWWPYPEIXOPAMMIUQYSHUVDBAAIXQJLLHREVHRXJKAZUQESQPJWWHHXB","hash":"9KNRM9OLLNOSDYNGJMTHCWZFKXJXMRAUCLOYEJXWRUJZAOWJBBP9HOGXFPFDVBGCHCSZVPLNRJSGQIASV"},{"in":"AVZYYYOLZTJMRGPVSRMWCFCYGPRUNX9ONSOKZELD9PBDZGKIQWFPVFUUXILTQBEJKJFJHRGWWYUEQDHQL","hash":"WAKBTIVPCU9CVVSAOPEFCMF9FO9ZI9AVRYWBDBHXFFBEXJRMCPIZIEBNCTFOPMVPIEHNVIGXLTUWVKIRC"},{"in":"DHPVGLPKBJIWRMMRMEOMUHLENJGXZLLHLFCBEOFBZRSDOJ9FLZHY9NRBXNWUXOVIDCXLZSPRTVVEZLDRC","hash":"FEM9AMKXF9EORHCMWMJDKHWZHMTTDBNLWOHTJWACRGOFUXTYWC9EEJMVJKUCPKHBAHJPFSPYXDXGYGQKF"},{"in":"XURTMHVXEIAUXM9CYTHYOQHIUVX9VAHFTZKDXUDXYTPVPNWTVXKUHKIWLTEIYKUKGGZVE9WCLZOHVKJBU","hash":"MQHXKNSEZWLDUURRRGEHNLNUNLQPDDHFLATACXQJE9BX9ILS9IQSJXXCOARMYGJKDSCRUK99BWIHLBSPK"},{"in":"YTJLBHIJEEHWWTHLSP9RBXHBIYPBUBHQYAERSEJZHNAOHBZOVSQZTS9PJQOGNSGFESCPFMFRERM9LAUSA","hash":"ZPIIDOAWJIAASTR99COEUEJYANJNJHLJXRVTUESVHEIAFJHNMUDGFUDHRZJJYJHCQEXGEFRSQZRS9WIQS"},{"in":"OS9QJTVUIVLQDADC9GVQGOSJM9TWPGBTHCXYDF9YCGVPMIGDXKNLFMZULQYAZRBIAYKDFFRZKEGSLRCF9","hash":"ADPMEUERNJDZLHMFDGAGKBN9ENDUSNRDZPRPIVCU9R9VDXGCPKHJTM9YHLJPS99UFWYRHEWSESYDYAGYJ"},{"in":"HUKPZPBOLDKUUXNZRIYDFINOOEJTKVXDYNFFGYZRPVIAVHQBXYTUWIQEHVXQTL99UFNJVDLNIJAMSFUTN","hash":"LRQKHCJINKIH9YXHAVHZBUYIPOBTNKJYCWTGLFBRDLPVOPBXUDANRYFZGTEYXCGXKRZZVKCHDMUAQSRGH"},{"in":"JVXGGQOJ9JVHUARLIUEJUTBIHTTMCRDZ9SBFSPPTLUUBQRCPQTRVLRSBZUERVXDYI9ORPXMHKBMR9RHB9","hash":"GNWROERGVUSKEBTJQHJUBUPRFFBUZRQIMBZWQBDTKRWEQWZC99AQQYQVVTWJNSOR9BUMYZLBLGHJKQFLV"},{"in":"ERAIJVUQHEBULOTEMNSA9LPMKB9DJGGYEQVESCFMCBDORQOHJJFBJQRWMORCUZAQECWPOLSWIXAUGZIPO","hash":"CVCHHPFERWTP9IBMHQBOLOXK9HV9OFVWFMSNF9TPDHLVJAQUAEBGHGKP9OMNMRUWMJHMCJBRYVEXVMSGN"},{"in":"RYFORW9EXEGYDLTYBS9XAFOSRSRKMGUFJKTWGMSPECZHU9WT9COVEABLXNOHSBKTTQOWYTQTJHZZKQTQSMDNUDYAJQRZQCLYLYROISDIUPPRJBSQDIRLQ9NHCTBMVTUERZIKCOWILRG9FIPIBMBQP9VJ9CBRLPJJQPDRBXFVDQDFHAJGXQKVGLTVNUO9NNSXHSPMHFUQ9P9OW9VBWYMFXYBGIOHUZZZKMHDDYVPEKHREXIHBUIO","hash":"GDIDKYQRYDRSMSZZASGZLKW9OLKDMETHADSSGGBDHCDYML9G9DYXHEKEJZXVSCUSPEDEMQXPBAIB9BVIZ"},{"in":"EAVPNATMLKNJJETFGDHWOQDVB9OESVJSYRGYAOFFWFDBSGNBYIBLTTKKSRIYAVRUWXQIHMWLXAHYAOARHBAGEVDHATFNGVIAPMLVEKLFPYVKPX9LESBMZIMXHH9OBXQPVPBDZTGTDZHAMWNLGAKKWHZFWKY99BEYAQNXXUTXINUBKULCWNKYMDMDRLRDUVKRH9MNSCJ9YIRLXNTHPUXWPDHLFAMHMXBARVEZODCHUNXHMIONBPJ","hash":"CQGHALZRIWMBCUEMOLCYBGUAJIOYHHBIGZPKSDHXAD9CNDTPGIAOYVLCUXKCCQMDQXPWCSABREGFUVS9Y"},{"in":"SWJPGAJQSQVOZMWXEKWWELDVZMTJGBNMYCFBLVNLSB9CSAQKQBQKQJWURT9WJECESARTPBTTZINMWFDWENMHCBXOIXXMRAOTSNZPR9ZRNRXUFS9Y9UVFAG9YVFEBNSBBQIKHZJAGIMHXYCKXUUS9X9PCGNBGNMIHHIRTPDDWQRQLIQYTMH9XXYZVHTFFQMUGGGUTTIPHKKMOONQABXCKMKKNQEHBZAAUVIYHRK9BHQVVFNPXU9Y","hash":"9ZDKZULVYPJVEAXWZOYHECBVDVBRP99BQVLHZZNAVKBJ9UAFEESENWLVBRTJQRHVVZMHAAXGAZDVFAEOJ"},{"in":"WKG9WROBFNEFGD9WKTNCTV9OAUTSKISPAGHRIPYW9VBJBIJAPRMMDSWTUVDCXYLMUBOZWIQKFQPHLAGRGZN9GXDGMSHCFLQP9CEASUMRHFUQJQFVECP9VRCWAHSXDHUGMBBOJQHLTRZAXNQZRHQLEFFEXPE99DVOFTVDTZQ9KVGEMFCETIEYCTRVMCKDGQUVDRQMSXFSXILHVYIBXOQUCCCCWWTYFMHI9JGU9XHLZTXPDAKJPTJ","hash":"SCAP9DXFPEEFVRJVF9QJHFFSOZZWNZXNXZYKUWMNIQDZJBOV99X9ZAZVWALQRTQTMVGN9ZPKR9CLGAIUC"},{"in":"K9ECWYYPTEIPFSMRSQOEDGCWZ9UCOUSWV9LUJ9GDSTEYJUJHXVTQASMYTFMCUTII9LCKINILDNKLUBCAEZAGPBJPQZBBJYATAWIVTMXLVXQF9OQCAXJWHKEHHKRLGLQMKJYPQFUBRWUBRAFHKZYLCTTLVWWCWHYFNXAGLDUHJHOUBPRUKTNFCPRTJHQKPUIMECCNCMFPT99TAIVVUGQFUBOSTXJQKMEQYPKKQNPI9HPJDSUOEFY","hash":"JNVOURHDVPZWTTEPYQJYBXNDSC99EVCDAGUVC9YOVNVSJPLK9KFR9JYFGJJEBIPSZLEYNKGARRVMBXHCA"},{"in":"XUFPYWPOMEY9AODCVUJRTUKYJAXPYBSCHZ9KWYACAYVWGDZHUFBNQFMYKPLTGHCUHP9BRAPPOGCS9FIGGUQFD9VCFOWTTWFR9CYDJFPLJUMBDDMPXSKFPNLOQYVVRQTAKBWRTTZYBFUSJLXXZXBDMIRSGBNJIW9XJFMIUE9GLSJOTLDLRFNYWIIYZNOWMBMNLMRTSJLOVQRTGRYXVILMJOLOWASZ9VZEUVJGMOKGLOENLFL9NHB","hash":"ADCREKAHYBUJOQTOYVTTHKMYYH9OZWAZSVPDLIRWKMCNALE9SDXPNQR9BKAQL9UYWGODVSGN9NA9USOWT"},{"in":"KBMRRFSBPI9DXLDHNGWNNEAMIVULMCVKLEOPATTZIDUNUTVFRXGACCCZCOQLZZKS9DTDWOEPBYPRVASODVATKQHDCD99VNEMTAXCNNDF9MPSQSVDNLHAWNKHWETQYCORCXDEURBWTJJHGITKXEEYODKGRQSSCKAZA9BNYHWQRQEFCOHKQYSVUNQKXZJPAGYOYBIQMQNW9IHB9QJFTPL9LIXDINI9IXN9TPEQGDKHJJEQVUFNTKV","hash":"CAEDND9WVHSOKADPSJJTXLDKHPQMKHUIUVSTROBHEAGNPSNNSNXQSKFYTEKAPVJJGKVYVVECKWQSRDUBY"},{"in":"GMLYSVKJTDWQFBZIJNONVBOLDMTXANFOYJDOFYTGQKZQOFXDKYEKTWJOYHQIMTLCFAQCSMCXXRNFRKAMWKEBZUMKHSUAZ9JBDJWA9FPN9BLEYNDTRCPISSYJYXQTK9PGBPSADGOFSDASNYYLFLMAAVZMMONTZNQZXGSNODNJSCC9HBSHDITFUDZIB9TLDQRFSCE9EFXZBBNEDOQJWQYKKEIEQFDUSNUGVQXSPPTLMPHRPVHQAQ9","hash":"EBUYOZJ9FCUKVLXQKTQJXDTHKOXRHFLVGMWEOTINQVOPDHGFDY9FTZUDUMMQVKLXWPFVMJRV9JZIBPCIY"},{"in":"DHVOW9AAJETCECSNZCGKGSQSX99CBOOPOHQGAHDKZOAH9PVVYRENHNLIHKYMEMYMS9SPVKCXG9GQYHGPMDQNIATQBLXIMSBRYSSXRCHMMMD9LJIZJELAOLKPWLRMAI9SOGJWTAMGUSEJHHWERSNBJXBHQUFOVHKZHJYBRAMZGZ9UZPZOLTEM9MBZFTDXUKLBHECIEEIWGUDDLSUGXYYDZEPVVFUDVTVG99HVFEKYRHPMSF9BFWQ","hash":"REKMFAPQZWWCVQHTKWDSSZGGLNIXNIGLLJFLWY9CONJWFFZSNQCPJGFDUXMJZSFEXBCHPJRVHZGHARDUR"},{"in":"OPSJUVYQHZAMTUM99BTLJSDKAVFURWKONGZLB99VWRS9EDRIBF9GNTNYINLBE9LG9MBESOYQJNCWZRO9BFXDWOAA9MRKLQQNRQUXRY9EMWVMGXWDVEDWOTLWHPPDPKJCSGWOYTOBC9OYLKLUNUBEHRKHFL9MDYM9QMEQSVAEZKFNGOOSCPRC9K9WIJXNNGJCVPIDHGS9NGJVQDFGQUSWSOGCVQEHCBDVGZXGOUUNMLPXTZFWIRL","hash":"FZHCRSTLDBLCXUHCIJSNYCZGNGDY9LJPZOMQWOBRFLEBF9YSEGGXNUBASFJIAHDQQBUJTNECOBF9OBYSG"},{"in":"KZVWLAFABXAHDODJFCBEGBTTIQTRVCBDFCUZDEUWJQYNP9SVWBRKWSUTO9L9ZMFXINVGSADJMQ9ZEXDINARYTYUEKBQEKAGTGPKSHXEUPOEHILPVFVA9ZGQTGDUMFKSRVGLGDJEPIA9EXAOKMIPJDYWDETYQRTQLWOMULRILKMDPPBAG9NTFXCT9NVEGCLRFSXSSGTHRWPAERAUJXULYJIBBOBG9HUNMWRU9IBMEZUWFWKSFITU","hash":"VGMVJTJOSRUNGSBXCNVXNBFEULGB9LDDXEHFHEB9KTZKWQMDXVFITGKDJPBBYSJAOGOOROMIRDBOUFYER"},{"in":"FJUDQXXKA9EILDAWPUVKHKEBBYFGUURJAAGYRPZW9ZWEFZCCRPWGIYUKYEKFDCBWNWZQWNRWALUURSCWLDI9EPMY9TNRWSUIQLCJPGNRHV9CEXFJXKBTJGGZWT9UQNSCA9XOHCZQUXAUQUYZAQUNKACOYQB9TJWHWTKBFJBHIGDBLZFMCSR9OZUVEGDWKTLBTUPUEKSATSK9USEEJF9JDLEMHNIGOMFNYEDOUOIAEQXUQZRFHGP","hash":"JTINLDDEKRXVMEXJOVTFMB9QMKLZGJYYOITWGQVFZDNHDLHM9KT9JGZMPQRA9RQDNXPDMNDYQPNLDG9NF"},{"in":"ZWSPL9HOGC9FGXDIQKRJWQIRBYCPUSMWUGUK99HCZOUOSBOERNE9IUVONZUUSFKATMVWIPKPFJNVWTEWGR9BQSEZCCWRJPZBTZ9ELGILRBFCNJYPONYEIKIL9SKDQUHGTLBIVLLOKZHOAGOUVBA9YJPWEQTHSHWKTYYBCFVEXRTLZLIKOC9MSCKW9YGFSPYMJDXJAMGACEMGTGANWKGP9WGNXSAEDJGOK9UEP9FXVVQUEDRWIQI","hash":"JLQWZVFTMWGKJHEVK9LKQPHHUXFVASVPJ9NVFDTSGTAHRGNMRXVDMQIRHYOMNYINLGROIRDKASODNAWQF"},{"in":"VGHHWQRLZCHX9IXWOCZGEYHPOBKWSJTFQFCTZPCGNPIOMURMVPATJOCAXLGVWWIBOHSLZISBCXOKLMCCFUAKPNLUFSBECSYOBLFKORSRYWUVHAVMWYNSYVALRYUJTTFLKGALGNKTCSIVIN9H9HWREVJJKFGRVOIKZYVYRV9SAFQCVCTXLOCVVPYTFLDWMGWFKSPAEXEJEMDJZFUEONMRSIISQMDTHCRSEHWN9F9AMTEIVMTGFLJ","hash":"EGDBCXQQDIHYUCYBCZVPHWS9ITQVVXRQIDZWBZMLIYRWYUNWZQUMPSZFVFBSGNUIVDXDVSRWKQNLOX9HH"},{"in":"WQDLAEVUWVWO9L9MQAOQJFKVNUWJJNTNKXPQDJWWHOGIPEY9CYFYCBSJBWHIOBLMXQKJEIWJZZSUJDOXMIEGHFWRGF9YCPXWBHDWOFQRI9GABEALNFVMDADORTPLNQBUKRSSYNKPCBHSFICGUVLYGFJAGU9CGM9ODLLHPLUXCBXTPQKCKUEPUBQGXAYJVJDZADRZVOUAMZNSLNUUSOOLFSLKWELGBRGQAIGDHNOLUZMEZD9MOGK","hash":"PUZQUNIQYKQLQV9KRISVXOXWYAHLFCFUUJHLQEAZXSKYGRWEPAPBFTNEHEFHSSHHRSFUFKLVPQRHWJRVQ"},{"in":"INYAJANIEPDQTAOODDBTIPTYNJFFQVRWNITBREFJKQSSKSDHYSIGUWRMMXCFEZ9WMMWZJZSTUSQHUBFDTUXYINOXOOEYHQJZADYICZJZBP9UKVHELRNZNDFXZT9MFSH9EKRNOSGNTPFDHGLCLQVA9HACVRJTLIAKZWOW9CNJVDW9XGJYMKSNFXTSCSOEMDCTNLMQFIPFPO9RWHZG9LNULJQ9BAHQOOTMYYSJEIDVPPZRMHCFATT","hash":"PBVUJYXNOFIOFWZJZPCLOGWYBHMEATRISVDK9HQVRFRCLU9PPIVHNDUFXWIQI9DNBUZIPF9ZFFY9KRICJ"},{"in":"NWDPANGZHTYOIAWQW9KHOKVG9GHKFKUIVIFPLJUNPDLLOGEKTMUSCWPYYBMKEETKNOUBCPLYHIQPIHCEMRTRLHBAFXYXZDSZAIRCZAZACLVYWUGDSXE9YEKPOJYUL9WOTFOLYOOPCKB9YOGBZNIQQGBNNYDXODOWDKDZPCNDFXWN9GCYFTMF9SXSMFSI9PYSOVOKXJPITMWBGWIH9KLNRWHEKXKXOIUCEZVFRHUQMVCDB9QPSAE","hash":"OGYSOSIWWNGFIVVTZLZVTTIAAHSNRCPYSJHZKSEGHHPXJRGRHVRMXCJTXMSLJBEZKNXNIGRGXHTNTPFJA"},{"in":"ZBDSDSAWWLKLJHBXRMBOTWBXURNXCVKFUIH9HCMUZMZBQCPCXQEAFJABMQ9BAPTZDOHTYCQISK9WOMWLXLPZZIRFQMKYELJUVYVXSPJRNIGWHGHRWXKLRCUUYGMSJYBWQXPFEVDPJBAXQMHGCDHLQGKRJIUIZWOLZMDGWQKPZNFYOXLEKDD9IINZPKAAOGDDMIYULZYDPXJURHIIKKOXKACQRKTOGLCUDCMZJIDVQCYZHLERZBL","hash":"UQUZDIGCEGNBPDSNLFWZPNIQXYECMJWBR9DDOZYSLBSJNWU9ASOSPYGSMWHGEIMJGPLZCA9KYSGNRTXAE"},{"in":"WVLSUAB9PXGXFIOXCZOIHVEILSFQSIVJOMQBSGWXPIZ9PGCQNPFCAWXCW9YHDZYRWVJGEONYLSLMFYNFUIBGQYBBCWM9K9FQF9CRZVQYHVJL9GCQEGMRUMRVUAQEPVJVUEMCOAOUXIXSEVGHSBNKE9IRKDHDHI9GTKJWQURXAQCWPJPUG9IILWPRVLCQQPOYSEFWAOHQLAWGDRTVUFWWLYJTPRXNWTOYZMMJWPJUOBECJWQVEBK","hash":"LCOII9LBPFPPLDVDCQFEFYLFBMB99GXDFHZFM9NN9GGTUJUPAEDZXWLOUWKYCOFIFAAZECFNMEFCFZQUA"},{"in":"ONBGGYXCADTHRSBKKUJV9QZWUKXWUO9IEQJFRWUI9MVBSAJMKMHSYHHLSWTQICQIYLHLKQTUD9CFSOWCRVHSF9XA9WKLWXXHKEUMXQGRGSMVIXGDULSOTHWNHPBDZKYQZNAWSYFNHDMYSZBI9ALPOZPMM9OSZCNHGBAPFAQY9FW9ICRDFNVALSAXGYXGJVWQHDQUCMOBPJQPEUPRO9OWNMGLXMP9MRIPMKZVUOTYCCQCEBXPQUH","hash":"JQHUDZOYFWYEQI9J9LOMJVBEGGIRXXVPOGXP9QXBKSSYGLVEYDMKFAQQXNQD9EFYNDBNMDIJMRYZUMXPI"},{"in":"9SCOJJDJYJCJQBINFXKAZLWNDRBLNBZLMQVULO9QNPCIN99HQJEN9AVOAWDXCHKRKWWDNBMLTLDPXFAJRBQEQKDGHNJDUZQLA9HCWPHDQEBYANIZVSDLRSZZMYGIQCLGUCJYUMQWJZXLFMFFA9ACMGF9MHARPIV9ZAAXFSDWDBXEVZWZEMPNYFMOFEUCVNLEPRZMCTOTCKHFZUUQNEYVRYHENMJNCQTKPCNW9BLMHVLWWBRRKQP","hash":"JXIMMKEDAOIVTCCBBG9SNFQGGYUWOWPREQUMBWBUOZEM9MMIBVDR9ALSWZHMIPQHVICGEDMIZLJ9PDNJZ"},{"in":"DBRIMLVGTATDOJICLBDZ9NKHQIVRTZLWKIGHEFGVBWXXQLHCDNPWLILRKVONODHRZASUPPFVIVDOYOSKAJTTOJWRPIDVUKQDJG9WRJIZGOTW9DGEVH9GJSBFUSHBMTZNKUQYQKIHMYVNDOLG9WBPLUAYPDWMGOGNIYWIIP9Y9XSJYDYICWY9XJEZJQQRHKEJVRWWKOHYPXQGEVEZFNJRY9DBCCPHZSGYFUKGKSPHMP9BJ9KQLCG","hash":"RTKKXVRIIXXTERNJYCZJUXXNTWQDYQPACEZNHHRYYVKASQXDMTXUMNTAXHKSAYWONCAUTIYSHFIZHORSZ"},{"in":"QBTZ9ACRGECNIBTTP9VGMJXYDHWZVRRCFALDYPPDVTVK9QBHQPJQCAWLFHUSBJSGDODRCM9PNGIYWEINWLQSQZPKC9BREDMDXVRWD9LFT9SCAJENZLJMTGGDMLCNEOILJJRNHQJNXSXDXDWDOLRUDTMRTOCEJP9UHLVNHKBZTTNUOWRRRGHNOANONMD9KBLAISVJQWGNRRAJTZNPVXAIYIZGCHYSYFK9PMPFFPTVESMZGQYCZDL","hash":"MNAMHJKRGYXXTQAAXDKCJBFXLXUJYWDCGUKXBPIODIKMMYMRREHEENUVQIS9YIL9Y99OSXG9STRXILQH9"},{"in":"GBHVOMCSBEHTAHQZFANOLFD9AOSSJXS9KQQ9ZSVFTAEUYQJBHBHIIMYUAMJXTGMFGXUCBZLLUYCKQRI9GLBVRCICINUHPAHANFWSTPDKXJMHUQTWBENQGCOFHKGVVQYFOPFUPVCJKPDCDCMXRSSRNNMMZNDWRGEQCFUNWDIAAHAJSEMMYVOXQWNMKTKHUJMGRMTDGYHLOWZPLFQCOCXVJZOSYKHBXSSAUQUFDOLNFURPK9N9GCR","hash":"VAGQBCFWWBDFWUX9WBBQLKUQOBRSTVECPAONDIAFZSABMUJXQ9JBRQQWDTRUWEPOEVMGCNQMCRTKBBJRB"},{"in":"FAJMXLCSMZFALNIEAG9UDIPCTDOTEJXGUYLAJF9SERJMRNFOVYK9RIEKRHWGXZKWXGHSAQPTBRYERQYPNFCHDTHQTPHGFYZ9ZLARH9PHDGQJYHURSYQSUTUGQNRKXBEIO9ZTSIOTFNKLQJABBUOPNB9SZRLCCEDE9FJFOJRRBTTCD9SEDNLHUPJF9PFKXJEFJRTNWNFROWULVTYKZAQZURPFPFPRIAGYZYHGLCYABOXQTMVZRHK","hash":"TEWMVVJUCHLIVBJRHLWFP9VSAF9WQ9FJEHGXDZHUYOVIJ9F9IBBWXJCASDSWMAKWOPE9XYRGBFAEMRMNU"},{"in":"BRNMTUAG9VZ9PHTWBQA9RLELGYDPFZ9FNRGBSNU9BEJOLUVADDIFHV9AMWIAKVIAPBKXMUC9EWXZMRNFL99XIQMFNEWHKT9PVAZLPTSTOAYWRLTYFX9ZWJTITNIFVEMDIJCIYZAYFP9WICZRQJIMCFOGRKCIUYWVUMJOZSXXCITRJAPSZRAAYBFUHZPOXHOGLPCCRYTSUJFSDWXXORYJGLBYXOSGXP9VT9G9OBEQRC9HDSCPXGF","hash":"GWKNTUYDCBMSDYQZBPVCOFICTPVRY9ZQ9SYNBDOZFPQPQUNO9YKNHNPFPYLKGOIOWHVQYURRMSAVZBEMM"},{"in":"ZAQVDLFNHRDJRRGQXRUERVXLECMUKYBERYAQGNCRTOABBNCOB99RHOFTHNWVDTOLGJNNWHIGCTHHCBS9HKIRGEA9WXJVMUCCSOZBLQPNSUFFZTHUSNIGQVJIDOACBMHUHZPZIFSJTXOLCSONDHPOBDTAP9IQDDP9VDQYOFTLDSXNOZZDJUACKEGW9FAVEM9SCFFFREUHIVQDNLHOHKCJNAFOFOIYWDLFAGZOTQCDXKBBPRYAUAV","hash":"TWSDAVTZALDQXRJHAIUUQNFC9BRKGPPCKQGVOFBFCGLNTZRUOJCEAJFKLJQIDPTJNKZZADVAMEZKOYRHY"},{"in":"SBVPUBLNDIDCEQWBBFGQDBJOXHDOWNYICZXQ9TXMCPWRZHZLOHVKFGZRYSVOBASOXBTYHYDFVPZAZVGWUCCHTUHPNKYLTHLESUEJQUSGPOEVRR9PWH9RMOCVKNDHQMBQVCHQQCQNSXFKXBTHVNOP9ESEHFUIZMVIPQCQGWCSEQXBKLOIQAZNKLAYJWWDBMEWQTLTTYWFSPO9MMAGGGQQEWTWQQGABILYPVTSQPJDD9LBHKSDMTB","hash":"QRBRIZGLBCBDVGZYFVIW9LUEISSYVWMMDAWBZCBIYZMD9M9NJ9GBQMDOMNAS9BJ9JYRDWTIIHPQVSARNS"},{"in":"KAZKQCHVGKEPIMJZGPCAZUTOQ9TAPR9NZOOPIYOWNREJIPFPQYOTZXWZVPKQUCANNFXQMTOFOUQVITZSASJCLOCZIOZMKCKFLFVCUROFWQOMBBBVTQYMAV9HD9KZHZDQIGXYBYXWVSILUHRVBMPBYVJFJ9DCSMJVZJUUSQFAJBMBKQJIYYCAOYRUVPZQYEM9JIPTLLXYY9LVFPVBO9XLXKDZOMRAHHHJOLNURVBMJS9WXXSQOVI","hash":"JQHORWKCRSHKY9R9SMPKWERIMKOUAW9OXAHCCPLSRWMNVRTJERKZHFQHGHYFEVBODKNIIGCKMJK9XWHMC"},{"in":"XXZTOQJQNAXWCTMDTWXWPOFPAGWQNSARIQVGMVSDKNXTCKLH9EOTHTPUVUAXGZOJFKNKPPGYAPQUPNZTEYMZDOSACAHEGCIKWEIYQAPBE9BJCMODBVRVA9DQJFBN9PCRIHDKRLNNGPYIHZLPMKIOPESNTRWWKQBTKBHUPKTRKQCTSAIAHQQQOHAIH9KGIDMDQPXFX9EJJMCISCSGHPOXCOCBDYT9MFEAWJQGTFE9BSCECECDTX9","hash":"EOMI9JLCXJRGHQNCMZAMIYNCOFPVALIIPKMBRICYCPDPYNEVCVTVXFSJYQTCOBY9TZYYVJQZYFSLPDFYY"},{"in":"PMEAPXXAENPSSBMPAMKBAIGKBIQTNDVDIBODVPCS9BZPPMYBUZPAKOGYKUZERPTCRAPHYARXZBWZHCIUDIUGFRRAGNAVIGMBKBHNTLQAJNWSZXJYNAAPKUPUZEICIBZBDVAFUKSJBGSQPSMPGLRJVVBFPCOUTPXXQZZFMLLKC9FOEPJWIKVEIHXSK9GOIWURDIJROQTQLJLABNLTP9CWNIKKQSDPQNHUDCNDHALDYCYQFHDQWRS","hash":"WO9IHCYRHPXPYPJZHW9ZEKUORUFEINMQGGGPMNOZIWYMOZVKTDJXHJELBGYGFZRECUFWEYVNOXVFTCCBQ"},{"in":"ZRKDCJZIDDDVWCBLEGVZ9NXEVVROWGOBZDY9HXUYKNKTIFKPNUMOGU9GTVSCMYEHNJIKFS9LOZRNLQTZQMFTCQ9UXGPQMBFNWJWY9HOO9TZZKHDRKSDPKRWZKIFVFFALOBUZCTCP9AWUVCCHGQHRWYRV9A9XWPZOFGIYBNCSPFUHWM9BMFPLOCERO9DTYBVFMGSBGQRPPISRZQNSLH9QR9CIS9NEIHUOBXPSDIOZEDMFGKFUIWJ","hash":"WQVTBRXADAGGQTNGCDAPIOFQTJIGDAAIWIWO9ZFTGIFOSQURWBZMPAQAOPUPYHZMNQZYPQNGPKNZRTQ9I"},{"in":"KOAGWVOZGSAEFQ9XZKMNOODFRTVQZGHJHQDQBCOWBEANVTEYOSSEVGSAHVADP9HUIGQRGRATIPFVFOXGEYZMTNBAGPECYKHIS9SZFNAIHUEWOZSEJOWVSNFTFV9XWCUGYDNXWWCWEPXHFSTPPSIYQMEDZEXVUWDUCOFHIVB9NPUHUHVYFSFMMNFVCDXUXMWZGXD9CPTOEAEXXIEMGTCEPQWNWD9ZJOONIBJMZOMHFVASSTGNJEM","hash":"YTUTBNW9HFQBURSYMWCTMEAFMCMQDAZTBLAPABESAHPC9KFTTYAOAILLQIR9ASNP9LCAFN9SYVNFHFECF"},{"in":"YWSU9QYDYQICFOKKAEEYQBBIBQPUNQQRFRQALLXHPKICMXC9ICITDCQTQWYOFSHQLU9ZYCWDAF9JYOQSTFMKDVNLD9TIHEPPUGYEYNBSJPNPYATQNCOLVRTGYRQKABB9BS9HLVKXRAVJGVNLQQDEKFM9SXQQUDKZAYKHMFKQCWPUIWZSQHMEHGNZFYEFOAKPGXHMQADZJZWOEQLS99ISMHV9KRWJUODLIAMEHPCEXIFBJNZPBFY","hash":"GUKPKEHKUIXJHJNUYWHJKHN9UIQH9UFJGVSZQP9RNJAHAAFHZPYXKMNEGDEAPEJ9MKJBGTYFMZSCUQUST"},{"in":"XRICUMNAZCQRU9B99XDYOYPIANJIMHOYIHLVNHTXHQHCCTFAZVMEC9PLFGCIVZVSJUJNSCCGAVIOJPYBBACTTLCDYVMSLOTVOTGKRTDCESCYERYJ9FAFIFCLDJMGMAFVMLRPGOPP9EYNXVBXVSPCKFU99IRFHRUWL9RXZHAGUYPDSWYYENGGRFSUKOQUBWIZTFBAGXRILPWKLBT9NBXMFXFFCYPJ9KJOFVLGQNIGRZUBHAOFBZI","hash":"FBB9OSKXAZVXLHKVTZXGCMNUCNQZILQBIILPJMNLUBJDOBKYQKNUPTKORUAXKANUKQPVWIUQCZN9DUPMQ"},{"in":"YTXDATXORRIFUYKNNAAQSVRRWMVEKSMMGNEZRLBRL9TVEQDCOGIGLWWFPWZKVTBAYFKVFXDOBTFJ9FUXSC9YJZMPVOLQRVWNKBRSGV9XTAYULKIWTBLEZRYQZGIXCKUSAZHSGIUDCO9WLQSIJHZWY9JAEBDGGHNZPFHYIRYXZM9EKQNJYTGUZVTFYGCSJVOWWZUYKFYOHXZJYSAQSLH9RSQEVEJJNYXIK9WAHXNZCOPQVWUVT9Y","hash":"HSWWUTNQT9HZDUUMGBLDL9XIHQNVCZAKFEHCCWVPXXYNISXKBNIIHUPQPDOJOXBUHMGXWSUSCPJCORDBH"},{"in":"DRWEQEAS9S9RVYNSZHONBVTOETQILYFGNVLXHCTPICWDKEQXQAQGF9BVX9HPPMBLZVWMCXINAYVSXCZVVWQCINEWHDYRYBJMXUPLXP9JHPXWXREAV9IMAVNJZCZEZIMQHGJARSITZJZEHKSRJWBQWCXWGVKXQFJTFPNFNGXVBLHCYAZMARUSTLDXLRAHQGTYPODQBGDLCGLIHS9LAIJIBSBAYGCSPNECNCDYLJ9LYZETWZOEIDB","hash":"SNRALVUBTAAD99JBBKUMHEVVNXAQ9GWEDOK9BHZTDRKRY9NQUFGRSZZTZYXLUFMLGTLACQPBBDXVUHTND"},{"in":"FMGX9VXPFCE9FBABWRWNQCBOAXGPUZTPOLOWVOLHSPKGPZTWERUSGN9XMPSEZAOKRHKZCESYOVHRIVSQNHSCWKABUBW9IGBUALCHTBXIGOOFXSMV9UGDIR9SWEGODOQHEDPOVUGPKZYIKTQHAIDRTUHPABBCBITZRCSLEYEOCUDIZSWHYVSCIHPYBLWGUZSUBIGCWKYGELQQXL9TKOXNUEHCPHTZAU9OAJTUOMCEYCZDFAHG9YY","hash":"XCTIJAFSHUHEVP9MVESNNRNMIDICCDWCSADWHESJ9SOTFYOGUM9WXIEZXARAQRBUMKXJGXLVFFHUGRSX9"},{"in":"QPDZRKTPLM9XNXBQKLYPRCSUZ9SJCCKP9EGD9OVINNOJPZKDXTRTPNZGCKJVBWBIRDF9ADDOFVPVHLBETRVFQNVRPEFUUENMJJGDPWPKDSFTFPFXYJHWVNOSVDPDH9FNVIACOEFCGVFX9XWDVZSYYUVKCRPPCQINUMYFAAPELOMKNNRLOOISXFNEOCXUWBOMFBDIMLVT9DVIOGBADABGWLDWIDEEESHYGAAYJTMGSMYKBKVCHNY","hash":"AJ9OJ9HYHWOKSEDKKOAQTUXIOXGEZZP9UGTFASUXWLHSSHIIKSJHODGA9OQCWEMPFWSJQPTOFHKLRFGJE"},{"in":"DCSNVKXIURGIIMJZMHMYVQDRCZDDKKMLEXHRSYHCCTAEOABMGIEDSX9SMCWEEBMMYARWEXSCI9SWEQPPTCNF9TTTTTDDUJFLISQHZHUZUTJKRQHRQOMCKWZYIPHLKNFWWZSBERWJYEYMUCALWXIKDCVXUIIOSJ9VIKUFCHWDCBGHOLYZQLDM9ZUFPHLQYFZVXVLYXOHHCNWWJYZFLN9CCCKEGVIFMFHOBQBQRFIGGJJNFKLQVSA","hash":"OXDRCQCZSWIFLPEIQTAJTMJSPWEOGNHHHYCDUJQONYDDCCKPEW9DXBSFEMLDVBGDCROECTLDKRJRPDZDY"},{"in":"IHQNUMKYXLUAYGIISVSBSFBAOMLRVCUEUGXIRXLVOVO9OCEBRHVJ9PBKMWIISZGYTNNN9MERXYAMPIAJLVQZQAMHJSOGJPDJLLVHSRZ9ARTCTVRFM9VJBAUHSVKCESJAFTMYGBSL9VDEYZTHXRKDJBA9MMEKZWAKRESVF9YFR9CVVQZMQOEMF9QARWWEPLNPYANYRMDUABWXTFTGVSVFDAVKOAHBTKI9XCQKQOTUTVTVVA9RINW","hash":"RPIFLCO9AQBOLMSEYNTLXYRDTSFRBQDIQJSMPANRXTSALOKATOVLJGLLCYIHVKFJEATHJWIE9EFJAQSGL"},{"in":"TPNHRLQVG9THMUXMMGHTVNYUDJPPOBL9FCNSIAROTGZXOOT9EMGJUCCRV9IZIZYJKCC9PHVXHJBE9KHBQIDWTMGMLEOKAVCRSTVECPT9CK9CDQTXDKTAYLGVNAMIGELIUBKOIIOAHEQIQADUBNRVNTDIWIS9AUEBEAPSNABNGLWUN9JHTRCOFUOOSI9DNPDXKTGHUKHPTOYEVB9XYWPUVVABXCXCKEWKMIAWOMHJDNITWHHSUOT","hash":"DMQXOIATTGVPJPUNESSYFHKCVPIMMHEXCGZCUXLYKEJWSNXCFZVYYXJBEUVZHJTPYPRQLXJXKZHXJFDUD"},{"in":"YWKRWTOSTLEDOPIKBWEXMVRI99WAJUNOLMJVGFELNCESJREZEBKPXJJVUSOBGGK99JGHRJFSAVMSAII9TGEASXWNZBBCJESOBFCCSM9QTVGRQJYHOKPMTDXYFIJAFBVDTBDKVYJJJLZIVQ9MUQKYZGGWHCOSKQRDVDDMEELKIPOWNJSFRIJBMAKFQUDXISRWGFLREDQCGFZFIYJUKNZJLZYBJPZLMQCTGZAEAYOGUHLMJPPQXCQ","hash":"PA9JBYZCIFHWUXAPXVOHRNFVOFVXTIWTUZHGDVPI9E9ZSYHQJLOSRRH9FTTKXZCP9UFBBXEFKPVQRDFOH"},{"in":"VUHQNZZUGJSEQML9QNYCHGFDSLRLQU9YQCVQPDKQNOVPWRUWISXMGVGDANEKUPCYGPWHHBMETQATITGTXMRPSSFL9XAHG9O9EJKVESYNSSHMSKMROXNOMFHQYLPSQFNXNZTWISNTUTXGSDRJKGDUBMXVZWZQNCVJTTSNWZNFPDXNJXYIRIOQFUHRODNJRUSORKPGQ9UNRCLODZDPXDSELGBNLFBNLOX9AVEDIGMPXKTHLSLUUMM","hash":"BJUJRUSZZNOLPRVCAOJIGYNEKKOZBSWTZRZGRAOBBGMZKNHKHXMVJLVCZATQSWOGZNFBNKPXUNFTSXIL9"},{"in":"BGJERYVOQHBPDBCWPNMVLFPNWKTFGOSCPQDITLLLXXTCDNNPJNVWPMBTUPXOPMYAWVCJEOZISNQSSMBWKGBNGBPZUUP9UAUTUKTWZQVOBFMGDTAPQYP9NTUBUVSLWXZZTDQYRCIRHEOE9DJDXPMRJPIPDUSFJDJEFKMNGSAYXBUDWWUFPEVRZSFHPFY9SRCOKORAGWNMNGQBPBEFCPYWKAULRLYMWWTLFALXATQBUDEOGJBAQKV","hash":"MAGJFRZRDEGA9DZFJGZDENTEQIGJZKXJYPSYZEYEGYZH9HUJJ9ZVJD9JTWGDOFSRGKGAJSGJVWVRDIJGB"},{"in":"FCUNAFGOTXKPUENKWLLC9WSRS9JRTIJZOMBDNIBAGCIXOWOTAHPQXIOTDYJFTIGAIWBDTXEDVVYRTSFTKCZ9ACVCLNQMWDGASLRVSSZCHMUAGSEDOAGREFSXWWOZKGI9OCIYPVESNNSRUXXDJIPLVTDWRCZTFDYEXAWZONZZKNHQLAHWQIMKTJIXRMPPRNXNGGMTVWRYCBYDKZHKXRMTDDQJYESSOUTCFU9D9UOJYGBETSYXEKW","hash":"Q9SHGYTNVNKYUSAZCQIBLXZKLKCZFUBZZJBPNMDXUHUWBLBSDBDJHAMFBIFZIQDSZ9UHNLTWLGDUCY9QF"},{"in":"RCBY9K9WQQUZEURURNJZKDPCCMTTIFVPTTPYSOBGCCQDBQLPJRKTFA9IYHPTRQDQFNFCVPNOZEFXYGILBFBIHZQCSKEFIDUCESFARDXFDLSPTZHCHINKHNWADDTDASQGWB9UEG9QQFJFAQJFKDPZOUADGORAHTQEJWNPIWQAXQHIUUW9YWLFTAURQQQXXKBAFRRUGSNFEBIDWSTYMEDOJGTWIZSXTMYSRLAZYCWCOUIEIZQAPN9","hash":"NHSJ9MVDL9WLRGRVBAHWRTLAZHI9MFPTKFYHYSJWK9ZAOFRO9VQMUJPBBIJDQVFRAJSVCXR9LHBTBFPSH"},{"in":"XBFWTGLSAGVJCRMEITJBGWRYFQWJULKXKDZD9QLAXMLMHIDPTDHA9JSRPKYYRYI9NYAFEWDSIFYCZRNNALKSEPRMNQSHYSY9TEGAGAUWGUZQOCMZHNEIIUYL9ABYYE9OJUPPNAIZCLEK9DEQFTHXNVCNHTOKJVEDAQYQYFNUCXZVATTSZSNUGXFLHJEWVYHAHLUVYJEXRTMIWBBREHXSGOJMGPICNTYGUBUBOMNHMHMPADSNRKG","hash":"9ABSNWGXTDS9KNLSLXVMF9CFECCPTNHVEQHRXTBEIVVVJPSWZMAOGQFGORMCORAQUDKPXQGHMDOTMMHIW"},{"in":"WHHFISLMWMINGIMMKDYLRCOHDSXYSLDVFPPLZYOIRYRFBUJHSITX9KX9ZUCLJVCFOJGEYDTIOWSEKOWVGFKJABBRAGVSZZBTUYIFXVEPZWPMBYZTCYNXP9SQOOBKL9TFSHXLIABAJHBBLKMSIAKOSKGXHHHVZXZWWIGGCRIMKKGOOWXTGLLKXFZXVQYQXOFDCPCA9T9VKMWWSAYJFBHCLKMUHBCDIHBZAOJCUFQQQREPBPSEYX9","hash":"SKBCNRUDLVXUXWKOKRJRFTOEWHGZX9ARW9UMSQQUHGFKQTMHLXCTOVD9XQNHR9WIDMZKDPHGQDJIBGCER"},{"in":"XOOPWQZPIIBBCAIVMIZSST9EIHRAAATLPHQMSRFILCPVTCHUVJBNKICOIEAMYMLVFYXYQZNFJPZBXCMKRQLSFYBPH9USLCYJZBHRRQFHUTZGTOV9JOZQITQKKERFYCQKRGUFOTFZKKVYR9ZFMCGXSKQ99VP9NVJTZYKBEYSBHWETDSSTBTSYVOFRXZNZERHBZFYFLBCYVF9HPYLCYNCYWWNDZZCWHLTZOYJHQKD9WTFFWIPAUCC","hash":"EUEIGZAMY99BSQJPZWTAROOB9AITMBVOPDTDZUARAIWNRBFHWRV9MACJOOGVFMFZOI9GFOHIAKBAFIVGR"},{"in":"MLHMSHDTXRBRNZFVARRJMLLVMFIIPOFHC9GAUJZ99SAGLEFGYDTMUYH9FWIZZYNRLYNFCZUEKQRNNHNTOXHKVWCCYEVRWYNOGBESBBESUDBFAIUYZYGRVTOAROTAESGDUCTOUESGARNBXHNCHKAQPTMJNADSSKFWCNN9BBUVTFPILWMPWXNORZKZLEXBEGTRUQARMNWI9PJTBJUL9ZB9NGXAHIDQOPKLOUYGPPIVULDBJIZWUCL","hash":"YEIM9OQYAPCXEDDMBAIYJECNTYCFTILAWPUSATPLWCLUENZBMBJTNPQRJWZLCIQINCMFOMOOGBJNVUYPG"},{"in":"NZPOTYOEJVIQA9SOBGAGWODYTEIE9PUUQYGECFJQIZFREYMCZNAHYPUHJJCVUVYFEGSYVDTXUYAZFRZGQZMOGKLYQC9I9BTPFZBHWDAVBRYNEKUECQMLWIMRVPKMSKMQJR9EWWVBXTKXMGHYBACLQCSXFFBZIXBYCAMUNPEPHYHJQCFOFOKKZYQNPORYDCSRJZRQXTXIAASIFLJPTLSJDKECHBXOKZAXZBGNSRDA9CFZAJIQCAT","hash":"LMWTAJCTZNHWDUTVPLBOQSF9WKOPGWYQQPFQTGMELIOJQCOETYBGRAWSPKEYVFDTOJABYKG9KEBWEZRMB"},{"in":"ZDP9PPILJGQXAYRQLWBJ9KPCEMOFJAOUVEGUOYZIUSVZ9QKSVQ9HXGLNQDVUQACXVTHNGTXVEMGAPQJIRFODGAIYFJRRBKUGVJSQMXJXLGLRTGCIIKTIBO9VDKBJWINCWVCVSYBMIOXRDGOSIZSGWXKKIETGDAIG9UOMSDS9GLGPKIPJTRBAHXUTU9H9IBSKSUUHICPLQZNARZBSNYUTXJNRVUWHLIMU9KQVDZZVGXDSBKMAJAH","hash":"JMKEKNBQPVTFWSSIHKHBPBBQS9YYNGZUCFEQOLRDFASLXKCEZUNCRAHAUDVZQWRDAZNBXONGIQNJUUMEO"},{"in":"UVYQZRZNTPGDUCOKEGZYFZWMA9VWNDBFUSHPOHBKUMSPBMECRTBWRTAZRKBAOIHJUXTVSADZXRNUXALVZAOGFORDNKEIANSSMDVIYGIGFXVVTTAGHFQJYUPBDVAAZPUOYQIV9NMOPU9XZEYPGCWYFLJVLQJPIGSUIDREIHHBPFHXMQNT9RF9VEDT9BKTXBUNAGFFRVZKNWZLUFETAHKYCJLUNFXE9WLWPJ9QTFAUTDYMDDMLMDB","hash":"MAIDRBAFOKJDZ99LRAUVOANNF9IDKRZJEGBXOGPBVWFPYVGFZBEPMUYTEEWEBBTVWQBSERZRB9XSEXWVF"},{"in":"KPKGWBGSIRQWWIHM9WYNVSKTDZGMIFQR9FHDRMLGUOITJACEWHXCCRGEWWNBHTZXZCIKVBDM9GOVSBIJVFYELOKLKLSJCCBOFKSQULMTKXPIPXOTVGXZPJQMOXUDTHRMGSEMWXTPMHFWKHTLJOKYLMFKLXDLOCMERQHJBPGFHTPUVBOD9DZGEBNTWASPFBCRB9VOYHVQROSUGQA9TGUMLWKXGPHV9QYFTSNHGUUZIJVOCKEHWRO","hash":"PBUZFXDMGJAYKTHQSUSTRUHLBFEJ9HSIH9NUEBJPHLXDVILMHIWSONZLRKGYOFZVQQHHXTHRMEHGNY9QT"},{"in":"LWGWJARL9HDOBC9ISIOPHQLDLTX9PNIJDDADQZYBEZDNAMGIEDVQ9CYFIDRCKKJFQDPDESBZDQSTIFNXADKGZMKVYKFSBOVYEHWKQG9HFGLBHUBSSNCPYBUBQEZQHNX9VZKTROOBADWWMPKDJ9FVCQHP9YBEXREKPGJPJHPCJDUZEDCEZQWDWOVUCFBMHXHKXXUCRSYELJWGWJPKTJEWLJKUKRKYLPJYCJWCR9KEOCNX9ONXXFH","hash":"IAFQWBYKEQDCTSMUEJCPNGFZJMBVAXPNED9BJOGBGPBFLSINBRWEADYZP9VVDGZMCPSFPLOXWZDTLPJOS"},{"in":"NLWW9LTROUWHUCYBJHZDYKWVHTDHBZXMGBIIJGJALILKYKHPWMJH9NMAD99HCTUGAYDBTQFV9THYWJT9VSVZSZ9MRRCVLQU9NJUPDKIQI9CMEGJYJUCGMWKPISR9SVHEPJYYMTPPYBUTECANWTXJHLMKFGNLAGYASCWNXARHQHVMNWAGKSPTJNINZUA9EFHKMPFWLVABTUKRYFOBYOHXVNFYFTHENEIJCDDIHJZZFCSXOATQHKZ","hash":"YSCEJGVBWBSDFTCOGGOXQFQUKNAQQWMDHJLURRBLWILDVSFEPX9IMRSJEJSQVTCSGWZVIXOSY9GBGYAPV"},{"in":"DPCHZYVUVLVPCBFOGXQXLPGPZBIZLHPZPYEPGLW9DGLIVXSQEOTC99IXTDWAAWDTANQJBTOIXOXHTGCBSBHDDRXXVVPQETIDLNUXUBUALGSDCODSQDWKFKCISWHYF9PQGFAPMTAALUNVZWPVGTWU9ULBRTLWLLDI9SLNSFAZCNZZGOPHTTBCFVRQURVXBF9VVRDULRXWIDSHHVNC9SJIRPNFOEBCHRIQNCSWCZOMT9BJDPAJKOP","hash":"DALSYNVQWIYOMFOBWPNVSSWIVLUSISSQA9PMPNTNRCAXABOPVCYDRADSYQYNFRVWVLWAGAVTWSARFRJCJ"},{"in":"BXFJGHACFBASSGZLGVMVNLGOHPIYSDUCUNLPPEATUFCKVRFQ9LRI9UYTVDIXKITDWRDZU9ADFBBPRKFYFJL9NYBOBYBGPCAVRHDJNHPNULKHOGHVLADFAUIBNTGEVDXHALEYRLEUVNANXQR9SIZDLKSJJEIINAOEBAWUA9MCSHMGNKUWXYAVJFLNTMJPWBFOHOLCZKBXOJPZDQSIDKXZBBLLVKBQFZGQUSBJZQPNQGRZKEXS9HJ","hash":"RWFTLCEATRNUTNKTZHMGCMAKTZIAQOYLYNEFRMYAVBLLWQBNJKDRM9BLVXBAUUTPNDQDQHIACMCPKVFSA"},{"in":"HCNJMXHSQWDHHYUUTXHMQPWNN9GWA9HDJVHEZENVMGEIRINDXYRIYLIHZHSRSRTYBFUAIUWKIGGCHHTGSAOQBKITGKVXPRC9MEIF9DJFGYOVFYABDXC9WEJIQLUFZJQSYV9SFRXGPOBNUGAYJUDTICWIVVTZBDNYVSNXNESFRTMZJPIGLXFHJ9WYRJAHYXWQUSPMVL9LDZETNPOLYGUKRICLDQJLCJ9YCOVDF9DDHFIBTOONGGO","hash":"GW9DMYBWWLQ9TLPUODHFJFRAQDXUKMPUXJHJILQMXKLKMK9RNLAX9RQEERHJHJKXDEKHCPRZOYNAFEIOO"},{"in":"9ZSLQTYA9XCCUDWJDABCXCWUAHTUUBPX9VNIBQQEEVPTLJMLGAYULKGIIPXL9KENTBBADQINITTP9PGBZGWXW999CQJGXDQKMUFMFRX9PZ9HYIAQF9GAJSS9KZMYBGKFABCVSNNNPSAKXFQDHHLOXBVVYQCWWITWTMAJHCHVHCGZZOTHMDMBJJEDNWUHMSWJHTPXYNS9KUUBIVKPUZHCCCUAM9VAWDCHDGWMXQAWAUEJUMIPMYK","hash":"KLNTPNGIR9FEVXUKFJZKFIWGOGPRJSOQZMGPIMHITAKSKWOZRTETOYUZGBPC9XJAMCGUGYHWMINYGDNID"},{"in":"EHHXCGNEDYEOTFOJBHBNMYKCCHPSOY9TAUEKBWSYOYVTYBXJPJKOFFOWVETXALJINYYIXTC9BX9KDIVLCJQBPSBPUASCG9PCUGJEPDTMV9PFWFFNDWXFMHCZJEAS9MJBZCSVUXCJKQWQOGWXJDJZEQAHFIXEQVGPOHOTMFOFUYKXPRJFICFJBNEKAZBTKUOJMTE99SQMCRQCKKXMVZUERTFOVKGQRKMTWDMROVIVMGFOKLPYGUD","hash":"ZXEDPYYFGPXMNHKQTG9IVFPDZYBBOIICAJKSXQZGWYQIMHADBOJDJZDFHFLBEYAUEOCT9FQXHAYQSHPVI"},{"in":"XQAWFDPREWDLEDBAHDRHKSTEGRNQKUASQXF9QCZGTMXAXQJAOMMOT9PVVPZZWSIUVSPTDEJFAVIOMKIYFXUVCHJLOHSUMJRDIVPSCYELLDKZOPKEOEIGRDBYGSGSAUNE9UMXWWPWZ9NIIAGSRWVRMTAJZTLASDEIXQQMWKUTXNQVFYV9TYJOMXRD9ZHNXUERCRFOEWKECXWNGSJSVMTNBIFQBFEAQEEFUEOTYKMTGJAHNLDGJFR","hash":"BBYTNJQXNMSOWJHYM9GBRXPHTXQ9QEUNUCWORRDCIESADTXWGSBWRRPSWOXRJPRWAZSDSFHJTIMCXEMOV"},{"in":"FTQSWMSTCHLZH9HWWIISM9LINTLIE9LHDTSCYCNYFVBWZXPGNWKGCNTVQHJDWXEIPICLVQBGNZVTBQPXWQBW9KEEWSPVCWIHAKAIBDUCFAKAKVGSPUNKSRAWTPVRPGPYKXBDJVSTUQXSYHMPB99IJNFS9JKONXXMAMVSYKAXXNTAWZYLRBSNZL9DUDGSOFRUFDTKVXWYRNFEXQB99IDQJLADLHET9HWLSKELFRIDJRTQEFTFSNG","hash":"QPHNMANYHET9GLCIRSWJDVUDIDGWQYEFPWILENCYRHAAGNDL9YRKUNUGKYWLDWOXNHFKQWDPDCTQLSKTN"},{"in":"ZOGEFWPTXQ9RHNDEGTXDVNRSLCLQHOBSDXMYOJREQTVVWRGXJFBSKPXXGTXDQHFHJWIMRXHDGWOEFIROBKNYFYBHDYNQ9X9UJBCQD9ZCXKGLNIIMY9AXKCCBIIJMUOE9SDYHFXJTMIDBESHOHRJEGHNROYBCQODMYMWTTG9ANWAUBZBPKTPBUEIHV9GBGGFLQTTUQ9YXRGIJID9LURXUKFEW9AZL9XEZVXZXWNHYKTSPZHTABMC","hash":"LUIWLQBVSNJPUGSJECRWPHCNGSOYMMBRCRSYDTFHKKMNQTCBTTGMDWOF9NTBITCQVVHBWKBSDF9H9SLGU"},{"in":"HIUVL9UUKJIPPRKGEHNAOAIRRKSBPQNISVOQKCUWGUEZONUWCORMCIFQLEJMUXEXVLATMWILQKRNGRMDZWHYWPRWGRSQANMSDDICCKBBDYUUTXZJPFJJFDDEVMUCIFMJXUABZANHCYMGB9NA9KEEBHYVRGNGYOLGXCRZWSZOAPBDPGV9VLERHCLSLHPHPYDDSWHRISUAORHRNFWZUNNJUKGYPCRHEOUOX9GKOXBOQZDHKEATTNA","hash":"JRXTDXHHKETFQVHYAGRNDGGWFDZDDIB9S9UCIULYHMMPFKQFVSUSEB9DSGYMCPWPLUFBOTQXYBQDCFSTM"},{"in":"ALAHGXXXOYIREIHC9PMIWXGZXCKEHLXHF99MGXAWTXCBMDSVWB9AWSINAEDROBB9VJZZBQNYN9ZLRVUCXGQZIGLDOSTYVAWUFNMUFMZLW9NIWXZOAOBLLBZEPFQUGYAIRPTKIZSSOQCJCESNBWZQUMJPMHGSLOWBGSHWJUVUJQYBGMFXRMLVBL9CLRUYZOVLWWTHEUKWFW9VUWTNMLVRRSYYZHHAVIILLPI9VPXAVPCXUJNRPTT","hash":"ZGWQAALVXRFLANYPCWQFALHZKAVRATMHECNXH9BSCFTVUFAOQLVB9MJIYNYFJLP9RKGGEOUDWVOFSIXOP"},{"in":"KUTTYHQYNSJU9QNYAETJGIPSEGAARHP9DKNBR9NAUKOPXDDAODNXYEHXAWCFWQB9WODDHXKFXWSEFHOJJ9EMZ9KMAAZHWLKAZABOHYJMZYCYRQYAIDXDVUQFXVTWSVWIXUPVDQNKUDDA9SCYUCWJRKVUOBCMGTJKEHCUGXBLZMHXERLSPRPXXZJMTCMQQPTAINJMJBBDRRCJDUXEHBUUFDZTBRSXOOWYKBTEEQCVZ9QGDTGPAMU","hash":"YQVUZ9YCFKSAFECQCLDKQZSABSPRRLIGIJBSAISDAZIPOKL9ZYYYA9DVVBECJ9AX9TTIMYEKGFPAEMLFJ"},{"in":"NBGEJHYFZ99NCRCTCUSVDEYUDSUNSOBBXAWXCFAVRJWIMBBUKOMPAS9SGIZKRTETSKGYRFCXXXFMYCSKWOBAELKKQQFRIYBSWBCMUJJMPFVEQN9OJUZUMFVPPZYMSHMNPSWGQSYVFOHDHXG9WANVLOITBSSVIFJKADBUQMOLPYRTTJNBZLLOCJFUSYRTIBWVBIGXDCVHKKMH9QMSIAFSYHK9XMDBCXVNVJZQ9QPQGKTXIQZRPJB","hash":"BUDCQXWJUUVQCMZNAQVUOWAOVE9YAPFSQNHZPXOSQFCOILUSH9AXXSTUOLNLMYZWFXSQXGYQJRLE9XSPS"},{"in":"KJAASBEDYHXKJLTWTCOETTJQTXJDMJ9JNNKWVHVHI9BBOOCLFNAHTHWFFIVQREIHGKRVMHNGEGGXMRR9BAKPUWIUKSZLCRSHE9CDLIZMEMTHFLGUFZOWYCWZZBTGWGTSBPNJUMFTIWLXKWS9S9IXXHYEYFTLOEPWXARGDT9TYIAATZBZ9MIROPSJISYJDIZDYRCVJSXBQCJOPQ9LYPEZCQDJHHZD9TPHJLBWI9RICGUNRNDHLET","hash":"E9AOH9BS9RT9HVXEDLTAVNVOFBD99O9JKRKFHPPYMIGK9SANLQQRJZBFOIZZXJIOZRGZBTOW9YMTSWLZQ"},{"in":"BGHSYBOMBGSBNJ9TKFF9CGGBCJY9VXZMTDPWODDPAERZWXIQWSOKKIYOPQJY9WXQYBAXOJGDMOYFEFYETRYCTKC9EKNZIBJBKIQXZVQYPBHYKVBRAWYPPZMETOFONRMYICAIBFXECL9UROKMZARMJRNTKDMDGKIRYAEZEVLZGIPYIQA9RTFWZLRKBEOMONDEOUAOMRAALYYBSDMXJYVV9TWUFVGMBZHRPKEOCIUTYZ9QJYUKVEC","hash":"OJDQE9GUHYOLHEQZXJVJMUYEIELPQOYBDVMMTFWOCMFSYSYQQKTNJ9CJZYCRUCAFUPEWQHROKTOCPCFAC"},{"in":"PRRQUNJTQXZBKYCYXWFQDVKTR9TPOBUPQOGYOYTKJWDMEE9UMIMRJDCKJEZWEGMRWENF9ATCNW9QTNXCQI99LHZSFGNUHFVDFPGWSGYNXLULCKQSHPSRCSKKQJHT9KBNUKHTRIRKDHN9HKKVEICZFSSEPCACZJRZJGSYOTGDAAEESWGMNHIBDAECV9RCUTVEAELSIBO9QAZBFVNCPHRKTOJXXHDGXFMTDUPAJGNEHHHIZLMUUKB","hash":"DFBHUEKNCVCYYRYDK9PYVJGCCWZOFQWRWBIXMPYUQLYRZGNLYZLFIBGQFRGMBPCJHDETSXJZYUFYYSGA9"},{"in":"BDFBPOPSBSLCRNX9UREJG9YJHRXSSXNMLBZTZPDORZDHSGWUHSXJBHSBSXTHBZZWUHTGIPHDWIONNWDMLF9JSXYUEKYNQQENN9AUJLXISMCDOAUQVCCKC9GMHLDODBYUUZZZ9QXMOMJFGWPWUJBQAGCYUMDAYSOOMJW9QHRRDWPPWVNHGOLSRFBPHRQLDDIOWATSMZXO9ZKVJGZ9JXEPEAMJJCCJIEWKKIAJMKBTQCSJDIPJLDI","hash":"DZYUSI9FPNOPMOTOQABEJIHMRMHTQPODKPIKSVLWXRPPKRHDGEDRYVLTRH9VTTVRUZPYHVPWGIY9KKQLQ"},{"in":"JZ9DUSPAGWKJGVTKHXMXHJXPDOUBZLMYTFL9NZQUFBWZZOQQJIFQO9ZLTORIVYNWDWCTXIVIEXFYMVIFLMKBE9BKOSCHLRQCPUKEFVMJURGVZFKV9ASKSV9QACXIKYBJKAWLPIGFRAAXAUFOLCTJXQJFTFSZWJSH9ZMV9RJBDTPYWWOMCQFG9DQ9LXTFUEDT9DNXIKHJSGUWCJDNTNNUWXONVHULFXDOXFZUIRKECDPZFSRYQVD","hash":"DNGJUAVBEAWVALJVGVMGMWM99BPCFBGZMMQISOIWHVWVCJMOCNFILUQPEMVG9KTOTNDTXZGUYQSSMLULN"},{"in":"IFKVFFUTBFBJAMDVORRRCNONAOEUXD9RBHIBH9QTDXWPAEZNRBQGDCRMSUSMSQDWDTXSMOHWYSHQEFP9EHUWMEIMITECYUADG9UOISYRVPMSLATJTKULDVYDUJEYTIEZCWZXPAIEGPGAVCPOCT9SSYNGKUNNVZPE9SDBOYYMVEIHQGUVVBJJRITFPJECPRQHRSIWXQQNCKCLZU9DQLLBERCCWUKFOCBRLFWDLYJQLHGMEGJV9RY","hash":"9AMNSZ9QEVLILKEY9ERNZOMVLWQNSAGCQP9GUIWJVGSJYARMPQAILVGCUKHG9P9GXEGFJWIZTQZXBHAWO"},{"in":"BCRYVOFUXTEOSAYKBGLPIAJPVYZNZCDIELTZIHDPO9SJVBHNGHPJSKHDRMDJSHJ99CBDPY9YQXNDWBRQRRDZFNCGYBYRRGCXACVTUGZQZQHGGTWAMVRCNLKNCNXVFZOQVLUDYOQINQINRSDH9FTPACFXCHPUFCBNIDGXXDLGMKTIWCCHMLXQXRZYKRHBJBJNNXADMPRDPTSSXQKDVN9AQGXPXSJBKCMUSGPXLNZKNLPNAWLARSH","hash":"FETVLWDCKKWUTPZZHSHWKLVJQYSPR9QHUYO9RNX9TZCFN9IJSWGMQHHGT9AAXOMQCGMKWPCTLLQMF9KCQ"},{"in":"PLNVLUFPPNGKMBVB9HHVNKOHPTIGRDLJ9MSYNCXSSZTTHNVABDFYNSZOVUZWJIFJMVTMIZEDVXEMPMPDKWVVBHLPGTDFYCVAWFWVTNCSBNVUSWKVUOBFJFENR9MGYSXXOWPZIGAUCVZKOEQZUDCRF9HDPMDIRNLRNXWKVJSPXVIYKBSNFYKLTQTLLNZAV9YASLPBSBTQTOEYPVGKZPFWCWUIMZ9WYMFWTPBCZQQNBAY9MYQMDWA","hash":"TEIQCRCHPMOF9IUPLIBSENTNWFRJXODNTAXXZKYOESXPOH9FHOJCEFOGNUFXWXYZ9WPPNVEJYUQCNFI9O"},{"in":"MLIVXZVHB9KJEUUQJPFQRDFVXEIQGDPWRYXTWJPVKMA9IEKCQCTRZSLKSRIBEEFWMQDUDPJHSQFDLOUDIJMBPTLV9NPPJBJPEIMBGVWCQRQL9KLDCYGOKLHKBXRKJWALQSNSSLDLFWOHPEWYRBIUSMUTWBJBLGMQUNJ99FEDBSLUASVBWYHTSLMLTZKPQHLXURSNXB9N9PCWSJIQRZLDASHRLRNVHK9KWAIKAYNAGA9BJYAAJ9F","hash":"PKJXMNQFIVYZOYVGBLNSEUUOEQU9GYFXVSSHOTIITKDFUOPMUGTTRGXSNDIZYILBVZGWOM9YSQWPLKFAZ"},{"in":"JEEAOGHZGZUHVAQQ9TUJEV9IGWCWRZFTNQSCXVADGXCOFYXA99OHYCZGVWTVPVRQELWLZZYKCUWVRGFMMZLYMEDVJTLBSM9ZCMDTLB9XKBXRUOXLSEQFXWSGMUVFVQODBGJCGPSBIAHSGHNCEUEUPBWJQ9WEPPJFVKSEMUUSPKTKJBZQNPCARDVHIEGQZZUTDKYKHIPIPEMCFDDZXAAQSJLVABLDXGYULF9XKVL9NQGLPAMUZWA","hash":"XIRVBQGX9WWWYUFGYFBJHKDVKMPWADXYLGINBLKAXCEGRLPARISTQHFFETBIUSKE9DGTHUJXGQHBEYLXH"},{"in":"FEEEPA9T9PJDRTCLXOPMR9LORHGKIZOHY9VKTRKWQIQAJWMPTIENTWBKNHLEPUPUSUIVOU9ITQNQFRJDJVNOFGUL9SSRBPRKWYNLUHL9NYRNMPOAZYZCKIDENODLWWSHLLMMJBULORJVDDWKBSRFYCQKHMTOIAAXFCUGILOMAY9AVBXFQCWAODLGIGWITZAJ9XSPZTUUXJTPBGWRYBFILSAOMVXLW99HAAP9BYPRGFDAIKJJBIF","hash":"ZKM9EFJNGNDGLXOITGZQGHEPSPY9KBDOZCUMWPWRONLWRTZFS9HUUFGVLQ9BTRAYVHNOKCD9CIXSTR9AR"},{"in":"QWUYSXKQJQMXJMDG9UFICVTHKHCBGKSGEWAYMJVDUTSZYE9HAWHHWFNGDDQKATRZVQZOMUA9ZEWYBSTOYKLWLAVXMZQNXAEMMGWUQJPRMAWFYEFLDFEFKBJIORXUTPCFBITRIVEEHCGZOVVOHJWA9XBUNOBPLVGMFJGVIGCD9LUHUJEGNAUMBACT9TKMCMFBFZTXZDYUBDVDLHKGSAIQNZLGVBGTJWCYE9QRBOBXVXHMBOVKBWW","hash":"DONXUNQ9DMOZGLSAYYWORLSZLWDNBKORWO9OURUSPCQWEJAHVENYJ9QFUF9EJXXGKEJEPOPBGBOVUIQET"},{"in":"CWZDKBCT9SPGJGITWYOOUGFCETOEUPHXRSXBUMFRESXWYPFUZJMXTYYNFDYONPDAYPMIPMNEF9GOQFGBVLC9GVBFSQJTTUXSKTJRZJKKXWMCEDBRIXACIRMVGUSFZBOHPUFTUZFUIDMKSDEHUXTYJRCFETTKNZUTQYRBFOTPWSXQZHUMGPYIHJHELXFTSRP9FO9VTKHVYHENICVLWBVIKKPALIAPHLCAILYKLHSSLDKHOGQENDB","hash":"OPAVOFZUJFBO9SCMUOPBSAHFWYGTXXWGAPLGKBNNJFHXVFZTSPMJNYPJCEXXRZXV9KDXEDRVEAYTBMTRH"},{"in":"TXTHUDEWJEYXVSVJOYRZUIOJWQIVBGLIISJSEGWV9DHTMVXXDFEZTZKWAWJUITQ9TKOBXBVEEMNI9PMJWBLEJEDFTNPXEQK99JBBNBWBLDIDMICHGBQVAEUZPJQOKAYTPBFMYKZ9JDOKKUURJCGVOCSCZAVSMV9FZDNRVSDDJAPLBEPAPCDHOXNASWDOZF99GB99RSOMADKJQOIAVLG9WSMBSF9OKQPUHHJXOITNRSPIRXZBTMB","hash":"AQCQWSSRKHHBX9XYTXFI9UOTZMBM9LSHIYZFJAIYEEPTKXCHJVQOCGKODBFKQNTICWYKHGHRDRBCXEMS9"},{"in":"H9UABWSRFVJUQSIODHWWPZFODSV9GMWAKXFZBYEPFTU9ZOEZLXDTUGKHTYEXOSYAJFIIBNVDAGM9VRGJACUHVSTMHKWIBXPBKVGOYTKCUQSTPGR9USMJPRLJAQBFOLCCVCVGDATNR9KXHRDXIQUJPUFHDVDZ9DRYYHFXWOZJZZJGH9IQJASQXFEEWRCXYVLRIXVPSKPYHXDHQHKEKQVXGVBUM9SFSPGBLMOVSHFVBIOQMZNYSHG","hash":"9TAH9XGKLQZUUSF9WDMV9TFEFRIPFQGKFUNNPZRO9IGMGIDL9KIZCKXXJLEEPILVLODPBAST9VLZLTDFP"},{"in":"KIQJKXEVMJDGCDWSLTWVMXSDQXMLQXBTCBFLCAWTRWMWCUAAUCOX9QKYTJOXUGXKBHJPVFLHVVHOMK9EJXTJGTPAPWODOBVDZZ99ZU9S9LX9OSBHFEZ9JHKEOSOFXXPQSNTRIYBMBYCOFJCXMGV9XBHBAOWKVIRZGHXJCQNNHRDXSGIAFKBTPQNADSAIUVACKBIRY9OMUT9MCAEUO9KKB9CRCYIMOUKUMBMIJKRQLDSOWFFKJMR","hash":"QWDJC9ZTOJBCXANKEEDKDIFMDDRWILFYYOVTFSSWTHNZXOCLVQNGIPOMDABTCKQOSOXATYTCBZKPFJNMF"},{"in":"AGECYBWJWUPWMDFMLQGMCWPFGICK9Z9JMSYSUALCHONM9MKVLXPSIEFPRJUKQUKZJABXXJOOMXUCFCKWOHGFUZPKLNRO9CUOZTGXRRCTGMRITSQPZTYFOCJZRBOMMGWHGWJEUZSJBUWPOMVKNDRCLLBPQRKTDHRTIMBTBAFCS9CDMHTRCUVWVFINNKQGARVDQ9JCDZPZDOWBFXZUOA9NMCQYDUESQBUNLAEIXRQK9WLCPZFBVMS","hash":"CPHEINNMYGIGKFWYFCYDSPHCJTPTMKBVSFGSLRWUTVFQCKRZJGKHSHRJNTDUXDZLXVNJYTEYFVQDLYAA9"},{"in":"RIGDALYSQSNOW9A9WENDYFXNQPQEHZFBJBOFOHUCVTZIVWLQGJAWNXF9LRXFEEJ9QQSMYUQLJCIMQTJUI9ZNGKR9PHMENILAKCEZLFN9YYN9RSGQWLWZDJEVNZJTUZXOBZQWZLAYZVBPMCMASMBFKPEEXPOMIAHTTLGAPMLKMZHRHAEOQLKQZKMDVVMRXPEOZDNIKFC9HNJBDNLZWMHVNRQFVGQSKSKACCEWFCWFTXKMOTWMFCE","hash":"ELRW9QFSERDLPRMPVIIRQOCXSDELBORLEFSEP9H9RJYLHJHKYGAHOKCJCVFMOGANNQ9KHLXWLJQBAAMGU"},{"in":"HWKQJKKUVBW9DRKWKFR9OJPWVWZMJJINTEMKQGXPLYZGPCULRBQBWDWQSNNQIDCKQPYTLGWWXQUX9SACAZGNLU9SIRWFBRIOQZCPRWMEWVAUQLUUGBTRYA9KEGUOPPBOPVGWKNSUAMXZTJHBBVCBELNZIGNNPITAUDN9OZAWXRZHEJYHSYVKPKHACL9SUFDQVDNHOFQKDFPIAZPAWBMSAENFBRGLBFRWWFYXMIQEPAMBHDPLGBP","hash":"MXLNDFHDOLYLCZGGPFGCZNCBGHHPAKTFMJV9YHEYQ9NQPYNJIHBQMWDHPCNEIDWADZMPRABOAKIPSYQLW"},{"in":"VSTBSOOXSFWRWPY99BVWIL9SLONHUVNCVKNTSNUPNJFSGOCVUDRSZDNFVJVQRQGPTSRZIIROYJTBKKVQCEBRLKXPCTVXIYJZSLRYG9ZRZFM9GNRKIQAJWUUDEYKZCFSYVVZ9AQLMQGKZZSCPGXCRUITBMNGEYSYFJHUBQPMYDVSKEPOBCCXZITOFNTWQFPEKP9SIONGAUQUYBEDFWPNYNEANASYLSBBSOWCUQRXCWUNVEVVWYWP","hash":"MS9NEAIMTRVRVUUMYQNQJDSPBLCDGONGOSCRVQPWEYYEYR9PYIRGLEKZGNQZJJYBCSSCGSMSRMFPFJGVE"},{"in":"DH9ROVDRLCWIHMMXLFGHNDUUGVMMGJIIXDRPXQMRCIMC9KNQCNQNVXBAZYUWPHFVQLESZTMDJRSJFWSHQJSHPFGLDAFIYLPOIGIRCPRCNZQDHWMRBD9TTRZMAUEIAIDMLIIW9LFGZKNURPTWMVHJGDPGNHXHDOCIPAOFTBTAXGQZFLAUI9IWZLGFHVNQRGGEG9GK9NMXVLTMCNNTQY9QJIVBAHVSJBBMMUZDQGVAOVUYKTMFYSV","hash":"JAQVZFDKJBUUFHOGESKDVT9YTQRSKXTIMTY9KI9ROLVBLQOSIE9CWTTPEWWZDMZEYVSWLOVKFYXXHSFLO"},{"in":"OFTRJMRDJZTRPYKDDMWVCPN9NYB9ZENDDUETMSGX9JMMNTZYGPICISPIIMLKR9QFRXSLFYONQ9ORTQHTWLXWSSVQXOQBUBSCMERZU9FMGXTVJCFAFJNKWYKDKTRUHHMWFKIAJ9CNQDZHIAOETFYVGGMXYULMME9TYZ9RODCNIPLGAVFJOURZVZEOMBLWRROTSESKWLYSWB9DSVTXO9IGTOFEMZTZUMW9OZFAMEZSDVJDYQAHUVH","hash":"HKQRYSSQGJALIATDDZZMJ9JPGBJVYRQYDZVFSDYPOWULLZVCLSMWVTEPLCMYN9FBCKFCOC9SWCRXGVCUE"},{"in":"IJVGATDFQBNDGMUXSKPWOKVYWUAWBNRT9LHVQKIXCTWONBIIDFXVCBQR9ZIZRKRNQKTYAXQJUKBGVORVCRKXIOUCPZVUHUIFFYZARGUXHBJIUWSWKHMCRCL9WFRSZHHYYANMPKTJQWQZNEJUYGHKN9KCPHM9BULNQUSBFNRHQ9WSRPFI9VVRIMFQXCYKHHRMDRVWNUVYIXAONOJBCCXUCNNRAUZQFXIWVNKRBQIOSGWWCGVZVYC","hash":"APOTSRHMMWLHMABWDMVVNZCFDPASFDUSSUJEVOBSEHISOHV9LUERAGVVVVYGFZROPKGWWVRWKAXPEEGXT"},{"in":"JPGLTF9DVHQ9UCPXHT9TEFRTYKPYKDXRTEUXWPVTS9PDDZPRFWJLWHFUZIQZNOIGWBXSECJJCONFVV9GRIVFDLFNJPAIBFRIPQKPILHURLMWCWSNELJIGZCGFJNNQQIPD9G9BCFCDMHIOZPLMQFVL9AIWWUMRLGHKCOXVYKWDWCNNCQMRIABWKENSRPBYUOJWHWSJQHXEOTMSQHGADNTI99KRMCOGWUYISACQHLDCKNBUOQDQVX","hash":"LWXIFY9CPVCNWWINLNEFDBVJJCZD9F9JTJSIWGQYYQCYRVRWQYPNGKGVVCSMUBQNISCGTGGGDZYVJH9NM"},{"in":"UIOZGWXGW9VVRNXWPFMTKQEJERWS9AHZINF9PMJHQHIGTAFZLQWBXSCFWYWCRGWGGIOXKNKEHD99DZRYJQPDPROI9VWDDBYBGG9EGJSCJGX9OPLUFJBRHVTAZHLBZZZURGAOBADVKDNLPREHHUB99ITQWDBZEVDZDCLOJQVKQNJMLEPGNKAI9AHCXTBUEIYJNSFQHSHNORENOWWCERKF9VCAWYLIQRCSUPAQFSRXPYPDKNTPDPD","hash":"UBDRQAPZCTFNCDRWMHVDKXUAZPFFRUYKDQ99QQEIKXPHMPEEXERL9KJTOTWFUDTMASZSRDOTSDKDYECPL"},{"in":"SH9ZKANIKWCTBLJNNLRHVH9RWRSFF99QAZZFJUMVDNNRPUWFIABGKHUBRZJODPVQTAYUQUJZETXVBXUNYFAGMXPQTNVJKOYDCNF9JQDSASGQACBXA9HN9YKU9DTZZKMHTPD9IYMXUXYPVZLAKFHKGADVCVTULGXBUGBGY9KJUHAARUFQLPJPHDLMJKHIMEWCVSOEAWMCGUJ9KAZROIFSFFDKA9WJNSZPAITVTFL9IIQVU9TVSBZ","hash":"OBSIMKEMCQALVHQWIRNCJABXNKPRFUEP9ALTTPQAHAWBALEMZRHYRRVJSTVNNWEPCUHNCTFHYAYPEXTHB"},{"in":"JRRBHBNFNSUMLDUIAAAECBGBJPRDQNODJBCBUGK9GGYZVZGIKWY9RDD9IISKEDJGEYIDBU9LKZOKUDDQKUTNCIHDMHBQVRKOAJNRTMCBYOHUWHAROZXAVK9ISTTCXLZLMWZLPKEFTFWFVHSVRTRUDURAIXNFCMFOMFQGJQWDXBLVCODICXEYWNJRAQVVUCIHWORP9OU9PLHZJVTTHPDAFGBZZPTUA9U9RPITCHXFDVVSGOKBGRO","hash":"ZTJ9YYPZLJLNXBLFVEKVWBFQFPKMLMJIM9J9MTEBREPSSFWAYMJOJGLOTMBMFAXWTLKYUFUFYNDSPLHVH"},{"in":"RFZ9ZGBJTORSCPFYUNEPDYDPBTLRWPGWJQNNHFGLVBWVPJGDAHEGLIYQSNGOLHHVFM9FJJUZTQDHPMPDTDVAATCPCGV9MXAXVNHBCDUPFAPLWCQHJRNMBJQMGISS99SMMBFFMEJZLIIOZBLPONNCFOITZUMAUKXJJPSNWVNSCDX9ZF9OUATUFFZSU9DLQFGFQATDGVKM9TJPAWPMLRKIUBED9NIYZSNIKRSVKQSCVA9CHTVQNBJ","hash":"KILCHGDKBSWSSCIXHRVGRSHQWG9SADDJFKGUTPAXRM9RHDQLYWYCKBOARKKHCUA9AZTPUMBADWEESLYOT"},{"in":"AAZJRQOGEKYPSVDPFCATXLDMMLJYVJVATUKNOBOLJOAPGIEVGRVHJVDYKHDUIZTBKWU9TPQJKQGFJXHBPXXKMHXXBXSCLFGMLQYSJOKONCJIBTRNMXWUWAWIUZEETFMQDEWOXBKLZBYEVLLOPXRAVTJNXSBCUXINFMTSZJLFG9WQMXISDAPWJODDTFTJABEQDZLZYMWICLU9NRSIXWCXPDLATNAJOOTEKBWDVIXKRT9IRIWGTQO","hash":"FCXXSFOXHRDIVMTFBTH9ZWRMSBMUNZFFMCPDUWXZECOAUKHADIICBZVCR9TNIXQJKFTWVCSGOYHWBDJAG"},{"in":"KXBACJAVSONKMYOGMNZTTVKA9EJYTAJYBQVDKWRRPXBBPJTENOAAHWQIDWSMVHJAWYJUMUVDTFGM9KWSTHJGXSSXYWOFKQKAOVKEL9SFFZBEUIITSCUMHOZOXKRFWAHHYLOWCSCJYCPYHR9QBLQMNUKWQOJIPZJMXJZNVAIZRGDQH9ZVHJZQO9V9MZGXOMFXTMFCIVIQPKRT9TMEV9FKTGGXQEO9WIIUAEPCIFGCRZVFFLHCFTO","hash":"BTGROMJ9BRTUNAUGMFWIKBSNURHBZTTJAUASH9CETPNPXXMUSP9O9IRGWVSBWSPVOUZBEN9SWG9R9PFRC"},{"in":"XUQIVDWFUZGPBKETGMJTFQNELPNX9YKSDBYVZVBUFZZJSPESMTIRKFJFDHPXYGWGOQBCNMWOLFWFUGCYAFIHWKFDSLP9OFXMHTABYBTN9YAAEVDYJ9FLDDMOOWBPKIVZSZXYIYATSAMZRQEXHPUNXKWGIZGBKX9Q9FSIIQWXAUOCYQMFEXKOEEEXBULUKFNAZOMYEJOEVVFYZXFHLTLINMIVJZU9NHXXVQLURHJRUVMFWBWLPEI","hash":"IP9GWCAPCMGPXATKYRTTPIGPUTOCQMUOOZQEQVOIBLK9KAXSXOBFI9HR99CMIRYSPSRUALZUKZFABSIB9"},{"in":"LLQLGFEBVXRSEARATBODKJWCTZO9DCVBIBEBEIQM9HBUF9DBW9HNWMERTJZMDMMYGEPNXKKNKYGCBBEVC","hash":"NBIJTCEUDVSEWAUAWLDRAKFKNDL9JXBIODMRTZ9WNJMPYWXPLGGCHWAZLLWMDLNVDEADGEEXIXYTDHWLGTWYPCGJEIMRZTABCXQKVKRAJEWNSDCBUHKMJOIAHMUYZONEJUEWKCNRPQCEZKKXJBXNEZTCHZVIAYPYCGK9VRKIDMQ9EMSYUTKUVZLLBLZUGRTYHKULMFJPWIIRJTJIXRJOKXWPDJTZX9KBGPDPQKLNHR9QIVJKDFF"},{"in":"ROYCEAEHUDLYYYTSCBQQIWYHZPF9YHPZRNURKBCTKBXNESVMJNPU9OCYDTKXRUKXBJOKHQWPRRD9JOQDO","hash":"NJPRPWC9AMFHLCBEVVQRYLNNNZX9CBJRCAUUXBQXXNFRUVZPERKDTPSWORDKTPIAPH9FSNTUPXLOKJ9KKJVJQBCGKPOA99IHDVUDSKTLNWIKILGWKOSFAV9GUJWGNHTGIDWDNPAFWPHVOYGKVWDNJOTUPCUTYLAGOSKSDOOUJTTBTGOBAHHEJSHYOBABLMLPFPDZHLMCBA9TMCRXKSYCOTVWUHAYYSEMWYFFF9ZAKXANDDZSHIC"},{"in":"VQTIBVSNGHWVTFCSTTJRGIIZJWVSKBLRENJXMRGMFPUCXFYNRJKISVCYVRHCZHTDUBJPEEZRSSIQAHAFZ","hash":"IV99BXZO9ZOG9PF9DRTQZBPTLQKKZMFCDEIEWIQAGAZEKQQFTDCDWETLEGHNAFXBAVWSWMWNSPGPR9AHOMZLUCVAGENUKXBIBIZJLMJLTIMVNYOC9YJQZGOVNNNLM9JIJLBOMEOUDOZRQDWIERHKPRKKCJZQGHCRJGWXGOYRHLPLOBTQRJAHXJKXNBPCNMNSJYBHRWQITPJWDVFNMODMFHJBHEB9KFDBZSEOROMTPIUEXYNDHC9"},{"in":"TPSKGCY9WUACJLHJMX9AKSHYHJP9EFS9QVXFDDTXGWASQAKIHUT9LNQZOQTCFCVAMOJWL9IUHYPKBILKP","hash":"ONVEXQR99PEDFYDVAAPBDQBEJBMSWPNS9PNLEBSCGBQAWVAHCYHZTGLHTJ9OZIJR9WDDYYYMXTPZNPLGDGSGHQBYU9PFVZWHATSOSRFFUWZNUTJZMGGBUJTQHGGUALII9TUYEDHNOZBQLZKN9WQO9BSZLHXCIOYLZRXYQBMQLXWPHUKIRO9SAWKQUUO9LEWABVCXXIJVMKIJCWA9UCHWDIUZZUMYNJSKOMYLHWN9YETYXYB9AAD"},{"in":"WWGSWOKEMYTUVM9ECJJJHADWV9XBYVF9UYGZXOOTIHPGDWZYAFQBATEJNMYRKFUIVHZPSGVUBFCDJIBHL","hash":"HKHJSPPHOFCWWSENUBYMSUZCGCSTCBM9MIXSNNDQIOJ9KYVWEGJLDGUGGPKYBJPEYKYRBPVDDYPDRWGU9Y9GXNDB9QTHLZEAWUHBTTYLGEUOFMJFBRJOWQGMEDNBYSREMTZVVPF9GFYT9CRMBSGCEHPHQWRGEMFMCPHZ9H9VUNYKHBGKDTSGH9IKEQGXRZYMDZYTPEYEVZGAXYNHHEOSWLXIIE9QBYBDJLSXIRFIESPKBEAQNCO"},{"in":"TZNVNJBXGAMLCMFSIMCVXDNIFAHUFAKRPVYEOFVIBTBRDNMMWXGNDLLDPUMPCLSOIODLCQEPUJZKC9FYX","hash":"LIGHKUVZJOOI9VNTTSHTMWJXLZTSMXCFGVPZKRBYWTWPCFMZMNUNBMPXYETFVDFVSUKRDPPYCBVMSAUYTZZZNCNUDTQJDNTOTMLJLGLQRBPDMYVKFKRHEYLILXFPTZQBUPYGLRXZPJUSGVXB9U9NOLWEXUIBNAITSHWMHDNWADYD9YABPPQIXTOOENWWAHYBNGXXXKXCTBIMDODXWGOGASHSMPPO9TFOIJUFZPEPYPOKAWPMI9M"},{"in":"LYVMUUZGPNQGVNUKCEXFLFPY9OVBSFSE9NSPZGMPIMTREHOSPUJJKDNXAO9KXYHFZPP9WZVLNRKKPNDQO","hash":"KRJETYAHSIPJLPLJIWYQJFGIWDQGUGFZZUEGOJGHIPOZBPXFDSXQIVVIFUHWC9PGQLVUFYJVOBMVJLTLQOKYDXIVADJPAEMFAHPJINOKUHXNOZNRPZKBGSAQTECHIRU9LWSYZJLHSGGCGNSFZMIO9FJAGD9BRVDMSHZETXQJSBUHVMZEPPILCYKFBGXKJDBXLSKY9HVOXYJANLVRAREPRXKRWAKLCYNVXXPMESBCBXZSAGCHQBV"},{"in":"YALMGA9EBUEEMLNTX9XGHTPBFIQKSZHJMPNKMKHXVFBZWAHBEWPJJYBBQDBOR9FQPNMDHWTKYJINUHGSQ","hash":"HXGVCDONKFTDKKAIDKKFFIUQAUOLTC99MXRVCZNEQICFNXGLZEGVUEMBPPGRXVQ9WZJGIDJVLXNKAJPNWMAFLBUMAZUNQUGUQPBVNQUCOXSYSBIYFFNM9WUIEWIBRZEBOQDKAYEHLKYBHXLIIIPWYYMCMBYTYEGCEERTLXTAODUGPKTTWGNRFLFTWPCCJIHFVFIPHIGQQOBDHIFHDZMMDVBCBZRUGLKFVCHDLWAICDQMYIEYYCQ"},{"in":"KSNLZGDURTURVAOSZRJPWEDZZPLPHXH9MBFADSCUTQBFLJCKYZIBLGOJKMXRUDODYUVVJGRTIVYFYOORR","hash":"OAATZMOGZQIWUYHEPNYNQOEIXOHTWCXFYBMGEKWKFQBTRUXNXEAYSVBRRKAQTOWMUJOBKDNSA9KSRBQJJUBVXRSANFGCAFVVIVLUIOOY9AA9KZGLVQYEWKVRNFAGOKTDXOAJQVTNSPWRKMOVVGOURZAF9KSNNYMAOYWVJTBXTKKT9YC9TNXCBPOBJYANBQUSVISNNUUXYIYNLTM9WUHSMMILBERPZFDXGDSH9QWEHNSULTFE9ZD"},{"in":"PBZRMAHMDTGISABHUOOLKUGAURADETQENGJEOYURBNPWMVKHUNHAIUSXPWCNZDYBRLKZXHJTYFEVQKLGE","hash":"DMWWBVSQDEVNRA9SAUFH9RQCNPAIFWQICLFEFCQLNVGTQDFVFLZSTYZGOIXIIZEIPRHTXFFWK9YKZIMNCZBVCZRNKARMGHV9CVPZAYM9FXHCMCOKEZDFACOGC9AIESBBMRTNJ9HHIXLV9QUXKLRJMNFOBYP9VXBTXDDVNJISDZFKNERRDOAOLH9FQKIGYIASVCHCLOJJYFVDSRAY9IMOSBOIDFSMLUZHCBBRJZEZHVWXMQWADEO"},{"in":"PEHLCZBRUYXAQCO9GERKIWKEBODYLCPITLMRHWHTOKUXKLWQTRYW9NDTTISATCJOWVBKNCCWTJJWBWZUM","hash":"IEWBEFQPGVLATFEYNXWM9GTJJEXJJSZBGHFHAAVWLPXOQXVPNEA9CHEOQI9AZPRMUSDW9NAIZIO9REZMIDSIGVLGTOYKDJGBLG9BEZMUYKGOSQNBFSRLPTXBG9TONODJV9QHJZCQVNYDUGBJ9AISWTCDAWXQCUTNODTLZCPDSFSGHCNBEZLUWKRLOGXBTVJYVONOVLJVTOO9XBNPIMIPPHZNICEYTSYBFXSVNKLOVRTXQOQNHAQ"},{"in":"FKFTSRNKJ9AHEWMAVAP9NJ9LCTDTIPVABAJJNWRYGCSU9HKMXCFZPMOJOPRWFQGZRQAURE9QWDHIA9BIG","hash":"JUJFXDMGPURECVVFFGZLNAXJNJZNUZOHTNZSPETADVCYPOLOFI9LDIRYRRKKLHTNNXNLWIHQZMFSJ9TAF9WOWYPGZROARAHYOOGXOZFEZIHNKVQBECSIFLMSISVILQZRJFTNGZMWLUMVNPLNINGZPNOXBEVLPRQHJXVFAWUVHGPIKHDWP9VEOGVPRJUDDLVMIWPTDSRVWHNEZMNGHSDVUEDRNGLNIKAQMOSIXQZFHPOITDAXZBV"},{"in":"KQOSW9KYYKGPMSUYXIYCZTDJCNDGOC9UEJQ9FEAEQYGWPGWBWCXGJOPKZRHDNJAPPVLHQTNVUHKA9CEMK","hash":"RKRLXOQUCXNRWKLFLRGKFCNVCYPUSKLHGNZVDYTGWPSHXNFUXCOVVXZLXSCOQ9SXEWFGMZVYXBJKNHO9BXKESNGIGCIRBQHFGPKNKOSVPNKNS9QBFN9LKIRZYGMBRIAVIAKQGWGK99IA9V9AYMTEQXWFVLEKQUAOCTWWBDMSZCBMXMM9AI9GXZMETRTOEP99NIPLIGTCOXA9GJITPVVZSYSYWTVRFVUMHEBBKNNAFW9TPEKEJQ9"},{"in":"VAMWLCYOLVGCNTFAJ9YMVGJCZULPYJEOGKDBSYIWYOMEYVGMHYPTGHX9WSZIRPIJMWDZQPGEJ9SALXWWG","hash":"FHBMABM9ZADLH9AVJKR99KAJSPHMFZLP9VWVGVDWGKZN9AKIOBF9GQOTWLKWLHVCGUZWWHEBKYIXOHPEVGGXDQLGTBKB9OFHMHGPFDARLIVEQG9QUUJLRXTSQS9EMG9QFDRYWEOKPVVLJBCBASSIXDQQFOCXWOZ9LWZFMIINNQHBEDUSQUZNJSKUKXOCPFCBU9UTIHXRNUDJMDHCDPGJZPCMVISPXPBVQTU9MRDIFIROBQEHOEQ"},{"in":"YIFIRYBXVSBVTKSSPCNAUREIMGWLIHHOMTDGRDPE9IFZTRKWRUSOBYGNRJFMCJRSFSEHKYDCUZOSMXV9Q","hash":"SZMMCNBJXBFFTJBF9OLCGVELUKSFWEHCHSQVACQPEYXB9WOT9TTKLLWBZXWAUBAPKGZXICWHTS9YUEGLPLFLGFUENLGSNHDBF9UUCUSZT9I9RTMPOAGDVCSPMHUJPBUOVEPMGMUSRIRDIKPUEPSUDPLCGRDZJHQP9PUHGIECNHQBWADZ9XHMKT9CQGLRLKVCHUQMBEEAW9N99ZZVEYDDVOBVHKX9XADFXXJMVXYXHVUYVXKDESF"},{"in":"URALKMRXTKAFMUHHYUTRGSVNMNUJEAVENBJJTFGRHIPUIFBDQMIKPLSGDNZHLZZJEPGUJRNNJZLXAJZMQ","hash":"YIXEEQBDAYZKKSMSTZEGSHRBVHBFGDXZECMIIDOHFEUMOZFZXMSPBTNSKICOYIYDPTXLAYRBIORRWFAGFGLKYA99P9ZFWMISRZZMTAVYTSFDVPMHLBXWUZEMIDZM9QBVCXZUTXNJYZMSREFSA9ESKQUYCHTUEQJAXICCYLRZJCU9FTWMJUZWNMZSXASTCTXBWNMFOIZWBCVBTXIVNYKMUTRGCTXWCKMSUKKESCGREYOEACIJPAE"},{"in":"MAUAUCBVDMACXUFMVNAX9JLYKKYOTSPZHKGQCCTBMEN9SRRNBGBFBDASGUNLPZNBYUIRCFPJ9LHPK9RQS","hash":"EAOHEKSRBOCFMVLGGDIPPMHLGJBYQHEQISTCLIRUPSJEWRSYRCFTSULTKVLOCWZNNRJKHNJQCBYAPKWHODEBLKOGNF9TGTYFATJXICCNYAG9QFDCBOSILOVGCTTHPGIIUETKI9ZVOAXGTRSQFJZPELQZDBRWPHHVZQ9RGNAJQXGUGFLNWRGGXI9BVFIGNRRHXHDBNAESCWBFUCFDHMBMEVQGWNAFSSAFNGHWHUYAPJVURFAGCMC"},{"in":"HLUZLGPIX9FGUUIIKTDVYHB9CXMTEQSXACBOBJCYRPQWLHSVYPHSKAQHTQ9HRLYYVLKCRIFHZKWYITPDW","hash":"FRVOYYNPHKKLRUNWWVAZQXTQD9UWIPHFZBBVPOMECKNECGWRZVJPRBHDRCKFQPXUHSGELEFOFYJCODPVOSVO9YUEDPBBTLEPOWWBGYUPIV9UFWVP9IGNNWQZZSGVXVOSUNPEQFQKWVS9TLHMKDSWLGKVUPBNCQVRZZOZNMSJJMEIWFOMQEEQWZOWEQGIPSNESAKMMSGKSANZXRDJVWVSAOSMYTUDJTDJKPGXOSYMOUMHTHKRVBV"},{"in":"PXLRPNA9DBWGVJBNGSZXVUDLCPHYDUR99VHONMCXGGHCAZBUSHH99J9DQAKBIODONDXPPGS9SKTPPPILF","hash":"JAXTTLYZMTTDHTBVWBA9IFXMTOCBZCCOMWCQPDBQOOGUVFHCSALVFFGQIMLRTTBWVXZP9ZMSQUJTAOIOLPWXGYKXZBBHRSVBX9WVUGOOZWQZRCLTHVPSBFVOWNJXXMIVOVPGHZOWVVBWDCKYCQHQAKZJ9ICANHSFIALE9WXZH9BE9IDOUUIRCZOSEUEIFVRCKVIUGJUYUIIRUBHCXSSHWTLSDCGSICWKLCKPWKBHRDSPAUNNUUE"},{"in":"DHVHDDALLSYOLU9LKRCTERNCOREGRQTNZZTDSNMULUANBMFBOYGPNGFJVMSLDSBVKEG9HVM9IKZHMSSAH","hash":"X9YCHTRD9DLKNWHLACGEZHRJILRCVNYXMW9RBKVIZTRLULZGNFU9FOEOQETRAPMKEQFTXAYSHPM9JWAQWPKJOQIRMZOIJMJNEMZURNVOOZBQLRBDWIY99GLKHKQWSOLATHVFPBJEWQYRIMWQBBLCJIUGYUDZLKYHDBLLNSMXARMMLUUYUDTJCCMARXGWIPYPUGHGFTRDOCGIL9IGD9ACMND99VEKEWQOBERBUHPQFUGNQXPBPPL"},{"in":"TZAG9DLZPNVNROUIYAJTTRBNLMIHZVSGB9BWTCZABHGRJAJXQQFLQUZNWTCTOTKGQZOPAYLUYXPK9IXLF","hash":"QAS9KHITOGOYAEKVSFOONVICVWASY9BXQJEMOGMWCJZVLXZSSZG9NR9EBNH9JYSMGJYWAKTTSDHNCISXBYTSKLYOJMHXINJ99WUW9T9XTFJWFRPSR9IFZDWNXDRVVUISNH9RALEGKHGOMGLCNSYLAAMDAWTVSF9UQRELADYMYKVAOLCEWFVDNJXVDWCXJPPUPKTAAWAWVURDWKNZU9PXJVIUCHCVMWDXRXSLZTAUFFLAHZSQDJO"},{"in":"WYFOC9CXGGVUGIBGKFSXMXJYVBHFTCUHL9GONLQYUQQHTLZFKPXPXLLXMAHLARFTJV9NLVPWVWUWIOYMX","hash":"9RGOMLMGVCIWNGRAOANZAMEJQSHXYQLLEPNXILNHRCT9QZZMOY9AVHVKEHKLNCZDQSJJDEEFAJNB9VSOCGQLE9VUDLYCOUBOBF9YLDRXYYANNGSHACHUBMDJULTONOH9NWNPTPJ9ZTPPADNHGXPXJM9EKMYWMRCZLJXZZKFMSAOBWCAGCPEYWIPEBSJKLHGXZQRMPOAQXCEUFXIYNYMENMWC99MWFMIYBHIXQWV9UTVGHTDF9PW"},{"in":"YVIJLRNRLQTGBUGOPKTW9ZCOIJNIZJGRKMLRYHLIIVMVAYRDWTFXPNMZTQAY9FJMWSMYHVXOEFBL9YKPO","hash":"LMELSWBUPGEIJMGLVMXNXSA9RXVROLWE9QSZJMTTDIMICEPUSBCYPCZUOYMSWZQFLBUNEEHBMFBEAQBNGMGGTOEKOMIMAGFO9DRKUOSGRWDLZLDZVOUGFGWRUVUQCEUUOOAJZLFJEDJNGJLEFCHUPZYGPDHYHHCZUADMHULQSZGAOIJCDTVVRTIZY9JEYGUOQLYXDKRXPPSDIXRAYFXXWRBBXZZJGOGFEYVPFLCGROELUQKAYK9"},{"in":"NTADPXFYNCTGWCAAOGCOZXJUNUCBIWHZPIMUWOBDIEAFELQWDFVVPIGZDL9SSFDONGRHTTGXERRHMAJIS","hash":"PWRFYLNUXJ9IMBLBYTUHUIFWJLWQHNEVGYLTOZUKGWFMBOALNY9UTNS9BHVFRSYCT9SCV9MGGLUQD9ZFCEZBFZILBUSXMTCQCLHX9ODHVBUS9LYRMAX9AUHX9NURJGEABZOJBZABZDQZHABVAMGUJXDEYKHZNU9IUQYZZO9AOVIMQUAXKFIT9YHERFR9CM9WQGPUHDGOTMJRSRIZJBZHLGRMANOEPOSWWVIS9EDUORPGNVUFFIM"},{"in":"GTURVDWUPFZC9HRLZDKBUB9DUJA9GWGNHMTATPMOTGBHNNAOENTEETTKIONNHPO9ZLQFVECCRLLAAFNDE","hash":"VLCMSPAHCRFGDI9TBFOSMNNZOZRNXKAACQDSKXCZCSPLN9IWYIQITBC9DILUZXQUXVRUIXMJIIEXBQON9RYZDVBSBSQGZO9SARUKYWZMQWCBBWEXGGQZMXFJFHIGGBQ9AZVLSDKQUWWPLNFIQZFCVPLDYKEBNVBESIDXVKIANHQOUFOHBEHUGHFBQEWVCPHCFIVZAPRSLFTIKYPZIOAGMRIMQIOOPOLDGAXNDQFZVBYXNYUTKDX"},{"in":"VOIMEEXFAJ9FJASTDBDWYIVQITRPKSGUJFK9WGEMYUNBLSFAMNWWOZKYUBZWBMOYPWWVQTPWNQYCFQPGN","hash":"XFNKBSNZHBEOCWPPEVZCUTQ9VBQGMKBFPHTLWTTBORMNBJ9HFBSCGFRXOAQEMPHIJHXAJQMMWXGPOCLZBBFYBAQK9HKUUTJKRULNSSZNVUHQPCZUKE9NCZUKFTXP9FAYDCKUIMFKCXSEALEJMJWCOODUTRGXQUXEKOFT9MHSALTLLSIYYOGFHPG9DWCRSDE9JTGSTGXISXPKBPIYUNTZJRCRNXSCY9SNVCRXA9CIWKDXDFMBMUK"},{"in":"ENQNOKKTFYWZMXMSOHNFDJJPFMDPLHOLBYENWWOJXDHAEUPIOWNLWOCWCTMENFTLBBQVJKBHPUOFIKRPX","hash":"ZLQODTXJMRGPYJGDFKHLCMA9HEYASH9NCJTRDERMFMDNYED9KBDTFIZPRADRQLCHXPRPPBG9BPZXRSJQICXOWFQVRK9VPIWSVYJWKYAFISAZOBETKKXDIMXGE9AEKDLKBUAYDMGRUSMDSLRKGZFSLFXHPYAEFZBOZPDDOAAYZESHCYWBQJLNWYTRQUBMFVSWOBFBAWEONUATZKINYCTUSVECNMMZBMROICZFJAFJVPFCIGUMPHE"},{"in":"EFWIA9OPQ9VSVIRNVAUAFWMCMJQGEUGRVGCGEBROTRAPGPATPPQFHHEH9ARPQE9AUNBMMKLCEYQ9USEOV","hash":"LRCCGBRJJXFIUHBAQADPUWTHACFOFSBTQYHRNEHZFTBNNADJJEQZXKOMSNEWJKAX9PJWDRXZCUFEOHPSLTJALEPEEMOWSV9WBSBSXVZDGIYLB9CZKOWGFRIYCXBFWHTPWIXRQNAOWZYWSKUUSEMGESDCNPSBIKPPVJURFGHSOWGPAZCQ9YQG9DJNCTHPEJSOLUYALPFVKXLMISPEHCYZBYHDRSJPHCOPAPTCVIQVHGXBFJOCMAV"},{"in":"BAKDBSLTUORVJYONPNYRXCHS9FKEBRQBWBFVGSBFXEFEWJX99CTDSZKASLCFISUEVCEBOFSB9RSWUMCBR","hash":"JLPZQBOCRZMDN9ZJGRYGQXMUV9TVZM9FGEV9ELKJWYWKWB9GQLZSBXOYCITBOPVPBXFPXRSAYWSJDO9LO9GQDUQTLOGCGPOZZCRXPVCJXUXNCBGCXBBFNFXZQLIOUFXDHBSEGDBEFJLOKHGRXAXRWHEWQWNHEUQQUVDBBAJVGKCRHMMOPQZQGUJBHZZS9ZOOASLCJBWUYUGOI9AYB9EGHRMGSTWOLTWVCIKMVZUREWRBAOTOCGP"},{"in":"BFXUKUH9BZSAKRJJXNERDI9YOFTRBSQJCIKTZHHLVVWGYJB9OLMFM9BRTAFTEAFNNXKEOIDWSOGACFAVX","hash":"WJSIPUMQNJMYXWTLSENMUGWNKTAKZOBNVKHQQQEABHKEHJPGOHRFDAQHULKC99MSTZDCUTUZTOTQKUKYKRANBSSOQISGGGRSHCRHYEVFJCLANFCHYL9GUIFISRZFUJ9NHFGTFBCOLVTNSIKDSCAMIF9OETZW9YCCN9JXALKFQCOYVKPXGHOUBJPVYHBRIUQWTYFAEETSFTIFUUTILXOSD9IYGBUSNBJVXPOERQYVWEVU9U9OKSK"},{"in":"HZKEJVYZZUDZPPRJLKISO9HLNLYPLUULR9NPBPWDZLMNG9BZIEZCZVN9EDHZVOFAFQHEPABRGNU9MHSJZ","hash":"QENRDTIGBNSVMGJJQNHOOPZQEWGVLKECNZLQJDIYDQMUJBTQ9KWTRAA9EPCVYNNTXIVXJGTGFEUH9HUNBA9VZQVVODYISHWLF9BQTMUYTIQUMYNBA9BM9PWSRHJHLCZBQTXTJILBRKVGARMXJFQHJPF9WNHIPAVIPNONMEFJUZLNHIOOIDDNXX9LEDZLIASZAEIRLEXVVEYQGJKJPAPMQQ9OOZFBIDRAJM9BTH9ALVJQKTSXLPI"},{"in":"KIDKJQNVVAPPJBCWZBDEZIMUHMQNXB9GSWJUCSDWYOEFKGMXONWVI9HGKYMTKEMV9EHTJBTHOSEAQFMSN","hash":"TLTRMPBDTVHHSKIHUKTEJGPACCOQNNABXWXEY9TGHCYLEPWMRCOVQUDMRQJDDEMNJUWGVUZJEPFRQMSVEVYKTXBMLITRRBKGMHKJ9LKZ9TOIQJFXUDCDILKKSLMEGPHN9MENJSBIIDOZSAKFXODONOZZLYOVFHURZOKBAEHWJNWS9QYNNCMOGSCSFNHBYQWTPCMWGWCJGRVEMNGEOZYC9CUUDPZCJVOQOQ9CMKLIEDIXQBPRSPJ"},{"in":"LVXODUAYUBMZYPDNQBJAHESSYKSOWVEYYVAKODFUOEJDPEJIVRTPKZHPYTVPOTOOTNGNTERFVCY9YWUOL","hash":"NHVYKYL9GDYDPSCFDVZFOWNBKA99RHLVMTI9DFUKZMCUTXHLGJOH9NUQDXUALXKCUXPTWEMFLHJBEFKDYZKXLECANBYKNXEAFHUMKUPUO9JW9HDKSIALUIMURWUCQWNBFYVDKNPQKIIQEUMZFX9OWPQMPEIZPPEZAK99YFYHCSLEUYVIVJQYKRNTJGWDHC9UEN9GGHRT9TUQFZWSBOZZSGMSCW9WGFHRIMBOSIQRTNAMBILIOSN"},{"in":"9ASOZZBIXAXJBOLVWCFFIXBMNPAGOMTMQTMQEOGYYNFTFJMUDQ99UY9UBNOQNKBQICVFILONOALOOLXDW","hash":"GRYLJAMRCWEZPROELPHFMXWYUSYBYZTSJBGRXKRLKGKIFSTCOMB9PJVMJ9SXXYVWRXGFPKVOTTBNEDVIEAPTBOSVOJBMPRTTHSZ9OSZQPGJXUWVLHSMPJZBSOEHLHMR9RYIUZRNP9BMRPUIMPCLWUMURJXCZAUWXEBBQIFAFZGDHWFZWETFJNQTHXNVLHXCCWQPRWGKXXZHZZOZIDAKZBSRKHREYIEC9UVEZSFUKGJVLYNFWUTO"},{"in":"HGXHUKMXVZARFJN9OCWEXA9XCCTRVRTOZPPPYCLYVLVAUXCSKVKQYCZPMOHCFSFZLTT9IGUGPMCNR9VSF","hash":"NECXZSCIQECGHZVSMHENDQYGEZW99ETTUYSFE9PGZYLUBCKGMKKT9QQSFVGDMTENIZNUVFEFKXIYZBTTJBQCEQTNPOZE9YULPXWAFN9ZEJINXKLMZOXZLHAEKTMKTOXJCDEVY9TZ9FWVSZUBGSMXREPLWGNYTO9ACCMVLZGLYLOXE9BIFIWSHWWBVMQTRXWTDZOEWVTKVOWFXTLEXCBNQFNFXWMUXHEJAIYLFSFXYUREIRKTMMV"},{"in":"N9EOMARSZQKUDVCXKARJNOTZPISZSZEPVFDOICYXPAYUFWSVDFOPSQNNIBVBBQGORG9IIAUHVVV9FBYXF","hash":"9AKWCAPHCQJPUGENC9NUGMWBMADQYOJYCIPCOJEEKFTVAJ9RSOODXYQVIFYY9APLAXZKZURRCTDMTXSFDYOGXEWWTBREKHVEQZNYKEARGLZVXUNORFIXRMFUJUISQZBANDJWX9YN9H9BVAUIZIVPAUEMOGUEYTUSOMWKGFYDYM9SGVJPMVESMWKXHRPBVRBAYBGZWTEHCIMWBFGABEXNMLYH9CLQJTWMODQRQTNZVBBYSAZVBPH"},{"in":"JRUTZKJVHYYGOUDZZL99NPXUDTZIJURQJGWIPMZTZQZZWPUCHVQZCDXOOUJUMKGSQLOFYGEMYBRDABMRV","hash":"SRKIGGYIOKDPUNVGSEEUFGSNHYRPOYMIDLBSEQLYUXFEPGKIEHCSKCKCLOGTPBXFDGYUESHAHMOCOI9NBLWMEKASLMXUWIUFNOAXASKMNURYMGCWZZSR9YTBVMFYNCBBQEQOSTXQQNYAMPGCJOMLEQPBOPSUYNPZVDSUXN99HHPJJWJK9PTQWXWULJCSGNQONAGULRTQHSTJJCDRC9ZUAMHUZVAN9MQWNBOBXUNTEYHMOPFVISP"},{"in":"KGUNUENDS9GOGLKPGDVTOJPPBZFAMPTPAPLDTORWYQFEXLCBL9QPEBUCVCEJXOGADBMSMIENNBHCEYWZK","hash":"XDXZRGEDWMRBBVGFMLSFYYDZDSLXMBDDSVSREUEMORIEPYCPAUHOTVGBALBOSKIWT9PNCRDTM9YNUWCBUJKUUAWKTHDQUDDUYLCHUMCCZFCEIOQAGUGOQLLZZDVMPXHVNF9FFZYHTSDTVPTFU9UUIICMNSWBASPXDDQBKYNVGXIBRBXYSPIIREXXJMPJWEMVCCEPZJIBKEIUBPPYJLQLDLFAANAHWTRYUJIUUNXFNCKVGVIVPVM"},{"in":"SKRFQDDFXVWUK9UODRFEWWDJUOELIYEHTJMOPKYEWSHWMOZMCLTUTRHUSBWUDOH9AR9RLOEXRQFGLOIRM","hash":"LMHMPNEGVXGBDXGAMLPVMUIFHRXAEXQBSSCCWFX9ESFEUHKESIKHKDUDFPBEBKWDNJHNQAZSRJOR9DJXQBCDPJFNGDUPIHNPGJROQGHAWNDXZL9NORAVBSELTDRKHPMPOFBPXFPMNJKHWFXN9ASX9NRNKZAPII9DUJRLKEZGCDCGB9X9DASSUOOVRXJ9J9KIAUNDCQNKEXU9AMP9NIVCDQGFBUEFSRAPSLYQ9IQDCWSFCXOLZTQ"},{"in":"TMMYUKZZFOMFOZN9WLUUNHRLUCVXO9SVNYAAPIQLZRLIYIPKKCADKZYWFLTLOKSPUJIAKDUDNJNPZHDEF","hash":"TDROCQRHKXDHFMNKFSOJBRCDRFAWRSFFUARQRCRJZMKNYNTNCXNMAQGQAASPALLMGFCDXYWQLKRBGKXIKHQN9FJEOGHZZOTIRQPNDLOOEAW9BQ9CQBTG9TTOORHGGVIIFIVCLRSCXATCMADQYWCTLFGPR9SUXQBNCRM9JKFOXV9PCM9MVEJZZTKHBEVIR9DZNIVRJSFMEV9YYNLXRPBRCFTMUYRQEJQLYRDHHNZR9GLYVBXZJSE"},{"in":"EMXMIYDEAFQGGNAM9ULUFNGARHFVWBRBXMVT9NGMXEZ9KDJCSKBUGUCUSEHWRBDB9TKWFZGDXY9BXQHND","hash":"USCUTARUVGTYMHJTPLIVVUEBNOXDODBSTHYQGZEAOGHEMBOIUSYKPEMCHIOGOPP9EFWS9JHG9MSXBMUPSHESAZVUXYOFJGJTQDIZVXRFNUV9LEK999CGIRTXXKWXBCFBDQKQWTFWJ9KDAHMZ9RQLNEDSTGZNEJTGIRV9BXCCKPIRUYDUFYBPWEZKLQTTH9BJNRQGWTUTTBSMULCOM9TMYPDKGPAYMTJTYYLD99W9JTT9XQKD99A"},{"in":"CKVQNHNYPYERZDMOFRZSNFHRFADEAOGOTHUSPDQRTRIYD9GEBEMCZIHEJDEDRYIWERISJXEHHLCEYPD9E","hash":"YPZZDQNJQITIQQSEVKHQGLGZKWYTRM9SZZPOXWUBJVITHLMTOICZUSFXSBJQIFYKSGVYSUTN9XHNNWYTQGIEPHXRMTF9MOGBYJKKBVEXQVHJIVIBRBROFWGGAUFICXBWJ9DKKAVHXBZQNUFK9DWIZHQJAAWJWZMOJUPEYWJBSHWCTWJCQPYLYTYQORPRWVLAYNFRHANRYUMMCCNWZWWNBMXYXKSHDCWBZLKYGIZAACGB9ZHGFPZ"},{"in":"FESBHVKWPPFVT9GBVUHAPNFRAFDRZWPCPQYR9KYK9VUN9RDDJLZSLGNAGNVJWKXNFZIYIATHWDRYZCIPF","hash":"BPXZFHRNQHWHPJTFLLKH9UVVDPHUPSPJJCETZCLJWVSUQGTKMYEDJPKBGC9DNOXBFKUPDBTCBGVAYITDPRZSJCWCNSWGT9HBHZNCTWKWOBXPTNXGHCQGPNCPSKZL9SLQSIJOAPLCRF99ETVGDCEVUZEXEXWXJVRFPNMNUZVNMDHLPMALBZGDWSUTTSTZNLDUBUOLEQWHMIGBLSHKNILGSVBLURTBYOPXBIBMURYMOUODJLDWRSU"},{"in":"EJTESYWYRD9KVHXGSGWXKKZEWOFBF9CYTXYTGSNM9YBHAY9QUSTUVKLXEXMCESVHOBZXGGPLJXWNOEGTB","hash":"GRUCAUNQLEDVVRQ9LTRENXIIUUE9X9TIFCTEBUMIAJDRQHEATZPOMZSPYFBGNNIXGAXPOGIWNJINVEPUPTCXD9BGOXPQGAIDHKZFNAWZAFLOIIXTTYY9ZGAOCWWVS9NJ9ZCFLAXWGFQEEHTFPYZDQ9MZV9QOFATBFFPSDRT9XLZOYPPC9DPDG9LADOKIHC9TIXLGFDLEIAQAABSGWBCAEFKUZIYXIMXQFSMGQIXVZBUCHLDNDAA"},{"in":"9VT9ZNIFHIAGVXXZGEIUETQGNMMGUIQJNIRJFLHIPOUSGJIKSTVKOSGFLYWXLZYYLHWVDHBGJNQDPITQ9","hash":"ESAJFUYTMGU9YKMKAIC9NPGQWBZKHVDRXAXIPGC9EJRUIOUWVGXAQMY9MGCVDO9CAVGXLJMALVQLRZDH9IXWNYNTKK9AVJWFAULMLLIHKUTURRZOPHKDFYQSLSE9MMTBWPKCQCPRGFHGZ9DQKT9MC9YOFIJECSNTKFPJVSVXNTCYODEZCBNHVLPFZTXWUHKTH9UWAPGCNGEF9MTIG9TWRD9RJYSUYWQOBGIFPDNEOPRS9WPMWXE"},{"in":"UENVQBGRTHONYPKTWDWSMECHW9YGIJUIJ9KQISPPZG9GMF99UWAIQHKUXYFBBPT9TWULHIUDDMCFTEYGK","hash":"ZVCQZQCKGFVXZDRTQFGIJECSOC9ETNCJWOBWKMCLLNTOMXF9MLXYKSMHXYAPDVBQXDJKXQ9QFDRAMBRYCEHBVEQZXTJFYVSNLFG9ZFBMSLEJKLGKJVAAVRDQNPITONVRJDQMEWSZIHJYDQIIEPEPGBPRBPSCJZVUMIELYUVNFITWRYGA9RWGPZFCGEYUEFNPZSVPWSLHKLBEOXEFODRKZANQSH9SEITWKTFZKIMUHHRTC9XOL9K"},{"in":"LUCAEFAZKEFFECUQPVWNMETTEPJVULSR99OK9WIQUYIWHGSWRAMQCU9DCCQVQG9ITXSQCBIJEWRPPOKUI","hash":"ZRUYAVJGWEANCXOGUJKPLHTUVOPRNPMORWBBHCNSBJGJIVRICOAXOTZAOOZ9BDUYTMGGCLWBWCKOQDICIJKGFPDCROUZLRTLTVSEKQPBJRXRKJGHGHXYZLFWDORVWBTFRLPGUVBIHNALUJLYSPSKIOQWVQDXKQYYJFYYRKKQGOBYLMQWGGYXBRCPDCJSEDONTKFIPFSMYIWUKAJWQWRDCHURUGQLCYYDTRHYEMMVEJRRGYKSNPG"},{"in":"BWTJGKXXVWLFWNZUYAHEWRMGYNFSYWEJDCEBQJMOWJTZGMKK9QVAYKOPCQGTMXUZZGLWULXQHVRSJYOVS","hash":"BBVABNRQKHVKINLWBAOGL9RYHZBRTTZMNJGBDRRXFGFDKEDY9QOXSSHFEZWMBHTTNNJLMA9JGCRL9QDPIFKVYBLFNQITTWPOGYACPLXKBSWCNRZX9ZU99KXFLSRTZWKPNKVIJFOYE9OASJODHFYGHWREBCWOPLOYFRTQXKQXIHKSAWTPHARSJYAQXFOUYFGWYMGYSHUFGCL9MZUCYT9TALOSMRBTIMFOZFMNECJLJOQVSAUTEWH"},{"in":"POSGKLADINJUSPRP9AUUJNEQM9EPEHNRBWTPNZXBHOJGYBZCMQRMCAIDUYICHOSGGHCNREVLTOGZPULDK","hash":"EMRPGTKQPDPIJVW9JRAOCBGUMRDMHOFNCCXAGPQXLGCXLAGGIZKAZCDLPGXKTXOUMISV9VVB9GQDPLUEJRPNFEQFENCTXNPDDCDGQGIOKPXTVLXRZVV9YNDZPHJNFLDIKAFUIJNHGVGYQRR9MXONOIHFRXMDUIBBTP9XYKGGOVVX9AXUSZJEUTDWCTFHCXAFD9MHMVMNKFAEGZVMLOMSJMBKVMSOXASANJTQGSTSAZNBHATHOQV"},{"in":"9OFOKDSHWOSSZQBUQBBMRMJINSNHDFIREDKTGTKKBANFRBPSMSSQMUARFESCXUVSEFDDXBKRYMFZSWFMB","hash":"YOUMP99TBZYBCHRUVUCWAR9MCXFCFESBSLPFMYWOTBKBNZCABJVIFIJYKNLFNTDBCTDSIVZYPOEPRFSRZCAANSFSMYTNA9LDHSUMNPGXLWBYVUHUAR9QE9FONYDCMQUGOSRCXNJLB9JJFYYYWDPVTXJSDZH9UYJFNCKBSVQFXVCDLBBHXAGFMVRUCHAWABAYCOLZTHA9OHDFCHWBVSAGVNXJEMCBRCGEUXTGMO9JRVYWSAA9DPG"},{"in":"BNX9WGHPXEOMFGNOENBUVRJMEOCJWR9TNBUKAW9BRFFHHIUPOIMBYEKUOOKJFUSIBRWBIEOHBXEGHDOSL","hash":"Y9EFEXV9UPUAMGRNKVJIJPTVQBXAXWHETVZJQPNILU9PMZ9W9KVDK99UKXBLGKEMSND9DEGALBJCC9FAVORJBTXKXQLBKDJHZQKPSMEEXFMCDNXUQ9BVQWJDSDRVPDHXOGDWMPPZH9HQROBAPKKGHHT9MGGY9HICCGPMB9OPOLGPYSIZCAOYZYCPCXQ9KFSJIJXOTFBCFZVYOIYYLNZUIRNAHCDDUOITKQJIYNKQWLUUNEFSZPA"},{"in":"PPHFCCWQLWHEJLEGUGDCYSSGUYVWCIRNPDOAGABEJQAPRSIWRC9KACKPMVORSLHTWR9VRLNZYPFAEOJPH","hash":"GRJCPPEBVYK9HJSPOKOICVKBMELW9EJSSLZYXII9USFISYZJIKRKYJWXASEMXGOFJIDLCRZGLWOCWCPCNBJJZBJXSXZUFKSBWPTWTOKWOPTRQ9SYMQEXQME9YIKUDWLACTICQTPUGDQZJCFWMAHOSWJSH9XTGYTTVZAHAIELJZFUSQPZDSAYLY9YKBTZWVOXTIUWPBFXTOGQJPPGSRWEPKCCHVRTRIPARECTPXIITFTPFNGXQEN"},{"in":"AMJQDTJQMTZXZNOEMCCHKGBSGBPEBMXOIVOUBRMPNNNMTWMUWJVAHYYBJLPYVLHBXIEPJJLJXVCSOASIG","hash":"BOLKEQGNPJDKCQHLDVSIDQYIOQMVNCWDYZKUQOWDJKFTMBNWLJWYDYXFBNHKXWBVGUOEFORDYIMREGSCPNRIYYVFLYXULJHXAMOLF9TSFDBPCAUFLK9DROEUTYQVVYPLAE9IAUVPDNEB9X9PWKNJAFHMEYNQAFUETXDADRJDPUHNAYCOPJSSASJWMDFEWHXSORFKJDYLCC9UKURNBPKPFK9CMQUXBYDSG9YLATIQOOZWZAAEBGD"},{"in":"XNRNNGEMOOSM9QPBBCEMGGCOVCICKXVSKDBQBNDF9WJXTUVCN9QNEQOUTEIFMNHL9PLRKD9MGHWIKMYOW","hash":"NQRCRBIWRSTYEBO9QZXDCQZZQSHNROSUWSMWNPACJEDTHYVZDDNKCKLRECXAFRM9BEUMTZJKQYUBRZXDHEXOHCPGBLGTSOZYYRZQSYBZWDDEIDNYLJUZGKCMJWCIGBCJDJHSFSFPIFQSBCEWSQFDJLLZW9VFTNB9IKYMAYKOFGUTJCMPNBYAFBKLVYQQLRSYJMJUEYODANXYDQRHYAUBYEKNWXHBIPWOLFWNOPLZJTYLPPITMSS"},{"in":"PWATRG9R9S9WCBLOF9QEDSWOT9JGVJZVDMSILQWU9ATVARREOOKZPJIIJN9CDESKBOCJQRPPUTWVPGUSL","hash":"9CZLYXCFCQMIJANURLNJXXBRZF9GRXIBYIJEWKVRHVJWU9PTDDHNEISFLISLSI9I9IHCDAMQRKTDJWEISDXF9KHJCTAUHAHABNPTLSJJYQSFLKLKBJQULNRBIMYKCJKRXLNBN9BNAWWKEOZEPRZIIAVM9PZQEDLDAUQOXWLWDFYOLIWTPLNNZEXXOJJSJTBB9YXULSUPYVKWRKFBTITSXAHNKYDMNLOBPCXGCKJCGU9LMNYXCVL"},{"in":"UKCRCNVPXDBWDLGTLNE9MHDFIQADQESKVIWCXVIMEASUOQDXLVUAKHZGQGLGWSOLQKXGSMAFEYBL9ITMT","hash":"MKRDBISMJLFZQITWFNRGYGNRKIBVVNPGCGNFAGPGEPWSWCVNMTDXLX9DUXDCEVYFLUYPTMFZBKJBLJJNAWDNFCNXELQUPTSXQSIDBWRMHOZBLJVCNI9XQECGQZYNJZGZD9TVJAP9GVAHDDZMSAMNROAVGCDTXVYJIPMIL9NNFGBYKFZGGIQKRKZEKNFLPWTUYQDLEUZSYYKEMKMKXSYTWQVOL9NMMRZE9RVAZHVVRTKC9OZBYKM"},{"in":"QHFMDJORENYKTGN9DINJNECJ9ROZNCJWVKML9ZT9HRFU9VKAAQZPCFMXPFNZMEVBPZPVYAYCORTDCWOKS","hash":"CCOEMAQLFLMYAVQ9TI9RJOWTEIHKXGFQKKRGDXBDKLDAKOXVTXNQKAEBBFZDAUPKFKWN9DSPRCCMMCIATPBVEZEUQMPFPJHOMAXKGWIFCOVVTYGUMRHYNAIUMKEPTG9FDGJQIIBPPSWHNEJVT9SSPOKQUNJYTZREZRLUOTSMEMPZLGYTFCYGCSSZDINLUIECSW9SBTVOLKGKKUNTPFSOPVUVEXXBXLK9ZOVVJGEPXRICUFAWMZG"},{"in":"OTMGXJNVYVEJVQHGLSGXGS9BOPQLRXGUCOFPXXNVBKQSHWDQN9SUBLXOEVXDJCD9MXPAIM9VGNVSHQERS","hash":"9IUKFTWLSYODWCADLE9PTNKTRDDIBEVCOVBGGDBNEDUSGANIBUXMRKZXQZAL9TRY9IWEQVWH9QVOXFCETHKG9UGGYCFIZIHNSNFQNIMNCTJOEISJZMGCCSBUXMHXDYVTDZENKAVOXU9WGSUJPJGQEKBFDXLPSIJKWKCSCNZKIHSZYNDGUIEKNZTKRAA9KGARQFMLIT9MXA9QSSVPUTGVJAWTFDGZLDWQENMRJRMNDJUDPKMIGMP"},{"in":"UWSQSTCPAQXQENYROAAVZCRNCLJDNACMQMZVOTQERLMGJWIUGLJMNHCMVAJXGDNFGRTSAKXOYODG9ZOQE","hash":"OJ9VGMWQGYQRQ9BWHOKMMSPPCGTJOEANVDWN9HLGPKWVLNRHAUXSBHMZGPIHLSPZNICODFVJINFMBVDWMCIEYFM9NDWNKCNLXVXHTMSIGTZBKAFYLADCKLINQWJYNZKEVZCZRJIALHLZ9AWDYMCJSUGNMOBZYXQUCMPNYPZNOH9WXBJWUABKVDOPOLMRXSKTNAOMWJYNVOVTVZAGRVYJURQBBIDLSVKMTYGGFSECKELZXCZSTAJ"},{"in":"GLNF9PDTKMCFEB9ZSWTJRNGYTQD9YGEVKTFESBJK9NSMGTCZPCCCRYEWQBQ9JTYTJDPUKBUFEFEEBTDVB","hash":"X9WMTGBFXEFHJWEKDSLNPCZVFGPBTVWVJTZSMLSC9ANJ9IAHVZTAYTDWQHQ9WUIIPJSCXG9CNYEETDKTPKZHADXDCWNAQFWQHKVYYLDDYRTPA9DV9HYRRUZMMGPNHRMYVQHIREZHUVAVBSWDQKSNDZFLFHLTMWUKKINHWJFSEGUMDDVMZWV9VLH9ONMOXKVSCKOQAMOYSHKPMUWTGRYRNEKKZVEBFBMVVQRYHZDGDXOIZEPM9FO"},{"in":"DFHVJBPZJYWTACAPHNPUPWTQMHBYUTNQIJPYOCGRSYBUVNRFWMOUPHUGIPLZCRGDAHW9OTMSBLJCFDGVI","hash":"SIRIPIBNNFBYZSBZMNSYFA9FYEXGCULJMMQXLPEKSDKEEWLT9HJLSOUAU9KWYURIXDGPSBZLXVVYUTUJKFCWKVQLN9EIJEEJNPMTAECEPC9YUWD9WKTFAHNEYPL9BBMLUCNZWYFISPGHJGXPSCTHHRXQX9YWETKBCZDS9NXJJMSKZJMUXQIBCBJQCZZGQPZPUOFESUGINMRYSVWBQVOWTZUBSASQUOADGBXTZTCPQOHLFXHBSVD"},{"in":"QLJQZAYKD9QJGBSYVRSCZOOLIIIEVSGS9CAEQCQNBBFWQOPTRDPZJFOAFTDVHFMQIVZALPFXGJSEVKDFK","hash":"MZU9BQLBWQNGLISZLEYHLOGSGPDYJJDBTGQKZ9VTNMSSWFFYXDQOLWILKRT9LQJYYXATZSLXJKNRRBCYQTFLVFPQSRGYQAKFEWOILYEUKPEBDZEYLHEYAZEHXAMRCYTFPROSFOYYLLRMCDZXTEKWRZ9NZQCUKOCZCLLSNFRCAGFRWRYERTPRYFXIV9THIRVRBEEQTJCZKYKLPPIAWRS9KHCZTQPGCHUUJPVKGMMYZHYKSMZJMZQ"},{"in":"DGSEECWZMHTDQEPSVBDAJQZVVCYEIKXWWSLEANTZYQIICMNMRNIKL99JQDSXHDOPDVUV9FHZNKCLAVZEI","hash":"DFJTBXLGR9BGSXCPFLNNBRDDDYGSNHUYGDVLLQ9FZRDQTNOJAWRFHACK9ITVNE9WWVXCBHQZAZWBINHZJVEKGAMMXDVV9FYTOTYR9UTXCNJZMI9SCBCETZMSRKIR9XWC9AMQTWZDBPSHTJUEQLKAXBVVNR9VHPXVSXSGBAOSFHUTEQMDBGUXMCUJYCGXMZTGZZPPYBTCOPJKEZGRFUYMQVKETJKDRVHSHTYGT9HDXMTUD9AYAKZ"},{"in":"DKTTBJ9BWUJYRZKWQMJRYUSWQZPLYTJLWYWSYHWRBAWFVOLVVXOXCNQYFXYCBLLUFFTBVVRJYVYPGVEBX","hash":"ALIASEHSNZJCYKFLEEW9HAUBDYENYGYVG9FIHPQ9UHMVBIZ9XBGXJEMZCWZGV9SLLGKOWCHWDYVXQ9EPYDQTXL99GYJCFENUONJVJIBSTN9DPTCSFTHZSTUOOKQLNFIPVVQPMYOILZHMNGNVZIHCNOXFFSOTKXIG9XPDYJIXBUEGU9ZSEZJBOWVDGJYEK9FKGOUMGQMPSHZFFUSHYHCMYL9UNMFDHUAMVSVOZUH9GMZJURDBWGJ"},{"in":"MLSKCTFBQSHZ9DFAGBS9NXOORLPEMHJQBKCTKOPHFCTIEHJCQYDZJCFQJYRFDKPVFKWOX9JMZKWUBFVZG","hash":"TMKNILODYCXZGSNUGJSKYZHHCQPTRNMUVCZADTTQXVCPMPBKOOWVCJUZCYGSQGWEINMSCNFOJUSAUTDCHEALZXXMUFFLGZGTK9JBWCULRSZNPAAMRNPDU99FLBGLL9XWKHWRMBOHWHBXKGWPYDEJXXWVZGVFYMERPJCMOMLTCNRTFWOWFZK9VHXJIYNWVJ9BYPNGCGYGERPSJUJXDWRYCPANQAUFJAVURUQLPQBXBAOLBDALHOU"},{"in":"ZAYXNJZGKA9PBF9DMJUQ9LJFS9AMSAODVAYLMTTAOPIWHMORFHWWDYJKMW9VL9CVDG9HWPBD9LSXCWITA","hash":"AUSHGZQOCYRAWCUUKCDAUQMLEFFMPWAMHIOZBJZZSHEDOERDKEEEAJGWNVNGGDVTDUYKEXUUYQPNWTMBZGFGCKGDAHGCIATRRNRXQKJVNWGZMVMFBADNCVECVZLDAHXDKXRLACWEH9MKNIVNAHDJEIPKJVKNLJOAAQSWTLHNDKVRPYPYVGKBUHYSWZAQIIFIGFJFUPPMIGBPABW9DVDDAMYLGYZHPFUXUHTFHNUSRJRXARWBUMX"},{"in":"WNX9W9N9IHFSMHYQXKTDTBGZSKCQFVIYHMJKOGNPR9EUAAUFKDBPMNFNIISCQPDLEZCIKZXXXORTEXUID","hash":"TICTIRCBVQAFIWX9AI9AJRYRMKJQWNIAF9ICJE9QJUBCVZDZQW9NTLKRIIHUZCDBVOZWMOVFJVZBXAWLGJNHEICPIMMLPUDDUJEZFKMOFLHPQGBZGLESGGECJLUPVWIDRASXXJPUIONPJWLKKVEZNAOLVZQRSQAP9UIVYNIQLS9OSTUKAMLFAAHSSETBFIVKRLSYNQGXSHQVTHMCSHKTEDEAZVMIAVPKNVLCU9HZPPFOSKWDUOJ"},{"in":"AKPXGJWDVFDCH9BJELLBCMOXTMEPESTQYPYWZGAVLFY9QDWBROJFFHIQYICBZCKRFRMCZBUJBIKWYFYQW","hash":"IBDZXXOO9KBBXAIGTMAVAHR9WFNRUCXFLD9CYZQEUPUXJP9QQWLILZVPDMXPCNAOZIW9OWVORIZFUUSJGFLAHXUNHWLJFAPARTZSQGNGMKJTTRNBYJ9PFXYKWAHDBTUCKBVQDJBSEAWFHWXUJQUCXCRXDEGLCQYTF9GUWPNHR9NOMEANROJUTEVJCBTEMJELLEHFDMOAQNE9IHPMIOEOTBFQQPVIEVABONLQOFOAIPER9BACJZJ"},{"in":"MMMQUATNIIFFTARFTIZCDVPNCNGJSUHS9WFFTOGJGRBX9U9KZRRVFX9YXULDOSKBWVKZOILIY9JSEUWKZ","hash":"JBASUGRCSY9YFICVSZBDOYTDDJXSZ9DGBGSKJFFYTCGNIEHFVHNSFSWPYTINO9ITZHVSBLRZJKJIPJL9FMPUPATRHMZD9PIRLCVXANENFUIYWCFZDMSFUTOYHBPBDMEMHYXYFQRK9XRJPHLDCQCVVGBQX9AEADFBNFCACDIMKFEABYFDVCJD9KVOJUDNKMSCHQTZ9MPQWQEAGGDXNWXSQGSQRTUDBBOV9WRY9GVNFISYDFABVUG"},{"in":"Z9UPPRERZAOCATYGQ99ZZNBAISMVYHJVGTRKZTPH9PFMDTTZFMMVXEIDOSKWHEWYVCCAL9EXQCBGKJTSA","hash":"LQJNXRFLBNGVWCDDX9KQXSDVKXIBOAELBCOIWSWAYGTYJUTNEPBMGICVIRFCXOMOHSCQKQBOKZUPEM9HBVZDKJIIVCCGAHAITJGZWTPRHCURXPFTAOJWCEGQKBSXWNJWSMACONXDTX9WEU9SGIIUDWDBWPZBYQCTLGBKGIQXFCQEIMIVFGDJQERSORJHOSYDWW9RPYIK9SRJAWSNSSJIFHZFHATTZWNILSAYBYPVOJQOWZORDBK"},{"in":"GWXJQLLKFZ9PBEIUCCLUQMEVEZTVDAPOAQHLHCADYDQUEJVDXMCKFMUIVSE9HAFBOLEI9DKGUNBLUKDGA","hash":"USVGRVORVYQPXZ9PUYCBQHXBZRQJU9OUQMMXBFZDSKZ9PBQG9BPQQBWYACQNPPVLACYRUWGJEPWLMCQWLMLALNRDMBU9TWYTERDKZLYMSTTCULAFMUNXODRVVQDNBBXFPLZCUBIUSMHIKU9WWJQWW9WGSLTKOWYSJBEGZVBN9ZNHJIU9RBK9NQLSX9MEBMTUKVJHDA9HVQPCNCGWETWHFCOVMKBCEFRDHZTCSTEQMGKTJMNTISL"},{"in":"GSOEVZENPCPDELPT9NEMVCDQRRIJACMAIOKIDHLGIGMBKZ9LQVLVFGIOCBAVVPEAXRJUTGQXTYTDL9D9M","hash":"NPEGVDWVBPLWTAHTQSHMKVPBGPAUNZHNNUZCSDROIOPYSFHQR9CMFOPXFCEWV9CWMITXOGBWJQOCBUW9EQMWJFSDXQKZHUMMCIJSHSRNBBQBNAIZIUREXLQNKTDVNTQ9COUUZHROJZMJZKPUQBGBLWMCJBVMBNXTSHLCFIHGWBTYAZQSEDHXNHXEGO9NWJYBXVLZUNRCDMMVFJVQHHAZINQTEIDATQ9WKSWKIRLHVZWPJIBMKMB"},{"in":"N9GFWWXSRHHJUBLVXVEEJDLFSBZJLYAPFBJTLMZIDDPFAQQGLPPSEHIMZUSNJGGOJKQFYIPUBCSUGSOCQ","hash":"NEALYRYRWNJW9ALDTYOPDXHLMVDYBCRWWJHBVQHUPRCNITQYSYTUKRRDSZOVJNVISFCVVMRPMYCP99BYCOTTALDTVSIOHVBOYZXIGMJDYOSQS9OGQTUETZEQOZMXMEEDMQFLDEFU9IHRFXCTX9FSJXKRGDEPFRAWVOBOWPNAXUWJOIVYKFOSMKUNZSQHWKGTLHECNH9IMJKOWKTVGO9SVATPLDVEEYOADWRRCFNCFQGUDWRSLOO"},{"in":"LVRGQC9QTTRQXEDPYLLQMJYGCAGPXS9LIRNPHIPQMTZFVJRTUBMVRDTEGVYFIQXFAWAIHZGBOXOJ99LBK","hash":"ROWZXUNWLMMHJNYK9DVEMZOFOMMQUHHEHPTKXZD9FWNHA9EDAHUIGZGVAWIYXPHZJYCMADDAOGCIVDNTLMRZYJUGMWOA9AAIJBTYPADIDGWYRWJ9DIVBLJTVPOVRVMVMKRHZBQIQJMUCANQACOWPMUPQ9YIRMVYESUIPYEBEZZJQZUVVKYAUDQGLBSJIJOTCDPVEFZYMVADBGECLYRZWEOAHFCC9VHHIRBYXOXZUCITQXFSQILH"},{"in":"L9HVKQYPTJQTPV9NSSXAWYPGKNJDVYUPDWDESIOXQOVZLTMRAHPGARTRDLNVFCXBEVJNGPRYAHJL9IRRN","hash":"GEERXSWKF9CF9GBELGKDCAVYLPWBHJGETMNNGOKXHNZHEDHLPISKGQHQHXMLNBDCRQJVMISVMBYUOAHTETXAVREOAAZJDVUZJLGABPJJSOGMIMBY9QNLSOWQTUSOLIDJVVQPGCEOHJLHOSSXSRVWTWMDNBKQKMXWOBTDGWDTLNMCJBUMWKXVX9IWTWNFFYNRZUNOIEFPPXTIJRQSUHHHPQLDECH99KFFYQIWYWXWIIAYWHIVANM"},{"in":"QDHOH9UI9UK9ZWYXCLZF9UQOVOSDBXXBQQHVTFHEKMHTGXGJOOP9FXKXTTLAFLLPBHHMHDLWPRGWJWHPL","hash":"OYZSSAGHUGNJBGFALAMQ9FBCTHAJIX9YGWZWSBNTWZME9ZTSXZ9V9OOVLZVWSWFZQCRJIROEKWTAVDPUHHTBOTBZLZLJAQTPIDUEIRTCOEEQSKHNZZJQGHSJFZLKZQWRVUTEQJVXQERAODLJGKDMLYLMLNBQELNSWARPHODLSTNMWAVHBIITUDBVSAFCWHCOGFDWVOLULVOWLXCESLRDVHITQCCRLIHSEIEXHCKDRFPEVDI9O9N"},{"in":"9WVZH9FREQRMB9YDPJBTCBEOPSHDBSUJHQZYKCEHFGRVTXST9SBM9PAHYPXGOPATWYUTNYWOVOMUFM9JN","hash":"XTDOXEABHWCUAUG9DJWAJZXZGREARWFQXSVKATUCNOJFTIGGGYZUKPQFJAZTFOXSCC9QHSS9RAYVGWMKTUNYCAJICGQSBNPYTXFPLKIZQVZAPVIJMRIUNERWXRGIXVHCJALLUXYFTHTITYUXHHOKOYMXRWTKWOUTNVY9OISIUARXIUEYMYHZJTUYEGOPMKVG9RKMSGGFZHYOQXGZSZITRD9KVPYMBDOOH9ZOKBNBQGDGNYZUHJB"},{"in":"KMQYO9VTSWBJAZPPRSKDWKWJNCBMCQZGKYGRHIAAYFCUQPTSTAXDRBJHMXGT9RYGZTBDTYGDLEUEVKSLN","hash":"OIURTZXBF9BPSALFPGGNNNWNKSWYVCGX9JUCNHRVKBFVNFAAMQSCYVFSSHKHO9LWDQIBHCWNEEWXV99DHNMEBANRQNDACVTUWUIGLYRFBTQSHDVSHDQWYPRTVYNYPIEFAIZPDNGBJXTVYMHOPUSBWZWJWCMZKE9WVZMJFPYMLJQOSLVLOVJR9TNGTWFXKT9PW9VWKFH9WFWHKIIYWNJJKIWWFAGRVZKNHPDAPFNOARPRGXUAPZU"},{"in":"9SBOQOFKHJDTD9UEFLPZOXJNMERHKYXZKRUKUMWWSSNATWY9PZQYL9KXTGXJIFJXZCBQZXXCQXHVLHPKO","hash":"FTK9JD9IIQVBZHUUIWAVAJICPMVAGJFSAKQOQHBWFQJJULTSNQVEGTCUTZUUMFBETCU9NKCUWOUGVCKYPEJTOKRHM99FVBBMCYSNXSNPXLW9HMAWQSSWCFHDKJXFJQFQOJBHTICDTPGBWQEIETMOASXWQAHPSWB9JOQCOMQEIMAEDPOYZDWYNUTMULORTOFWKGNBEGFTUCASZAVSYDJFZVMP9NIXZQLPFCNGOTPUBTRYLQTDNOH"},{"in":"GHZLXTVRXHGRMLMLOYOGBKTUDJFQWCXQTSLBVVUTFCJVKANRUB9LZRRNEPGXDDTMRQJMQGHWYYSQTGPQW","hash":"YNDHZUXKHNALAIXG9FGFKTDF9DI9UBQVHWCWHSEIEQLNEWPAKJWPZBCXN9UULHRGNEBRZXJKUKWAQPGPMHESDYEKMWDSMHKMRHHCGRKWVJF9LLRWGWRCKADFIVLQHLOKSGAMXTZYVDAAZWBD9DXPEEPQRLJMFCX9MYVH9HW99IRILLHQHRAMPXKBLH9UFKPCSDXGGCJPSIMOKOLPQRNZLAT9WPLSMQODWCWPAHWMLPK9ZNNENQW"},{"in":"GFVSNDMYXDIWRVKJOGAWLRTXUXHZISVOTQIXNIKCNFSFWIRZEYORIEGI9ZDWLQYUKSPOYINSBBTVAQIRZ","hash":"HVBTSIYIONLUIUCTBMJQSOMH9KDWN9HHUMEOZRCTFRDYSGXUVSLSOORAQZXRHMXLCLRJJEZIGNFLBJCJSKOTJVFOXYQMCAYYQSMLOYZMNCDBNZIFJXCRCVCCQDTJQOZSVIGR9JKKWNU9FIBLGCTWMOPTYRAVZXICDMHDBEVMULBKWPEZV9ARPOGKTZVLAXDUEWVESH9ZSBNSFQCB9JJQWKKCMTIEDAV9UZWVYZKJJQWHNRQTCTC"},{"in":"XFIURUQRKMMEKSZI9GEFJJKVQLUQ9JSGOSAOGLJVEJAKULEBIZFFPZCIZPIPJN9OVYERGJBIGMYBQIDWX","hash":"BPDZKWUZMPVWTYYELRCNHE9SCVDXIMNGCQJTJGHJEJHJMA9ALDOGKAOSWOKZGCDZR9UUMBBZXHZWJNBGZHUZOOWOXSSHRKMPYSXNYJDRRYDKVLTBBLBQEFHLFBHGOLEHCDRDBZNEHPHOHVUCPVZMJKQZMXZLQTWXTBKLBCBWXNQJJU9RSEKOUVHHBFRXJZ9LLOJSPYWFXERRFKDAXQEULS9NWVU9ONXKUJSRFWZQVV9NQHGYYOQ"},{"in":"BGOWRGZOSYBLEIJWRBSDFCPBQVWXPFVIGVZTDZEVNLUQVLIGORNKSQCGZCWZYK9WWQOPMRSEQASLGYSGK","hash":"URCTWMFYZEXXZSNIXSHWADAYAUIZ9RQQYUEZTYPOMTGAKVFIT9UHAVBFVXVTDRTBUFOPEDYCTZVAPPUSYPOBXFUXFKFXWPYIFEZYVNGCBTULJPBLXVJDXKRARHDPRXDPYIE99WWYFKKHZTPHQLXTHYCKUUBBIOFFMVWZFANZZKMOZKEXVHDTNHME9YOSBIXNPDNDEWUYVJZAIZYMWTHJHNPWKLDXOJAMZTRJGNNKEWYCDZKKKLN"},{"in":"OGKN9MZWAJDPJSNCWCYNYKCVOBTXVHSWNPKDYFMQITBUS9VNGCCUWMTQYYLMYQOUNPKBMVXEAMKGSBJWU","hash":"YDLQDLBXITFYGGBVRKBEOMEMVLLUYALCLVYAA9RZOPSZRUYBNARGJTKVFCKBMSFMGZJQKBHVGBPRXLIXFBV99LYNTRSYOXCA9TUSXACGSSNTETTXTSHLKSURBPVWYHFKELCLKZPRMNEROVJBNFNPDQXRXBSVPUNBRAJRPBTXJIYJFLBQFSCIPSNYUEBQBNYJN9UVTDTWFZCZADOPEPZN9MQYKBFDDRPVROTW9UAFH9J9WFYTLZD"},{"in":"NAQQFISEEDDZKBPCEWQCHCLQTLKLFLBRNGAACSVPNRRQNJKANRBULKGQLIAOPH9SDHIOBADQAZBCC9JPT","hash":"EIWYJNKQWMKAB9HVKGBQE9HA9FXMXMGUDFIZZHGKFLLRQHODXGH9AOKPBBLGQIOHPXJRSNMSNBJJTRTFJIQOJQQFHFUJEVLEUJYWJHPV9NDTHAWBVVXSJYEDQICTBQQGMLSQSBBYZVXRFSVJSEUBTQGSOBCKLOUWZWCNIFUMCBSAFYXOKYPJUQUEVJAHKSXMRIHRTMZFRTOOUZOZYM9TQLFUIDNNU9ZIOPUCGKLAGQTZLRVTZFM"},{"in":"MHUIZSXBRXRHQUVHPDTS9ETMVSCNVTVIUGWRJGUMCDWXQKXCACJXTRLABIUVKWFZBOKGPJLKUXEMDJLNV","hash":"OFAKKUGJIVJEYMVCT9VADKZEQGBZPYBPDQDDPCAKEWPYFCQQHHESCAVSGGEKZDTEFKKNCSSHAFLELVKAWNINAKGGUXSQGBUFDPAGQQQJBOGNHIBKIRXBKQSXRMOJBEGEW9AFJCKISNRGCSDIZLYHDASSBDXXWETHUKIAFTYX9ZSCLOURCPMTMLGKXF9WYMOPRGHUSRXOGIXWMBVHCSOTGWSDPSTJ9NQNMSNPIZBRUWQJESUPF9J"},{"in":"DWHLTXCLYDYLMGCHWZRRAPYHEZERUYSNYVVNWBBNAXITAWRUWVFREWQOHKJEVWXJEOUXJJGJVBUBFZRXZ","hash":"ULJASYV9VSBOKNGNWDMJFQRPHHIJYJWIECJGGZVHUVBDUWJJWWXYWAONZBZXHXFLVZTOSCDZHZELPHLNVVBPSDZOFZPTJCTHPPRFEH9MOFNDRLIXLPUHBOKMVUMDNGELBCYNPKOOHABACYCGIOWIYYABFWAJDLIDXDXBLPORCLDXVVQEZFINPDKHHYYDIHLYFOOJCCFATTXIBMCXLVWMENGPQBKPDRJMLJAGFAAPGVJTACOGPVL"},{"in":"XVHTRMQFOYSOLFTQRUHQIK9SXBEQDB9ODJMBPUW9KEVJDHGVCHFZCADK9HHHNJWTWNAGTIIWAWMWOZZUE","hash":"HPPAMKALGZN9WZ9LWRYOKPRCYKBTOHPJFXZFX9RRUPYRRQOX9WXGQEULTJKMTJRMIBHCZZPGDMXIEQ9FPJLGKZKMFFPKREXUMDAMQLPBGEZMOUMJBNSVBPSFEMOJBUNOSEMVMJACWYSPBR9YHZYVDBZJIPEMD9JDJH9QRQHRGSWHNILUQOUCJYZ9VBJMUZLGAQQATYSGDCBPQPHOIH9WMMSHHLS9AOOOQIIHUWEPBGVDBWDQC9A"},{"in":"PURCZTXVCDOJYLQZOGNFX9UBKSPYOGUZLCJIO9ZXEDPONRVVDVCKEEKBDUPOVHFSCSTXKXKALQS9DEKOP","hash":"TFLWYIK9BYSKLMURPCTGEIKJYYQXTEMUTAWFGFUKDPSEZYSQEUXKFJR9EHGFGYDNMSDKSHLHHYUQKUWVWU9AQXCJMIU9IAHPZFNCQNIRZ9HHTKFPBWJDLJHHHMOIPOWLNSFQ9WAVMEENBOVSVJDQAOKQMWHNAVQJDKNDWMXHUFKMSQWSUIP99VMQIUYKXWQQHOHNVRGPDILDVKIRIMTTHBHDGSKGBTOHXEQ9RQFBEPSMJBHZ9CE"},{"in":"WUCFMXATJFCVYEXJWNZWYKLQKYBSNNBCU9VDAFJR9HBTUEKNZFCRSQPVWJNRYQNNBJSZRIWWEO9FKTQGI","hash":"KOLCETIYKDHMARHTITUVGEZXDQPCKPPEVXWGXUO9JGKU9OTRFCVJST9EZSXWDEETHCOWWKVHCLXHQVULQFWJWZEXTORQCEMCGBLCMNBNAOIHCFX9FPFIVHEHQOOCPMSZGSDFFTONWHJLWLZDALXI9JOUCAUFTZYGMZRQBEMHWYWAJTQMQUCO9EOYIPCTAUUBQCSVNATUOAKBJIMLQKAVSSYNTMTQXGTEQDGZQFCYCCA9HZEGDVF"},{"in":"D9BMQGSOWYGEQXKTPVYVJKYQHVDUDHSBJLDIPYLZHLMJISGFJPC9ZKLFATBQYZXUQEYGRXDQJZEMVQFNE","hash":"DLDPAXBNEDVNXKKMXVKDZANQISZMBQGDQHEOAYBD9CKUGYH9AYTKWMPACVKIMCDBWXQNKOJPYGWZIJPYKYLJSSUYZROFHSZGIBTIXVHQMIEMCDUFIFINCJXHGPKIDEPARCLNWJKEA9FFBZ9GAVQWTBCSRFNJFNCMQMCET9FSLVPFP9DFTJMWHTR9HMQVJV9XQZNQOEER9SCMUWOZQAXPQDE9VMGRYPWQBSPJSVHLCSBUCZPCVSH"},{"in":"HEVMKKLD9GETGED9EEWXCPRAL9BMPSKKUDWLPU9YCKPCMIXASJAZUTAWJJU9CCYICJOBUIGVCLESOCOLR","hash":"JZVM9SZYNOOJ9XLIGNHRSHIWMOBKDMSYZSFEIOCNTZVDIHTWTADIHNBEJTAEKXPSQAPLXWRITVRYWXCGRSKBMSFFKPTLSPZYVJRVQPOHRKIXDSQUZNUZ9ZVVZQRHXAMETRKGISRUEPPJMZFJNYQIUEZBNPGZKBTYZNEGMMZLFNYNUYLBUMLDTIW9WXNNHIAJJZPMGBNSYDSIYHGBAWVDXLMXAAVFYBCUIIQCVBPDKAJFOJJXJZH"},{"in":"SLLOAOKDFYRHCZJFWAB9IBZXYNUNQJMWRYE9RTPZEDHNMSJQGIFSS9GFGLGFSIOMGLDTE9WRWAGWKKJHV","hash":"NWTGEKPXYEITXANDDHZZXYVSFPAAQKWXIJNNA9RRGWGEUKKJNWKOECBGGR9OKDMLJKELFKGHBTKKVQAPGQCZJNZFGCCVALU9RBLWOADRFLXP9QNWMULITLYU9YYHQVYKDIBELE9RVZ9RMAE9BX9O99CLFUZTIRWXRLCQFMUMAZMOHVJLLQMQ9BMNUKTZNEZKTCCOGRRLBCOUSFJBAYVHBRJH9PJD9MFSVSNAAENNSEKQLZURISV"},{"in":"KPOVGUBOVYDGFNKVYBTWSLCBULQWFUDJ9HCLRP9J9ANJEGHHWOHXLNLSQTVZTRYTIHJEFXPO9FEWDHASD","hash":"AZKQUOEDWONPUHVHJJHPZMAIFEJEDB9RWUHVNIKLWHRYBPKTYKPOONHJEIAQOKWGTBZCWWQTMVKGBLIKPZIAGZEFTZHUSGSRCXFNRIZPBLFUCLPFJ9YEJVGI9HBJZLYSVQS9LUZAJYUIDESMMZNHX99XYFMZY9SQFKYYRXVEMHOXTKYPOEITDTMJODJEVGJBQJYQJNULOVU9QKUQJCUEULEFFWJSOHGCYUARWLBLFDCXVTBRUI9"},{"in":"YYDMSICOBUGBGHIGHQSOMWZZQQDPNASQNWNRLLXFCDEZVBWKLKVDTWUGUHYJUWUWIDULTADZIBZLMKDZA","hash":"VA9CHVL9OJULYIPVCOMVPWSNLXNV9QTWVSVCNLUWNQZDXZCTILVVTHCTRWLOMKF9TAOHUA9REV9DGRDXMCPUZRK9MAHRAZKURYULAITZWODETVPFEQVAMWKYYTHQDCBZ9UUWXBXGLWZMW9YTFBLRDUAHRBTXIAGTXRRRKMKVMIORNKB9AUYMXOODVK9SNZBHSM9KULAVQFI9PWTBWEXZSFUJPRBXBIECTLSETW9OJEXLTQWHALL"},{"in":"UQDVTGUYHZRAJHVEJRGVVZFQFQJIJAONIAMTKCACHRKSYPUMUTYLYYONYJTPJXMAPTWRDWZCURWBYQVFK","hash":"LMTZIYPCAPPOHSKCRHPLW9UGSJSRJRKNOYNCHKODHSRHCRWVPVRTTHVBNTCARUUMVGZUKFIOEOMZTNKUTBHCUZUGYSYHDZIEHQYOAXFLZBLCG9TRISKTHZTYHHE9MFAJRRSQIWJUTCDBTRDAZZAFZE9KJLBRVULYXFMAUCZAD9FESHXGTVUYEETGETUAYNQGFMWQKLWRLZJZRGUHUILISWLNOEA9YMSRUUT9BXXSMUKTLITFQCX"},{"in":"LHEJMCH9RWJISSNHDKPS9RTJPEYUUGMQUNWNXZKOPBYJMTOVDBKGRWHWCKVFSVAYCJUYNMBEIZQ9ICVFY","hash":"CXEINZRRBVOIVLTKTOUNWO9LSSMVG9QZKXMXFSOR9ECSDBUOAZCBDJRGZNHHMKNCAHPX9AFHILXVEHPPS9TNPUZLV9CVHGNESQSECFABFQETCLTGBCLJFK9REILYZUCEFBIDMTQJMIVGY9TWNZLFAFAUVICKQVUTEMCKG9XOXLWFQZABUKEVEKKBIBAVXBYOJNNTGARABFWORJOPKYAMDXHFQYVVTQPIBGKJZXBRJOHRLF9WEE9"},{"in":"ECXGXAXVUMIRKNTGETPNFNIHFXXIB9JCHBYIXUYC9SJU9D9VPCJBPXAZTALWRBMCKBPFRCWFOAPLAZMKT","hash":"KYRBYUGLKXKTFKOUQXNZDQZAK9XKRMLSGQK9YWDZHNDVQPEJECISXDXWHKOGNIANVLHIQSZT9PPVWCCDJDESEHTQXDMPGWIARDSSQRLANXDGECQUSOKLEABN9PLNHVODZTTGRWFILDRBRXABXLWB9FLVIGYLGXWROAJXZALXEMQZNIYSEYGRMJJKIGHCWQPQOUWUWOZSDQWJBPUGCPTRDRSNU9DVFUVHSQGHVT9GSTUM9JABQQS"},{"in":"FVFDOQDYPXLJWUZLUWHCOFXQFASKXULPC9FBLELD9WVKGFLWHC9HBLZRECWYSCPSOUBFRWTCEWUR9HKHB","hash":"YRMCHIWLTKHMONEIRYCRPXLCRTV9EONPKI9D9BXENQKPLYMZGPSQCGBROVGOTTU9JOIFWZIJWNWQNFJBNYBIKHQHKMFAANAXFSLCFTIOZJNDTBCWILKRMEIBQMDGUCQXZAA9DCXGZDSTMNWQWULNSCRKCXSRVNRBB9RMOQZBBGSIRBRDUHGG9BADACEFYDXKDOJWOEGAOWNHR9JQV9WIDTTKBEXGDPMLHHVQKUUOBFSAZPQLRGQ"},{"in":"LCABLKLBO9LWVGEVBZXSWH9PMCHFESH9ROESAECCBVEWEMDOWFRPLJOAKKMXWTU9UBGCQYCOQXSUVOJRP","hash":"HWYAVOKLHBYDAXQ9UHHINFZBRYWTLQXICE9CJWO9FXGTKTCXZLINFEBCOIBIFVDVCVHY9MADBEDAAMUBFIVOGBNUUMJZYSEXYHLVJILRVEPONXMIGKGSGACYYGQBIUEARFNCNGCNFLSVOCWJJZ9QUZBLILREICCAPSMFQ9MSUXWYOABGTNJYQRPV9NKWEMTJF9DLMUJZVQVSASDTI9GBPOUCILVHTBKANWLKQTFWAVVKCABASHE"}] \ No newline at end of file diff --git a/pkg/curl/transform.go b/pkg/curl/transform.go deleted file mode 100644 index fbecc7b..0000000 --- a/pkg/curl/transform.go +++ /dev/null @@ -1,36 +0,0 @@ -package curl - -func transformGeneric(lto, hto, lfrom, hfrom *[StateSize]uint) { - for r := NumRounds; r > 0; r-- { - aL, aH := lfrom[0], hfrom[0] - bL, bH := lfrom[364], hfrom[364] - lto[0], hto[0] = sBox(aL, aH, bL, bH) - - t := 364 // rotation offset - for i := 1; i <= StateSize-4; i += 4 { - t += 364 - aL, aH = lfrom[t], hfrom[t] - lto[i+0], hto[i+0] = sBox(bL, bH, aL, aH) - - t -= 365 - bL, bH = lfrom[t], hfrom[t] - lto[i+1], hto[i+1] = sBox(aL, aH, bL, bH) - - t += 364 - aL, aH = lfrom[t], hfrom[t] - lto[i+2], hto[i+2] = sBox(bL, bH, aL, aH) - - t -= 365 - bL, bH = lfrom[t], hfrom[t] - lto[i+3], hto[i+3] = sBox(aL, aH, bL, bH) - } - // swap buffers - lfrom, lto = lto, lfrom - hfrom, hto = hto, hfrom - } -} - -func sBox(aL, aH, bL, bH uint) (uint, uint) { - tmp := aL & (aH ^ bL) - return ^tmp, (aL ^ bH) | tmp -} diff --git a/pkg/curl/transform_amd64.go b/pkg/curl/transform_amd64.go deleted file mode 100644 index 77c2066..0000000 --- a/pkg/curl/transform_amd64.go +++ /dev/null @@ -1,9 +0,0 @@ -// Code generated by command: go run transform_amd64_asm.go -out ../transform_amd64.s -stubs ../transform_amd64.go -pkg curl. DO NOT EDIT. - -//go:build amd64 && gc && !purego - -package curl - -// transform transforms the sponge state. It works like transformGeneric. -//go:noescape -func transform(lto *[729]uint, hto *[729]uint, lfrom *[729]uint, hfrom *[729]uint) diff --git a/pkg/curl/transform_amd64.s b/pkg/curl/transform_amd64.s deleted file mode 100644 index 35e4173..0000000 --- a/pkg/curl/transform_amd64.s +++ /dev/null @@ -1,112 +0,0 @@ -// Code generated by command: go run transform_amd64_asm.go -out ../transform_amd64.s -stubs ../transform_amd64.go -pkg curl. DO NOT EDIT. - -//go:build amd64 && gc && !purego - -#include "textflag.h" - -// func transform(lto *[729]uint, hto *[729]uint, lfrom *[729]uint, hfrom *[729]uint) -TEXT ·transform(SB), NOSPLIT, $0-32 - MOVQ lto+0(FP), AX - MOVQ hto+8(FP), CX - MOVQ lfrom+16(FP), DX - MOVQ hfrom+24(FP), BX - MOVQ $0x00000051, SI - -RoundLoop: - // a = from[0] - MOVQ (DX), DI - MOVQ (BX), R8 - - // b = from[364] - MOVQ 2912(DX), R9 - MOVQ 2912(BX), R10 - - // s = sBox(a, b) - MOVQ R9, R11 - XORQ R8, R11 - ANDQ DI, R11 - XORQ R10, DI - ORQ R11, DI - NOTQ R11 - - // to[0] = s - MOVQ R11, (AX) - MOVQ DI, (CX) - MOVQ $0x0000016c, R11 - MOVQ $0x00000001, R12 - -StateLoop: - // a = from[364+t] - MOVQ 2912(DX)(R11*8), DI - MOVQ 2912(BX)(R11*8), R8 - - // s = sBox(b, a) - MOVQ DI, R13 - XORQ R10, R13 - ANDQ R9, R13 - XORQ R8, R9 - ORQ R13, R9 - NOTQ R13 - - // to[0+i] = s - MOVQ R13, (AX)(R12*8) - MOVQ R9, (CX)(R12*8) - - // b = from[-1+t] - MOVQ -8(DX)(R11*8), R9 - MOVQ -8(BX)(R11*8), R10 - - // s = sBox(a, b) - MOVQ R9, R13 - XORQ R8, R13 - ANDQ DI, R13 - XORQ R10, DI - ORQ R13, DI - NOTQ R13 - - // to[1+i] = s - MOVQ R13, 8(AX)(R12*8) - MOVQ DI, 8(CX)(R12*8) - - // a = from[363+t] - MOVQ 2904(DX)(R11*8), DI - MOVQ 2904(BX)(R11*8), R8 - - // s = sBox(b, a) - MOVQ DI, R13 - XORQ R10, R13 - ANDQ R9, R13 - XORQ R8, R9 - ORQ R13, R9 - NOTQ R13 - - // to[2+i] = s - MOVQ R13, 16(AX)(R12*8) - MOVQ R9, 16(CX)(R12*8) - - // b = from[-2+t] - MOVQ -16(DX)(R11*8), R9 - MOVQ -16(BX)(R11*8), R10 - - // s = sBox(a, b) - MOVQ R9, R13 - XORQ R8, R13 - ANDQ DI, R13 - XORQ R10, DI - ORQ R13, DI - NOTQ R13 - - // to[3+i] = s - MOVQ R13, 24(AX)(R12*8) - MOVQ DI, 24(CX)(R12*8) - SUBQ $0x00000002, R11 - ADDQ $0x00000004, R12 - CMPQ R12, $0x000002d9 - JL StateLoop - - // swap buffers - XCHGQ DX, AX - XCHGQ BX, CX - DECQ SI - JNZ RoundLoop - RET diff --git a/pkg/curl/transform_noasm.go b/pkg/curl/transform_noasm.go deleted file mode 100644 index 5baf97a..0000000 --- a/pkg/curl/transform_noasm.go +++ /dev/null @@ -1,7 +0,0 @@ -// +build !amd64 !gc purego - -package curl - -func transform(lto, hto, lfrom, hfrom *[StateSize]uint) { - transformGeneric(lto, hto, lfrom, hfrom) -} diff --git a/pkg/ed25519/ed25519_test.go b/pkg/ed25519/ed25519_test.go index 7986625..d325a00 100644 --- a/pkg/ed25519/ed25519_test.go +++ b/pkg/ed25519/ed25519_test.go @@ -11,9 +11,9 @@ import ( "path" "testing" + "github.com/iotaledger/iota-crypto-demo/pkg/ed25519" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/wollac/iota-crypto-demo/pkg/ed25519" ) var nullSeed = make([]byte, ed25519.SeedSize) diff --git a/pkg/ed25519/rfc28_test.go b/pkg/ed25519/rfc28_test.go index d8b25e5..fff0068 100644 --- a/pkg/ed25519/rfc28_test.go +++ b/pkg/ed25519/rfc28_test.go @@ -7,10 +7,10 @@ import ( "path/filepath" "testing" + "github.com/iotaledger/iota-crypto-demo/internal/hexutil" + "github.com/iotaledger/iota-crypto-demo/pkg/bech32/address" + "github.com/iotaledger/iota-crypto-demo/pkg/ed25519" "github.com/stretchr/testify/require" - "github.com/wollac/iota-crypto-demo/internal/hexutil" - "github.com/wollac/iota-crypto-demo/pkg/bech32/address" - "github.com/wollac/iota-crypto-demo/pkg/ed25519" ) type testCase struct { diff --git a/pkg/ed25519/zip215_test.go b/pkg/ed25519/zip215_test.go index dc191fc..6f7f9fc 100644 --- a/pkg/ed25519/zip215_test.go +++ b/pkg/ed25519/zip215_test.go @@ -4,8 +4,8 @@ import ( "encoding/hex" "testing" + "github.com/iotaledger/iota-crypto-demo/pkg/ed25519" "github.com/stretchr/testify/assert" - "github.com/wollac/iota-crypto-demo/pkg/ed25519" ) var message = []byte("Zcash") diff --git a/pkg/encoding/b1t6/b1t6.go b/pkg/encoding/b1t6/b1t6.go deleted file mode 100644 index 9ecdbaf..0000000 --- a/pkg/encoding/b1t6/b1t6.go +++ /dev/null @@ -1,118 +0,0 @@ -// Package b1t6 implements the b1t6 encoding which uses a group of 6 trits to encode each byte. -// See the IOTA protocol TIP-5 https://iotaledger.github.io/tips/tips/TIP-0005/tip-0005.html for details. -package b1t6 - -import ( - "errors" - "fmt" - "math" - "strings" - - "github.com/iotaledger/iota.go/consts" - "github.com/iotaledger/iota.go/trinary" -) - -const ( - tritsPerByte = 6 - trytesPerByte = tritsPerByte / consts.TritsPerTryte -) - -// EncodedLen returns the trit-length of an encoding of n source bytes. -func EncodedLen(n int) int { return n * tritsPerByte } - -// Encode encodes src into EncodedLen(len(in)) trits of dst. As a convenience, it returns the number of trits written, -// but this value is always EncodedLen(len(src)). -// Encode implements the b1t6 encoding converting a bit string into ternary. -func Encode(dst trinary.Trits, src []byte) int { - j := 0 - for i := range src { - t1, t2 := encodeGroup(src[i]) - trinary.MustPutTryteTrits(dst[j:], t1) - trinary.MustPutTryteTrits(dst[j+consts.TritsPerTryte:], t2) - j += 6 - } - return j -} - -// EncodeToTrytes returns the encoding of src converted into trytes. -func EncodeToTrytes(src []byte) trinary.Trytes { - var dst strings.Builder - dst.Grow(EncodedLen(len(src)) / consts.TritsPerTryte) - - for i := range src { - t1, t2 := encodeGroup(src[i]) - dst.WriteByte(trinary.MustTryteValueToTryte(t1)) - dst.WriteByte(trinary.MustTryteValueToTryte(t2)) - } - return dst.String() -} - -var ( - // ErrInvalidLength reports an attempt to decode an input which has a trit-length that is not a multiple of 6. - ErrInvalidLength = errors.New("length must be a multiple of 6 trits") - // ErrInvalidTrits reports an attempt to decode an input that contains an invalid trit sequence. - ErrInvalidTrits = errors.New("invalid trits") -) - -// DecodedLen returns the byte-length of a decoding of n source trits. -func DecodedLen(n int) int { return n / tritsPerByte } - -// Decode decodes src into DecodedLen(len(in)) bytes of dst and returns the actual number of bytes written. -// Decode expects that src contains a valid b1t6 encoding and that src has a length that is a multiple of 6, -// it returns an error otherwise. If src does not contain trits, the behavior of Decode is undefined. -func Decode(dst []byte, src trinary.Trits) (int, error) { - i := 0 - for j := 0; j <= len(src)-tritsPerByte; j += tritsPerByte { - t1 := trinary.MustTritsToTryteValue(src[j:]) - t2 := trinary.MustTritsToTryteValue(src[j+consts.TritsPerTryte:]) - b, ok := decodeGroup(t1, t2) - if !ok { - return i, fmt.Errorf("%w: %v", ErrInvalidTrits, src[j:j+6]) - } - dst[i] = b - i++ - } - if len(src)%tritsPerByte != 0 { - return i, ErrInvalidLength - } - return i, nil -} - -// DecodeTrytes returns the bytes represented by the t6b1 encoded trytes. -// DecodeTrytes expects that src contains a valid b1t6 encoding and that in has even length, -// it returns an error otherwise. If src does not contain trytes, the behavior of DecodeTrytes is undefined. -func DecodeTrytes(src trinary.Trytes) ([]byte, error) { - dst := make([]byte, DecodedLen(len(src)*consts.TritsPerTryte)) - i := 0 - for j := 0; j <= len(src)-trytesPerByte; j += trytesPerByte { - t1 := trinary.MustTryteToTryteValue(src[j]) - t2 := trinary.MustTryteToTryteValue(src[j+1]) - b, ok := decodeGroup(t1, t2) - if !ok { - return nil, fmt.Errorf("%w: %s", ErrInvalidTrits, src[j:j+2]) - } - dst[i] = b - i++ - } - if len(src)%trytesPerByte != 0 { - return nil, ErrInvalidLength - } - return dst, nil -} - -// encodeGroup converts a byte into two tryte values. -func encodeGroup(b byte) (int8, int8) { - // this is equivalent to: IntToTrytes(int8(b), 2) - v := int(int8(b)) + (consts.TryteRadix/2)*consts.TryteRadix + consts.TryteRadix/2 // make un-balanced - quo, rem := v/consts.TryteRadix, v%consts.TryteRadix - return int8(rem + consts.MinTryteValue), int8(quo + consts.MinTryteValue) -} - -// decodeGroup converts two tryte values into a byte and a success flag. -func decodeGroup(t1, t2 int8) (byte, bool) { - v := int(t1) + int(t2)*consts.TryteRadix - if v < math.MinInt8 || v > math.MaxInt8 { - return 0, false - } - return byte(v), true -} diff --git a/pkg/encoding/b1t6/b1t6_test.go b/pkg/encoding/b1t6/b1t6_test.go deleted file mode 100644 index 0e6bbd4..0000000 --- a/pkg/encoding/b1t6/b1t6_test.go +++ /dev/null @@ -1,169 +0,0 @@ -package b1t6_test - -import ( - "bytes" - "encoding/hex" - "errors" - "math/rand" - "strings" - "testing" - - "github.com/iotaledger/iota.go/trinary" - "github.com/stretchr/testify/assert" - "github.com/wollac/iota-crypto-demo/pkg/encoding/b1t6" -) - -func TestValidEncodings(t *testing.T) { - type args struct { - bytes []byte - trytes trinary.Trytes - } - tests := []struct { - name string - args args - }{ - {name: "empty", args: args{bytes: []byte{}, trytes: ""}}, - {name: "normal", args: args{bytes: []byte{1}, trytes: "A9"}}, - {name: "min byte value", args: args{bytes: []byte{0}, trytes: "99"}}, - {name: "max byte value", args: args{bytes: []byte{255}, trytes: "Z9"}}, - {name: "max trytes value", args: args{bytes: []byte{127}, trytes: "SE"}}, - {name: "min trytes value", args: args{bytes: []byte{128}, trytes: "GV"}}, - {name: "endianness", args: args{bytes: []byte{0, 1}, trytes: "99A9"}}, - {name: "long", args: args{ - bytes: bytes.Repeat([]byte{0, 1}, 25), - trytes: strings.Repeat("99A9", 25)}, - }, - {name: "RFC example I", args: args{ - bytes: mustDecodeHex("00"), - trytes: "99"}, - }, - {name: "RFC example II", args: args{ - bytes: mustDecodeHex("0001027e7f8081fdfeff"), - trytes: "99A9B9RESEGVHVX9Y9Z9"}, - }, - {name: "RFC example III", args: args{ - bytes: mustDecodeHex("9ba06c78552776a596dfe360cc2b5bf644c0f9d343a10e2e71debecd30730d03"), - trytes: "GWLW9DLDDCLAJDQXBWUZYZODBYPBJCQ9NCQYT9IYMBMWNASBEDTZOYCYUBGDM9C9"}, - }, - } - for _, test := range tests { - test := test - t.Run(test.name, func(t *testing.T) { - - t.Run("Encode()", func(t *testing.T) { - dst := make(trinary.Trits, b1t6.EncodedLen(len(test.args.bytes))) - n := b1t6.Encode(dst, test.args.bytes) - assert.Len(t, dst, n) - assert.Equal(t, trinary.MustTrytesToTrits(test.args.trytes), dst) - }) - - t.Run("EncodeToTrytes()", func(t *testing.T) { - dst := b1t6.EncodeToTrytes(test.args.bytes) - assert.Equal(t, test.args.trytes, dst) - }) - - t.Run("Decode()", func(t *testing.T) { - src := trinary.MustTrytesToTrits(test.args.trytes) - dst := make([]byte, b1t6.DecodedLen(len(src))) - n, err := b1t6.Decode(dst, src) - assert.NoError(t, err) - assert.Len(t, dst, n) - assert.Equal(t, test.args.bytes, dst) - }) - - t.Run("DecodeTrytes()", func(t *testing.T) { - dst, err := b1t6.DecodeTrytes(test.args.trytes) - assert.NoError(t, err) - assert.Equal(t, test.args.bytes, dst) - }) - }) - } -} - -func TestInvalidEncodings(t *testing.T) { - type args struct { - bytes []byte - trytes trinary.Trytes - } - tests := []struct { - name string - args args - err error - }{ - {name: "one tryte", args: args{bytes: []byte{}, trytes: "A"}, err: b1t6.ErrInvalidLength}, - {name: "3 trytes", args: args{bytes: []byte{1}, trytes: "A9A"}, err: b1t6.ErrInvalidLength}, - {name: "5 trytes", args: args{bytes: []byte{0, 1}, trytes: "99A9A"}, err: b1t6.ErrInvalidLength}, - {name: "above max group value", args: args{bytes: []byte{}, trytes: "TE"}, err: b1t6.ErrInvalidTrits}, - {name: "below min group value", args: args{bytes: []byte{}, trytes: "FV"}, err: b1t6.ErrInvalidTrits}, - {name: "max trytes value", args: args{bytes: []byte{}, trytes: "MM"}, err: b1t6.ErrInvalidTrits}, - {name: "min trytes value", args: args{bytes: []byte{}, trytes: "NN"}, err: b1t6.ErrInvalidTrits}, - {name: "2nd group invalid", args: args{bytes: []byte{255}, trytes: "Z9TE"}, err: b1t6.ErrInvalidTrits}, - {name: "3rd group invalid", args: args{bytes: []byte{0, 1}, trytes: "99A9AFV"}, err: b1t6.ErrInvalidTrits}, - } - for _, test := range tests { - test := test - t.Run(test.name, func(t *testing.T) { - - t.Run("Decode()", func(t *testing.T) { - trits := trinary.MustTrytesToTrits(test.args.trytes) - dst := make([]byte, b1t6.DecodedLen(len(trits))+10) - n, err := b1t6.Decode(dst, trits) - assert.True(t, errors.Is(err, test.err)) - assert.LessOrEqual(t, n, b1t6.DecodedLen(len(trits))) - assert.Equal(t, test.args.bytes, dst[:n]) - }) - - t.Run("DecodeTrytes()", func(t *testing.T) { - dst, err := b1t6.DecodeTrytes(test.args.trytes) - assert.True(t, errors.Is(err, test.err)) - assert.Nil(t, dst) - }) - }) - } -} - -func mustDecodeHex(s string) []byte { - dst, err := hex.DecodeString(s) - if err != nil { - panic(err) - } - return dst -} - -var ( - benchBytesLen = 1000 - benchTritsLen = b1t6.EncodedLen(benchBytesLen) -) - -func BenchmarkEncode(b *testing.B) { - data := make([][]byte, b.N) - for i := range data { - data[i] = randomBytes(benchBytesLen) - } - b.ResetTimer() - - dst := make(trinary.Trits, benchTritsLen) - for i := range data { - _ = b1t6.Encode(dst, data[i]) - } -} - -func BenchmarkDecode(b *testing.B) { - data := make([]trinary.Trits, b.N) - for i := range data { - data[i] = make(trinary.Trits, benchTritsLen) - b1t6.Encode(data[i], randomBytes(benchBytesLen)) - } - b.ResetTimer() - - dst := make([]byte, benchBytesLen) - for i := range data { - _, _ = b1t6.Decode(dst, data[i]) - } -} - -func randomBytes(n int) []byte { - result := make([]byte, n) - rand.Read(result) - return result -} diff --git a/pkg/encoding/b1t8/b1t8.go b/pkg/encoding/b1t8/b1t8.go deleted file mode 100644 index ffa531e..0000000 --- a/pkg/encoding/b1t8/b1t8.go +++ /dev/null @@ -1,78 +0,0 @@ -// Package b1t8 implements the b1t8 encoding which uses 8 trits to encode each byte. -package b1t8 - -import ( - "errors" - "fmt" - - "github.com/iotaledger/iota.go/trinary" -) - -const ( - tritsPerByte = 8 -) - -// EncodedLen returns the trit-length of an encoding of n source bytes. -func EncodedLen(n int) int { return n * tritsPerByte } - -// Encode encodes src into EncodedLen(len(src)) trits of dst. As a convenience, it returns the number of trits written, -// but this value is always EncodedLen(len(src)). -// Encode implements the b1t8 encoding converting a bit string into ternary. -func Encode(dst trinary.Trits, src []byte) int { - for _, b := range src { - _ = dst[7] // early bounds check to guarantee safety of writes below - dst[0] = int8(b & 0x01 >> 0) - dst[1] = int8(b & 0x02 >> 1) - dst[2] = int8(b & 0x04 >> 2) - dst[3] = int8(b & 0x08 >> 3) - dst[4] = int8(b & 0x10 >> 4) - dst[5] = int8(b & 0x20 >> 5) - dst[6] = int8(b & 0x40 >> 6) - dst[7] = int8(b & 0x80 >> 7) - - dst = dst[8:] - } - return EncodedLen(len(src)) -} - -var ( - // ErrInvalidLength reports an attempt to decode an input which has a trit-length that is not a multiple of 8. - ErrInvalidLength = errors.New("length must be a multiple of 8 trits") - // ErrInvalidTrit reports an attempt to decode an input that contains an invalid trit sequence. - ErrInvalidTrit = errors.New("invalid trits") -) - -// DecodedLen returns the byte-length of a decoding of n source trits. -func DecodedLen(n int) int { return n / tritsPerByte } - -// Decode decodes src into DecodedLen(len(src)) bytes of dst and returns the actual number of bytes written. -// Decode expects that src contains a valid b1t8 encoding and that src has a length that is a multiple of 8, -// it returns an error otherwise. -// If the input is malformed, Decode returns the number of bytes decoded before the error. -func Decode(dst []byte, src trinary.Trits) (int, error) { - i := 0 - for len(src) >= tritsPerByte { - var b byte - for j := 0; j < tritsPerByte; j++ { - trit := uint(src[j]) - if trit > 1 { - return i, fmt.Errorf("%w: %d", ErrInvalidTrit, src[j]) - } - b |= byte(trit << j) - } - dst[i] = b - src = src[tritsPerByte:] - i++ - } - if len(src) > 0 { - // Check for invalid char before reporting bad length, - // since the invalid trit (if present) is an earlier problem. - for _, t := range src { - if byte(t) > 1 { - return i, fmt.Errorf("%w: %d", ErrInvalidTrit, t) - } - } - return i, ErrInvalidLength - } - return i, nil -} diff --git a/pkg/encoding/b1t8/b1t8_test.go b/pkg/encoding/b1t8/b1t8_test.go deleted file mode 100644 index 3666390..0000000 --- a/pkg/encoding/b1t8/b1t8_test.go +++ /dev/null @@ -1,112 +0,0 @@ -package b1t8 - -import ( - "errors" - "fmt" - "math/rand" - "testing" - - "github.com/iotaledger/iota.go/trinary" - "github.com/stretchr/testify/assert" -) - -var encDecTests = []*struct { - bytes []byte - trits trinary.Trits -}{ - {[]byte{}, []int8{}}, - {[]byte{0x00}, []int8{0, 0, 0, 0, 0, 0, 0, 0}}, - {[]byte{0x01}, []int8{1, 0, 0, 0, 0, 0, 0, 0}}, - {[]byte{0x80}, []int8{0, 0, 0, 0, 0, 0, 0, 1}}, - {[]byte{0xaa}, []int8{0, 1, 0, 1, 0, 1, 0, 1}}, - {[]byte{0x55}, []int8{1, 0, 1, 0, 1, 0, 1, 0}}, - {[]byte{0xff}, []int8{1, 1, 1, 1, 1, 1, 1, 1}}, - {[]byte{0x00, 0x01}, []int8{0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}}, // endianness -} - -func TestEncode(t *testing.T) { - for _, tt := range encDecTests { - t.Run(fmt.Sprintf("%x", tt.bytes), func(t *testing.T) { - dst := make(trinary.Trits, EncodedLen(len(tt.bytes))) - n := Encode(dst, tt.bytes) - assert.Equal(t, EncodedLen(len(tt.bytes)), n) - assert.Equal(t, tt.trits, dst) - }) - } -} - -func TestDecode(t *testing.T) { - for _, tt := range encDecTests { - t.Run(fmt.Sprint(tt.trits), func(t *testing.T) { - dst := make([]byte, DecodedLen(len(tt.trits))) - n, err := Decode(dst, tt.trits) - if assert.NoError(t, err) { - assert.Equal(t, DecodedLen(len(tt.trits)), n) - assert.Equal(t, tt.bytes, dst) - } - }) - } -} - -func TestDecodeErr(t *testing.T) { - var tests = []*struct { - src trinary.Trits - dst []byte - err error - }{ - {trinary.Trits{0, 0, 0, 0, 0, 0, 0}, []byte{}, ErrInvalidLength}, - {trinary.Trits{1, 0, 0}, []byte{}, ErrInvalidLength}, - {trinary.Trits{1, 0, 0, 0, 0, 0, 0, 0, 0}, []byte{1}, ErrInvalidLength}, - {trinary.Trits{-1, 0, 0, 0, 0, 0, 0, 0}, []byte{}, ErrInvalidTrit}, - {trinary.Trits{-1, 0, 0, 0, 0, 0, 0, 0}, []byte{}, ErrInvalidTrit}, - {trinary.Trits{1, 1, 1, 1, 1, 1, 1, 1, -1}, []byte{0xff}, ErrInvalidTrit}, - {trinary.Trits{0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, -1}, []byte{0, 1}, ErrInvalidTrit}, - } - - for _, tt := range tests { - t.Run(fmt.Sprint(tt.src), func(t *testing.T) { - dst := make([]byte, DecodedLen(len(tt.src))) - n, err := Decode(dst, tt.src) - assert.Truef(t, errors.Is(err, tt.err), "unexpected error: %v", err) - assert.Equal(t, tt.dst, dst[:n]) - }) - } -} - -var ( - benchBytesLen = 1000 - benchTritsLen = EncodedLen(benchBytesLen) -) - -func BenchmarkEncode(b *testing.B) { - data := make([][]byte, b.N) - for i := range data { - data[i] = randomBytes(benchBytesLen) - } - b.ResetTimer() - - dst := make(trinary.Trits, benchTritsLen) - for i := range data { - _ = Encode(dst, data[i]) - } -} - -func BenchmarkDecode(b *testing.B) { - data := make([]trinary.Trits, b.N) - for i := range data { - data[i] = make(trinary.Trits, benchTritsLen) - Encode(data[i], randomBytes(benchBytesLen)) - } - b.ResetTimer() - - dst := make([]byte, benchBytesLen) - for i := range data { - _, _ = Decode(dst, data[i]) - } -} - -func randomBytes(n int) []byte { - result := make([]byte, n) - rand.Read(result) - return result -} diff --git a/pkg/migration/migration.go b/pkg/migration/migration.go deleted file mode 100644 index a36f27c..0000000 --- a/pkg/migration/migration.go +++ /dev/null @@ -1,55 +0,0 @@ -package migration - -import ( - "bytes" - "fmt" - "strings" - - "github.com/iotaledger/iota.go/consts" - "github.com/iotaledger/iota.go/encoding/b1t6" - "github.com/iotaledger/iota.go/guards" - "github.com/iotaledger/iota.go/trinary" - "golang.org/x/crypto/blake2b" -) - -const ( - Ed25519AddressSize = blake2b.Size256 - ChecksumSize = 4 - Prefix = trinary.Trytes("TRANSFER") - Suffix = "9" -) - -func Encode(addr [Ed25519AddressSize]byte) trinary.Trytes { - hash := blake2b.Sum256(addr[:]) - return Prefix + b1t6.EncodeToTrytes(append(addr[:], hash[:ChecksumSize]...)) + Suffix -} - -func Decode(trytes trinary.Hash) (addr [Ed25519AddressSize]byte, err error) { - if !guards.IsTrytesOfExactLength(trytes, consts.HashTrytesSize) { - return addr, consts.ErrInvalidTrytesLength - } - if !strings.HasPrefix(trytes, Prefix) { - return addr, fmt.Errorf("expected prefix '%s'", Prefix) - } - trytes = strings.TrimPrefix(trytes, Prefix) - if !strings.HasSuffix(trytes, Suffix) { - return addr, fmt.Errorf("expected suffix '%s'", Suffix) - } - trytes = strings.TrimSuffix(trytes, Suffix) - - addrTrytesLen := b1t6.EncodedLen(Ed25519AddressSize) / consts.TritsPerTryte - addrBytes, err := b1t6.DecodeTrytes(trytes[:addrTrytesLen]) - if err != nil { - return addr, fmt.Errorf("invalid address encoding: %w", err) - } - checksumBytes, err := b1t6.DecodeTrytes(trytes[addrTrytesLen:]) - if err != nil { - return addr, fmt.Errorf("invalid checksum encoding: %w", err) - } - hash := blake2b.Sum256(addrBytes) - if !bytes.Equal(checksumBytes, hash[:len(checksumBytes)]) { - return addr, consts.ErrInvalidChecksum - } - copy(addr[:], addrBytes) - return addr, nil -} diff --git a/pkg/migration/migration_test.go b/pkg/migration/migration_test.go deleted file mode 100644 index 0aa94c7..0000000 --- a/pkg/migration/migration_test.go +++ /dev/null @@ -1,19 +0,0 @@ -package migration - -import ( - "math/rand" - "testing" - - "github.com/stretchr/testify/require" -) - -func TestEncodeDecode(t *testing.T) { - var expected [Ed25519AddressSize]byte - for i := 0; i < 1000; i++ { - rand.Read(expected[:]) - trytes := Encode(expected) - address, err := Decode(trytes) - require.NoError(t, err) - require.Equal(t, expected, address) - } -} diff --git a/pkg/pow/pow.go b/pkg/pow/pow.go deleted file mode 100644 index 0766172..0000000 --- a/pkg/pow/pow.go +++ /dev/null @@ -1,63 +0,0 @@ -// Package pow implements the Curl-based proof of work for arbitrary binary data. -package pow - -import ( - "crypto" - "encoding/binary" - "math" - - "github.com/iotaledger/iota.go/consts" - "github.com/iotaledger/iota.go/curl" - "github.com/iotaledger/iota.go/encoding/b1t6" - "github.com/iotaledger/iota.go/trinary" - _ "golang.org/x/crypto/blake2b" // BLAKE2b_256 is the default hash function for the PoW digest -) - -// Hash defines the hash function that is used to compute the PoW digest. -var Hash = crypto.BLAKE2b_256 - -const ( - nonceBytes = 8 // len(uint64) -) - -// Score returns the PoW score of msg. -func Score(msg []byte) float64 { - if len(msg) < nonceBytes { - panic("pow: invalid message length") - } - - h := Hash.New() - dataLen := len(msg) - nonceBytes - // the PoW digest is the hash of msg without the nonce - h.Write(msg[:dataLen]) - powDigest := h.Sum(nil) - - // extract the nonce from msg and compute the number of trailing zeros - nonce := binary.LittleEndian.Uint64(msg[dataLen:]) - zeros := trailingZeros(powDigest, nonce) - - // compute the score - return math.Pow(consts.TrinaryRadix, float64(zeros)) / float64(len(msg)) -} - -func trailingZeros(powDigest []byte, nonce uint64) int { - // allocate exactly one Curl block - buf := make(trinary.Trits, consts.HashTrinarySize) - n := b1t6.Encode(buf, powDigest) - // add the nonce to the trit buffer - encodeNonce(buf[n:], nonce) - - c := curl.NewCurlP81() - if err := c.Absorb(buf); err != nil { - panic(err) - } - digest, _ := c.Squeeze(consts.HashTrinarySize) - return trinary.TrailingZeros(digest) -} - -// encodeNonce encodes nonce as 48 trits using the b1t6 encoding. -func encodeNonce(dst trinary.Trits, nonce uint64) { - var nonceBuf [nonceBytes]byte - binary.LittleEndian.PutUint64(nonceBuf[:], nonce) - b1t6.Encode(dst, nonceBuf[:]) -} diff --git a/pkg/pow/pow_test.go b/pkg/pow/pow_test.go deleted file mode 100644 index d982bd6..0000000 --- a/pkg/pow/pow_test.go +++ /dev/null @@ -1,103 +0,0 @@ -package pow - -import ( - "context" - "encoding/binary" - "math" - "math/rand" - "sync" - "sync/atomic" - "testing" - "time" - - "github.com/iotaledger/iota.go/consts" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "golang.org/x/crypto/blake2b" -) - -const ( - workers = 2 - targetScore = 4000. -) - -var testWorker = New(workers) - -func TestScore(t *testing.T) { - tests := []*struct { - msg []byte - expPoW float64 - }{ - {msg: []byte{0, 0, 0, 0, 0, 0, 0, 0}, expPoW: math.Pow(3, 1) / 8}, - {msg: []byte{203, 124, 2, 0, 0, 0, 0, 0}, expPoW: math.Pow(3, 10) / 8}, - {msg: []byte{65, 235, 119, 85, 85, 85, 85, 85}, expPoW: math.Pow(3, 14) / 8}, - {msg: make([]byte, 10000), expPoW: math.Pow(3, 0) / 10000}, - } - - for _, tt := range tests { - pow := Score(tt.msg) - assert.Equal(t, tt.expPoW, pow) - } -} - -func TestWorker_Mine(t *testing.T) { - msg := append([]byte("Hello, World!"), make([]byte, nonceBytes)...) - nonce, err := testWorker.Mine(context.Background(), msg[:len(msg)-nonceBytes], targetScore) - require.NoError(t, err) - - // add nonce to message and check the resulting PoW score - binary.LittleEndian.PutUint64(msg[len(msg)-nonceBytes:], nonce) - pow := Score(msg) - assert.GreaterOrEqual(t, pow, targetScore) -} - -func TestWorker_Cancel(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - var err error - go func() { - _, err = testWorker.Mine(ctx, nil, math.MaxInt32) - }() - time.Sleep(10 * time.Millisecond) - cancel() - - assert.Eventually(t, func() bool { return err == ErrCancelled }, time.Second, 10*time.Millisecond) -} - -const benchBytesLen = 1600 - -func BenchmarkScore(b *testing.B) { - data := make([][]byte, b.N) - for i := range data { - data[i] = make([]byte, benchBytesLen) - if _, err := rand.Read(data[i]); err != nil { - b.Fatal(err) - } - } - b.ResetTimer() - - for i := range data { - _ = Score(data[i]) - } -} - -func BenchmarkWorker(b *testing.B) { - var ( - wg sync.WaitGroup - w = New(1) - digest = blake2b.Sum256(nil) - done uint32 - counter uint64 - ) - wg.Add(1) - go func() { - defer wg.Done() - _, _ = w.worker(digest[:], 0, consts.HashTrinarySize, &done, &counter) - }() - b.ResetTimer() - for atomic.LoadUint64(&counter) < uint64(b.N) { - } - atomic.StoreUint32(&done, 1) - wg.Wait() -} diff --git a/pkg/pow/v2/pow.go b/pkg/pow/v2/pow.go deleted file mode 100644 index 64040f6..0000000 --- a/pkg/pow/v2/pow.go +++ /dev/null @@ -1,119 +0,0 @@ -package v2 - -import ( - "encoding/binary" - "math" - "math/big" - - "golang.org/x/crypto/blake2b" - - "github.com/iotaledger/iota.go/consts" - "github.com/iotaledger/iota.go/curl" - "github.com/iotaledger/iota.go/encoding/b1t6" - "github.com/iotaledger/iota.go/trinary" - - _ "golang.org/x/crypto/blake2b" // BLAKE2b_256 is the default hash function for the PoW digest -) - -const ( - nonceBytes = 8 // len(uint64) - tritsPerUint64 = 40 // largest x s.t. 3^x <= maxUint64 -) - -var ( - // largest possible integer representation of a Curl hash, i.e. 3^243 - maxHash = hexToInt("2367b879df2fe073dfc27f021fbc70343b4661546d9dcaa0de38db00a48d9b295613405167b19e1ddba02c679e2d7385b") - // largest power of 3 fitting in an uint64, i.e. 3^tritsPerUint64 = 3^40 - uint64Radix = new(big.Int).SetUint64(12157665459056928801) - one = new(big.Int).SetUint64(1) -) - -func hexToInt(s string) *big.Int { - b, _ := new(big.Int).SetString(s, 16) - return b -} - -// Score returns the PoW score of msg. -func Score(msg []byte) uint64 { - if len(msg) < nonceBytes { - panic("pow: invalid message length") - } - - dataLen := len(msg) - nonceBytes - // the PoW digest is the hash of msg without the nonce - powDigest := blake2b.Sum256(msg[:dataLen]) - - // extract the nonce from msg and compute the number of trailing zeros - nonce := binary.LittleEndian.Uint64(msg[dataLen:]) - d := difficulty(powDigest[:], nonce) - - // the score is the difficulty per bytes, so we need to divide by the message length - if d.IsUint64() { - return d.Uint64() / uint64(len(msg)) - } - // try big.Int division - d.Quo(d, big.NewInt(int64(len(msg)))) - if d.IsUint64() { - return d.Uint64() - } - // otherwise return the largest possible score - return math.MaxUint64 -} - -func difficulty(powDigest []byte, nonce uint64) *big.Int { - // allocate exactly one Curl block - buf := make(trinary.Trits, consts.HashTrinarySize) - n := b1t6.Encode(buf, powDigest) - // add the nonce to the trit buffer - encodeNonce(buf[n:], nonce) - - c := curl.NewCurlP81() - if err := c.Absorb(buf); err != nil { - panic(err) - } - digest, _ := c.Squeeze(consts.HashTrinarySize) - - h := toInt(digest) - return h.Quo(maxHash, h) -} - -// encodeNonce encodes nonce as 48 trits using the b1t6 encoding. -func encodeNonce(dst trinary.Trits, nonce uint64) { - var nonceBuf [nonceBytes]byte - binary.LittleEndian.PutUint64(nonceBuf[:], nonce) - b1t6.Encode(dst, nonceBuf[:]) -} - -// toInt converts the little-endian trinary hash into a positive integer. -// It returns t[242]*3^242 + ... + t[0]*3^0 + 1, where t[i] = { 2 if trits[i] = -1, trits[i] otherwise }. -func toInt(trits trinary.Trits) *big.Int { - if len(trits) != consts.HashTrinarySize { - panic("pow: invalid hash") - } - - const n = consts.HashTrinarySize - b := new(big.Int).SetUint64(tritToUint(trits[n-1])*9 + tritToUint(trits[n-2])*3 + tritToUint(trits[n-3])) - - // process as uint64 chunks to avoid costly bigint multiplication - tmp := new(big.Int) - for i := consts.HashTrinarySize/tritsPerUint64 - 1; i >= 0; i-- { - chunk := trits[i*tritsPerUint64 : i*tritsPerUint64+tritsPerUint64] - - var v uint64 - for j := len(chunk) - 1; j >= 0; j-- { - v = v*3 + tritToUint(chunk[j]) - } - if i == 0 { - v++ - } - b.Add(b.Mul(b, uint64Radix), tmp.SetUint64(v)) - } - return b -} - -func tritToUint(t int8) uint64 { - if t == -1 { - return 2 - } - return uint64(t) -} diff --git a/pkg/pow/v2/pow_test.go b/pkg/pow/v2/pow_test.go deleted file mode 100644 index 631f761..0000000 --- a/pkg/pow/v2/pow_test.go +++ /dev/null @@ -1,113 +0,0 @@ -package v2 - -import ( - "context" - "encoding/binary" - "math" - "math/big" - "math/rand" - "strings" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/iotaledger/iota.go/consts" - "github.com/iotaledger/iota.go/trinary" -) - -const ( - workers = 2 - targetScore uint64 = 4000 -) - -var testWorker = New(workers) - -func TestWorker_Mine(t *testing.T) { - msg := append([]byte("Hello, World!"), make([]byte, nonceBytes)...) - nonce, err := testWorker.Mine(context.Background(), msg[:len(msg)-nonceBytes], targetScore) - require.NoError(t, err) - - // add nonce to message and check the resulting PoW score - binary.LittleEndian.PutUint64(msg[len(msg)-nonceBytes:], nonce) - score := Score(msg) - assert.GreaterOrEqual(t, score, targetScore) - t.Log(nonce, score) -} - -func TestToInt(t *testing.T) { - require.Zero(t, toInt(make(trinary.Trits, consts.HashTrinarySize)).Cmp(one)) - require.Zero(t, toInt(largest(0)).Cmp(maxHash)) -} - -func TestSufficientTrailingZeros(t *testing.T) { - const dataLen = 9 - for score := uint64(1); score <= math.MaxUint64/dataLen; score *= 3 { - // the largest possible hash should be feasible - s := sufficientTrailingZeros(make([]byte, dataLen-nonceBytes), score) - largestDifficulty := new(big.Int).Quo(maxHash, toInt(largest(s))).Uint64() - require.GreaterOrEqual(t, largestDifficulty, dataLen*score) - - // the smallest possible hash should be infeasible - r := s - 1 - smallestDifficulty := new(big.Int).Quo(maxHash, toInt(smallest(r))).Uint64() - require.Less(t, smallestDifficulty, dataLen*score) - } -} - -func smallest(trailing int) trinary.Trits { - trits := make(trinary.Trits, consts.HashTrinarySize) - trits[consts.HashTrinarySize-(trailing+1)] = 1 - return trits -} - -func largest(trailing int) trinary.Trits { - trits := make(trinary.Trits, consts.HashTrinarySize) - for i := 0; i < consts.HashTrinarySize-trailing; i++ { - trits[i] = -1 - } - return trits -} - -func BenchmarkTritsToInt(b *testing.B) { - src := make([]trinary.Trits, b.N) - for i := range src { - src[i] = randomTrits(consts.HashTrinarySize) - } - b.ResetTimer() - - for i := range src { - _ = toInt(src[i]) - } -} - -const benchBytesLen = 1600 - -func BenchmarkScore(b *testing.B) { - data := make([][]byte, b.N) - for i := range data { - data[i] = make([]byte, benchBytesLen) - if _, err := rand.Read(data[i]); err != nil { - b.Fatal(err) - } - } - b.ResetTimer() - - for i := range data { - _ = Score(data[i]) - } -} - -func randomTrits(n int) trinary.Trits { - trytes := randomTrytes((n + 2) / 3) - return trinary.MustTrytesToTrits(trytes)[:n] -} - -func randomTrytes(n int) trinary.Trytes { - var result strings.Builder - result.Grow(n) - for i := 0; i < n; i++ { - result.WriteByte(consts.TryteAlphabet[rand.Intn(len(consts.TryteAlphabet))]) - } - return result.String() -} diff --git a/pkg/pow/v2/worker.go b/pkg/pow/v2/worker.go deleted file mode 100644 index f2d5664..0000000 --- a/pkg/pow/v2/worker.go +++ /dev/null @@ -1,216 +0,0 @@ -package v2 - -import ( - "context" - "errors" - "math" - "math/big" - "math/bits" - "sync" - "sync/atomic" - - "golang.org/x/crypto/blake2b" - - "github.com/iotaledger/iota.go/consts" - "github.com/iotaledger/iota.go/curl/bct" - "github.com/iotaledger/iota.go/encoding/b1t6" - "github.com/iotaledger/iota.go/trinary" -) - -// errors returned by the PoW -var ( - ErrCancelled = errors.New("canceled") - ErrDone = errors.New("done") -) - -// The Worker performs the PoW. -type Worker struct { - numWorkers int -} - -// New creates a new PoW Worker. -// The optional numWorkers specifies how many go routines should be used to perform the PoW. -func New(numWorkers ...int) *Worker { - w := &Worker{ - numWorkers: 1, - } - if len(numWorkers) > 0 && numWorkers[0] > 0 { - w.numWorkers = numWorkers[0] - } - return w -} - -// Mine performs the PoW for data. -// It returns a nonce that appended to data results in a PoW score of at least targetScore. -// The computation can be canceled anytime using ctx. -func (w *Worker) Mine(ctx context.Context, data []byte, targetScore uint64) (uint64, error) { - // for the zero target score, the solution is trivial - if targetScore == 0 { - return 0, nil - } - - var ( - done uint32 - counter uint64 - wg sync.WaitGroup - results = make(chan uint64, w.numWorkers) - closing = make(chan struct{}) - ) - - // compute the digest - powDigest := blake2b.Sum256(data) - - // stop when the context has been canceled - go func() { - select { - case <-ctx.Done(): - atomic.StoreUint32(&done, 1) - case <-closing: - return - } - }() - - sufficientTrailing := sufficientTrailingZeros(data, targetScore) - target := targetHash(data, targetScore) - - workerWidth := math.MaxUint64 / uint64(w.numWorkers) - for i := 0; i < w.numWorkers; i++ { - startNonce := uint64(i) * workerWidth - wg.Add(1) - go func() { - defer wg.Done() - - nonce, workerErr := w.worker(powDigest[:], startNonce, sufficientTrailing, target, &done, &counter) - if workerErr != nil { - return - } - atomic.StoreUint32(&done, 1) - results <- nonce - }() - } - wg.Wait() - close(results) - close(closing) - - nonce, ok := <-results - if !ok { - return 0, ErrCancelled - } - return nonce, nil -} - -// sufficientTrailingZeros returns 𝑠 s.t. any hash with 𝑠 trailing zeroes is feasible, i.e. smallest 𝑠 with 3^𝑠 ≥ 𝑙·𝑥. -// It panics when 𝑙·𝑥 overflows an uint64. -// It is sufficient to show that the largest (worst) hash h with 𝑠 trailing zeroes is feasible i.e. ⌊ maxHash / h ⌋ ≥ 𝑙·𝑥 -// ⌊ maxHash / h ⌋ ≥ ⌊ 3^243 / 3^(243 - 𝑠) ⌋ = ⌊ 3^𝑠 ⌋ = 3^𝑠 ≥ 𝑙·𝑥 -func sufficientTrailingZeros(data []byte, targetScore uint64) int { - // assure that (len(data)+nonceBytes) * targetScore <= MaxUint64 - if (math.MaxUint64-1)/(uint64(len(data)+nonceBytes))+1 < targetScore { - panic("pow: invalid target score") - } - lx := uint64(len(data)+nonceBytes) * targetScore - - // in order to prevent floating point rounding errors, compute the exact integer logarithm - for s, v := 0, uint64(1); s <= tritsPerUint64; s++ { - if v >= lx { - return s - } - v *= 3 - } - return tritsPerUint64 + 1 -} - -// targetHash returns 𝑡 s.t. any hash with h ≤ 𝑡 is feasible, i.e. h = ⌊ maxHash / (𝑙·𝑥 + 1) ⌋. -// It panics when 𝑙·𝑥 overflows an uint64. -// It is sufficient to show that for the hash h with h = ⌊ maxHash / (𝑙·𝑥 + 1) ⌋, ⌊ maxHash / h ⌋ ≥ 𝑙·𝑥 always holds: -// h = ⌊ maxHash / (𝑙·𝑥 + 1) ⌋ ≤ maxHash / (𝑙·𝑥 + 1) ⇔ 𝑙·𝑥 + 1 ≤ maxHash / h ⇔ 𝑙·𝑥 ≤ maxHash / h - 1 ⇔ 𝑙·𝑥 < ⌊ maxHash / h ⌋ -func targetHash(data []byte, targetScore uint64) *big.Int { - // return ⌊ maxHash / (𝑙·𝑥 + 1) ⌋ - z := new(big.Int).SetUint64(targetScore) - z.Mul(z, big.NewInt(int64(len(data)+nonceBytes))) - z.Add(z, one) - return z.Quo(maxHash, z) -} - -func (w *Worker) worker(powDigest []byte, startNonce uint64, sufficientTrailing int, target *big.Int, done *uint32, counter *uint64) (uint64, error) { - if sufficientTrailing > consts.HashTrinarySize { - panic("pow: invalid trailing zeros target") - } - - // use batched Curl hashing - c := bct.NewCurlP81() - var l, h [consts.HashTrinarySize]uint - - // allocate exactly one Curl block for each batch index and fill it with the encoded digest - buf := make([]trinary.Trits, bct.MaxBatchSize) - for i := range buf { - buf[i] = make(trinary.Trits, consts.HashTrinarySize) - b1t6.Encode(buf[i], powDigest) - } - - digestTritsLen := b1t6.EncodedLen(len(powDigest)) - for nonce := startNonce; atomic.LoadUint32(done) == 0; nonce += bct.MaxBatchSize { - // add the nonce to each trit buffer - for i := range buf { - nonceBuf := buf[i][digestTritsLen:] - encodeNonce(nonceBuf, nonce+uint64(i)) - } - - // process the batch - c.Reset() - if err := c.Absorb(buf, consts.HashTrinarySize); err != nil { - return 0, err - } - c.CopyState(l[:], h[:]) // the first 243 entries of the state correspond to the resulting hashes - atomic.AddUint64(counter, bct.MaxBatchSize) - - // check the state whether it corresponds to a hash with sufficient amount of trailing zeros - // this is equivalent to computing the hashes with Squeeze and then checking TrailingZeros of each - if i := checkStateTrits(&l, &h, sufficientTrailing, target); i < bct.MaxBatchSize { - // if i := checkStateTrits2(&l, &h, target); i < bct.MaxBatchSize { - return nonce + uint64(i), nil - } - } - return 0, ErrDone -} - -func checkStateTrits(l, h *[consts.HashTrinarySize]uint, sufficientTrailing int, target *big.Int) int { - var v uint - - requiredTrailing := sufficientTrailing - 1 - for i := consts.HashTrinarySize - requiredTrailing; i < consts.HashTrinarySize; i++ { - v |= l[i] ^ h[i] // 0 if trit is zero, 1 otherwise - } - // no hash has at least sufficientTrailing number of trailing zeroes - if v == ^uint(0) { - // there cannot be a valid hash - return bct.MaxBatchSize - } - - // find hashes with at least sufficientTrailing+1 number of trailing zeroes - w := v | (l[consts.HashTrinarySize-sufficientTrailing] ^ h[consts.HashTrinarySize-sufficientTrailing]) - // if there is one this is sufficient, and we can return the index - if w != ^uint(0) { - // return the index of the first zero bit, this corresponds to the hash with sufficient trailing zeros - return bits.TrailingZeros(^w) - } - - // otherwise, we have to convert all hashes with at least sufficientTrailing number of trailing zeroes and check - lo, hi := bits.TrailingZeros(^v), bits.Len(^v) - for i := lo; i < hi; i++ { - if (v>>i)&1 == 0 && stateToInt(l, h, uint(i)).Cmp(target) <= 0 { - return i - } - } - return bct.MaxBatchSize -} - -func stateToInt(l, h *[consts.HashTrinarySize]uint, idx uint) *big.Int { - idx &= bits.UintSize - 1 // hint to the compiler that shifts don't need guard code - - var trits [consts.HashTrinarySize]int8 - for j := consts.HashTrinarySize - 1; j >= 0; j-- { - trits[j] = int8((h[j]>>idx)&1) - int8((l[j]>>idx)&1) - } - return toInt(trits[:]) -} diff --git a/pkg/pow/worker.go b/pkg/pow/worker.go deleted file mode 100644 index 33964c9..0000000 --- a/pkg/pow/worker.go +++ /dev/null @@ -1,146 +0,0 @@ -package pow - -import ( - "context" - "errors" - "math" - "math/bits" - "sync" - "sync/atomic" - - "github.com/iotaledger/iota.go/consts" - "github.com/iotaledger/iota.go/curl/bct" - "github.com/iotaledger/iota.go/encoding/b1t6" - "github.com/iotaledger/iota.go/trinary" -) - -// errors returned by the PoW -var ( - ErrCancelled = errors.New("canceled") - ErrDone = errors.New("done") -) - -// The Worker performs the PoW. -type Worker struct { - numWorkers int -} - -// New creates a new PoW Worker. -// The optional numWorkers specifies how many go routines should be used to perform the PoW. -func New(numWorkers ...int) *Worker { - w := &Worker{ - numWorkers: 1, - } - if len(numWorkers) > 0 && numWorkers[0] > 0 { - w.numWorkers = numWorkers[0] - } - return w -} - -const ln3 = 1.098612288668109691395245236922525704647490557822749451734694333 // https://oeis.org/A002391 - -// Mine performs the PoW for data. -// It returns a nonce that appended to data results in a PoW score of at least targetScore. -// The computation can be canceled anytime using ctx. -func (w *Worker) Mine(ctx context.Context, data []byte, targetScore float64) (uint64, error) { - var ( - done uint32 - counter uint64 - wg sync.WaitGroup - results = make(chan uint64, w.numWorkers) - closing = make(chan struct{}) - ) - - // compute the digest - h := Hash.New() - h.Write(data) - powDigest := h.Sum(nil) - - // stop when the context has been canceled - go func() { - select { - case <-ctx.Done(): - atomic.StoreUint32(&done, 1) - case <-closing: - return - } - }() - - // compute the minimum numbers of trailing zeros required to get a PoW score ≥ targetScore - targetZeros := uint(math.Ceil(math.Log(float64(len(data)+nonceBytes)*targetScore) / ln3)) - - workerWidth := math.MaxUint64 / uint64(w.numWorkers) - for i := 0; i < w.numWorkers; i++ { - startNonce := uint64(i) * workerWidth - wg.Add(1) - go func() { - defer wg.Done() - - nonce, workerErr := w.worker(powDigest, startNonce, targetZeros, &done, &counter) - if workerErr != nil { - return - } - atomic.StoreUint32(&done, 1) - results <- nonce - }() - } - wg.Wait() - close(results) - close(closing) - - nonce, ok := <-results - if !ok { - return 0, ErrCancelled - } - return nonce, nil -} - -func (w *Worker) worker(powDigest []byte, startNonce uint64, target uint, done *uint32, counter *uint64) (uint64, error) { - if target > consts.HashTrinarySize { - panic("pow: invalid trailing zeros target") - } - - // use batched Curl hashing - c := bct.NewCurlP81() - var l, h [consts.HashTrinarySize]uint - - // allocate exactly one Curl block for each batch index and fill it with the encoded digest - buf := make([]trinary.Trits, bct.MaxBatchSize) - for i := range buf { - buf[i] = make(trinary.Trits, consts.HashTrinarySize) - b1t6.Encode(buf[i], powDigest) - } - - digestTritsLen := b1t6.EncodedLen(len(powDigest)) - for nonce := startNonce; atomic.LoadUint32(done) == 0; nonce += bct.MaxBatchSize { - // add the nonce to each trit buffer - for i := range buf { - nonceBuf := buf[i][digestTritsLen:] - encodeNonce(nonceBuf, nonce+uint64(i)) - } - - // process the batch - c.Reset() - if err := c.Absorb(buf, consts.HashTrinarySize); err != nil { - return 0, err - } - c.CopyState(l[:], h[:]) // the first 243 entries of the state correspond to the resulting hashes - atomic.AddUint64(counter, bct.MaxBatchSize) - - // check the state whether it corresponds to a hash with sufficient amount of trailing zeros - // this is equivalent to computing the hashes with Squeeze and then checking TrailingZeros of each - if i := checkStateTrits(&l, &h, target); i < bct.MaxBatchSize { - return nonce + uint64(i), nil - } - } - return 0, ErrDone -} - -func checkStateTrits(l, h *[consts.HashTrinarySize]uint, n uint) int { - var v uint - for i := consts.HashTrinarySize - n; i < consts.HashTrinarySize; i++ { - v |= l[i] ^ h[i] // 0 if trit is zero, 1 otherwise - } - // return the index of the first zero bit, this corresponds to the index of the hash with n trailing zero trits - return bits.TrailingZeros(^v) -} diff --git a/pkg/slip10/eddsa/ed25519.go b/pkg/slip10/eddsa/ed25519.go index 1784d29..a6e9f50 100644 --- a/pkg/slip10/eddsa/ed25519.go +++ b/pkg/slip10/eddsa/ed25519.go @@ -3,8 +3,8 @@ package eddsa import ( "errors" - "github.com/wollac/iota-crypto-demo/pkg/ed25519" - "github.com/wollac/iota-crypto-demo/pkg/slip10" + "github.com/iotaledger/iota-crypto-demo/pkg/ed25519" + "github.com/iotaledger/iota-crypto-demo/pkg/slip10" ) // ErrNotHardened is returned when the input led to an invalid private or public key. diff --git a/pkg/slip10/elliptic/curve.go b/pkg/slip10/elliptic/curve.go index 1c7d8ed..6e2b414 100644 --- a/pkg/slip10/elliptic/curve.go +++ b/pkg/slip10/elliptic/curve.go @@ -4,8 +4,8 @@ import ( "crypto/elliptic" "math/big" - "github.com/wollac/iota-crypto-demo/pkg/slip10" - "github.com/wollac/iota-crypto-demo/pkg/slip10/elliptic/internal/btccurve" + "github.com/iotaledger/iota-crypto-demo/pkg/slip10" + "github.com/iotaledger/iota-crypto-demo/pkg/slip10/elliptic/internal/btccurve" ) // Curve is an abstract implementation of slip10.Curve based on elliptic.Curve. diff --git a/pkg/slip10/elliptic/key.go b/pkg/slip10/elliptic/key.go index b7fd3ab..a65bc34 100644 --- a/pkg/slip10/elliptic/key.go +++ b/pkg/slip10/elliptic/key.go @@ -6,7 +6,7 @@ import ( "fmt" "math/big" - "github.com/wollac/iota-crypto-demo/pkg/slip10" + "github.com/iotaledger/iota-crypto-demo/pkg/slip10" ) // PrivateKey implements slip10.Key and represents a private key for elliptic.Curve. diff --git a/pkg/slip10/slip10_test.go b/pkg/slip10/slip10_test.go index b326490..3feffa6 100644 --- a/pkg/slip10/slip10_test.go +++ b/pkg/slip10/slip10_test.go @@ -11,14 +11,14 @@ import ( "strings" "testing" + "github.com/iotaledger/iota-crypto-demo/internal/hexutil" + "github.com/iotaledger/iota-crypto-demo/pkg/bip32path" + "github.com/iotaledger/iota-crypto-demo/pkg/ed25519" + "github.com/iotaledger/iota-crypto-demo/pkg/slip10" + "github.com/iotaledger/iota-crypto-demo/pkg/slip10/eddsa" + "github.com/iotaledger/iota-crypto-demo/pkg/slip10/elliptic" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/wollac/iota-crypto-demo/internal/hexutil" - "github.com/wollac/iota-crypto-demo/pkg/bip32path" - "github.com/wollac/iota-crypto-demo/pkg/ed25519" - "github.com/wollac/iota-crypto-demo/pkg/slip10" - "github.com/wollac/iota-crypto-demo/pkg/slip10/eddsa" - "github.com/wollac/iota-crypto-demo/pkg/slip10/elliptic" ) type Test struct { diff --git a/pkg/vrf/canonical_test.go b/pkg/vrf/canonical_test.go index af06c24..8a277c5 100644 --- a/pkg/vrf/canonical_test.go +++ b/pkg/vrf/canonical_test.go @@ -4,8 +4,8 @@ import ( "math/rand" "testing" + "github.com/iotaledger/iota-crypto-demo/internal/hexutil" "github.com/stretchr/testify/require" - "github.com/wollac/iota-crypto-demo/internal/hexutil" ) func TestNewPointFromCanonicalBytes(t *testing.T) { diff --git a/pkg/vrf/vrf.go b/pkg/vrf/vrf.go index 5ac5342..f5b0944 100644 --- a/pkg/vrf/vrf.go +++ b/pkg/vrf/vrf.go @@ -7,7 +7,7 @@ import ( "strconv" "filippo.io/edwards25519" - "github.com/wollac/iota-crypto-demo/pkg/ed25519" + "github.com/iotaledger/iota-crypto-demo/pkg/ed25519" ) const ( diff --git a/pkg/vrf/vrf_test.go b/pkg/vrf/vrf_test.go index 5e56dc6..caf1b9d 100644 --- a/pkg/vrf/vrf_test.go +++ b/pkg/vrf/vrf_test.go @@ -8,8 +8,8 @@ import ( "path/filepath" "testing" + "github.com/iotaledger/iota-crypto-demo/internal/hexutil" "github.com/stretchr/testify/require" - "github.com/wollac/iota-crypto-demo/internal/hexutil" ) var nullSeed = make([]byte, SeedSize)