cardano-crypto (empty) → 1.3.0
raw patch · 57 files changed
+11232/−0 lines, 57 filesdep +basedep +basementdep +bytestringsetup-changed
Dependencies added: base, basement, bytestring, cardano-crypto, crypton, deepseq, foundation, gauge, hashable, inspector, integer-gmp, memory
Files
- CHANGELOG.md +3/−0
- LICENSE +19/−0
- README.md +6/−0
- Setup.hs +2/−0
- benchs/Bench.hs +45/−0
- cardano-crypto.cabal +144/−0
- cbits/crypton_pbkdf2.h +31/−0
- cbits/crypton_sha512.h +59/−0
- cbits/ed25519/curve25519-donna-32bit.h +579/−0
- cbits/ed25519/curve25519-donna-64bit.h +413/−0
- cbits/ed25519/curve25519-donna-helpers.h +67/−0
- cbits/ed25519/ed25519-donna-32bit-sse2.h +513/−0
- cbits/ed25519/ed25519-donna-32bit-tables.h +61/−0
- cbits/ed25519/ed25519-donna-64bit-tables.h +53/−0
- cbits/ed25519/ed25519-donna-64bit-x86-32bit.h +435/−0
- cbits/ed25519/ed25519-donna-64bit-x86.h +351/−0
- cbits/ed25519/ed25519-donna-basepoint-table.h +259/−0
- cbits/ed25519/ed25519-donna-batchverify.h +275/−0
- cbits/ed25519/ed25519-donna-impl-base.h +364/−0
- cbits/ed25519/ed25519-donna-portable-identify.h +103/−0
- cbits/ed25519/ed25519-donna-portable.h +138/−0
- cbits/ed25519/ed25519-donna.h +115/−0
- cbits/ed25519/ed25519-hash.h +26/−0
- cbits/ed25519/ed25519-randombytes.h +4/−0
- cbits/ed25519/ed25519.c +159/−0
- cbits/ed25519/ed25519.h +26/−0
- cbits/ed25519/modm-donna-32bit.h +469/−0
- cbits/ed25519/modm-donna-64bit.h +361/−0
- cbits/encrypted_sign.c +401/−0
- cbits/hmac.h +76/−0
- src/Cardano/Crypto/Encoding/BIP39.hs +43/−0
- src/Cardano/Crypto/Encoding/Seed.hs +179/−0
- src/Cardano/Crypto/Wallet.hs +202/−0
- src/Cardano/Crypto/Wallet/Encrypted.hs +226/−0
- src/Cardano/Crypto/Wallet/Pure.hs +108/−0
- src/Cardano/Crypto/Wallet/Types.hs +29/−0
- src/Cardano/Internal/Compat.hs +11/−0
- src/Crypto/ECC/Ed25519BIP32.hs +313/−0
- src/Crypto/ECC/Ed25519Donna.hs +183/−0
- src/Crypto/Encoding/BIP39.hs +440/−0
- src/Crypto/Encoding/BIP39/Dictionary.hs +88/−0
- src/Crypto/Encoding/BIP39/English.hs +2081/−0
- src/Crypto/Math/Bits.hs +110/−0
- src/Crypto/Math/Bytes.hs +104/−0
- src/Crypto/Math/Edwards25519.hs +268/−0
- src/Crypto/Math/NatMath.hs +173/−0
- test/GoldenTest.hs +250/−0
- test/Spec.hs +425/−0
- test/Test/Cardano.hs +14/−0
- test/Test/Cardano/Crypto.hs +14/−0
- test/Test/Cardano/Crypto/Encoding.hs +14/−0
- test/Test/Cardano/Crypto/Encoding/Seed.hs +50/−0
- test/Test/Crypto.hs +14/−0
- test/Test/Crypto/Encoding.hs +14/−0
- test/Test/Crypto/Encoding/BIP39.hs +111/−0
- test/Test/Orphans.hs +101/−0
- test/Utils.hs +110/−0
+ CHANGELOG.md view
@@ -0,0 +1,3 @@+## 1.3.0 - 2025-02-26++**Note**: This version exists solely for the purpose of publishing this package to [Hackage](https://hackage.haskell.org). Previous version (1.2.0) was published on [CHaP](https://chap.intersectmbo.org/package/cardano-crypto-1.2.0/).
+ LICENSE view
@@ -0,0 +1,19 @@+Copyright (c) 2016-2021 IOHK++Permission is hereby granted, free of charge, to any person obtaining a copy of+this software and associated documentation files (the "Software"), to deal in+the Software without restriction, including without limitation the rights to+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies+of the Software, and to permit persons to whom the Software is furnished to+do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in+all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN+THE SOFTWARE.
+ README.md view
@@ -0,0 +1,6 @@+The Cardano-crypto Project+==========================++This repository provides cryptographic libraries that are used in the Byron era of the Cardano node (but not Shelley+or more recent eras). It is a dependency for various repositories that are used to build the node. It is therefore maintained, +but is unlikely to be modified.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ benchs/Bench.hs view
@@ -0,0 +1,45 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE BangPatterns #-}+module Main where++import Gauge+import Gauge.Main++import Crypto.Random+import Cardano.Crypto.Wallet+import Data.ByteArray (Bytes)+import qualified Data.ByteArray as B++hardIdx, softIdx :: DerivationIndex+hardIdx = 0x80000001+softIdx = 0x00000001++derivePass :: Bytes+derivePass = B.pack [10..30]++noDerivePass :: Bytes+noDerivePass = B.empty++doDeriveBench dscheme pass parent =+ [ bench "derive-hard" $ nf (\p -> deriveXPrv dscheme pass p hardIdx) parent+ , bench "derive-soft" $ nf (\p -> deriveXPrv dscheme pass p softIdx) parent+ ]++main = do+ seed <- getRandomBytes 32 :: IO Bytes+ let !parentPass = generate seed derivePass+ !parentNoPass = generate seed noDerivePass++ defaultMain+ [ bgroup "derivation-v1-nopass" $ doDeriveBench DerivationScheme1 noDerivePass parentNoPass+ , bgroup "derivation-v2-nopass" $ doDeriveBench DerivationScheme2 noDerivePass parentNoPass+ , bgroup "derivation-v1-pass" $ doDeriveBench DerivationScheme1 derivePass parentPass+ , bgroup "derivation-v2-pass" $ doDeriveBench DerivationScheme2 derivePass parentPass+ ]
+ cardano-crypto.cabal view
@@ -0,0 +1,144 @@+name: cardano-crypto+version: 1.3.0+synopsis: Cryptography primitives for cardano+description: This package provide cryptographic primitives in use in the Cardano network, mostly related to legacy Byron era.+homepage: https://github.com/input-output-hk/cardano-crypto#readme+license: MIT+license-file: LICENSE+author: Vincent Hanquez+maintainer: contact@typed.io+copyright: 2016-2021 IOHK+category: Crypto+build-type: Simple+extra-source-files: README.md+ CHANGELOG.md+ cbits/*.h+ cbits/ed25519/*.h+cabal-version: >=1.10++flag golden-tests+ description: compile the golden tests and run them+ default: False+ manual: True++flag golden-tests-exe+ description: compile the golden test binary allowing to generate pretty markdown output+ default: False+ manual: True++library+ hs-source-dirs: src+ exposed-modules: Cardano.Crypto.Wallet+ Cardano.Crypto.Wallet.Encrypted+ Cardano.Crypto.Wallet.Types+ Cardano.Crypto.Wallet.Pure+ Cardano.Crypto.Encoding.BIP39+ Cardano.Crypto.Encoding.Seed+ Crypto.Math.Edwards25519+ Crypto.Math.Bits+ Crypto.Math.Bytes+ Crypto.Math.NatMath+ Crypto.ECC.Ed25519Donna+ Crypto.ECC.Ed25519BIP32+ Crypto.Encoding.BIP39+ Crypto.Encoding.BIP39.Dictionary+ Crypto.Encoding.BIP39.English+ Cardano.Internal.Compat+ build-depends: base >= 4.7 && < 5+ , basement >= 0.0.16+ , bytestring >= 0.11+ , crypton >= 0.32 && < 1.1+ , deepseq+ , foundation+ , integer-gmp+ , hashable >= 1.4 && < 1.6+ , memory >= 0.18+ default-language: Haskell2010+ C-sources: cbits/ed25519/ed25519.c+ cbits/encrypted_sign.c+ include-dirs: cbits/ed25519 cbits+ default-extensions: GeneralizedNewtypeDeriving+ ghc-options: -Wall+ cc-options: -Wall -Wno-unused-function+ if impl(ghc >= 8.6)+ default-extensions: NoStarIsType++test-suite cardano-crypto-test+ type: exitcode-stdio-1.0+ hs-source-dirs: test+ main-is: Spec.hs+ other-modules: Test.Crypto+ Test.Crypto.Encoding+ Test.Crypto.Encoding.BIP39+ Test.Cardano+ Test.Cardano.Crypto+ Test.Cardano.Crypto.Encoding+ Test.Cardano.Crypto.Encoding.Seed+ Utils+ build-depends: base+ , bytestring+ , memory+ , crypton+ , cardano-crypto+ , basement+ , foundation+ ghc-options: -threaded -rtsopts -with-rtsopts=-N+ default-language: Haskell2010++test-suite cardano-crypto-golden-tests+ type: exitcode-stdio-1.0+ hs-source-dirs: test+ main-is: GoldenTest.hs+ other-modules: Test.Orphans+ build-depends: base+ , basement+ , foundation+ , memory+ , bytestring+ , crypton+ , cardano-crypto+ ghc-options: -threaded -rtsopts -with-rtsopts=-N+ default-extensions: NoImplicitPrelude+ default-language: Haskell2010+ if flag(golden-tests)+ build-depends: inspector+ buildable: True+ else+ buildable: False++executable golden-tests+ hs-source-dirs: test+ main-is: GoldenTest.hs+ other-modules: Test.Orphans+ if flag(golden-tests-exe)+ build-depends: inspector+ buildable: True+ else+ buildable: False+ build-depends: base+ , basement+ , foundation+ , memory+ , bytestring+ , crypton+ , cardano-crypto+ ghc-options: -threaded -rtsopts -with-rtsopts=-N+ default-extensions: NoImplicitPrelude+ default-language: Haskell2010++benchmark cardano-crypto-bench+ type: exitcode-stdio-1.0+ hs-source-dirs: benchs+ Main-is: Bench.hs+ build-depends: base+ , bytestring+ , memory+ , crypton+ , cardano-crypto+ , gauge+ ghc-options: -threaded -rtsopts -with-rtsopts=-N+ default-language: Haskell2010++source-repository head+ type: git+ location: https://github.com/input-output-hk/cardano-crypto
+ cbits/crypton_pbkdf2.h view
@@ -0,0 +1,31 @@+#ifndef CRYPTONITE_PBKDF2_H_+#define CRYPTONITE_PBKDF2_H_++#include <stdlib.h>+#include <stdint.h>++#ifdef __cplusplus+extern "C" {+#endif++void crypton_fastpbkdf2_hmac_sha1( const uint8_t *pw, size_t npw+ , const uint8_t *salt, size_t nsalt+ , uint32_t iterations+ , uint8_t *out, size_t nout+ );+void crypton_fastpbkdf2_hmac_sha256( const uint8_t *pw, size_t npw+ , const uint8_t *salt, size_t nsalt+ , uint32_t iterations+ , uint8_t *out, size_t nout+ );+void crypton_fastpbkdf2_hmac_sha512( const uint8_t *pw, size_t npw+ , const uint8_t *salt, size_t nsalt+ , uint32_t iterations+ , uint8_t *out, size_t nout+ );++#ifdef __cplusplus+}+#endif++#endif
+ cbits/crypton_sha512.h view
@@ -0,0 +1,59 @@+/*+ * Copyright (C) 2006-2009 Vincent Hanquez <vincent@snarc.org>+ *+ * Redistribution and use in source and binary forms, with or without+ * modification, are permitted provided that the following conditions+ * are met:+ * 1. Redistributions of source code must retain the above copyright+ * notice, this list of conditions and the following disclaimer.+ * 2. Redistributions in binary form must reproduce the above copyright+ * notice, this list of conditions and the following disclaimer in the+ * documentation and/or other materials provided with the distribution.+ *+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.+ */+#ifndef CRYPTOHASH_SHA512_H+#define CRYPTOHASH_SHA512_H++#include <stdint.h>++# define SHA512_BLOCK_SIZE 128++struct sha512_ctx+{+ uint64_t sz[2];+ uint8_t buf[SHA512_BLOCK_SIZE];+ uint64_t h[8];+};++#define sha384_ctx sha512_ctx++#define SHA384_DIGEST_SIZE 48+#define SHA384_CTX_SIZE sizeof(struct sha384_ctx)++#define SHA512_DIGEST_SIZE 64+#define SHA512_CTX_SIZE sizeof(struct sha512_ctx)++void crypton_sha384_init(struct sha384_ctx *ctx);+void crypton_sha384_update(struct sha384_ctx *ctx, const uint8_t *data, uint32_t len);+void crypton_sha384_finalize(struct sha384_ctx *ctx, uint8_t *out);++void crypton_sha512_init(struct sha512_ctx *ctx);+void crypton_sha512_update(struct sha512_ctx *ctx, const uint8_t *data, uint32_t len);+void crypton_sha512_finalize(struct sha512_ctx *ctx, uint8_t *out);++/* only multiples of 8 are supported as valid t values */+void crypton_sha512t_init(struct sha512_ctx *ctx, uint32_t hashlen);+void crypton_sha512t_update(struct sha512_ctx *ctx, const uint8_t *data, uint32_t len);+void crypton_sha512t_finalize(struct sha512_ctx *ctx, uint32_t hashlen, uint8_t *out);++#endif
+ cbits/ed25519/curve25519-donna-32bit.h view
@@ -0,0 +1,579 @@+/*+ Public domain by Andrew M. <liquidsun@gmail.com>+ See: https://github.com/floodyberry/curve25519-donna++ 32 bit integer curve25519 implementation+*/++typedef uint32_t bignum25519[10];+typedef uint32_t bignum25519align16[12];++static const uint32_t reduce_mask_25 = (1 << 25) - 1;+static const uint32_t reduce_mask_26 = (1 << 26) - 1;+++/* out = in */+DONNA_INLINE static void+curve25519_copy(bignum25519 out, const bignum25519 in) {+ out[0] = in[0];+ out[1] = in[1];+ out[2] = in[2];+ out[3] = in[3];+ out[4] = in[4];+ out[5] = in[5];+ out[6] = in[6];+ out[7] = in[7];+ out[8] = in[8];+ out[9] = in[9];+}++/* out = a + b */+DONNA_INLINE static void+curve25519_add(bignum25519 out, const bignum25519 a, const bignum25519 b) {+ out[0] = a[0] + b[0];+ out[1] = a[1] + b[1];+ out[2] = a[2] + b[2];+ out[3] = a[3] + b[3];+ out[4] = a[4] + b[4];+ out[5] = a[5] + b[5];+ out[6] = a[6] + b[6];+ out[7] = a[7] + b[7];+ out[8] = a[8] + b[8];+ out[9] = a[9] + b[9];+}++DONNA_INLINE static void +curve25519_add_after_basic(bignum25519 out, const bignum25519 a, const bignum25519 b) {+ uint32_t c;+ out[0] = a[0] + b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26;+ out[1] = a[1] + b[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25;+ out[2] = a[2] + b[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26;+ out[3] = a[3] + b[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25;+ out[4] = a[4] + b[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26;+ out[5] = a[5] + b[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25;+ out[6] = a[6] + b[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26;+ out[7] = a[7] + b[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25;+ out[8] = a[8] + b[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26;+ out[9] = a[9] + b[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25;+ out[0] += 19 * c;+}++DONNA_INLINE static void+curve25519_add_reduce(bignum25519 out, const bignum25519 a, const bignum25519 b) {+ uint32_t c;+ out[0] = a[0] + b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26;+ out[1] = a[1] + b[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25;+ out[2] = a[2] + b[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26;+ out[3] = a[3] + b[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25;+ out[4] = a[4] + b[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26;+ out[5] = a[5] + b[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25;+ out[6] = a[6] + b[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26;+ out[7] = a[7] + b[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25;+ out[8] = a[8] + b[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26;+ out[9] = a[9] + b[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25;+ out[0] += 19 * c;+}++/* multiples of p */+static const uint32_t twoP0 = 0x07ffffda;+static const uint32_t twoP13579 = 0x03fffffe;+static const uint32_t twoP2468 = 0x07fffffe;+static const uint32_t fourP0 = 0x0fffffb4;+static const uint32_t fourP13579 = 0x07fffffc;+static const uint32_t fourP2468 = 0x0ffffffc;++/* out = a - b */+DONNA_INLINE static void+curve25519_sub(bignum25519 out, const bignum25519 a, const bignum25519 b) {+ uint32_t c;+ out[0] = twoP0 + a[0] - b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26;+ out[1] = twoP13579 + a[1] - b[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25;+ out[2] = twoP2468 + a[2] - b[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26;+ out[3] = twoP13579 + a[3] - b[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25;+ out[4] = twoP2468 + a[4] - b[4] + c;+ out[5] = twoP13579 + a[5] - b[5] ;+ out[6] = twoP2468 + a[6] - b[6] ;+ out[7] = twoP13579 + a[7] - b[7] ;+ out[8] = twoP2468 + a[8] - b[8] ;+ out[9] = twoP13579 + a[9] - b[9] ;+}++/* out = a - b, where a is the result of a basic op (add,sub) */+DONNA_INLINE static void+curve25519_sub_after_basic(bignum25519 out, const bignum25519 a, const bignum25519 b) {+ uint32_t c;+ out[0] = fourP0 + a[0] - b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26;+ out[1] = fourP13579 + a[1] - b[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25;+ out[2] = fourP2468 + a[2] - b[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26;+ out[3] = fourP13579 + a[3] - b[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25;+ out[4] = fourP2468 + a[4] - b[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26;+ out[5] = fourP13579 + a[5] - b[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25;+ out[6] = fourP2468 + a[6] - b[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26;+ out[7] = fourP13579 + a[7] - b[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25;+ out[8] = fourP2468 + a[8] - b[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26;+ out[9] = fourP13579 + a[9] - b[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25;+ out[0] += 19 * c;+}++DONNA_INLINE static void+curve25519_sub_reduce(bignum25519 out, const bignum25519 a, const bignum25519 b) {+ uint32_t c;+ out[0] = fourP0 + a[0] - b[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26;+ out[1] = fourP13579 + a[1] - b[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25;+ out[2] = fourP2468 + a[2] - b[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26;+ out[3] = fourP13579 + a[3] - b[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25;+ out[4] = fourP2468 + a[4] - b[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26;+ out[5] = fourP13579 + a[5] - b[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25;+ out[6] = fourP2468 + a[6] - b[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26;+ out[7] = fourP13579 + a[7] - b[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25;+ out[8] = fourP2468 + a[8] - b[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26;+ out[9] = fourP13579 + a[9] - b[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25;+ out[0] += 19 * c;+}++/* out = -a */+DONNA_INLINE static void+curve25519_neg(bignum25519 out, const bignum25519 a) {+ uint32_t c;+ out[0] = twoP0 - a[0] ; c = (out[0] >> 26); out[0] &= reduce_mask_26;+ out[1] = twoP13579 - a[1] + c; c = (out[1] >> 25); out[1] &= reduce_mask_25;+ out[2] = twoP2468 - a[2] + c; c = (out[2] >> 26); out[2] &= reduce_mask_26;+ out[3] = twoP13579 - a[3] + c; c = (out[3] >> 25); out[3] &= reduce_mask_25;+ out[4] = twoP2468 - a[4] + c; c = (out[4] >> 26); out[4] &= reduce_mask_26;+ out[5] = twoP13579 - a[5] + c; c = (out[5] >> 25); out[5] &= reduce_mask_25;+ out[6] = twoP2468 - a[6] + c; c = (out[6] >> 26); out[6] &= reduce_mask_26;+ out[7] = twoP13579 - a[7] + c; c = (out[7] >> 25); out[7] &= reduce_mask_25;+ out[8] = twoP2468 - a[8] + c; c = (out[8] >> 26); out[8] &= reduce_mask_26;+ out[9] = twoP13579 - a[9] + c; c = (out[9] >> 25); out[9] &= reduce_mask_25;+ out[0] += 19 * c;+}++/* out = a * b */+#define curve25519_mul_noinline curve25519_mul+static void+curve25519_mul(bignum25519 out, const bignum25519 a, const bignum25519 b) {+ uint32_t r0,r1,r2,r3,r4,r5,r6,r7,r8,r9;+ uint32_t s0,s1,s2,s3,s4,s5,s6,s7,s8,s9;+ uint64_t m0,m1,m2,m3,m4,m5,m6,m7,m8,m9,c;+ uint32_t p;++ r0 = b[0];+ r1 = b[1];+ r2 = b[2];+ r3 = b[3];+ r4 = b[4];+ r5 = b[5];+ r6 = b[6];+ r7 = b[7];+ r8 = b[8];+ r9 = b[9];++ s0 = a[0];+ s1 = a[1];+ s2 = a[2];+ s3 = a[3];+ s4 = a[4];+ s5 = a[5];+ s6 = a[6];+ s7 = a[7];+ s8 = a[8];+ s9 = a[9];++ m1 = mul32x32_64(r0, s1) + mul32x32_64(r1, s0);+ m3 = mul32x32_64(r0, s3) + mul32x32_64(r1, s2) + mul32x32_64(r2, s1) + mul32x32_64(r3, s0);+ m5 = mul32x32_64(r0, s5) + mul32x32_64(r1, s4) + mul32x32_64(r2, s3) + mul32x32_64(r3, s2) + mul32x32_64(r4, s1) + mul32x32_64(r5, s0);+ m7 = mul32x32_64(r0, s7) + mul32x32_64(r1, s6) + mul32x32_64(r2, s5) + mul32x32_64(r3, s4) + mul32x32_64(r4, s3) + mul32x32_64(r5, s2) + mul32x32_64(r6, s1) + mul32x32_64(r7, s0);+ m9 = mul32x32_64(r0, s9) + mul32x32_64(r1, s8) + mul32x32_64(r2, s7) + mul32x32_64(r3, s6) + mul32x32_64(r4, s5) + mul32x32_64(r5, s4) + mul32x32_64(r6, s3) + mul32x32_64(r7, s2) + mul32x32_64(r8, s1) + mul32x32_64(r9, s0);++ r1 *= 2;+ r3 *= 2;+ r5 *= 2;+ r7 *= 2;++ m0 = mul32x32_64(r0, s0);+ m2 = mul32x32_64(r0, s2) + mul32x32_64(r1, s1) + mul32x32_64(r2, s0);+ m4 = mul32x32_64(r0, s4) + mul32x32_64(r1, s3) + mul32x32_64(r2, s2) + mul32x32_64(r3, s1) + mul32x32_64(r4, s0);+ m6 = mul32x32_64(r0, s6) + mul32x32_64(r1, s5) + mul32x32_64(r2, s4) + mul32x32_64(r3, s3) + mul32x32_64(r4, s2) + mul32x32_64(r5, s1) + mul32x32_64(r6, s0);+ m8 = mul32x32_64(r0, s8) + mul32x32_64(r1, s7) + mul32x32_64(r2, s6) + mul32x32_64(r3, s5) + mul32x32_64(r4, s4) + mul32x32_64(r5, s3) + mul32x32_64(r6, s2) + mul32x32_64(r7, s1) + mul32x32_64(r8, s0);++ r1 *= 19;+ r2 *= 19;+ r3 = (r3 / 2) * 19;+ r4 *= 19;+ r5 = (r5 / 2) * 19;+ r6 *= 19;+ r7 = (r7 / 2) * 19;+ r8 *= 19;+ r9 *= 19;++ m1 += (mul32x32_64(r9, s2) + mul32x32_64(r8, s3) + mul32x32_64(r7, s4) + mul32x32_64(r6, s5) + mul32x32_64(r5, s6) + mul32x32_64(r4, s7) + mul32x32_64(r3, s8) + mul32x32_64(r2, s9));+ m3 += (mul32x32_64(r9, s4) + mul32x32_64(r8, s5) + mul32x32_64(r7, s6) + mul32x32_64(r6, s7) + mul32x32_64(r5, s8) + mul32x32_64(r4, s9));+ m5 += (mul32x32_64(r9, s6) + mul32x32_64(r8, s7) + mul32x32_64(r7, s8) + mul32x32_64(r6, s9));+ m7 += (mul32x32_64(r9, s8) + mul32x32_64(r8, s9));++ r3 *= 2;+ r5 *= 2;+ r7 *= 2;+ r9 *= 2;++ m0 += (mul32x32_64(r9, s1) + mul32x32_64(r8, s2) + mul32x32_64(r7, s3) + mul32x32_64(r6, s4) + mul32x32_64(r5, s5) + mul32x32_64(r4, s6) + mul32x32_64(r3, s7) + mul32x32_64(r2, s8) + mul32x32_64(r1, s9));+ m2 += (mul32x32_64(r9, s3) + mul32x32_64(r8, s4) + mul32x32_64(r7, s5) + mul32x32_64(r6, s6) + mul32x32_64(r5, s7) + mul32x32_64(r4, s8) + mul32x32_64(r3, s9));+ m4 += (mul32x32_64(r9, s5) + mul32x32_64(r8, s6) + mul32x32_64(r7, s7) + mul32x32_64(r6, s8) + mul32x32_64(r5, s9));+ m6 += (mul32x32_64(r9, s7) + mul32x32_64(r8, s8) + mul32x32_64(r7, s9));+ m8 += (mul32x32_64(r9, s9));++ r0 = (uint32_t)m0 & reduce_mask_26; c = (m0 >> 26);+ m1 += c; r1 = (uint32_t)m1 & reduce_mask_25; c = (m1 >> 25);+ m2 += c; r2 = (uint32_t)m2 & reduce_mask_26; c = (m2 >> 26);+ m3 += c; r3 = (uint32_t)m3 & reduce_mask_25; c = (m3 >> 25);+ m4 += c; r4 = (uint32_t)m4 & reduce_mask_26; c = (m4 >> 26);+ m5 += c; r5 = (uint32_t)m5 & reduce_mask_25; c = (m5 >> 25);+ m6 += c; r6 = (uint32_t)m6 & reduce_mask_26; c = (m6 >> 26);+ m7 += c; r7 = (uint32_t)m7 & reduce_mask_25; c = (m7 >> 25);+ m8 += c; r8 = (uint32_t)m8 & reduce_mask_26; c = (m8 >> 26);+ m9 += c; r9 = (uint32_t)m9 & reduce_mask_25; p = (uint32_t)(m9 >> 25);+ m0 = r0 + mul32x32_64(p,19); r0 = (uint32_t)m0 & reduce_mask_26; p = (uint32_t)(m0 >> 26);+ r1 += p;++ out[0] = r0;+ out[1] = r1;+ out[2] = r2;+ out[3] = r3;+ out[4] = r4;+ out[5] = r5;+ out[6] = r6;+ out[7] = r7;+ out[8] = r8;+ out[9] = r9;+}++/* out = in*in */+static void+curve25519_square(bignum25519 out, const bignum25519 in) {+ uint32_t r0,r1,r2,r3,r4,r5,r6,r7,r8,r9;+ uint32_t d6,d7,d8,d9;+ uint64_t m0,m1,m2,m3,m4,m5,m6,m7,m8,m9,c;+ uint32_t p;++ r0 = in[0];+ r1 = in[1];+ r2 = in[2];+ r3 = in[3];+ r4 = in[4];+ r5 = in[5];+ r6 = in[6];+ r7 = in[7];+ r8 = in[8];+ r9 = in[9];++ m0 = mul32x32_64(r0, r0);+ r0 *= 2;+ m1 = mul32x32_64(r0, r1);+ m2 = mul32x32_64(r0, r2) + mul32x32_64(r1, r1 * 2);+ r1 *= 2;+ m3 = mul32x32_64(r0, r3) + mul32x32_64(r1, r2 );+ m4 = mul32x32_64(r0, r4) + mul32x32_64(r1, r3 * 2) + mul32x32_64(r2, r2);+ r2 *= 2;+ m5 = mul32x32_64(r0, r5) + mul32x32_64(r1, r4 ) + mul32x32_64(r2, r3);+ m6 = mul32x32_64(r0, r6) + mul32x32_64(r1, r5 * 2) + mul32x32_64(r2, r4) + mul32x32_64(r3, r3 * 2);+ r3 *= 2;+ m7 = mul32x32_64(r0, r7) + mul32x32_64(r1, r6 ) + mul32x32_64(r2, r5) + mul32x32_64(r3, r4 );+ m8 = mul32x32_64(r0, r8) + mul32x32_64(r1, r7 * 2) + mul32x32_64(r2, r6) + mul32x32_64(r3, r5 * 2) + mul32x32_64(r4, r4 );+ m9 = mul32x32_64(r0, r9) + mul32x32_64(r1, r8 ) + mul32x32_64(r2, r7) + mul32x32_64(r3, r6 ) + mul32x32_64(r4, r5 * 2);++ d6 = r6 * 19;+ d7 = r7 * 2 * 19;+ d8 = r8 * 19;+ d9 = r9 * 2 * 19;++ m0 += (mul32x32_64(d9, r1 ) + mul32x32_64(d8, r2 ) + mul32x32_64(d7, r3 ) + mul32x32_64(d6, r4 * 2) + mul32x32_64(r5, r5 * 2 * 19));+ m1 += (mul32x32_64(d9, r2 / 2) + mul32x32_64(d8, r3 ) + mul32x32_64(d7, r4 ) + mul32x32_64(d6, r5 * 2));+ m2 += (mul32x32_64(d9, r3 ) + mul32x32_64(d8, r4 * 2) + mul32x32_64(d7, r5 * 2) + mul32x32_64(d6, r6 ));+ m3 += (mul32x32_64(d9, r4 ) + mul32x32_64(d8, r5 * 2) + mul32x32_64(d7, r6 ));+ m4 += (mul32x32_64(d9, r5 * 2) + mul32x32_64(d8, r6 * 2) + mul32x32_64(d7, r7 ));+ m5 += (mul32x32_64(d9, r6 ) + mul32x32_64(d8, r7 * 2));+ m6 += (mul32x32_64(d9, r7 * 2) + mul32x32_64(d8, r8 ));+ m7 += (mul32x32_64(d9, r8 ));+ m8 += (mul32x32_64(d9, r9 ));++ r0 = (uint32_t)m0 & reduce_mask_26; c = (m0 >> 26);+ m1 += c; r1 = (uint32_t)m1 & reduce_mask_25; c = (m1 >> 25);+ m2 += c; r2 = (uint32_t)m2 & reduce_mask_26; c = (m2 >> 26);+ m3 += c; r3 = (uint32_t)m3 & reduce_mask_25; c = (m3 >> 25);+ m4 += c; r4 = (uint32_t)m4 & reduce_mask_26; c = (m4 >> 26);+ m5 += c; r5 = (uint32_t)m5 & reduce_mask_25; c = (m5 >> 25);+ m6 += c; r6 = (uint32_t)m6 & reduce_mask_26; c = (m6 >> 26);+ m7 += c; r7 = (uint32_t)m7 & reduce_mask_25; c = (m7 >> 25);+ m8 += c; r8 = (uint32_t)m8 & reduce_mask_26; c = (m8 >> 26);+ m9 += c; r9 = (uint32_t)m9 & reduce_mask_25; p = (uint32_t)(m9 >> 25);+ m0 = r0 + mul32x32_64(p,19); r0 = (uint32_t)m0 & reduce_mask_26; p = (uint32_t)(m0 >> 26);+ r1 += p;++ out[0] = r0;+ out[1] = r1;+ out[2] = r2;+ out[3] = r3;+ out[4] = r4;+ out[5] = r5;+ out[6] = r6;+ out[7] = r7;+ out[8] = r8;+ out[9] = r9;+}+++/* out = in ^ (2 * count) */+static void+curve25519_square_times(bignum25519 out, const bignum25519 in, int count) {+ uint32_t r0,r1,r2,r3,r4,r5,r6,r7,r8,r9;+ uint32_t d6,d7,d8,d9;+ uint64_t m0,m1,m2,m3,m4,m5,m6,m7,m8,m9,c;+ uint32_t p;++ r0 = in[0];+ r1 = in[1];+ r2 = in[2];+ r3 = in[3];+ r4 = in[4];+ r5 = in[5];+ r6 = in[6];+ r7 = in[7];+ r8 = in[8];+ r9 = in[9];++ do {+ m0 = mul32x32_64(r0, r0);+ r0 *= 2;+ m1 = mul32x32_64(r0, r1);+ m2 = mul32x32_64(r0, r2) + mul32x32_64(r1, r1 * 2);+ r1 *= 2;+ m3 = mul32x32_64(r0, r3) + mul32x32_64(r1, r2 );+ m4 = mul32x32_64(r0, r4) + mul32x32_64(r1, r3 * 2) + mul32x32_64(r2, r2);+ r2 *= 2;+ m5 = mul32x32_64(r0, r5) + mul32x32_64(r1, r4 ) + mul32x32_64(r2, r3);+ m6 = mul32x32_64(r0, r6) + mul32x32_64(r1, r5 * 2) + mul32x32_64(r2, r4) + mul32x32_64(r3, r3 * 2);+ r3 *= 2;+ m7 = mul32x32_64(r0, r7) + mul32x32_64(r1, r6 ) + mul32x32_64(r2, r5) + mul32x32_64(r3, r4 );+ m8 = mul32x32_64(r0, r8) + mul32x32_64(r1, r7 * 2) + mul32x32_64(r2, r6) + mul32x32_64(r3, r5 * 2) + mul32x32_64(r4, r4 );+ m9 = mul32x32_64(r0, r9) + mul32x32_64(r1, r8 ) + mul32x32_64(r2, r7) + mul32x32_64(r3, r6 ) + mul32x32_64(r4, r5 * 2);++ d6 = r6 * 19;+ d7 = r7 * 2 * 19;+ d8 = r8 * 19;+ d9 = r9 * 2 * 19;++ m0 += (mul32x32_64(d9, r1 ) + mul32x32_64(d8, r2 ) + mul32x32_64(d7, r3 ) + mul32x32_64(d6, r4 * 2) + mul32x32_64(r5, r5 * 2 * 19));+ m1 += (mul32x32_64(d9, r2 / 2) + mul32x32_64(d8, r3 ) + mul32x32_64(d7, r4 ) + mul32x32_64(d6, r5 * 2));+ m2 += (mul32x32_64(d9, r3 ) + mul32x32_64(d8, r4 * 2) + mul32x32_64(d7, r5 * 2) + mul32x32_64(d6, r6 ));+ m3 += (mul32x32_64(d9, r4 ) + mul32x32_64(d8, r5 * 2) + mul32x32_64(d7, r6 ));+ m4 += (mul32x32_64(d9, r5 * 2) + mul32x32_64(d8, r6 * 2) + mul32x32_64(d7, r7 ));+ m5 += (mul32x32_64(d9, r6 ) + mul32x32_64(d8, r7 * 2));+ m6 += (mul32x32_64(d9, r7 * 2) + mul32x32_64(d8, r8 ));+ m7 += (mul32x32_64(d9, r8 ));+ m8 += (mul32x32_64(d9, r9 ));++ r0 = (uint32_t)m0 & reduce_mask_26; c = (m0 >> 26);+ m1 += c; r1 = (uint32_t)m1 & reduce_mask_25; c = (m1 >> 25);+ m2 += c; r2 = (uint32_t)m2 & reduce_mask_26; c = (m2 >> 26);+ m3 += c; r3 = (uint32_t)m3 & reduce_mask_25; c = (m3 >> 25);+ m4 += c; r4 = (uint32_t)m4 & reduce_mask_26; c = (m4 >> 26);+ m5 += c; r5 = (uint32_t)m5 & reduce_mask_25; c = (m5 >> 25);+ m6 += c; r6 = (uint32_t)m6 & reduce_mask_26; c = (m6 >> 26);+ m7 += c; r7 = (uint32_t)m7 & reduce_mask_25; c = (m7 >> 25);+ m8 += c; r8 = (uint32_t)m8 & reduce_mask_26; c = (m8 >> 26);+ m9 += c; r9 = (uint32_t)m9 & reduce_mask_25; p = (uint32_t)(m9 >> 25);+ m0 = r0 + mul32x32_64(p,19); r0 = (uint32_t)m0 & reduce_mask_26; p = (uint32_t)(m0 >> 26);+ r1 += p;+ } while (--count);++ out[0] = r0;+ out[1] = r1;+ out[2] = r2;+ out[3] = r3;+ out[4] = r4;+ out[5] = r5;+ out[6] = r6;+ out[7] = r7;+ out[8] = r8;+ out[9] = r9;+}++/* Take a little-endian, 32-byte number and expand it into polynomial form */+static void+curve25519_expand(bignum25519 out, const unsigned char in[32]) {+ static const union { uint8_t b[2]; uint16_t s; } endian_check = {{1,0}};+ uint32_t x0,x1,x2,x3,x4,x5,x6,x7;++ if (endian_check.s == 1) {+ x0 = *(uint32_t *)(in + 0);+ x1 = *(uint32_t *)(in + 4);+ x2 = *(uint32_t *)(in + 8);+ x3 = *(uint32_t *)(in + 12);+ x4 = *(uint32_t *)(in + 16);+ x5 = *(uint32_t *)(in + 20);+ x6 = *(uint32_t *)(in + 24);+ x7 = *(uint32_t *)(in + 28);+ } else {+ #define F(s) \+ ((((uint32_t)in[s + 0]) ) | \+ (((uint32_t)in[s + 1]) << 8) | \+ (((uint32_t)in[s + 2]) << 16) | \+ (((uint32_t)in[s + 3]) << 24))+ x0 = F(0);+ x1 = F(4);+ x2 = F(8);+ x3 = F(12);+ x4 = F(16);+ x5 = F(20);+ x6 = F(24);+ x7 = F(28);+ #undef F+ }++ out[0] = ( x0 ) & 0x3ffffff;+ out[1] = ((((uint64_t)x1 << 32) | x0) >> 26) & 0x1ffffff;+ out[2] = ((((uint64_t)x2 << 32) | x1) >> 19) & 0x3ffffff;+ out[3] = ((((uint64_t)x3 << 32) | x2) >> 13) & 0x1ffffff;+ out[4] = (( x3) >> 6) & 0x3ffffff;+ out[5] = ( x4 ) & 0x1ffffff;+ out[6] = ((((uint64_t)x5 << 32) | x4) >> 25) & 0x3ffffff;+ out[7] = ((((uint64_t)x6 << 32) | x5) >> 19) & 0x1ffffff;+ out[8] = ((((uint64_t)x7 << 32) | x6) >> 12) & 0x3ffffff;+ out[9] = (( x7) >> 6) & 0x1ffffff;+}++/* Take a fully reduced polynomial form number and contract it into a+ * little-endian, 32-byte array+ */+static void+curve25519_contract(unsigned char out[32], const bignum25519 in) {+ bignum25519 f;+ curve25519_copy(f, in);++ #define carry_pass() \+ f[1] += f[0] >> 26; f[0] &= reduce_mask_26; \+ f[2] += f[1] >> 25; f[1] &= reduce_mask_25; \+ f[3] += f[2] >> 26; f[2] &= reduce_mask_26; \+ f[4] += f[3] >> 25; f[3] &= reduce_mask_25; \+ f[5] += f[4] >> 26; f[4] &= reduce_mask_26; \+ f[6] += f[5] >> 25; f[5] &= reduce_mask_25; \+ f[7] += f[6] >> 26; f[6] &= reduce_mask_26; \+ f[8] += f[7] >> 25; f[7] &= reduce_mask_25; \+ f[9] += f[8] >> 26; f[8] &= reduce_mask_26;++ #define carry_pass_full() \+ carry_pass() \+ f[0] += 19 * (f[9] >> 25); f[9] &= reduce_mask_25;++ #define carry_pass_final() \+ carry_pass() \+ f[9] &= reduce_mask_25;++ carry_pass_full()+ carry_pass_full()++ /* now t is between 0 and 2^255-1, properly carried. */+ /* case 1: between 0 and 2^255-20. case 2: between 2^255-19 and 2^255-1. */+ f[0] += 19;+ carry_pass_full()++ /* now between 19 and 2^255-1 in both cases, and offset by 19. */+ f[0] += (reduce_mask_26 + 1) - 19;+ f[1] += (reduce_mask_25 + 1) - 1;+ f[2] += (reduce_mask_26 + 1) - 1;+ f[3] += (reduce_mask_25 + 1) - 1;+ f[4] += (reduce_mask_26 + 1) - 1;+ f[5] += (reduce_mask_25 + 1) - 1;+ f[6] += (reduce_mask_26 + 1) - 1;+ f[7] += (reduce_mask_25 + 1) - 1;+ f[8] += (reduce_mask_26 + 1) - 1;+ f[9] += (reduce_mask_25 + 1) - 1;++ /* now between 2^255 and 2^256-20, and offset by 2^255. */+ carry_pass_final()++ #undef carry_pass+ #undef carry_full+ #undef carry_final++ f[1] <<= 2;+ f[2] <<= 3;+ f[3] <<= 5;+ f[4] <<= 6;+ f[6] <<= 1;+ f[7] <<= 3;+ f[8] <<= 4;+ f[9] <<= 6;++ #define F(i, s) \+ out[s+0] |= (unsigned char )(f[i] & 0xff); \+ out[s+1] = (unsigned char )((f[i] >> 8) & 0xff); \+ out[s+2] = (unsigned char )((f[i] >> 16) & 0xff); \+ out[s+3] = (unsigned char )((f[i] >> 24) & 0xff);++ out[0] = 0;+ out[16] = 0;+ F(0,0);+ F(1,3);+ F(2,6);+ F(3,9);+ F(4,12);+ F(5,16);+ F(6,19);+ F(7,22);+ F(8,25);+ F(9,28);+ #undef F+}+++/* out = (flag) ? in : out */+DONNA_INLINE static void+curve25519_move_conditional_bytes(uint8_t out[96], const uint8_t in[96], uint32_t flag) {+ const uint32_t nb = flag - 1, b = ~nb;+ const uint32_t *inl = (const uint32_t *)in;+ uint32_t *outl = (uint32_t *)out;+ outl[0] = (outl[0] & nb) | (inl[0] & b);+ outl[1] = (outl[1] & nb) | (inl[1] & b);+ outl[2] = (outl[2] & nb) | (inl[2] & b);+ outl[3] = (outl[3] & nb) | (inl[3] & b);+ outl[4] = (outl[4] & nb) | (inl[4] & b);+ outl[5] = (outl[5] & nb) | (inl[5] & b);+ outl[6] = (outl[6] & nb) | (inl[6] & b);+ outl[7] = (outl[7] & nb) | (inl[7] & b);+ outl[8] = (outl[8] & nb) | (inl[8] & b);+ outl[9] = (outl[9] & nb) | (inl[9] & b);+ outl[10] = (outl[10] & nb) | (inl[10] & b);+ outl[11] = (outl[11] & nb) | (inl[11] & b);+ outl[12] = (outl[12] & nb) | (inl[12] & b);+ outl[13] = (outl[13] & nb) | (inl[13] & b);+ outl[14] = (outl[14] & nb) | (inl[14] & b);+ outl[15] = (outl[15] & nb) | (inl[15] & b);+ outl[16] = (outl[16] & nb) | (inl[16] & b);+ outl[17] = (outl[17] & nb) | (inl[17] & b);+ outl[18] = (outl[18] & nb) | (inl[18] & b);+ outl[19] = (outl[19] & nb) | (inl[19] & b);+ outl[20] = (outl[20] & nb) | (inl[20] & b);+ outl[21] = (outl[21] & nb) | (inl[21] & b);+ outl[22] = (outl[22] & nb) | (inl[22] & b);+ outl[23] = (outl[23] & nb) | (inl[23] & b);++}++/* if (iswap) swap(a, b) */+DONNA_INLINE static void+curve25519_swap_conditional(bignum25519 a, bignum25519 b, uint32_t iswap) {+ const uint32_t swap = (uint32_t)(-(int32_t)iswap);+ uint32_t x0,x1,x2,x3,x4,x5,x6,x7,x8,x9;++ x0 = swap & (a[0] ^ b[0]); a[0] ^= x0; b[0] ^= x0;+ x1 = swap & (a[1] ^ b[1]); a[1] ^= x1; b[1] ^= x1;+ x2 = swap & (a[2] ^ b[2]); a[2] ^= x2; b[2] ^= x2;+ x3 = swap & (a[3] ^ b[3]); a[3] ^= x3; b[3] ^= x3;+ x4 = swap & (a[4] ^ b[4]); a[4] ^= x4; b[4] ^= x4;+ x5 = swap & (a[5] ^ b[5]); a[5] ^= x5; b[5] ^= x5;+ x6 = swap & (a[6] ^ b[6]); a[6] ^= x6; b[6] ^= x6;+ x7 = swap & (a[7] ^ b[7]); a[7] ^= x7; b[7] ^= x7;+ x8 = swap & (a[8] ^ b[8]); a[8] ^= x8; b[8] ^= x8;+ x9 = swap & (a[9] ^ b[9]); a[9] ^= x9; b[9] ^= x9;+}
+ cbits/ed25519/curve25519-donna-64bit.h view
@@ -0,0 +1,413 @@+/*+ Public domain by Adam Langley <agl@imperialviolet.org> &+ Andrew M. <liquidsun@gmail.com>+ See: https://github.com/floodyberry/curve25519-donna++ 64bit integer curve25519 implementation+*/++typedef uint64_t bignum25519[5];++static const uint64_t reduce_mask_40 = ((uint64_t)1 << 40) - 1;+static const uint64_t reduce_mask_51 = ((uint64_t)1 << 51) - 1;+static const uint64_t reduce_mask_56 = ((uint64_t)1 << 56) - 1;++/* out = in */+DONNA_INLINE static void+curve25519_copy(bignum25519 out, const bignum25519 in) {+ out[0] = in[0];+ out[1] = in[1];+ out[2] = in[2];+ out[3] = in[3];+ out[4] = in[4];+}++/* out = a + b */+DONNA_INLINE static void+curve25519_add(bignum25519 out, const bignum25519 a, const bignum25519 b) {+ out[0] = a[0] + b[0];+ out[1] = a[1] + b[1];+ out[2] = a[2] + b[2];+ out[3] = a[3] + b[3];+ out[4] = a[4] + b[4];+}++/* out = a + b, where a and/or b are the result of a basic op (add,sub) */+DONNA_INLINE static void+curve25519_add_after_basic(bignum25519 out, const bignum25519 a, const bignum25519 b) {+ out[0] = a[0] + b[0];+ out[1] = a[1] + b[1];+ out[2] = a[2] + b[2];+ out[3] = a[3] + b[3];+ out[4] = a[4] + b[4];+}++DONNA_INLINE static void+curve25519_add_reduce(bignum25519 out, const bignum25519 a, const bignum25519 b) {+ uint64_t c;+ out[0] = a[0] + b[0] ; c = (out[0] >> 51); out[0] &= reduce_mask_51;+ out[1] = a[1] + b[1] + c; c = (out[1] >> 51); out[1] &= reduce_mask_51;+ out[2] = a[2] + b[2] + c; c = (out[2] >> 51); out[2] &= reduce_mask_51;+ out[3] = a[3] + b[3] + c; c = (out[3] >> 51); out[3] &= reduce_mask_51;+ out[4] = a[4] + b[4] + c; c = (out[4] >> 51); out[4] &= reduce_mask_51;+ out[0] += c * 19;+}++/* multiples of p */+static const uint64_t twoP0 = 0x0fffffffffffda;+static const uint64_t twoP1234 = 0x0ffffffffffffe;+static const uint64_t fourP0 = 0x1fffffffffffb4;+static const uint64_t fourP1234 = 0x1ffffffffffffc;++/* out = a - b */+DONNA_INLINE static void+curve25519_sub(bignum25519 out, const bignum25519 a, const bignum25519 b) {+ out[0] = a[0] + twoP0 - b[0];+ out[1] = a[1] + twoP1234 - b[1];+ out[2] = a[2] + twoP1234 - b[2];+ out[3] = a[3] + twoP1234 - b[3];+ out[4] = a[4] + twoP1234 - b[4];+}++/* out = a - b, where a and/or b are the result of a basic op (add,sub) */+DONNA_INLINE static void+curve25519_sub_after_basic(bignum25519 out, const bignum25519 a, const bignum25519 b) {+ out[0] = a[0] + fourP0 - b[0];+ out[1] = a[1] + fourP1234 - b[1];+ out[2] = a[2] + fourP1234 - b[2];+ out[3] = a[3] + fourP1234 - b[3];+ out[4] = a[4] + fourP1234 - b[4];+}++DONNA_INLINE static void+curve25519_sub_reduce(bignum25519 out, const bignum25519 a, const bignum25519 b) {+ uint64_t c;+ out[0] = a[0] + fourP0 - b[0] ; c = (out[0] >> 51); out[0] &= reduce_mask_51;+ out[1] = a[1] + fourP1234 - b[1] + c; c = (out[1] >> 51); out[1] &= reduce_mask_51;+ out[2] = a[2] + fourP1234 - b[2] + c; c = (out[2] >> 51); out[2] &= reduce_mask_51;+ out[3] = a[3] + fourP1234 - b[3] + c; c = (out[3] >> 51); out[3] &= reduce_mask_51;+ out[4] = a[4] + fourP1234 - b[4] + c; c = (out[4] >> 51); out[4] &= reduce_mask_51;+ out[0] += c * 19;+}++/* out = -a */+DONNA_INLINE static void+curve25519_neg(bignum25519 out, const bignum25519 a) {+ uint64_t c;+ out[0] = twoP0 - a[0] ; c = (out[0] >> 51); out[0] &= reduce_mask_51;+ out[1] = twoP1234 - a[1] + c; c = (out[1] >> 51); out[1] &= reduce_mask_51;+ out[2] = twoP1234 - a[2] + c; c = (out[2] >> 51); out[2] &= reduce_mask_51;+ out[3] = twoP1234 - a[3] + c; c = (out[3] >> 51); out[3] &= reduce_mask_51;+ out[4] = twoP1234 - a[4] + c; c = (out[4] >> 51); out[4] &= reduce_mask_51;+ out[0] += c * 19;+}++/* out = a * b */+DONNA_INLINE static void+curve25519_mul(bignum25519 out, const bignum25519 in2, const bignum25519 in) {+#if !defined(HAVE_NATIVE_UINT128)+ uint128_t mul;+#endif+ uint128_t t[5];+ uint64_t r0,r1,r2,r3,r4,s0,s1,s2,s3,s4,c;++ r0 = in[0];+ r1 = in[1];+ r2 = in[2];+ r3 = in[3];+ r4 = in[4];++ s0 = in2[0];+ s1 = in2[1];+ s2 = in2[2];+ s3 = in2[3];+ s4 = in2[4];++#if defined(HAVE_NATIVE_UINT128)+ t[0] = ((uint128_t) r0) * s0;+ t[1] = ((uint128_t) r0) * s1 + ((uint128_t) r1) * s0;+ t[2] = ((uint128_t) r0) * s2 + ((uint128_t) r2) * s0 + ((uint128_t) r1) * s1;+ t[3] = ((uint128_t) r0) * s3 + ((uint128_t) r3) * s0 + ((uint128_t) r1) * s2 + ((uint128_t) r2) * s1;+ t[4] = ((uint128_t) r0) * s4 + ((uint128_t) r4) * s0 + ((uint128_t) r3) * s1 + ((uint128_t) r1) * s3 + ((uint128_t) r2) * s2;+#else+ mul64x64_128(t[0], r0, s0)+ mul64x64_128(t[1], r0, s1) mul64x64_128(mul, r1, s0) add128(t[1], mul)+ mul64x64_128(t[2], r0, s2) mul64x64_128(mul, r2, s0) add128(t[2], mul) mul64x64_128(mul, r1, s1) add128(t[2], mul)+ mul64x64_128(t[3], r0, s3) mul64x64_128(mul, r3, s0) add128(t[3], mul) mul64x64_128(mul, r1, s2) add128(t[3], mul) mul64x64_128(mul, r2, s1) add128(t[3], mul)+ mul64x64_128(t[4], r0, s4) mul64x64_128(mul, r4, s0) add128(t[4], mul) mul64x64_128(mul, r3, s1) add128(t[4], mul) mul64x64_128(mul, r1, s3) add128(t[4], mul) mul64x64_128(mul, r2, s2) add128(t[4], mul)+#endif++ r1 *= 19;+ r2 *= 19;+ r3 *= 19;+ r4 *= 19;++#if defined(HAVE_NATIVE_UINT128)+ t[0] += ((uint128_t) r4) * s1 + ((uint128_t) r1) * s4 + ((uint128_t) r2) * s3 + ((uint128_t) r3) * s2;+ t[1] += ((uint128_t) r4) * s2 + ((uint128_t) r2) * s4 + ((uint128_t) r3) * s3;+ t[2] += ((uint128_t) r4) * s3 + ((uint128_t) r3) * s4;+ t[3] += ((uint128_t) r4) * s4;+#else+ mul64x64_128(mul, r4, s1) add128(t[0], mul) mul64x64_128(mul, r1, s4) add128(t[0], mul) mul64x64_128(mul, r2, s3) add128(t[0], mul) mul64x64_128(mul, r3, s2) add128(t[0], mul)+ mul64x64_128(mul, r4, s2) add128(t[1], mul) mul64x64_128(mul, r2, s4) add128(t[1], mul) mul64x64_128(mul, r3, s3) add128(t[1], mul)+ mul64x64_128(mul, r4, s3) add128(t[2], mul) mul64x64_128(mul, r3, s4) add128(t[2], mul)+ mul64x64_128(mul, r4, s4) add128(t[3], mul)+#endif+++ r0 = lo128(t[0]) & reduce_mask_51; shr128(c, t[0], 51);+ add128_64(t[1], c) r1 = lo128(t[1]) & reduce_mask_51; shr128(c, t[1], 51);+ add128_64(t[2], c) r2 = lo128(t[2]) & reduce_mask_51; shr128(c, t[2], 51);+ add128_64(t[3], c) r3 = lo128(t[3]) & reduce_mask_51; shr128(c, t[3], 51);+ add128_64(t[4], c) r4 = lo128(t[4]) & reduce_mask_51; shr128(c, t[4], 51);+ r0 += c * 19; c = r0 >> 51; r0 = r0 & reduce_mask_51;+ r1 += c;++ out[0] = r0;+ out[1] = r1;+ out[2] = r2;+ out[3] = r3;+ out[4] = r4;+}++DONNA_NOINLINE static void+curve25519_mul_noinline(bignum25519 out, const bignum25519 in2, const bignum25519 in) {+ curve25519_mul(out, in2, in);+}++/* out = in^(2 * count) */+DONNA_NOINLINE static void+curve25519_square_times(bignum25519 out, const bignum25519 in, uint64_t count) {+#if !defined(HAVE_NATIVE_UINT128)+ uint128_t mul;+#endif+ uint128_t t[5];+ uint64_t r0,r1,r2,r3,r4,c;+ uint64_t d0,d1,d2,d4,d419;++ r0 = in[0];+ r1 = in[1];+ r2 = in[2];+ r3 = in[3];+ r4 = in[4];++ do {+ d0 = r0 * 2;+ d1 = r1 * 2;+ d2 = r2 * 2 * 19;+ d419 = r4 * 19;+ d4 = d419 * 2;++#if defined(HAVE_NATIVE_UINT128)+ t[0] = ((uint128_t) r0) * r0 + ((uint128_t) d4) * r1 + (((uint128_t) d2) * (r3 ));+ t[1] = ((uint128_t) d0) * r1 + ((uint128_t) d4) * r2 + (((uint128_t) r3) * (r3 * 19));+ t[2] = ((uint128_t) d0) * r2 + ((uint128_t) r1) * r1 + (((uint128_t) d4) * (r3 ));+ t[3] = ((uint128_t) d0) * r3 + ((uint128_t) d1) * r2 + (((uint128_t) r4) * (d419 ));+ t[4] = ((uint128_t) d0) * r4 + ((uint128_t) d1) * r3 + (((uint128_t) r2) * (r2 ));+#else+ mul64x64_128(t[0], r0, r0) mul64x64_128(mul, d4, r1) add128(t[0], mul) mul64x64_128(mul, d2, r3) add128(t[0], mul)+ mul64x64_128(t[1], d0, r1) mul64x64_128(mul, d4, r2) add128(t[1], mul) mul64x64_128(mul, r3, r3 * 19) add128(t[1], mul)+ mul64x64_128(t[2], d0, r2) mul64x64_128(mul, r1, r1) add128(t[2], mul) mul64x64_128(mul, d4, r3) add128(t[2], mul)+ mul64x64_128(t[3], d0, r3) mul64x64_128(mul, d1, r2) add128(t[3], mul) mul64x64_128(mul, r4, d419) add128(t[3], mul)+ mul64x64_128(t[4], d0, r4) mul64x64_128(mul, d1, r3) add128(t[4], mul) mul64x64_128(mul, r2, r2) add128(t[4], mul)+#endif++ r0 = lo128(t[0]) & reduce_mask_51;+ r1 = lo128(t[1]) & reduce_mask_51; shl128(c, t[0], 13); r1 += c;+ r2 = lo128(t[2]) & reduce_mask_51; shl128(c, t[1], 13); r2 += c;+ r3 = lo128(t[3]) & reduce_mask_51; shl128(c, t[2], 13); r3 += c;+ r4 = lo128(t[4]) & reduce_mask_51; shl128(c, t[3], 13); r4 += c; + shl128(c, t[4], 13); r0 += c * 19;+ c = r0 >> 51; r0 &= reduce_mask_51;+ r1 += c ; c = r1 >> 51; r1 &= reduce_mask_51;+ r2 += c ; c = r2 >> 51; r2 &= reduce_mask_51;+ r3 += c ; c = r3 >> 51; r3 &= reduce_mask_51;+ r4 += c ; c = r4 >> 51; r4 &= reduce_mask_51;+ r0 += c * 19;+ } while(--count);++ out[0] = r0;+ out[1] = r1;+ out[2] = r2;+ out[3] = r3;+ out[4] = r4;+}++DONNA_INLINE static void+curve25519_square(bignum25519 out, const bignum25519 in) {+#if !defined(HAVE_NATIVE_UINT128)+ uint128_t mul;+#endif+ uint128_t t[5];+ uint64_t r0,r1,r2,r3,r4,c;+ uint64_t d0,d1,d2,d4,d419;++ r0 = in[0];+ r1 = in[1];+ r2 = in[2];+ r3 = in[3];+ r4 = in[4];++ d0 = r0 * 2;+ d1 = r1 * 2;+ d2 = r2 * 2 * 19;+ d419 = r4 * 19;+ d4 = d419 * 2;++#if defined(HAVE_NATIVE_UINT128)+ t[0] = ((uint128_t) r0) * r0 + ((uint128_t) d4) * r1 + (((uint128_t) d2) * (r3 ));+ t[1] = ((uint128_t) d0) * r1 + ((uint128_t) d4) * r2 + (((uint128_t) r3) * (r3 * 19));+ t[2] = ((uint128_t) d0) * r2 + ((uint128_t) r1) * r1 + (((uint128_t) d4) * (r3 ));+ t[3] = ((uint128_t) d0) * r3 + ((uint128_t) d1) * r2 + (((uint128_t) r4) * (d419 ));+ t[4] = ((uint128_t) d0) * r4 + ((uint128_t) d1) * r3 + (((uint128_t) r2) * (r2 ));+#else+ mul64x64_128(t[0], r0, r0) mul64x64_128(mul, d4, r1) add128(t[0], mul) mul64x64_128(mul, d2, r3) add128(t[0], mul)+ mul64x64_128(t[1], d0, r1) mul64x64_128(mul, d4, r2) add128(t[1], mul) mul64x64_128(mul, r3, r3 * 19) add128(t[1], mul)+ mul64x64_128(t[2], d0, r2) mul64x64_128(mul, r1, r1) add128(t[2], mul) mul64x64_128(mul, d4, r3) add128(t[2], mul)+ mul64x64_128(t[3], d0, r3) mul64x64_128(mul, d1, r2) add128(t[3], mul) mul64x64_128(mul, r4, d419) add128(t[3], mul)+ mul64x64_128(t[4], d0, r4) mul64x64_128(mul, d1, r3) add128(t[4], mul) mul64x64_128(mul, r2, r2) add128(t[4], mul)+#endif++ r0 = lo128(t[0]) & reduce_mask_51; shr128(c, t[0], 51);+ add128_64(t[1], c) r1 = lo128(t[1]) & reduce_mask_51; shr128(c, t[1], 51);+ add128_64(t[2], c) r2 = lo128(t[2]) & reduce_mask_51; shr128(c, t[2], 51);+ add128_64(t[3], c) r3 = lo128(t[3]) & reduce_mask_51; shr128(c, t[3], 51);+ add128_64(t[4], c) r4 = lo128(t[4]) & reduce_mask_51; shr128(c, t[4], 51);+ r0 += c * 19; c = r0 >> 51; r0 = r0 & reduce_mask_51;+ r1 += c;++ out[0] = r0;+ out[1] = r1;+ out[2] = r2;+ out[3] = r3;+ out[4] = r4;+}++/* Take a little-endian, 32-byte number and expand it into polynomial form */+DONNA_INLINE static void+curve25519_expand(bignum25519 out, const unsigned char *in) {+ static const union { uint8_t b[2]; uint16_t s; } endian_check = {{1,0}};+ uint64_t x0,x1,x2,x3;++ if (endian_check.s == 1) {+ x0 = *(uint64_t *)(in + 0);+ x1 = *(uint64_t *)(in + 8);+ x2 = *(uint64_t *)(in + 16);+ x3 = *(uint64_t *)(in + 24);+ } else {+ #define F(s) \+ ((((uint64_t)in[s + 0]) ) | \+ (((uint64_t)in[s + 1]) << 8) | \+ (((uint64_t)in[s + 2]) << 16) | \+ (((uint64_t)in[s + 3]) << 24) | \+ (((uint64_t)in[s + 4]) << 32) | \+ (((uint64_t)in[s + 5]) << 40) | \+ (((uint64_t)in[s + 6]) << 48) | \+ (((uint64_t)in[s + 7]) << 56))++ x0 = F(0);+ x1 = F(8);+ x2 = F(16);+ x3 = F(24);+ }++ out[0] = x0 & reduce_mask_51; x0 = (x0 >> 51) | (x1 << 13);+ out[1] = x0 & reduce_mask_51; x1 = (x1 >> 38) | (x2 << 26);+ out[2] = x1 & reduce_mask_51; x2 = (x2 >> 25) | (x3 << 39);+ out[3] = x2 & reduce_mask_51; x3 = (x3 >> 12);+ out[4] = x3 & reduce_mask_51;+}++/* Take a fully reduced polynomial form number and contract it into a+ * little-endian, 32-byte array+ */+DONNA_INLINE static void+curve25519_contract(unsigned char *out, const bignum25519 input) {+ uint64_t t[5];+ uint64_t f, i;++ t[0] = input[0];+ t[1] = input[1];+ t[2] = input[2];+ t[3] = input[3];+ t[4] = input[4];++ #define curve25519_contract_carry() \+ t[1] += t[0] >> 51; t[0] &= reduce_mask_51; \+ t[2] += t[1] >> 51; t[1] &= reduce_mask_51; \+ t[3] += t[2] >> 51; t[2] &= reduce_mask_51; \+ t[4] += t[3] >> 51; t[3] &= reduce_mask_51;++ #define curve25519_contract_carry_full() curve25519_contract_carry() \+ t[0] += 19 * (t[4] >> 51); t[4] &= reduce_mask_51;++ #define curve25519_contract_carry_final() curve25519_contract_carry() \+ t[4] &= reduce_mask_51;++ curve25519_contract_carry_full()+ curve25519_contract_carry_full()++ /* now t is between 0 and 2^255-1, properly carried. */+ /* case 1: between 0 and 2^255-20. case 2: between 2^255-19 and 2^255-1. */+ t[0] += 19;+ curve25519_contract_carry_full()++ /* now between 19 and 2^255-1 in both cases, and offset by 19. */+ t[0] += (reduce_mask_51 + 1) - 19;+ t[1] += (reduce_mask_51 + 1) - 1;+ t[2] += (reduce_mask_51 + 1) - 1;+ t[3] += (reduce_mask_51 + 1) - 1;+ t[4] += (reduce_mask_51 + 1) - 1;++ /* now between 2^255 and 2^256-20, and offset by 2^255. */+ curve25519_contract_carry_final()++ #define write51full(n,shift) \+ f = ((t[n] >> shift) | (t[n+1] << (51 - shift))); \+ for (i = 0; i < 8; i++, f >>= 8) *out++ = (unsigned char)f;+ #define write51(n) write51full(n,13*n)+ write51(0)+ write51(1)+ write51(2)+ write51(3)+}++#if !defined(ED25519_GCC_64BIT_CHOOSE)++/* out = (flag) ? in : out */+DONNA_INLINE static void+curve25519_move_conditional_bytes(uint8_t out[96], const uint8_t in[96], uint64_t flag) {+ const uint64_t nb = flag - 1, b = ~nb;+ const uint64_t *inq = (const uint64_t *)in;+ uint64_t *outq = (uint64_t *)out;+ outq[0] = (outq[0] & nb) | (inq[0] & b);+ outq[1] = (outq[1] & nb) | (inq[1] & b);+ outq[2] = (outq[2] & nb) | (inq[2] & b);+ outq[3] = (outq[3] & nb) | (inq[3] & b);+ outq[4] = (outq[4] & nb) | (inq[4] & b);+ outq[5] = (outq[5] & nb) | (inq[5] & b);+ outq[6] = (outq[6] & nb) | (inq[6] & b);+ outq[7] = (outq[7] & nb) | (inq[7] & b);+ outq[8] = (outq[8] & nb) | (inq[8] & b);+ outq[9] = (outq[9] & nb) | (inq[9] & b);+ outq[10] = (outq[10] & nb) | (inq[10] & b);+ outq[11] = (outq[11] & nb) | (inq[11] & b);+}++/* if (iswap) swap(a, b) */+DONNA_INLINE static void+curve25519_swap_conditional(bignum25519 a, bignum25519 b, uint64_t iswap) {+ const uint64_t swap = (uint64_t)(-(int64_t)iswap);+ uint64_t x0,x1,x2,x3,x4;++ x0 = swap & (a[0] ^ b[0]); a[0] ^= x0; b[0] ^= x0;+ x1 = swap & (a[1] ^ b[1]); a[1] ^= x1; b[1] ^= x1;+ x2 = swap & (a[2] ^ b[2]); a[2] ^= x2; b[2] ^= x2;+ x3 = swap & (a[3] ^ b[3]); a[3] ^= x3; b[3] ^= x3;+ x4 = swap & (a[4] ^ b[4]); a[4] ^= x4; b[4] ^= x4;+}++#endif /* ED25519_GCC_64BIT_CHOOSE */++#define ED25519_64BIT_TABLES+
+ cbits/ed25519/curve25519-donna-helpers.h view
@@ -0,0 +1,67 @@+/*+ Public domain by Andrew M. <liquidsun@gmail.com>+ See: https://github.com/floodyberry/curve25519-donna++ Curve25519 implementation agnostic helpers+*/++/*+ * In: b = 2^5 - 2^0+ * Out: b = 2^250 - 2^0+ */+static void+curve25519_pow_two5mtwo0_two250mtwo0(bignum25519 b) {+ bignum25519 ALIGN(16) t0,c;++ /* 2^5 - 2^0 */ /* b */+ /* 2^10 - 2^5 */ curve25519_square_times(t0, b, 5);+ /* 2^10 - 2^0 */ curve25519_mul_noinline(b, t0, b);+ /* 2^20 - 2^10 */ curve25519_square_times(t0, b, 10);+ /* 2^20 - 2^0 */ curve25519_mul_noinline(c, t0, b);+ /* 2^40 - 2^20 */ curve25519_square_times(t0, c, 20);+ /* 2^40 - 2^0 */ curve25519_mul_noinline(t0, t0, c);+ /* 2^50 - 2^10 */ curve25519_square_times(t0, t0, 10);+ /* 2^50 - 2^0 */ curve25519_mul_noinline(b, t0, b);+ /* 2^100 - 2^50 */ curve25519_square_times(t0, b, 50);+ /* 2^100 - 2^0 */ curve25519_mul_noinline(c, t0, b);+ /* 2^200 - 2^100 */ curve25519_square_times(t0, c, 100);+ /* 2^200 - 2^0 */ curve25519_mul_noinline(t0, t0, c);+ /* 2^250 - 2^50 */ curve25519_square_times(t0, t0, 50);+ /* 2^250 - 2^0 */ curve25519_mul_noinline(b, t0, b);+}++/*+ * z^(p - 2) = z(2^255 - 21)+ */+static void+curve25519_recip(bignum25519 out, const bignum25519 z) {+ bignum25519 ALIGN(16) a,t0,b;++ /* 2 */ curve25519_square_times(a, z, 1); /* a = 2 */+ /* 8 */ curve25519_square_times(t0, a, 2);+ /* 9 */ curve25519_mul_noinline(b, t0, z); /* b = 9 */+ /* 11 */ curve25519_mul_noinline(a, b, a); /* a = 11 */+ /* 22 */ curve25519_square_times(t0, a, 1);+ /* 2^5 - 2^0 = 31 */ curve25519_mul_noinline(b, t0, b);+ /* 2^250 - 2^0 */ curve25519_pow_two5mtwo0_two250mtwo0(b);+ /* 2^255 - 2^5 */ curve25519_square_times(b, b, 5);+ /* 2^255 - 21 */ curve25519_mul_noinline(out, b, a);+}++/*+ * z^((p-5)/8) = z^(2^252 - 3)+ */+static void+curve25519_pow_two252m3(bignum25519 two252m3, const bignum25519 z) {+ bignum25519 ALIGN(16) b,c,t0;++ /* 2 */ curve25519_square_times(c, z, 1); /* c = 2 */+ /* 8 */ curve25519_square_times(t0, c, 2); /* t0 = 8 */+ /* 9 */ curve25519_mul_noinline(b, t0, z); /* b = 9 */+ /* 11 */ curve25519_mul_noinline(c, b, c); /* c = 11 */+ /* 22 */ curve25519_square_times(t0, c, 1);+ /* 2^5 - 2^0 = 31 */ curve25519_mul_noinline(b, t0, b);+ /* 2^250 - 2^0 */ curve25519_pow_two5mtwo0_two250mtwo0(b);+ /* 2^252 - 2^2 */ curve25519_square_times(b, b, 2);+ /* 2^252 - 3 */ curve25519_mul_noinline(two252m3, b, z);+}
+ cbits/ed25519/ed25519-donna-32bit-sse2.h view
@@ -0,0 +1,513 @@+#if defined(ED25519_GCC_32BIT_SSE_CHOOSE)++#define HAVE_GE25519_SCALARMULT_BASE_CHOOSE_NIELS++DONNA_NOINLINE static void+ge25519_scalarmult_base_choose_niels(ge25519_niels *t, const uint8_t table[256][96], uint32_t pos, signed char b) {+ int32_t breg = (int32_t)b;+ uint32_t sign = (uint32_t)breg >> 31;+ uint32_t mask = ~(sign - 1);+ uint32_t u = (breg + mask) ^ mask;++ __asm__ __volatile__ (+ /* ysubx+xaddy */+ "movl %0, %%eax ;\n"+ "movd %%eax, %%xmm6 ;\n"+ "pshufd $0x00, %%xmm6, %%xmm6 ;\n"+ "pxor %%xmm0, %%xmm0 ;\n"+ "pxor %%xmm1, %%xmm1 ;\n"+ "pxor %%xmm2, %%xmm2 ;\n"+ "pxor %%xmm3, %%xmm3 ;\n"++ /* 0 */+ "movl $0, %%eax ;\n"+ "movd %%eax, %%xmm7 ;\n"+ "pshufd $0x00, %%xmm7, %%xmm7 ;\n"+ "pcmpeqd %%xmm6, %%xmm7 ;\n"+ "movl $1, %%ecx ;\n"+ "movd %%ecx, %%xmm4 ;\n"+ "pxor %%xmm5, %%xmm5 ;\n"+ "pand %%xmm7, %%xmm4 ;\n"+ "pand %%xmm7, %%xmm5 ;\n"+ "por %%xmm4, %%xmm0 ;\n"+ "por %%xmm5, %%xmm1 ;\n"+ "por %%xmm4, %%xmm2 ;\n"+ "por %%xmm5, %%xmm3 ;\n"++ /* 1 */+ "movl $1, %%eax ;\n"+ "movd %%eax, %%xmm7 ;\n"+ "pshufd $0x00, %%xmm7, %%xmm7 ;\n"+ "pcmpeqd %%xmm6, %%xmm7 ;\n"+ "movdqa 0(%1), %%xmm4 ;\n"+ "movdqa 16(%1), %%xmm5 ;\n"+ "pand %%xmm7, %%xmm4 ;\n"+ "pand %%xmm7, %%xmm5 ;\n"+ "por %%xmm4, %%xmm0 ;\n"+ "por %%xmm5, %%xmm1 ;\n"+ "movdqa 32(%1), %%xmm4 ;\n"+ "movdqa 48(%1), %%xmm5 ;\n"+ "pand %%xmm7, %%xmm4 ;\n"+ "pand %%xmm7, %%xmm5 ;\n"+ "por %%xmm4, %%xmm2 ;\n"+ "por %%xmm5, %%xmm3 ;\n"++ /* 2 */+ "movl $2, %%eax ;\n"+ "movd %%eax, %%xmm7 ;\n"+ "pshufd $0x00, %%xmm7, %%xmm7 ;\n"+ "pcmpeqd %%xmm6, %%xmm7 ;\n"+ "movdqa 96(%1), %%xmm4 ;\n"+ "movdqa 112(%1), %%xmm5 ;\n"+ "pand %%xmm7, %%xmm4 ;\n"+ "pand %%xmm7, %%xmm5 ;\n"+ "por %%xmm4, %%xmm0 ;\n"+ "por %%xmm5, %%xmm1 ;\n"+ "movdqa 128(%1), %%xmm4 ;\n"+ "movdqa 144(%1), %%xmm5 ;\n"+ "pand %%xmm7, %%xmm4 ;\n"+ "pand %%xmm7, %%xmm5 ;\n"+ "por %%xmm4, %%xmm2 ;\n"+ "por %%xmm5, %%xmm3 ;\n"++ /* 3 */+ "movl $3, %%eax ;\n"+ "movd %%eax, %%xmm7 ;\n"+ "pshufd $0x00, %%xmm7, %%xmm7 ;\n"+ "pcmpeqd %%xmm6, %%xmm7 ;\n"+ "movdqa 192(%1), %%xmm4 ;\n"+ "movdqa 208(%1), %%xmm5 ;\n"+ "pand %%xmm7, %%xmm4 ;\n"+ "pand %%xmm7, %%xmm5 ;\n"+ "por %%xmm4, %%xmm0 ;\n"+ "por %%xmm5, %%xmm1 ;\n"+ "movdqa 224(%1), %%xmm4 ;\n"+ "movdqa 240(%1), %%xmm5 ;\n"+ "pand %%xmm7, %%xmm4 ;\n"+ "pand %%xmm7, %%xmm5 ;\n"+ "por %%xmm4, %%xmm2 ;\n"+ "por %%xmm5, %%xmm3 ;\n"++ /* 4 */+ "movl $4, %%eax ;\n"+ "movd %%eax, %%xmm7 ;\n"+ "pshufd $0x00, %%xmm7, %%xmm7 ;\n"+ "pcmpeqd %%xmm6, %%xmm7 ;\n"+ "movdqa 288(%1), %%xmm4 ;\n"+ "movdqa 304(%1), %%xmm5 ;\n"+ "pand %%xmm7, %%xmm4 ;\n"+ "pand %%xmm7, %%xmm5 ;\n"+ "por %%xmm4, %%xmm0 ;\n"+ "por %%xmm5, %%xmm1 ;\n"+ "movdqa 320(%1), %%xmm4 ;\n"+ "movdqa 336(%1), %%xmm5 ;\n"+ "pand %%xmm7, %%xmm4 ;\n"+ "pand %%xmm7, %%xmm5 ;\n"+ "por %%xmm4, %%xmm2 ;\n"+ "por %%xmm5, %%xmm3 ;\n"++ /* 5 */+ "movl $5, %%eax ;\n"+ "movd %%eax, %%xmm7 ;\n"+ "pshufd $0x00, %%xmm7, %%xmm7 ;\n"+ "pcmpeqd %%xmm6, %%xmm7 ;\n"+ "movdqa 384(%1), %%xmm4 ;\n"+ "movdqa 400(%1), %%xmm5 ;\n"+ "pand %%xmm7, %%xmm4 ;\n"+ "pand %%xmm7, %%xmm5 ;\n"+ "por %%xmm4, %%xmm0 ;\n"+ "por %%xmm5, %%xmm1 ;\n"+ "movdqa 416(%1), %%xmm4 ;\n"+ "movdqa 432(%1), %%xmm5 ;\n"+ "pand %%xmm7, %%xmm4 ;\n"+ "pand %%xmm7, %%xmm5 ;\n"+ "por %%xmm4, %%xmm2 ;\n"+ "por %%xmm5, %%xmm3 ;\n"++ /* 6 */+ "movl $6, %%eax ;\n"+ "movd %%eax, %%xmm7 ;\n"+ "pshufd $0x00, %%xmm7, %%xmm7 ;\n"+ "pcmpeqd %%xmm6, %%xmm7 ;\n"+ "movdqa 480(%1), %%xmm4 ;\n"+ "movdqa 496(%1), %%xmm5 ;\n"+ "pand %%xmm7, %%xmm4 ;\n"+ "pand %%xmm7, %%xmm5 ;\n"+ "por %%xmm4, %%xmm0 ;\n"+ "por %%xmm5, %%xmm1 ;\n"+ "movdqa 512(%1), %%xmm4 ;\n"+ "movdqa 528(%1), %%xmm5 ;\n"+ "pand %%xmm7, %%xmm4 ;\n"+ "pand %%xmm7, %%xmm5 ;\n"+ "por %%xmm4, %%xmm2 ;\n"+ "por %%xmm5, %%xmm3 ;\n"++ /* 7 */+ "movl $7, %%eax ;\n"+ "movd %%eax, %%xmm7 ;\n"+ "pshufd $0x00, %%xmm7, %%xmm7 ;\n"+ "pcmpeqd %%xmm6, %%xmm7 ;\n"+ "movdqa 576(%1), %%xmm4 ;\n"+ "movdqa 592(%1), %%xmm5 ;\n"+ "pand %%xmm7, %%xmm4 ;\n"+ "pand %%xmm7, %%xmm5 ;\n"+ "por %%xmm4, %%xmm0 ;\n"+ "por %%xmm5, %%xmm1 ;\n"+ "movdqa 608(%1), %%xmm4 ;\n"+ "movdqa 624(%1), %%xmm5 ;\n"+ "pand %%xmm7, %%xmm4 ;\n"+ "pand %%xmm7, %%xmm5 ;\n"+ "por %%xmm4, %%xmm2 ;\n"+ "por %%xmm5, %%xmm3 ;\n"++ /* 8 */+ "movl $8, %%eax ;\n"+ "movd %%eax, %%xmm7 ;\n"+ "pshufd $0x00, %%xmm7, %%xmm7 ;\n"+ "pcmpeqd %%xmm6, %%xmm7 ;\n"+ "movdqa 672(%1), %%xmm4 ;\n"+ "movdqa 688(%1), %%xmm5 ;\n"+ "pand %%xmm7, %%xmm4 ;\n"+ "pand %%xmm7, %%xmm5 ;\n"+ "por %%xmm4, %%xmm0 ;\n"+ "por %%xmm5, %%xmm1 ;\n"+ "movdqa 704(%1), %%xmm4 ;\n"+ "movdqa 720(%1), %%xmm5 ;\n"+ "pand %%xmm7, %%xmm4 ;\n"+ "pand %%xmm7, %%xmm5 ;\n"+ "por %%xmm4, %%xmm2 ;\n"+ "por %%xmm5, %%xmm3 ;\n"++ /* conditional swap based on sign */+ "movl %3, %%ecx ;\n"+ "movl %2, %%eax ;\n"+ "xorl $1, %%ecx ;\n"+ "movd %%ecx, %%xmm6 ;\n"+ "pxor %%xmm7, %%xmm7 ;\n"+ "pshufd $0x00, %%xmm6, %%xmm6 ;\n"+ "pxor %%xmm0, %%xmm2 ;\n"+ "pxor %%xmm1, %%xmm3 ;\n"+ "pcmpeqd %%xmm6, %%xmm7 ;\n"+ "movdqa %%xmm2, %%xmm4 ;\n"+ "movdqa %%xmm3, %%xmm5 ;\n"+ "pand %%xmm7, %%xmm4 ;\n"+ "pand %%xmm7, %%xmm5 ;\n"+ "pxor %%xmm4, %%xmm0 ;\n"+ "pxor %%xmm5, %%xmm1 ;\n"+ "pxor %%xmm0, %%xmm2 ;\n"+ "pxor %%xmm1, %%xmm3 ;\n"++ /* store ysubx */+ "movd %%xmm0, %%ecx ;\n"+ "movl %%ecx, %%edx ;\n"+ "pshufd $0x39, %%xmm0, %%xmm0 ;\n"+ "andl $0x3ffffff, %%ecx ;\n"+ "movl %%ecx, 0(%%eax) ;\n"+ "movd %%xmm0, %%ecx ;\n"+ "pshufd $0x39, %%xmm0, %%xmm0 ;\n"+ "shrdl $26, %%ecx, %%edx ;\n"+ "andl $0x1ffffff, %%edx ;\n"+ "movl %%edx, 4(%%eax) ;\n"+ "movd %%xmm0, %%edx ;\n"+ "pshufd $0x39, %%xmm0, %%xmm0 ;\n"+ "shrdl $19, %%edx, %%ecx ;\n"+ "andl $0x3ffffff, %%ecx ;\n"+ "movl %%ecx, 8(%%eax) ;\n"+ "movd %%xmm0, %%ecx ;\n"+ "shrdl $13, %%ecx, %%edx ;\n"+ "andl $0x1ffffff, %%edx ;\n"+ "movl %%edx, 12(%%eax) ;\n"+ "movd %%xmm1, %%edx ;\n"+ "pshufd $0x39, %%xmm1, %%xmm1 ;\n"+ "shrl $6, %%ecx ;\n"+ "andl $0x3ffffff, %%ecx ;\n"+ "movl %%ecx, 16(%%eax) ;\n"+ "movl %%edx, %%ecx ;\n"+ "andl $0x1ffffff, %%edx ;\n"+ "movl %%edx, 20(%%eax) ;\n"+ "movd %%xmm1, %%edx ;\n"+ "pshufd $0x39, %%xmm1, %%xmm1 ;\n"+ "shrdl $25, %%edx, %%ecx ;\n"+ "andl $0x3ffffff, %%ecx ;\n"+ "movl %%ecx, 24(%%eax) ;\n"+ "movd %%xmm1, %%ecx ;\n"+ "pshufd $0x39, %%xmm1, %%xmm1 ;\n"+ "shrdl $19, %%ecx, %%edx ;\n"+ "andl $0x1ffffff, %%edx ;\n"+ "movl %%edx, 28(%%eax) ;\n"+ "movd %%xmm1, %%edx ;\n"+ "shrdl $12, %%edx, %%ecx ;\n"+ "andl $0x3ffffff, %%ecx ;\n"+ "movl %%ecx, 32(%%eax) ;\n"+ "shrl $6, %%edx ;\n"+ "andl $0x1ffffff, %%edx ;\n"+ "xorl %%ecx, %%ecx ;\n"+ "movl %%edx, 36(%%eax) ;\n"+ "movl %%ecx, 40(%%eax) ;\n"+ "movl %%ecx, 44(%%eax) ;\n"++ /* store xaddy */+ "addl $48, %%eax ;\n"+ "movdqa %%xmm2, %%xmm0 ;\n"+ "movdqa %%xmm3, %%xmm1 ;\n"+ "movd %%xmm0, %%ecx ;\n"+ "movl %%ecx, %%edx ;\n"+ "pshufd $0x39, %%xmm0, %%xmm0 ;\n"+ "andl $0x3ffffff, %%ecx ;\n"+ "movl %%ecx, 0(%%eax) ;\n"+ "movd %%xmm0, %%ecx ;\n"+ "pshufd $0x39, %%xmm0, %%xmm0 ;\n"+ "shrdl $26, %%ecx, %%edx ;\n"+ "andl $0x1ffffff, %%edx ;\n"+ "movl %%edx, 4(%%eax) ;\n"+ "movd %%xmm0, %%edx ;\n"+ "pshufd $0x39, %%xmm0, %%xmm0 ;\n"+ "shrdl $19, %%edx, %%ecx ;\n"+ "andl $0x3ffffff, %%ecx ;\n"+ "movl %%ecx, 8(%%eax) ;\n"+ "movd %%xmm0, %%ecx ;\n"+ "shrdl $13, %%ecx, %%edx ;\n"+ "andl $0x1ffffff, %%edx ;\n"+ "movl %%edx, 12(%%eax) ;\n"+ "movd %%xmm1, %%edx ;\n"+ "pshufd $0x39, %%xmm1, %%xmm1 ;\n"+ "shrl $6, %%ecx ;\n"+ "andl $0x3ffffff, %%ecx ;\n"+ "movl %%ecx, 16(%%eax) ;\n"+ "movl %%edx, %%ecx ;\n"+ "andl $0x1ffffff, %%edx ;\n"+ "movl %%edx, 20(%%eax) ;\n"+ "movd %%xmm1, %%edx ;\n"+ "pshufd $0x39, %%xmm1, %%xmm1 ;\n"+ "shrdl $25, %%edx, %%ecx ;\n"+ "andl $0x3ffffff, %%ecx ;\n"+ "movl %%ecx, 24(%%eax) ;\n"+ "movd %%xmm1, %%ecx ;\n"+ "pshufd $0x39, %%xmm1, %%xmm1 ;\n"+ "shrdl $19, %%ecx, %%edx ;\n"+ "andl $0x1ffffff, %%edx ;\n"+ "movl %%edx, 28(%%eax) ;\n"+ "movd %%xmm1, %%edx ;\n"+ "shrdl $12, %%edx, %%ecx ;\n"+ "andl $0x3ffffff, %%ecx ;\n"+ "movl %%ecx, 32(%%eax) ;\n"+ "shrl $6, %%edx ;\n"+ "andl $0x1ffffff, %%edx ;\n"+ "xorl %%ecx, %%ecx ;\n"+ "movl %%edx, 36(%%eax) ;\n"+ "movl %%ecx, 40(%%eax) ;\n"+ "movl %%ecx, 44(%%eax) ;\n"++ /* t2d */+ "movl %0, %%eax ;\n"+ "movd %%eax, %%xmm6 ;\n"+ "pshufd $0x00, %%xmm6, %%xmm6 ;\n"+ "pxor %%xmm0, %%xmm0 ;\n"+ "pxor %%xmm1, %%xmm1 ;\n"++ /* 0 */+ "movl $0, %%eax ;\n"+ "movd %%eax, %%xmm7 ;\n"+ "pshufd $0x00, %%xmm7, %%xmm7 ;\n"+ "pcmpeqd %%xmm6, %%xmm7 ;\n"+ "pxor %%xmm0, %%xmm0 ;\n"+ "pxor %%xmm1, %%xmm1 ;\n"++ /* 1 */+ "movl $1, %%eax ;\n"+ "movd %%eax, %%xmm7 ;\n"+ "pshufd $0x00, %%xmm7, %%xmm7 ;\n"+ "pcmpeqd %%xmm6, %%xmm7 ;\n"+ "movdqa 64(%1), %%xmm3 ;\n"+ "movdqa 80(%1), %%xmm4 ;\n"+ "pand %%xmm7, %%xmm3 ;\n"+ "pand %%xmm7, %%xmm4 ;\n"+ "por %%xmm3, %%xmm0 ;\n"+ "por %%xmm4, %%xmm1 ;\n"++ /* 2 */+ "movl $2, %%eax ;\n"+ "movd %%eax, %%xmm7 ;\n"+ "pshufd $0x00, %%xmm7, %%xmm7 ;\n"+ "pcmpeqd %%xmm6, %%xmm7 ;\n"+ "movdqa 160(%1), %%xmm3 ;\n"+ "movdqa 176(%1), %%xmm4 ;\n"+ "pand %%xmm7, %%xmm3 ;\n"+ "pand %%xmm7, %%xmm4 ;\n"+ "por %%xmm3, %%xmm0 ;\n"+ "por %%xmm4, %%xmm1 ;\n"++ /* 3 */+ "movl $3, %%eax ;\n"+ "movd %%eax, %%xmm7 ;\n"+ "pshufd $0x00, %%xmm7, %%xmm7 ;\n"+ "pcmpeqd %%xmm6, %%xmm7 ;\n"+ "movdqa 256(%1), %%xmm3 ;\n"+ "movdqa 272(%1), %%xmm4 ;\n"+ "pand %%xmm7, %%xmm3 ;\n"+ "pand %%xmm7, %%xmm4 ;\n"+ "por %%xmm3, %%xmm0 ;\n"+ "por %%xmm4, %%xmm1 ;\n"++ /* 4 */+ "movl $4, %%eax ;\n"+ "movd %%eax, %%xmm7 ;\n"+ "pshufd $0x00, %%xmm7, %%xmm7 ;\n"+ "pcmpeqd %%xmm6, %%xmm7 ;\n"+ "movdqa 352(%1), %%xmm3 ;\n"+ "movdqa 368(%1), %%xmm4 ;\n"+ "pand %%xmm7, %%xmm3 ;\n"+ "pand %%xmm7, %%xmm4 ;\n"+ "por %%xmm3, %%xmm0 ;\n"+ "por %%xmm4, %%xmm1 ;\n"++ /* 5 */+ "movl $5, %%eax ;\n"+ "movd %%eax, %%xmm7 ;\n"+ "pshufd $0x00, %%xmm7, %%xmm7 ;\n"+ "pcmpeqd %%xmm6, %%xmm7 ;\n"+ "movdqa 448(%1), %%xmm3 ;\n"+ "movdqa 464(%1), %%xmm4 ;\n"+ "pand %%xmm7, %%xmm3 ;\n"+ "pand %%xmm7, %%xmm4 ;\n"+ "por %%xmm3, %%xmm0 ;\n"+ "por %%xmm4, %%xmm1 ;\n"++ /* 6 */+ "movl $6, %%eax ;\n"+ "movd %%eax, %%xmm7 ;\n"+ "pshufd $0x00, %%xmm7, %%xmm7 ;\n"+ "pcmpeqd %%xmm6, %%xmm7 ;\n"+ "movdqa 544(%1), %%xmm3 ;\n"+ "movdqa 560(%1), %%xmm4 ;\n"+ "pand %%xmm7, %%xmm3 ;\n"+ "pand %%xmm7, %%xmm4 ;\n"+ "por %%xmm3, %%xmm0 ;\n"+ "por %%xmm4, %%xmm1 ;\n"++ /* 7 */+ "movl $7, %%eax ;\n"+ "movd %%eax, %%xmm7 ;\n"+ "pshufd $0x00, %%xmm7, %%xmm7 ;\n"+ "pcmpeqd %%xmm6, %%xmm7 ;\n"+ "movdqa 640(%1), %%xmm3 ;\n"+ "movdqa 656(%1), %%xmm4 ;\n"+ "pand %%xmm7, %%xmm3 ;\n"+ "pand %%xmm7, %%xmm4 ;\n"+ "por %%xmm3, %%xmm0 ;\n"+ "por %%xmm4, %%xmm1 ;\n"++ /* 8 */+ "movl $8, %%eax ;\n"+ "movd %%eax, %%xmm7 ;\n"+ "pshufd $0x00, %%xmm7, %%xmm7 ;\n"+ "pcmpeqd %%xmm6, %%xmm7 ;\n"+ "movdqa 736(%1), %%xmm3 ;\n"+ "movdqa 752(%1), %%xmm4 ;\n"+ "pand %%xmm7, %%xmm3 ;\n"+ "pand %%xmm7, %%xmm4 ;\n"+ "por %%xmm3, %%xmm0 ;\n"+ "por %%xmm4, %%xmm1 ;\n"++ /* store t2d */+ "movl %2, %%eax ;\n"+ "addl $96, %%eax ;\n"+ "movd %%xmm0, %%ecx ;\n"+ "movl %%ecx, %%edx ;\n"+ "pshufd $0x39, %%xmm0, %%xmm0 ;\n"+ "andl $0x3ffffff, %%ecx ;\n"+ "movl %%ecx, 0(%%eax) ;\n"+ "movd %%xmm0, %%ecx ;\n"+ "pshufd $0x39, %%xmm0, %%xmm0 ;\n"+ "shrdl $26, %%ecx, %%edx ;\n"+ "andl $0x1ffffff, %%edx ;\n"+ "movl %%edx, 4(%%eax) ;\n"+ "movd %%xmm0, %%edx ;\n"+ "pshufd $0x39, %%xmm0, %%xmm0 ;\n"+ "shrdl $19, %%edx, %%ecx ;\n"+ "andl $0x3ffffff, %%ecx ;\n"+ "movl %%ecx, 8(%%eax) ;\n"+ "movd %%xmm0, %%ecx ;\n"+ "shrdl $13, %%ecx, %%edx ;\n"+ "andl $0x1ffffff, %%edx ;\n"+ "movl %%edx, 12(%%eax) ;\n"+ "movd %%xmm1, %%edx ;\n"+ "pshufd $0x39, %%xmm1, %%xmm1 ;\n"+ "shrl $6, %%ecx ;\n"+ "andl $0x3ffffff, %%ecx ;\n"+ "movl %%ecx, 16(%%eax) ;\n"+ "movl %%edx, %%ecx ;\n"+ "andl $0x1ffffff, %%edx ;\n"+ "movl %%edx, 20(%%eax) ;\n"+ "movd %%xmm1, %%edx ;\n"+ "pshufd $0x39, %%xmm1, %%xmm1 ;\n"+ "shrdl $25, %%edx, %%ecx ;\n"+ "andl $0x3ffffff, %%ecx ;\n"+ "movl %%ecx, 24(%%eax) ;\n"+ "movd %%xmm1, %%ecx ;\n"+ "pshufd $0x39, %%xmm1, %%xmm1 ;\n"+ "shrdl $19, %%ecx, %%edx ;\n"+ "andl $0x1ffffff, %%edx ;\n"+ "movl %%edx, 28(%%eax) ;\n"+ "movd %%xmm1, %%edx ;\n"+ "movd %%xmm1, %%edx ;\n"+ "shrdl $12, %%edx, %%ecx ;\n"+ "andl $0x3ffffff, %%ecx ;\n"+ "movl %%ecx, 32(%%eax) ;\n"+ "shrl $6, %%edx ;\n"+ "andl $0x1ffffff, %%edx ;\n"+ "xorl %%ecx, %%ecx ;\n"+ "movl %%edx, 36(%%eax) ;\n"+ "movl %%ecx, 40(%%eax) ;\n"+ "movl %%ecx, 44(%%eax) ;\n"+ "movdqa 0(%%eax), %%xmm0 ;\n"+ "movdqa 16(%%eax), %%xmm1 ;\n"+ "movdqa 32(%%eax), %%xmm2 ;\n"++ /* conditionally negate t2d */++ /* set up 2p in to 3/4 */+ "movl $0x7ffffda, %%ecx ;\n"+ "movl $0x3fffffe, %%edx ;\n"+ "movd %%ecx, %%xmm3 ;\n"+ "movd %%edx, %%xmm5 ;\n"+ "movl $0x7fffffe, %%ecx ;\n"+ "movd %%ecx, %%xmm4 ;\n"+ "punpckldq %%xmm5, %%xmm3 ;\n"+ "punpckldq %%xmm5, %%xmm4 ;\n"+ "punpcklqdq %%xmm4, %%xmm3 ;\n"+ "movdqa %%xmm4, %%xmm5 ;\n"+ "punpcklqdq %%xmm4, %%xmm4 ;\n"++ /* subtract and conditionally move */+ "movl %3, %%ecx ;\n"+ "sub $1, %%ecx ;\n"+ "movd %%ecx, %%xmm6 ;\n"+ "pshufd $0x00, %%xmm6, %%xmm6 ;\n"+ "movdqa %%xmm6, %%xmm7 ;\n"+ "psubd %%xmm0, %%xmm3 ;\n"+ "psubd %%xmm1, %%xmm4 ;\n"+ "psubd %%xmm2, %%xmm5 ;\n"+ "pand %%xmm6, %%xmm0 ;\n"+ "pand %%xmm6, %%xmm1 ;\n"+ "pand %%xmm6, %%xmm2 ;\n"+ "pandn %%xmm3, %%xmm6 ;\n"+ "movdqa %%xmm7, %%xmm3 ;\n"+ "pandn %%xmm4, %%xmm7 ;\n"+ "pandn %%xmm5, %%xmm3 ;\n"+ "por %%xmm6, %%xmm0 ;\n"+ "por %%xmm7, %%xmm1 ;\n"+ "por %%xmm3, %%xmm2 ;\n"++ /* store */+ "movdqa %%xmm0, 0(%%eax) ;\n"+ "movdqa %%xmm1, 16(%%eax) ;\n"+ "movdqa %%xmm2, 32(%%eax) ;\n"+ :+ : "m"(u), "r"(&table[pos * 8]), "m"(t), "m"(sign) /* %0 = u, %1 = table, %2 = t, %3 = sign */+ : "%eax", "%ecx", "%edx", "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7", "cc", "memory"+ );+}++#endif /* defined(ED25519_GCC_32BIT_SSE_CHOOSE) */+
+ cbits/ed25519/ed25519-donna-32bit-tables.h view
@@ -0,0 +1,61 @@+static const ge25519 ALIGN(16) ge25519_basepoint = {+ {0x0325d51a,0x018b5823,0x00f6592a,0x0104a92d,0x01a4b31d,0x01d6dc5c,0x027118fe,0x007fd814,0x013cd6e5,0x0085a4db},+ {0x02666658,0x01999999,0x00cccccc,0x01333333,0x01999999,0x00666666,0x03333333,0x00cccccc,0x02666666,0x01999999},+ {0x00000001,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000,0x00000000},+ {0x01b7dda3,0x01a2ace9,0x025eadbb,0x0003ba8a,0x0083c27e,0x00abe37d,0x01274732,0x00ccacdd,0x00fd78b7,0x019e1d7c}+};++/*+ d+*/++static const bignum25519 ALIGN(16) ge25519_ecd = {+ 0x035978a3,0x00d37284,0x03156ebd,0x006a0a0e,0x0001c029,0x0179e898,0x03a03cbb,0x01ce7198,0x02e2b6ff,0x01480db3+};++static const bignum25519 ALIGN(16) ge25519_ec2d = {+ 0x02b2f159,0x01a6e509,0x022add7a,0x00d4141d,0x00038052,0x00f3d130,0x03407977,0x019ce331,0x01c56dff,0x00901b67+};++/*+ sqrt(-1)+*/++static const bignum25519 ALIGN(16) ge25519_sqrtneg1 = {+ 0x020ea0b0,0x0186c9d2,0x008f189d,0x0035697f,0x00bd0c60,0x01fbd7a7,0x02804c9e,0x01e16569,0x0004fc1d,0x00ae0c92+};++static const ge25519_niels ALIGN(16) ge25519_niels_sliding_multiples[32] = {+ {{0x0340913e,0x000e4175,0x03d673a2,0x002e8a05,0x03f4e67c,0x008f8a09,0x00c21a34,0x004cf4b8,0x01298f81,0x0113f4be},{0x018c3b85,0x0124f1bd,0x01c325f7,0x0037dc60,0x033e4cb7,0x003d42c2,0x01a44c32,0x014ca4e1,0x03a33d4b,0x001f3e74},{0x037aaa68,0x00448161,0x0093d579,0x011e6556,0x009b67a0,0x0143598c,0x01bee5ee,0x00b50b43,0x0289f0c6,0x01bc45ed}},+ {{0x00fcd265,0x0047fa29,0x034faacc,0x01ef2e0d,0x00ef4d4f,0x014bd6bd,0x00f98d10,0x014c5026,0x007555bd,0x00aae456},{0x00ee9730,0x016c2a13,0x017155e4,0x01874432,0x00096a10,0x01016732,0x01a8014f,0x011e9823,0x01b9a80f,0x01e85938},{0x01d0d889,0x01a4cfc3,0x034c4295,0x0110e1ae,0x0162508c,0x00f2db4c,0x0072a2c6,0x0098da2e,0x02f12b9b,0x0168a09a}},+ {{0x0047d6ba,0x0060b0e9,0x0136eff2,0x008a5939,0x03540053,0x0064a087,0x02788e5c,0x00be7c67,0x033eb1b5,0x005529f9},{0x00a5bb33,0x00af1102,0x01a05442,0x001e3af7,0x02354123,0x00bfec44,0x01f5862d,0x00dd7ba3,0x03146e20,0x00a51733},{0x012a8285,0x00f6fc60,0x023f9797,0x003e85ee,0x009c3820,0x01bda72d,0x01b3858d,0x00d35683,0x0296b3bb,0x010eaaf9}},+ {{0x023221b1,0x01cb26aa,0x0074f74d,0x0099ddd1,0x01b28085,0x00192c3a,0x013b27c9,0x00fc13bd,0x01d2e531,0x0075bb75},{0x004ea3bf,0x00973425,0x001a4d63,0x01d59cee,0x01d1c0d4,0x00542e49,0x01294114,0x004fce36,0x029283c9,0x01186fa9},{0x01b8b3a2,0x00db7200,0x00935e30,0x003829f5,0x02cc0d7d,0x0077adf3,0x0220dd2c,0x0014ea53,0x01c6a0f9,0x01ea7eec}},+ {{0x039d8064,0x01885f80,0x00337e6d,0x01b7a902,0x02628206,0x015eb044,0x01e30473,0x0191f2d9,0x011fadc9,0x01270169},{0x02a8632f,0x0199e2a9,0x00d8b365,0x017a8de2,0x02994279,0x0086f5b5,0x0119e4e3,0x01eb39d6,0x0338add7,0x00d2e7b4},{0x0045af1b,0x013a2fe4,0x0245e0d6,0x014538ce,0x038bfe0f,0x01d4cf16,0x037e14c9,0x0160d55e,0x0021b008,0x01cf05c8}},+ {{0x01864348,0x01d6c092,0x0070262b,0x014bb844,0x00fb5acd,0x008deb95,0x003aaab5,0x00eff474,0x00029d5c,0x0062ad66},{0x02802ade,0x01c02122,0x01c4e5f7,0x00781181,0x039767fb,0x01703406,0x0342388b,0x01f5e227,0x022546d8,0x0109d6ab},{0x016089e9,0x00cb317f,0x00949b05,0x01099417,0x000c7ad2,0x011a8622,0x0088ccda,0x01290886,0x022b53df,0x00f71954}},+ {{0x027fbf93,0x01c04ecc,0x01ed6a0d,0x004cdbbb,0x02bbf3af,0x00ad5968,0x01591955,0x0094f3a2,0x02d17602,0x00099e20},{0x02007f6d,0x003088a8,0x03db77ee,0x00d5ade6,0x02fe12ce,0x0107ba07,0x0107097d,0x00482a6f,0x02ec346f,0x008d3f5f},{0x032ea378,0x0028465c,0x028e2a6c,0x018efc6e,0x0090df9a,0x01a7e533,0x039bfc48,0x010c745d,0x03daa097,0x0125ee9b}},+ {{0x028ccf0b,0x00f36191,0x021ac081,0x012154c8,0x034e0a6e,0x01b25192,0x00180403,0x01d7eea1,0x00218d05,0x010ed735},{0x03cfeaa0,0x01b300c4,0x008da499,0x0068c4e1,0x0219230a,0x01f2d4d0,0x02defd60,0x00e565b7,0x017f12de,0x018788a4},{0x03d0b516,0x009d8be6,0x03ddcbb3,0x0071b9fe,0x03ace2bd,0x01d64270,0x032d3ec9,0x01084065,0x0210ae4d,0x01447584}},+ {{0x0020de87,0x00e19211,0x01b68102,0x00b5ac97,0x022873c0,0x01942d25,0x01271394,0x0102073f,0x02fe2482,0x01c69ff9},{0x010e9d81,0x019dbbe5,0x0089f258,0x006e06b8,0x02951883,0x018f1248,0x019b3237,0x00bc7553,0x024ddb85,0x01b4c964},{0x01c8c854,0x0060ae29,0x01406d8e,0x01cff2f9,0x00cff451,0x01778d0c,0x03ac8c41,0x01552e59,0x036559ee,0x011d1b12}},+ {{0x00741147,0x0151b219,0x01092690,0x00e877e6,0x01f4d6bb,0x0072a332,0x01cd3b03,0x00dadff2,0x0097db5e,0x0086598d},{0x01c69a2b,0x01decf1b,0x02c2fa6e,0x013b7c4f,0x037beac8,0x013a16b5,0x028e7bda,0x01f6e8ac,0x01e34fe9,0x01726947},{0x01f10e67,0x003c73de,0x022b7ea2,0x010f32c2,0x03ff776a,0x00142277,0x01d38b88,0x00776138,0x03c60822,0x01201140}},+ {{0x0236d175,0x0008748e,0x03c6476d,0x013f4cdc,0x02eed02a,0x00838a47,0x032e7210,0x018bcbb3,0x00858de4,0x01dc7826},{0x00a37fc7,0x0127b40b,0x01957884,0x011d30ad,0x02816683,0x016e0e23,0x00b76be4,0x012db115,0x02516506,0x0154ce62},{0x00451edf,0x00bd749e,0x03997342,0x01cc2c4c,0x00eb6975,0x01a59508,0x03a516cf,0x00c228ef,0x0168ff5a,0x01697b47}},+ {{0x00527359,0x01783156,0x03afd75c,0x00ce56dc,0x00e4b970,0x001cabe9,0x029e0f6d,0x0188850c,0x0135fefd,0x00066d80},{0x02150e83,0x01448abf,0x02bb0232,0x012bf259,0x033c8268,0x00711e20,0x03fc148f,0x005e0e70,0x017d8bf9,0x0112b2e2},{0x02134b83,0x001a0517,0x0182c3cc,0x00792182,0x0313d799,0x001a3ed7,0x0344547e,0x01f24a0d,0x03de6ad2,0x00543127}},+ {{0x00dca868,0x00618f27,0x015a1709,0x00ddc38a,0x0320fd13,0x0036168d,0x0371ab06,0x01783fc7,0x0391e05f,0x01e29b5d},{0x01471138,0x00fca542,0x00ca31cf,0x01ca7bad,0x0175bfbc,0x01a708ad,0x03bce212,0x01244215,0x0075bb99,0x01acad68},{0x03a0b976,0x01dc12d1,0x011aab17,0x00aba0ba,0x029806cd,0x0142f590,0x018fd8ea,0x01a01545,0x03c4ad55,0x01c971ff}},+ {{0x00d098c0,0x000afdc7,0x006cd230,0x01276af3,0x03f905b2,0x0102994c,0x002eb8a4,0x015cfbeb,0x025f855f,0x01335518},{0x01cf99b2,0x0099c574,0x01a69c88,0x00881510,0x01cd4b54,0x0112109f,0x008abdc5,0x0074647a,0x0277cb1f,0x01e53324},{0x02ac5053,0x01b109b0,0x024b095e,0x016997b3,0x02f26bb6,0x00311021,0x00197885,0x01d0a55a,0x03b6fcc8,0x01c020d5}},+ {{0x02584a34,0x00e7eee0,0x03257a03,0x011e95a3,0x011ead91,0x00536202,0x00b1ce24,0x008516c6,0x03669d6d,0x004ea4a8},{0x00773f01,0x0019c9ce,0x019f6171,0x01d4afde,0x02e33323,0x01ad29b6,0x02ead1dc,0x01ed51a5,0x01851ad0,0x001bbdfa},{0x00577de5,0x00ddc730,0x038b9952,0x00f281ae,0x01d50390,0x0002e071,0x000780ec,0x010d448d,0x01f8a2af,0x00f0a5b7}},+ {{0x031f2541,0x00d34bae,0x0323ff9d,0x003a056d,0x02e25443,0x00a1ad05,0x00d1bee8,0x002f7f8e,0x03007477,0x002a24b1},{0x0114a713,0x01457e76,0x032255d5,0x01cc647f,0x02a4bdef,0x0153d730,0x00118bcf,0x00f755ff,0x013490c7,0x01ea674e},{0x02bda3e8,0x00bb490d,0x00f291ea,0x000abf40,0x01dea321,0x002f9ce0,0x00b2b193,0x00fa54b5,0x0128302f,0x00a19d8b}},+ {{0x022ef5bd,0x01638af3,0x038c6f8a,0x01a33a3d,0x039261b2,0x01bb89b8,0x010bcf9d,0x00cf42a9,0x023d6f17,0x01da1bca},{0x00e35b25,0x000d824f,0x0152e9cf,0x00ed935d,0x020b8460,0x01c7b83f,0x00c969e5,0x01a74198,0x0046a9d9,0x00cbc768},{0x01597c6a,0x0144a99b,0x00a57551,0x0018269c,0x023c464c,0x0009b022,0x00ee39e1,0x0114c7f2,0x038a9ad2,0x01584c17}},+ {{0x03b0c0d5,0x00b30a39,0x038a6ce4,0x01ded83a,0x01c277a6,0x01010a61,0x0346d3eb,0x018d995e,0x02f2c57c,0x000c286b},{0x0092aed1,0x0125e37b,0x027ca201,0x001a6b6b,0x03290f55,0x0047ba48,0x018d916c,0x01a59062,0x013e35d4,0x0002abb1},{0x003ad2aa,0x007ddcc0,0x00c10f76,0x0001590b,0x002cfca6,0x000ed23e,0x00ee4329,0x00900f04,0x01c24065,0x0082fa70}},+ {{0x02025e60,0x003912b8,0x0327041c,0x017e5ee5,0x02c0ecec,0x015a0d1c,0x02b1ce7c,0x0062220b,0x0145067e,0x01a5d931},{0x009673a6,0x00e1f609,0x00927c2a,0x016faa37,0x01650ef0,0x016f63b5,0x03cd40e1,0x003bc38f,0x0361f0ac,0x01d42acc},{0x02f81037,0x008ca0e8,0x017e23d1,0x011debfe,0x01bcbb68,0x002e2563,0x03e8add6,0x000816e5,0x03fb7075,0x0153e5ac}},+ {{0x02b11ecd,0x016bf185,0x008f22ef,0x00e7d2bb,0x0225d92e,0x00ece785,0x00508873,0x017e16f5,0x01fbe85d,0x01e39a0e},{0x01669279,0x017c810a,0x024941f5,0x0023ebeb,0x00eb7688,0x005760f1,0x02ca4146,0x0073cde7,0x0052bb75,0x00f5ffa7},{0x03b8856b,0x00cb7dcd,0x02f14e06,0x001820d0,0x01d74175,0x00e59e22,0x03fba550,0x00484641,0x03350088,0x01c3c9a3}},+ {{0x00dcf355,0x0104481c,0x0022e464,0x01f73fe7,0x00e03325,0x0152b698,0x02ef769a,0x00973663,0x00039b8c,0x0101395b},{0x01805f47,0x019160ec,0x03832cd0,0x008b06eb,0x03d4d717,0x004cb006,0x03a75b8f,0x013b3d30,0x01cfad88,0x01f034d1},{0x0078338a,0x01c7d2e3,0x02bc2b23,0x018b3f05,0x0280d9aa,0x005f3d44,0x0220a95a,0x00eeeb97,0x0362aaec,0x00835d51}},+ {{0x01b9f543,0x013fac4d,0x02ad93ae,0x018ef464,0x0212cdf7,0x01138ba9,0x011583ab,0x019c3d26,0x028790b4,0x00e2e2b6},{0x033bb758,0x01f0dbf1,0x03734bd1,0x0129b1e5,0x02b3950e,0x003bc922,0x01a53ec8,0x018c5532,0x006f3cee,0x00ae3c79},{0x0351f95d,0x0012a737,0x03d596b8,0x017658fe,0x00ace54a,0x008b66da,0x0036c599,0x012a63a2,0x032ceba1,0x00126bac}},+ {{0x03dcfe7e,0x019f4f18,0x01c81aee,0x0044bc2b,0x00827165,0x014f7c13,0x03b430f0,0x00bf96cc,0x020c8d62,0x01471997},{0x01fc7931,0x001f42dd,0x00ba754a,0x005bd339,0x003fbe49,0x016b3930,0x012a159c,0x009f83b0,0x03530f67,0x01e57b85},{0x02ecbd81,0x0096c294,0x01fce4a9,0x017701a5,0x0175047d,0x00ee4a31,0x012686e5,0x008efcd4,0x0349dc54,0x01b3466f}},+ {{0x02179ca3,0x01d86414,0x03f0afd0,0x00305964,0x015c7428,0x0099711e,0x015d5442,0x00c71014,0x01b40b2e,0x01d483cf},{0x01afc386,0x01984859,0x036203ff,0x0045c6a8,0x0020a8aa,0x00990baa,0x03313f10,0x007ceede,0x027429e4,0x017806ce},{0x039357a1,0x0142f8f4,0x0294a7b6,0x00eaccf4,0x0259edb3,0x01311e6e,0x004d326f,0x0130c346,0x01ccef3c,0x01c424b2}},+ {{0x0364918c,0x00148fc0,0x01638a7b,0x01a1fd5b,0x028ad013,0x0081e5a4,0x01a54f33,0x0174e101,0x003d0257,0x003a856c},{0x00051dcf,0x00f62b1d,0x0143d0ad,0x0042adbd,0x000fda90,0x01743ceb,0x0173e5e4,0x017bc749,0x03b7137a,0x0105ce96},{0x00f9218a,0x015b8c7c,0x00e102f8,0x0158d7e2,0x0169a5b8,0x00b2f176,0x018b347a,0x014cfef2,0x0214a4e3,0x017f1595}},+ {{0x006d7ae5,0x0195c371,0x0391e26d,0x0062a7c6,0x003f42ab,0x010dad86,0x024f8198,0x01542b2a,0x0014c454,0x0189c471},{0x0390988e,0x00b8799d,0x02e44912,0x0078e2e6,0x00075654,0x01923eed,0x0040cd72,0x00a37c76,0x0009d466,0x00c8531d},{0x02651770,0x00609d01,0x0286c265,0x0134513c,0x00ee9281,0x005d223c,0x035c760c,0x00679b36,0x0073ecb8,0x016faa50}},+ {{0x02c89be4,0x016fc244,0x02f38c83,0x018beb72,0x02b3ce2c,0x0097b065,0x034f017b,0x01dd957f,0x00148f61,0x00eab357},{0x0343d2f8,0x003398fc,0x011e368e,0x00782a1f,0x00019eea,0x00117b6f,0x0128d0d1,0x01a5e6bb,0x01944f1b,0x012b41e1},{0x03318301,0x018ecd30,0x0104d0b1,0x0038398b,0x03726701,0x019da88c,0x002d9769,0x00a7a681,0x031d9028,0x00ebfc32}},+ {{0x0220405e,0x0171face,0x02d930f8,0x017f6d6a,0x023b8c47,0x0129d5f9,0x02972456,0x00a3a524,0x006f4cd2,0x004439fa},{0x00c53505,0x0190c2fd,0x00507244,0x009930f9,0x01a39270,0x01d327c6,0x0399bc47,0x01cfe13d,0x0332bd99,0x00b33e7d},{0x0203f5e4,0x003627b5,0x00018af8,0x01478581,0x004a2218,0x002e3bb7,0x039384d0,0x0146ea62,0x020b9693,0x0017155f}},+ {{0x03c97e6f,0x00738c47,0x03b5db1f,0x01808fcf,0x01e8fc98,0x01ed25dd,0x01bf5045,0x00eb5c2b,0x0178fe98,0x01b85530},{0x01c20eb0,0x01aeec22,0x030b9eee,0x01b7d07e,0x0187e16f,0x014421fb,0x009fa731,0x0040b6d7,0x00841861,0x00a27fbc},{0x02d69abf,0x0058cdbf,0x0129f9ec,0x013c19ae,0x026c5b93,0x013a7fe7,0x004bb2ba,0x0063226f,0x002a95ca,0x01abefd9}},+ {{0x02f5d2c1,0x00378318,0x03734fb5,0x01258073,0x0263f0f6,0x01ad70e0,0x01b56d06,0x01188fbd,0x011b9503,0x0036d2e1},{0x0113a8cc,0x01541c3e,0x02ac2bbc,0x01d95867,0x01f47459,0x00ead489,0x00ab5b48,0x01db3b45,0x00edb801,0x004b024f},{0x00b8190f,0x011fe4c2,0x00621f82,0x010508d7,0x001a5a76,0x00c7d7fd,0x03aab96d,0x019cd9dc,0x019c6635,0x00ceaa1e}},+ {{0x01085cf2,0x01fd47af,0x03e3f5e1,0x004b3e99,0x01e3d46a,0x0060033c,0x015ff0a8,0x0150cdd8,0x029e8e21,0x008cf1bc},{0x00156cb1,0x003d623f,0x01a4f069,0x00d8d053,0x01b68aea,0x01ca5ab6,0x0316ae43,0x0134dc44,0x001c8d58,0x0084b343},{0x0318c781,0x0135441f,0x03a51a5e,0x019293f4,0x0048bb37,0x013d3341,0x0143151e,0x019c74e1,0x00911914,0x0076ddde}},+ {{0x006bc26f,0x00d48e5f,0x00227bbe,0x00629ea8,0x01ea5f8b,0x0179a330,0x027a1d5f,0x01bf8f8e,0x02d26e2a,0x00c6b65e},{0x01701ab6,0x0051da77,0x01b4b667,0x00a0ce7c,0x038ae37b,0x012ac852,0x03a0b0fe,0x0097c2bb,0x00a017d2,0x01eb8b2a},{0x0120b962,0x0005fb42,0x0353b6fd,0x0061f8ce,0x007a1463,0x01560a64,0x00e0a792,0x01907c92,0x013a6622,0x007b47f1}}+};
+ cbits/ed25519/ed25519-donna-64bit-tables.h view
@@ -0,0 +1,53 @@+static const ge25519 ge25519_basepoint = {+ {0x00062d608f25d51a,0x000412a4b4f6592a,0x00075b7171a4b31d,0x0001ff60527118fe,0x000216936d3cd6e5},+ {0x0006666666666658,0x0004cccccccccccc,0x0001999999999999,0x0003333333333333,0x0006666666666666},+ {0x0000000000000001,0x0000000000000000,0x0000000000000000,0x0000000000000000,0x0000000000000000},+ {0x00068ab3a5b7dda3,0x00000eea2a5eadbb,0x0002af8df483c27e,0x000332b375274732,0x00067875f0fd78b7}+};++static const bignum25519 ge25519_ecd = {+ 0x00034dca135978a3,0x0001a8283b156ebd,0x0005e7a26001c029,0x000739c663a03cbb,0x00052036cee2b6ff+};++static const bignum25519 ge25519_ec2d = {+ 0x00069b9426b2f159,0x00035050762add7a,0x0003cf44c0038052,0x0006738cc7407977,0x0002406d9dc56dff+};++static const bignum25519 ge25519_sqrtneg1 = {+ 0x00061b274a0ea0b0,0x0000d5a5fc8f189d,0x0007ef5e9cbd0c60,0x00078595a6804c9e,0x0002b8324804fc1d+};++static const ge25519_niels ge25519_niels_sliding_multiples[32] = {+ {{0x00003905d740913e,0x0000ba2817d673a2,0x00023e2827f4e67c,0x000133d2e0c21a34,0x00044fd2f9298f81},{0x000493c6f58c3b85,0x0000df7181c325f7,0x0000f50b0b3e4cb7,0x0005329385a44c32,0x00007cf9d3a33d4b},{0x00011205877aaa68,0x000479955893d579,0x00050d66309b67a0,0x0002d42d0dbee5ee,0x0006f117b689f0c6}},+ {{0x00011fe8a4fcd265,0x0007bcb8374faacc,0x00052f5af4ef4d4f,0x0005314098f98d10,0x0002ab91587555bd},{0x0005b0a84cee9730,0x00061d10c97155e4,0x0004059cc8096a10,0x00047a608da8014f,0x0007a164e1b9a80f},{0x0006933f0dd0d889,0x00044386bb4c4295,0x0003cb6d3162508c,0x00026368b872a2c6,0x0005a2826af12b9b}},+ {{0x000182c3a447d6ba,0x00022964e536eff2,0x000192821f540053,0x0002f9f19e788e5c,0x000154a7e73eb1b5},{0x0002bc4408a5bb33,0x000078ebdda05442,0x0002ffb112354123,0x000375ee8df5862d,0x0002945ccf146e20},{0x0003dbf1812a8285,0x0000fa17ba3f9797,0x0006f69cb49c3820,0x00034d5a0db3858d,0x00043aabe696b3bb}},+ {{0x00072c9aaa3221b1,0x000267774474f74d,0x000064b0e9b28085,0x0003f04ef53b27c9,0x0001d6edd5d2e531},{0x00025cd0944ea3bf,0x00075673b81a4d63,0x000150b925d1c0d4,0x00013f38d9294114,0x000461bea69283c9},{0x00036dc801b8b3a2,0x0000e0a7d4935e30,0x0001deb7cecc0d7d,0x000053a94e20dd2c,0x0007a9fbb1c6a0f9}},+ {{0x0006217e039d8064,0x0006dea408337e6d,0x00057ac112628206,0x000647cb65e30473,0x00049c05a51fadc9},{0x0006678aa6a8632f,0x0005ea3788d8b365,0x00021bd6d6994279,0x0007ace75919e4e3,0x00034b9ed338add7},{0x0004e8bf9045af1b,0x000514e33a45e0d6,0x0007533c5b8bfe0f,0x000583557b7e14c9,0x00073c172021b008}},+ {{0x00075b0249864348,0x00052ee11070262b,0x000237ae54fb5acd,0x0003bfd1d03aaab5,0x00018ab598029d5c},{0x000700848a802ade,0x0001e04605c4e5f7,0x0005c0d01b9767fb,0x0007d7889f42388b,0x0004275aae2546d8},{0x00032cc5fd6089e9,0x000426505c949b05,0x00046a18880c7ad2,0x0004a4221888ccda,0x0003dc65522b53df}},+ {{0x0007013b327fbf93,0x0001336eeded6a0d,0x0002b565a2bbf3af,0x000253ce89591955,0x0000267882d17602},{0x0000c222a2007f6d,0x000356b79bdb77ee,0x00041ee81efe12ce,0x000120a9bd07097d,0x000234fd7eec346f},{0x0000a119732ea378,0x00063bf1ba8e2a6c,0x00069f94cc90df9a,0x000431d1779bfc48,0x000497ba6fdaa097}},+ {{0x0003cd86468ccf0b,0x00048553221ac081,0x0006c9464b4e0a6e,0x00075fba84180403,0x00043b5cd4218d05},{0x0006cc0313cfeaa0,0x0001a313848da499,0x0007cb534219230a,0x00039596dedefd60,0x00061e22917f12de},{0x0002762f9bd0b516,0x0001c6e7fbddcbb3,0x00075909c3ace2bd,0x00042101972d3ec9,0x000511d61210ae4d}},+ {{0x000386484420de87,0x0002d6b25db68102,0x000650b4962873c0,0x0004081cfd271394,0x00071a7fe6fe2482},{0x000676ef950e9d81,0x0001b81ae089f258,0x00063c4922951883,0x0002f1d54d9b3237,0x0006d325924ddb85},{0x000182b8a5c8c854,0x00073fcbe5406d8e,0x0005de3430cff451,0x000554b967ac8c41,0x0004746c4b6559ee}},+ {{0x000546c864741147,0x0003a1df99092690,0x0001ca8cc9f4d6bb,0x00036b7fc9cd3b03,0x000219663497db5e},{0x00077b3c6dc69a2b,0x0004edf13ec2fa6e,0x0004e85ad77beac8,0x0007dba2b28e7bda,0x0005c9a51de34fe9},{0x0000f1cf79f10e67,0x00043ccb0a2b7ea2,0x00005089dfff776a,0x0001dd84e1d38b88,0x0004804503c60822}},+ {{0x000021d23a36d175,0x0004fd3373c6476d,0x00020e291eeed02a,0x00062f2ecf2e7210,0x000771e098858de4},{0x00049ed02ca37fc7,0x000474c2b5957884,0x0005b8388e816683,0x0004b6c454b76be4,0x000553398a516506},{0x0002f5d278451edf,0x000730b133997342,0x0006965420eb6975,0x000308a3bfa516cf,0x0005a5ed1d68ff5a}},+ {{0x0005e0c558527359,0x0003395b73afd75c,0x000072afa4e4b970,0x00062214329e0f6d,0x000019b60135fefd},{0x0005122afe150e83,0x0004afc966bb0232,0x0001c478833c8268,0x00017839c3fc148f,0x00044acb897d8bf9},{0x000068145e134b83,0x0001e4860982c3cc,0x000068fb5f13d799,0x0007c9283744547e,0x000150c49fde6ad2}},+ {{0x0001863c9cdca868,0x0003770e295a1709,0x0000d85a3720fd13,0x0005e0ff1f71ab06,0x00078a6d7791e05f},{0x0003f29509471138,0x000729eeb4ca31cf,0x00069c22b575bfbc,0x0004910857bce212,0x0006b2b5a075bb99},{0x0007704b47a0b976,0x0002ae82e91aab17,0x00050bd6429806cd,0x00068055158fd8ea,0x000725c7ffc4ad55}},+ {{0x00002bf71cd098c0,0x00049dabcc6cd230,0x00040a6533f905b2,0x000573efac2eb8a4,0x0004cd54625f855f},{0x00026715d1cf99b2,0x0002205441a69c88,0x000448427dcd4b54,0x0001d191e88abdc5,0x000794cc9277cb1f},{0x0006c426c2ac5053,0x0005a65ece4b095e,0x0000c44086f26bb6,0x0007429568197885,0x0007008357b6fcc8}},+ {{0x00039fbb82584a34,0x00047a568f257a03,0x00014d88091ead91,0x0002145b18b1ce24,0x00013a92a3669d6d},{0x0000672738773f01,0x000752bf799f6171,0x0006b4a6dae33323,0x0007b54696ead1dc,0x00006ef7e9851ad0},{0x0003771cc0577de5,0x0003ca06bb8b9952,0x00000b81c5d50390,0x00043512340780ec,0x0003c296ddf8a2af}},+ {{0x00034d2ebb1f2541,0x0000e815b723ff9d,0x000286b416e25443,0x0000bdfe38d1bee8,0x0000a892c7007477},{0x000515f9d914a713,0x00073191ff2255d5,0x00054f5cc2a4bdef,0x0003dd57fc118bcf,0x0007a99d393490c7},{0x0002ed2436bda3e8,0x00002afd00f291ea,0x0000be7381dea321,0x0003e952d4b2b193,0x000286762d28302f}},+ {{0x00058e2bce2ef5bd,0x00068ce8f78c6f8a,0x0006ee26e39261b2,0x00033d0aa50bcf9d,0x0007686f2a3d6f17},{0x000036093ce35b25,0x0003b64d7552e9cf,0x00071ee0fe0b8460,0x00069d0660c969e5,0x00032f1da046a9d9},{0x000512a66d597c6a,0x0000609a70a57551,0x000026c08a3c464c,0x0004531fc8ee39e1,0x000561305f8a9ad2}},+ {{0x0002cc28e7b0c0d5,0x00077b60eb8a6ce4,0x0004042985c277a6,0x000636657b46d3eb,0x000030a1aef2c57c},{0x0004978dec92aed1,0x000069adae7ca201,0x00011ee923290f55,0x00069641898d916c,0x00000aaec53e35d4},{0x0001f773003ad2aa,0x000005642cc10f76,0x00003b48f82cfca6,0x0002403c10ee4329,0x00020be9c1c24065}},+ {{0x0000e44ae2025e60,0x0005f97b9727041c,0x0005683472c0ecec,0x000188882eb1ce7c,0x00069764c545067e},{0x000387d8249673a6,0x0005bea8dc927c2a,0x0005bd8ed5650ef0,0x0000ef0e3fcd40e1,0x000750ab3361f0ac},{0x00023283a2f81037,0x000477aff97e23d1,0x0000b8958dbcbb68,0x0000205b97e8add6,0x00054f96b3fb7075}},+ {{0x0005afc616b11ecd,0x00039f4aec8f22ef,0x0003b39e1625d92e,0x0005f85bd4508873,0x00078e6839fbe85d},{0x0005f20429669279,0x00008fafae4941f5,0x00015d83c4eb7688,0x0001cf379eca4146,0x0003d7fe9c52bb75},{0x00032df737b8856b,0x0000608342f14e06,0x0003967889d74175,0x0001211907fba550,0x00070f268f350088}},+ {{0x0004112070dcf355,0x0007dcff9c22e464,0x00054ada60e03325,0x00025cd98eef769a,0x000404e56c039b8c},{0x00064583b1805f47,0x00022c1baf832cd0,0x000132c01bd4d717,0x0004ecf4c3a75b8f,0x0007c0d345cfad88},{0x00071f4b8c78338a,0x00062cfc16bc2b23,0x00017cf51280d9aa,0x0003bbae5e20a95a,0x00020d754762aaec}},+ {{0x0004feb135b9f543,0x00063bd192ad93ae,0x00044e2ea612cdf7,0x000670f4991583ab,0x00038b8ada8790b4},{0x0007c36fc73bb758,0x0004a6c797734bd1,0x0000ef248ab3950e,0x00063154c9a53ec8,0x0002b8f1e46f3cee},{0x00004a9cdf51f95d,0x0005d963fbd596b8,0x00022d9b68ace54a,0x0004a98e8836c599,0x000049aeb32ceba1}},+ {{0x00067d3c63dcfe7e,0x000112f0adc81aee,0x00053df04c827165,0x0002fe5b33b430f0,0x00051c665e0c8d62},{0x00007d0b75fc7931,0x00016f4ce4ba754a,0x0005ace4c03fbe49,0x00027e0ec12a159c,0x000795ee17530f67},{0x00025b0a52ecbd81,0x0005dc0695fce4a9,0x0003b928c575047d,0x00023bf3512686e5,0x0006cd19bf49dc54}},+ {{0x0007619052179ca3,0x0000c16593f0afd0,0x000265c4795c7428,0x00031c40515d5442,0x0007520f3db40b2e},{0x0006612165afc386,0x0001171aa36203ff,0x0002642ea820a8aa,0x0001f3bb7b313f10,0x0005e01b3a7429e4},{0x00050be3d39357a1,0x0003ab33d294a7b6,0x0004c479ba59edb3,0x0004c30d184d326f,0x00071092c9ccef3c}},+ {{0x0000523f0364918c,0x000687f56d638a7b,0x00020796928ad013,0x0005d38405a54f33,0x0000ea15b03d0257},{0x0003d8ac74051dcf,0x00010ab6f543d0ad,0x0005d0f3ac0fda90,0x0005ef1d2573e5e4,0x0004173a5bb7137a},{0x00056e31f0f9218a,0x0005635f88e102f8,0x0002cbc5d969a5b8,0x000533fbc98b347a,0x0005fc565614a4e3}},+ {{0x0006570dc46d7ae5,0x00018a9f1b91e26d,0x000436b6183f42ab,0x000550acaa4f8198,0x00062711c414c454},{0x0002e1e67790988e,0x0001e38b9ae44912,0x000648fbb4075654,0x00028df1d840cd72,0x0003214c7409d466},{0x0001827406651770,0x0004d144f286c265,0x00017488f0ee9281,0x00019e6cdb5c760c,0x0005bea94073ecb8}},+ {{0x0005bf0912c89be4,0x00062fadcaf38c83,0x00025ec196b3ce2c,0x00077655ff4f017b,0x0003aacd5c148f61},{0x0000ce63f343d2f8,0x0001e0a87d1e368e,0x000045edbc019eea,0x0006979aed28d0d1,0x0004ad0785944f1b},{0x00063b34c3318301,0x0000e0e62d04d0b1,0x000676a233726701,0x00029e9a042d9769,0x0003aff0cb1d9028}},+ {{0x0005c7eb3a20405e,0x0005fdb5aad930f8,0x0004a757e63b8c47,0x00028e9492972456,0x000110e7e86f4cd2},{0x0006430bf4c53505,0x000264c3e4507244,0x00074c9f19a39270,0x00073f84f799bc47,0x0002ccf9f732bd99},{0x0000d89ed603f5e4,0x00051e1604018af8,0x0000b8eedc4a2218,0x00051ba98b9384d0,0x00005c557e0b9693}},+ {{0x0001ce311fc97e6f,0x0006023f3fb5db1f,0x0007b49775e8fc98,0x0003ad70adbf5045,0x0006e154c178fe98},{0x0006bbb089c20eb0,0x0006df41fb0b9eee,0x00051087ed87e16f,0x000102db5c9fa731,0x000289fef0841861},{0x00016336fed69abf,0x0004f066b929f9ec,0x0004e9ff9e6c5b93,0x00018c89bc4bb2ba,0x0006afbf642a95ca}},+ {{0x0000de0c62f5d2c1,0x00049601cf734fb5,0x0006b5c38263f0f6,0x0004623ef5b56d06,0x0000db4b851b9503},{0x00055070f913a8cc,0x000765619eac2bbc,0x0003ab5225f47459,0x00076ced14ab5b48,0x00012c093cedb801},{0x00047f9308b8190f,0x000414235c621f82,0x00031f5ff41a5a76,0x0006736773aab96d,0x00033aa8799c6635}},+ {{0x0007f51ebd085cf2,0x00012cfa67e3f5e1,0x0001800cf1e3d46a,0x00054337615ff0a8,0x000233c6f29e8e21},{0x0000f588fc156cb1,0x000363414da4f069,0x0007296ad9b68aea,0x0004d3711316ae43,0x000212cd0c1c8d58},{0x0004d5107f18c781,0x00064a4fd3a51a5e,0x0004f4cd0448bb37,0x000671d38543151e,0x0001db7778911914}},+ {{0x000352397c6bc26f,0x00018a7aa0227bbe,0x0005e68cc1ea5f8b,0x0006fe3e3a7a1d5f,0x00031ad97ad26e2a},{0x00014769dd701ab6,0x00028339f1b4b667,0x0004ab214b8ae37b,0x00025f0aefa0b0fe,0x0007ae2ca8a017d2},{0x000017ed0920b962,0x000187e33b53b6fd,0x00055829907a1463,0x000641f248e0a792,0x0001ed1fc53a6622}}+};
+ cbits/ed25519/ed25519-donna-64bit-x86-32bit.h view
@@ -0,0 +1,435 @@+#if defined(ED25519_GCC_64BIT_32BIT_CHOOSE)++#define HAVE_GE25519_SCALARMULT_BASE_CHOOSE_NIELS++DONNA_NOINLINE static void+ge25519_scalarmult_base_choose_niels(ge25519_niels *t, const uint8_t table[256][96], uint32_t pos, signed char b) {+ int64_t breg = (int64_t)b;+ uint64_t sign = (uint64_t)breg >> 63;+ uint64_t mask = ~(sign - 1);+ uint64_t u = (breg + mask) ^ mask;++ __asm__ __volatile__ (+ /* ysubx+xaddy+t2d */+ "movq %0, %%rax ;\n"+ "movd %%rax, %%xmm14 ;\n"+ "pshufd $0x00, %%xmm14, %%xmm14 ;\n"+ "pxor %%xmm0, %%xmm0 ;\n"+ "pxor %%xmm1, %%xmm1 ;\n"+ "pxor %%xmm2, %%xmm2 ;\n"+ "pxor %%xmm3, %%xmm3 ;\n"+ "pxor %%xmm4, %%xmm4 ;\n"+ "pxor %%xmm5, %%xmm5 ;\n"++ /* 0 */+ "movq $0, %%rax ;\n"+ "movd %%rax, %%xmm15 ;\n"+ "pshufd $0x00, %%xmm15, %%xmm15 ;\n"+ "pcmpeqd %%xmm14, %%xmm15 ;\n"+ "movq $1, %%rax ;\n"+ "movd %%rax, %%xmm6 ;\n"+ "pxor %%xmm7, %%xmm7 ;\n"+ "pand %%xmm15, %%xmm6 ;\n"+ "pand %%xmm15, %%xmm7 ;\n"+ "por %%xmm6, %%xmm0 ;\n"+ "por %%xmm7, %%xmm1 ;\n"+ "por %%xmm6, %%xmm2 ;\n"+ "por %%xmm7, %%xmm3 ;\n"++ /* 1 */+ "movq $1, %%rax ;\n"+ "movd %%rax, %%xmm15 ;\n"+ "pshufd $0x00, %%xmm15, %%xmm15 ;\n"+ "pcmpeqd %%xmm14, %%xmm15 ;\n"+ "movdqa 0(%1), %%xmm6 ;\n"+ "movdqa 16(%1), %%xmm7 ;\n"+ "movdqa 32(%1), %%xmm8 ;\n"+ "movdqa 48(%1), %%xmm9 ;\n"+ "movdqa 64(%1), %%xmm10 ;\n"+ "movdqa 80(%1), %%xmm11 ;\n"+ "pand %%xmm15, %%xmm6 ;\n"+ "pand %%xmm15, %%xmm7 ;\n"+ "pand %%xmm15, %%xmm8 ;\n"+ "pand %%xmm15, %%xmm9 ;\n"+ "pand %%xmm15, %%xmm10 ;\n"+ "pand %%xmm15, %%xmm11 ;\n"+ "por %%xmm6, %%xmm0 ;\n"+ "por %%xmm7, %%xmm1 ;\n"+ "por %%xmm8, %%xmm2 ;\n"+ "por %%xmm9, %%xmm3 ;\n"+ "por %%xmm10, %%xmm4 ;\n"+ "por %%xmm11, %%xmm5 ;\n"++ /* 2 */+ "movq $2, %%rax ;\n"+ "movd %%rax, %%xmm15 ;\n"+ "pshufd $0x00, %%xmm15, %%xmm15 ;\n"+ "pcmpeqd %%xmm14, %%xmm15 ;\n"+ "movdqa 96(%1), %%xmm6 ;\n"+ "movdqa 112(%1), %%xmm7 ;\n"+ "movdqa 128(%1), %%xmm8 ;\n"+ "movdqa 144(%1), %%xmm9 ;\n"+ "movdqa 160(%1), %%xmm10 ;\n"+ "movdqa 176(%1), %%xmm11 ;\n"+ "pand %%xmm15, %%xmm6 ;\n"+ "pand %%xmm15, %%xmm7 ;\n"+ "pand %%xmm15, %%xmm8 ;\n"+ "pand %%xmm15, %%xmm9 ;\n"+ "pand %%xmm15, %%xmm10 ;\n"+ "pand %%xmm15, %%xmm11 ;\n"+ "por %%xmm6, %%xmm0 ;\n"+ "por %%xmm7, %%xmm1 ;\n"+ "por %%xmm8, %%xmm2 ;\n"+ "por %%xmm9, %%xmm3 ;\n"+ "por %%xmm10, %%xmm4 ;\n"+ "por %%xmm11, %%xmm5 ;\n"++ /* 3 */+ "movq $3, %%rax ;\n"+ "movd %%rax, %%xmm15 ;\n"+ "pshufd $0x00, %%xmm15, %%xmm15 ;\n"+ "pcmpeqd %%xmm14, %%xmm15 ;\n"+ "movdqa 192(%1), %%xmm6 ;\n"+ "movdqa 208(%1), %%xmm7 ;\n"+ "movdqa 224(%1), %%xmm8 ;\n"+ "movdqa 240(%1), %%xmm9 ;\n"+ "movdqa 256(%1), %%xmm10 ;\n"+ "movdqa 272(%1), %%xmm11 ;\n"+ "pand %%xmm15, %%xmm6 ;\n"+ "pand %%xmm15, %%xmm7 ;\n"+ "pand %%xmm15, %%xmm8 ;\n"+ "pand %%xmm15, %%xmm9 ;\n"+ "pand %%xmm15, %%xmm10 ;\n"+ "pand %%xmm15, %%xmm11 ;\n"+ "por %%xmm6, %%xmm0 ;\n"+ "por %%xmm7, %%xmm1 ;\n"+ "por %%xmm8, %%xmm2 ;\n"+ "por %%xmm9, %%xmm3 ;\n"+ "por %%xmm10, %%xmm4 ;\n"+ "por %%xmm11, %%xmm5 ;\n"++ /* 4 */+ "movq $4, %%rax ;\n"+ "movd %%rax, %%xmm15 ;\n"+ "pshufd $0x00, %%xmm15, %%xmm15 ;\n"+ "pcmpeqd %%xmm14, %%xmm15 ;\n"+ "movdqa 288(%1), %%xmm6 ;\n"+ "movdqa 304(%1), %%xmm7 ;\n"+ "movdqa 320(%1), %%xmm8 ;\n"+ "movdqa 336(%1), %%xmm9 ;\n"+ "movdqa 352(%1), %%xmm10 ;\n"+ "movdqa 368(%1), %%xmm11 ;\n"+ "pand %%xmm15, %%xmm6 ;\n"+ "pand %%xmm15, %%xmm7 ;\n"+ "pand %%xmm15, %%xmm8 ;\n"+ "pand %%xmm15, %%xmm9 ;\n"+ "pand %%xmm15, %%xmm10 ;\n"+ "pand %%xmm15, %%xmm11 ;\n"+ "por %%xmm6, %%xmm0 ;\n"+ "por %%xmm7, %%xmm1 ;\n"+ "por %%xmm8, %%xmm2 ;\n"+ "por %%xmm9, %%xmm3 ;\n"+ "por %%xmm10, %%xmm4 ;\n"+ "por %%xmm11, %%xmm5 ;\n"++ /* 5 */+ "movq $5, %%rax ;\n"+ "movd %%rax, %%xmm15 ;\n"+ "pshufd $0x00, %%xmm15, %%xmm15 ;\n"+ "pcmpeqd %%xmm14, %%xmm15 ;\n"+ "movdqa 384(%1), %%xmm6 ;\n"+ "movdqa 400(%1), %%xmm7 ;\n"+ "movdqa 416(%1), %%xmm8 ;\n"+ "movdqa 432(%1), %%xmm9 ;\n"+ "movdqa 448(%1), %%xmm10 ;\n"+ "movdqa 464(%1), %%xmm11 ;\n"+ "pand %%xmm15, %%xmm6 ;\n"+ "pand %%xmm15, %%xmm7 ;\n"+ "pand %%xmm15, %%xmm8 ;\n"+ "pand %%xmm15, %%xmm9 ;\n"+ "pand %%xmm15, %%xmm10 ;\n"+ "pand %%xmm15, %%xmm11 ;\n"+ "por %%xmm6, %%xmm0 ;\n"+ "por %%xmm7, %%xmm1 ;\n"+ "por %%xmm8, %%xmm2 ;\n"+ "por %%xmm9, %%xmm3 ;\n"+ "por %%xmm10, %%xmm4 ;\n"+ "por %%xmm11, %%xmm5 ;\n"++ /* 6 */+ "movq $6, %%rax ;\n"+ "movd %%rax, %%xmm15 ;\n"+ "pshufd $0x00, %%xmm15, %%xmm15 ;\n"+ "pcmpeqd %%xmm14, %%xmm15 ;\n"+ "movdqa 480(%1), %%xmm6 ;\n"+ "movdqa 496(%1), %%xmm7 ;\n"+ "movdqa 512(%1), %%xmm8 ;\n"+ "movdqa 528(%1), %%xmm9 ;\n"+ "movdqa 544(%1), %%xmm10 ;\n"+ "movdqa 560(%1), %%xmm11 ;\n"+ "pand %%xmm15, %%xmm6 ;\n"+ "pand %%xmm15, %%xmm7 ;\n"+ "pand %%xmm15, %%xmm8 ;\n"+ "pand %%xmm15, %%xmm9 ;\n"+ "pand %%xmm15, %%xmm10 ;\n"+ "pand %%xmm15, %%xmm11 ;\n"+ "por %%xmm6, %%xmm0 ;\n"+ "por %%xmm7, %%xmm1 ;\n"+ "por %%xmm8, %%xmm2 ;\n"+ "por %%xmm9, %%xmm3 ;\n"+ "por %%xmm10, %%xmm4 ;\n"+ "por %%xmm11, %%xmm5 ;\n"++ /* 7 */+ "movq $7, %%rax ;\n"+ "movd %%rax, %%xmm15 ;\n"+ "pshufd $0x00, %%xmm15, %%xmm15 ;\n"+ "pcmpeqd %%xmm14, %%xmm15 ;\n"+ "movdqa 576(%1), %%xmm6 ;\n"+ "movdqa 592(%1), %%xmm7 ;\n"+ "movdqa 608(%1), %%xmm8 ;\n"+ "movdqa 624(%1), %%xmm9 ;\n"+ "movdqa 640(%1), %%xmm10 ;\n"+ "movdqa 656(%1), %%xmm11 ;\n"+ "pand %%xmm15, %%xmm6 ;\n"+ "pand %%xmm15, %%xmm7 ;\n"+ "pand %%xmm15, %%xmm8 ;\n"+ "pand %%xmm15, %%xmm9 ;\n"+ "pand %%xmm15, %%xmm10 ;\n"+ "pand %%xmm15, %%xmm11 ;\n"+ "por %%xmm6, %%xmm0 ;\n"+ "por %%xmm7, %%xmm1 ;\n"+ "por %%xmm8, %%xmm2 ;\n"+ "por %%xmm9, %%xmm3 ;\n"+ "por %%xmm10, %%xmm4 ;\n"+ "por %%xmm11, %%xmm5 ;\n"++ /* 8 */+ "movq $8, %%rax ;\n"+ "movd %%rax, %%xmm15 ;\n"+ "pshufd $0x00, %%xmm15, %%xmm15 ;\n"+ "pcmpeqd %%xmm14, %%xmm15 ;\n"+ "movdqa 672(%1), %%xmm6 ;\n"+ "movdqa 688(%1), %%xmm7 ;\n"+ "movdqa 704(%1), %%xmm8 ;\n"+ "movdqa 720(%1), %%xmm9 ;\n"+ "movdqa 736(%1), %%xmm10 ;\n"+ "movdqa 752(%1), %%xmm11 ;\n"+ "pand %%xmm15, %%xmm6 ;\n"+ "pand %%xmm15, %%xmm7 ;\n"+ "pand %%xmm15, %%xmm8 ;\n"+ "pand %%xmm15, %%xmm9 ;\n"+ "pand %%xmm15, %%xmm10 ;\n"+ "pand %%xmm15, %%xmm11 ;\n"+ "por %%xmm6, %%xmm0 ;\n"+ "por %%xmm7, %%xmm1 ;\n"+ "por %%xmm8, %%xmm2 ;\n"+ "por %%xmm9, %%xmm3 ;\n"+ "por %%xmm10, %%xmm4 ;\n"+ "por %%xmm11, %%xmm5 ;\n"++ /* conditionally swap ysubx and xaddy */+ "movq %3, %%rax ;\n"+ "xorq $1, %%rax ;\n"+ "movd %%rax, %%xmm14 ;\n"+ "pxor %%xmm15, %%xmm15 ;\n"+ "pshufd $0x00, %%xmm14, %%xmm14 ;\n"+ "pxor %%xmm0, %%xmm2 ;\n"+ "pxor %%xmm1, %%xmm3 ;\n"+ "pcmpeqd %%xmm14, %%xmm15 ;\n"+ "movdqa %%xmm2, %%xmm6 ;\n"+ "movdqa %%xmm3, %%xmm7 ;\n"+ "pand %%xmm15, %%xmm6 ;\n"+ "pand %%xmm15, %%xmm7 ;\n"+ "pxor %%xmm6, %%xmm0 ;\n"+ "pxor %%xmm7, %%xmm1 ;\n"+ "pxor %%xmm0, %%xmm2 ;\n"+ "pxor %%xmm1, %%xmm3 ;\n"++ /* store ysubx */+ "xorq %%rax, %%rax ;\n"+ "movd %%xmm0, %%rcx ;\n"+ "movd %%xmm0, %%r8 ;\n"+ "movd %%xmm1, %%rsi ;\n"+ "pshufd $0xee, %%xmm0, %%xmm0 ;\n"+ "pshufd $0xee, %%xmm1, %%xmm1 ;\n"+ "movd %%xmm0, %%rdx ;\n"+ "movd %%xmm1, %%rdi ;\n"+ "shrdq $51, %%rdx, %%r8 ;\n"+ "shrdq $38, %%rsi, %%rdx ;\n"+ "shrdq $25, %%rdi, %%rsi ;\n"+ "shrq $12, %%rdi ;\n"+ "movq %%rcx, %%r9 ;\n"+ "movq %%r8, %%r10 ;\n"+ "movq %%rdx, %%r11 ;\n"+ "movq %%rsi, %%r12 ;\n"+ "movq %%rdi, %%r13 ;\n"+ "shrq $26, %%r9 ;\n"+ "shrq $26, %%r10 ;\n"+ "shrq $26, %%r11 ;\n"+ "shrq $26, %%r12 ;\n"+ "shrq $26, %%r13 ;\n"+ "andl $0x3ffffff, %%ecx ;\n"+ "andl $0x1ffffff, %%r9d ;\n"+ "andl $0x3ffffff, %%r8d ;\n"+ "andl $0x1ffffff, %%r10d ;\n"+ "andl $0x3ffffff, %%edx ;\n"+ "andl $0x1ffffff, %%r11d ;\n"+ "andl $0x3ffffff, %%esi ;\n"+ "andl $0x1ffffff, %%r12d ;\n"+ "andl $0x3ffffff, %%edi ;\n"+ "andl $0x1ffffff, %%r13d ;\n"+ "movl %%ecx, 0(%2) ;\n"+ "movl %%r9d, 4(%2) ;\n"+ "movl %%r8d, 8(%2) ;\n"+ "movl %%r10d, 12(%2) ;\n"+ "movl %%edx, 16(%2) ;\n"+ "movl %%r11d, 20(%2) ;\n"+ "movl %%esi, 24(%2) ;\n"+ "movl %%r12d, 28(%2) ;\n"+ "movl %%edi, 32(%2) ;\n"+ "movl %%r13d, 36(%2) ;\n"++ /* store xaddy */+ "movd %%xmm2, %%rcx ;\n"+ "movd %%xmm2, %%r8 ;\n"+ "movd %%xmm3, %%rsi ;\n"+ "pshufd $0xee, %%xmm2, %%xmm2 ;\n"+ "pshufd $0xee, %%xmm3, %%xmm3 ;\n"+ "movd %%xmm2, %%rdx ;\n"+ "movd %%xmm3, %%rdi ;\n"+ "shrdq $51, %%rdx, %%r8 ;\n"+ "shrdq $38, %%rsi, %%rdx ;\n"+ "shrdq $25, %%rdi, %%rsi ;\n"+ "shrq $12, %%rdi ;\n"+ "movq %%rcx, %%r9 ;\n"+ "movq %%r8, %%r10 ;\n"+ "movq %%rdx, %%r11 ;\n"+ "movq %%rsi, %%r12 ;\n"+ "movq %%rdi, %%r13 ;\n"+ "shrq $26, %%r9 ;\n"+ "shrq $26, %%r10 ;\n"+ "shrq $26, %%r11 ;\n"+ "shrq $26, %%r12 ;\n"+ "shrq $26, %%r13 ;\n"+ "andl $0x3ffffff, %%ecx ;\n"+ "andl $0x1ffffff, %%r9d ;\n"+ "andl $0x3ffffff, %%r8d ;\n"+ "andl $0x1ffffff, %%r10d ;\n"+ "andl $0x3ffffff, %%edx ;\n"+ "andl $0x1ffffff, %%r11d ;\n"+ "andl $0x3ffffff, %%esi ;\n"+ "andl $0x1ffffff, %%r12d ;\n"+ "andl $0x3ffffff, %%edi ;\n"+ "andl $0x1ffffff, %%r13d ;\n"+ "movl %%ecx, 40(%2) ;\n"+ "movl %%r9d, 44(%2) ;\n"+ "movl %%r8d, 48(%2) ;\n"+ "movl %%r10d, 52(%2) ;\n"+ "movl %%edx, 56(%2) ;\n"+ "movl %%r11d, 60(%2) ;\n"+ "movl %%esi, 64(%2) ;\n"+ "movl %%r12d, 68(%2) ;\n"+ "movl %%edi, 72(%2) ;\n"+ "movl %%r13d, 76(%2) ;\n"++ /* extract t2d */+ "xorq %%rax, %%rax ;\n"+ "movd %%xmm4, %%rcx ;\n"+ "movd %%xmm4, %%r8 ;\n"+ "movd %%xmm5, %%rsi ;\n"+ "pshufd $0xee, %%xmm4, %%xmm4 ;\n"+ "pshufd $0xee, %%xmm5, %%xmm5 ;\n"+ "movd %%xmm4, %%rdx ;\n"+ "movd %%xmm5, %%rdi ;\n"+ "shrdq $51, %%rdx, %%r8 ;\n"+ "shrdq $38, %%rsi, %%rdx ;\n"+ "shrdq $25, %%rdi, %%rsi ;\n"+ "shrq $12, %%rdi ;\n"+ "movq %%rcx, %%r9 ;\n"+ "movq %%r8, %%r10 ;\n"+ "movq %%rdx, %%r11 ;\n"+ "movq %%rsi, %%r12 ;\n"+ "movq %%rdi, %%r13 ;\n"+ "shrq $26, %%r9 ;\n"+ "shrq $26, %%r10 ;\n"+ "shrq $26, %%r11 ;\n"+ "shrq $26, %%r12 ;\n"+ "shrq $26, %%r13 ;\n"+ "andl $0x3ffffff, %%ecx ;\n"+ "andl $0x1ffffff, %%r9d ;\n"+ "andl $0x3ffffff, %%r8d ;\n"+ "andl $0x1ffffff, %%r10d ;\n"+ "andl $0x3ffffff, %%edx ;\n"+ "andl $0x1ffffff, %%r11d ;\n"+ "andl $0x3ffffff, %%esi ;\n"+ "andl $0x1ffffff, %%r12d ;\n"+ "andl $0x3ffffff, %%edi ;\n"+ "andl $0x1ffffff, %%r13d ;\n"+ "movd %%ecx, %%xmm0 ;\n"+ "movd %%r9d, %%xmm4 ;\n"+ "movd %%r8d, %%xmm8 ;\n"+ "movd %%r10d, %%xmm3 ;\n"+ "movd %%edx, %%xmm1 ;\n"+ "movd %%r11d, %%xmm5 ;\n"+ "movd %%esi, %%xmm6 ;\n"+ "movd %%r12d, %%xmm7 ;\n"+ "movd %%edi, %%xmm2 ;\n"+ "movd %%r13d, %%xmm9 ;\n"+ "punpckldq %%xmm4, %%xmm0 ;\n"+ "punpckldq %%xmm3, %%xmm8 ;\n"+ "punpckldq %%xmm5, %%xmm1 ;\n"+ "punpckldq %%xmm7, %%xmm6 ;\n"+ "punpckldq %%xmm9, %%xmm2 ;\n"+ "punpcklqdq %%xmm8, %%xmm0 ;\n"+ "punpcklqdq %%xmm6, %%xmm1 ;\n"++ /* set up 2p in to 3/4 */+ "movl $0x7ffffda, %%ecx ;\n"+ "movl $0x3fffffe, %%edx ;\n"+ "movl $0x7fffffe, %%eax ;\n"+ "movd %%ecx, %%xmm3 ;\n"+ "movd %%edx, %%xmm5 ;\n"+ "movd %%eax, %%xmm4 ;\n"+ "punpckldq %%xmm5, %%xmm3 ;\n"+ "punpckldq %%xmm5, %%xmm4 ;\n"+ "punpcklqdq %%xmm4, %%xmm3 ;\n"+ "movdqa %%xmm4, %%xmm5 ;\n"+ "punpcklqdq %%xmm4, %%xmm4 ;\n"++ /* subtract and conditionally move */+ "movl %3, %%ecx ;\n"+ "sub $1, %%ecx ;\n"+ "movd %%ecx, %%xmm6 ;\n"+ "pshufd $0x00, %%xmm6, %%xmm6 ;\n"+ "movdqa %%xmm6, %%xmm7 ;\n"+ "psubd %%xmm0, %%xmm3 ;\n"+ "psubd %%xmm1, %%xmm4 ;\n"+ "psubd %%xmm2, %%xmm5 ;\n"+ "pand %%xmm6, %%xmm0 ;\n"+ "pand %%xmm6, %%xmm1 ;\n"+ "pand %%xmm6, %%xmm2 ;\n"+ "pandn %%xmm3, %%xmm6 ;\n"+ "movdqa %%xmm7, %%xmm3 ;\n"+ "pandn %%xmm4, %%xmm7 ;\n"+ "pandn %%xmm5, %%xmm3 ;\n"+ "por %%xmm6, %%xmm0 ;\n"+ "por %%xmm7, %%xmm1 ;\n"+ "por %%xmm3, %%xmm2 ;\n"++ /* store t2d */+ "movdqa %%xmm0, 80(%2) ;\n"+ "movdqa %%xmm1, 96(%2) ;\n"+ "movd %%xmm2, %%rax ;\n"+ "movq %%rax, 112(%2) ;\n"+ :+ : "m"(u), "r"(&table[pos * 8]), "r"(t), "m"(sign) /* %0 = u, %1 = table, %2 = t, %3 = sign */+ :+ "%rax", "%rcx", "%rdx", "%rdi", "%rsi", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", + "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7", "%xmm8", "%xmm9", "%xmm10", "%xmm11", "%xmm14", "%xmm14",+ "cc", "memory"+ );+}++#endif /* defined(ED25519_GCC_64BIT_32BIT_CHOOSE) */+
+ cbits/ed25519/ed25519-donna-64bit-x86.h view
@@ -0,0 +1,351 @@+#if defined(ED25519_GCC_64BIT_X86_CHOOSE)++#define HAVE_GE25519_SCALARMULT_BASE_CHOOSE_NIELS++DONNA_NOINLINE static void+ge25519_scalarmult_base_choose_niels(ge25519_niels *t, const uint8_t table[256][96], uint32_t pos, signed char b) {+ int64_t breg = (int64_t)b;+ uint64_t sign = (uint64_t)breg >> 63;+ uint64_t mask = ~(sign - 1);+ uint64_t u = (breg + mask) ^ mask;++ __asm__ __volatile__ (+ /* ysubx+xaddy+t2d */+ "movq %0, %%rax ;\n"+ "movd %%rax, %%xmm14 ;\n"+ "pshufd $0x00, %%xmm14, %%xmm14 ;\n"+ "pxor %%xmm0, %%xmm0 ;\n"+ "pxor %%xmm1, %%xmm1 ;\n"+ "pxor %%xmm2, %%xmm2 ;\n"+ "pxor %%xmm3, %%xmm3 ;\n"+ "pxor %%xmm4, %%xmm4 ;\n"+ "pxor %%xmm5, %%xmm5 ;\n"++ /* 0 */+ "movq $0, %%rax ;\n"+ "movd %%rax, %%xmm15 ;\n"+ "pshufd $0x00, %%xmm15, %%xmm15 ;\n"+ "pcmpeqd %%xmm14, %%xmm15 ;\n"+ "movq $1, %%rax ;\n"+ "movd %%rax, %%xmm6 ;\n"+ "pxor %%xmm7, %%xmm7 ;\n"+ "pand %%xmm15, %%xmm6 ;\n"+ "pand %%xmm15, %%xmm7 ;\n"+ "por %%xmm6, %%xmm0 ;\n"+ "por %%xmm7, %%xmm1 ;\n"+ "por %%xmm6, %%xmm2 ;\n"+ "por %%xmm7, %%xmm3 ;\n"++ /* 1 */+ "movq $1, %%rax ;\n"+ "movd %%rax, %%xmm15 ;\n"+ "pshufd $0x00, %%xmm15, %%xmm15 ;\n"+ "pcmpeqd %%xmm14, %%xmm15 ;\n"+ "movdqa 0(%1), %%xmm6 ;\n"+ "movdqa 16(%1), %%xmm7 ;\n"+ "movdqa 32(%1), %%xmm8 ;\n"+ "movdqa 48(%1), %%xmm9 ;\n"+ "movdqa 64(%1), %%xmm10 ;\n"+ "movdqa 80(%1), %%xmm11 ;\n"+ "pand %%xmm15, %%xmm6 ;\n"+ "pand %%xmm15, %%xmm7 ;\n"+ "pand %%xmm15, %%xmm8 ;\n"+ "pand %%xmm15, %%xmm9 ;\n"+ "pand %%xmm15, %%xmm10 ;\n"+ "pand %%xmm15, %%xmm11 ;\n"+ "por %%xmm6, %%xmm0 ;\n"+ "por %%xmm7, %%xmm1 ;\n"+ "por %%xmm8, %%xmm2 ;\n"+ "por %%xmm9, %%xmm3 ;\n"+ "por %%xmm10, %%xmm4 ;\n"+ "por %%xmm11, %%xmm5 ;\n"++ /* 2 */+ "movq $2, %%rax ;\n"+ "movd %%rax, %%xmm15 ;\n"+ "pshufd $0x00, %%xmm15, %%xmm15 ;\n"+ "pcmpeqd %%xmm14, %%xmm15 ;\n"+ "movdqa 96(%1), %%xmm6 ;\n"+ "movdqa 112(%1), %%xmm7 ;\n"+ "movdqa 128(%1), %%xmm8 ;\n"+ "movdqa 144(%1), %%xmm9 ;\n"+ "movdqa 160(%1), %%xmm10 ;\n"+ "movdqa 176(%1), %%xmm11 ;\n"+ "pand %%xmm15, %%xmm6 ;\n"+ "pand %%xmm15, %%xmm7 ;\n"+ "pand %%xmm15, %%xmm8 ;\n"+ "pand %%xmm15, %%xmm9 ;\n"+ "pand %%xmm15, %%xmm10 ;\n"+ "pand %%xmm15, %%xmm11 ;\n"+ "por %%xmm6, %%xmm0 ;\n"+ "por %%xmm7, %%xmm1 ;\n"+ "por %%xmm8, %%xmm2 ;\n"+ "por %%xmm9, %%xmm3 ;\n"+ "por %%xmm10, %%xmm4 ;\n"+ "por %%xmm11, %%xmm5 ;\n"++ /* 3 */+ "movq $3, %%rax ;\n"+ "movd %%rax, %%xmm15 ;\n"+ "pshufd $0x00, %%xmm15, %%xmm15 ;\n"+ "pcmpeqd %%xmm14, %%xmm15 ;\n"+ "movdqa 192(%1), %%xmm6 ;\n"+ "movdqa 208(%1), %%xmm7 ;\n"+ "movdqa 224(%1), %%xmm8 ;\n"+ "movdqa 240(%1), %%xmm9 ;\n"+ "movdqa 256(%1), %%xmm10 ;\n"+ "movdqa 272(%1), %%xmm11 ;\n"+ "pand %%xmm15, %%xmm6 ;\n"+ "pand %%xmm15, %%xmm7 ;\n"+ "pand %%xmm15, %%xmm8 ;\n"+ "pand %%xmm15, %%xmm9 ;\n"+ "pand %%xmm15, %%xmm10 ;\n"+ "pand %%xmm15, %%xmm11 ;\n"+ "por %%xmm6, %%xmm0 ;\n"+ "por %%xmm7, %%xmm1 ;\n"+ "por %%xmm8, %%xmm2 ;\n"+ "por %%xmm9, %%xmm3 ;\n"+ "por %%xmm10, %%xmm4 ;\n"+ "por %%xmm11, %%xmm5 ;\n"++ /* 4 */+ "movq $4, %%rax ;\n"+ "movd %%rax, %%xmm15 ;\n"+ "pshufd $0x00, %%xmm15, %%xmm15 ;\n"+ "pcmpeqd %%xmm14, %%xmm15 ;\n"+ "movdqa 288(%1), %%xmm6 ;\n"+ "movdqa 304(%1), %%xmm7 ;\n"+ "movdqa 320(%1), %%xmm8 ;\n"+ "movdqa 336(%1), %%xmm9 ;\n"+ "movdqa 352(%1), %%xmm10 ;\n"+ "movdqa 368(%1), %%xmm11 ;\n"+ "pand %%xmm15, %%xmm6 ;\n"+ "pand %%xmm15, %%xmm7 ;\n"+ "pand %%xmm15, %%xmm8 ;\n"+ "pand %%xmm15, %%xmm9 ;\n"+ "pand %%xmm15, %%xmm10 ;\n"+ "pand %%xmm15, %%xmm11 ;\n"+ "por %%xmm6, %%xmm0 ;\n"+ "por %%xmm7, %%xmm1 ;\n"+ "por %%xmm8, %%xmm2 ;\n"+ "por %%xmm9, %%xmm3 ;\n"+ "por %%xmm10, %%xmm4 ;\n"+ "por %%xmm11, %%xmm5 ;\n"++ /* 5 */+ "movq $5, %%rax ;\n"+ "movd %%rax, %%xmm15 ;\n"+ "pshufd $0x00, %%xmm15, %%xmm15 ;\n"+ "pcmpeqd %%xmm14, %%xmm15 ;\n"+ "movdqa 384(%1), %%xmm6 ;\n"+ "movdqa 400(%1), %%xmm7 ;\n"+ "movdqa 416(%1), %%xmm8 ;\n"+ "movdqa 432(%1), %%xmm9 ;\n"+ "movdqa 448(%1), %%xmm10 ;\n"+ "movdqa 464(%1), %%xmm11 ;\n"+ "pand %%xmm15, %%xmm6 ;\n"+ "pand %%xmm15, %%xmm7 ;\n"+ "pand %%xmm15, %%xmm8 ;\n"+ "pand %%xmm15, %%xmm9 ;\n"+ "pand %%xmm15, %%xmm10 ;\n"+ "pand %%xmm15, %%xmm11 ;\n"+ "por %%xmm6, %%xmm0 ;\n"+ "por %%xmm7, %%xmm1 ;\n"+ "por %%xmm8, %%xmm2 ;\n"+ "por %%xmm9, %%xmm3 ;\n"+ "por %%xmm10, %%xmm4 ;\n"+ "por %%xmm11, %%xmm5 ;\n"++ /* 6 */+ "movq $6, %%rax ;\n"+ "movd %%rax, %%xmm15 ;\n"+ "pshufd $0x00, %%xmm15, %%xmm15 ;\n"+ "pcmpeqd %%xmm14, %%xmm15 ;\n"+ "movdqa 480(%1), %%xmm6 ;\n"+ "movdqa 496(%1), %%xmm7 ;\n"+ "movdqa 512(%1), %%xmm8 ;\n"+ "movdqa 528(%1), %%xmm9 ;\n"+ "movdqa 544(%1), %%xmm10 ;\n"+ "movdqa 560(%1), %%xmm11 ;\n"+ "pand %%xmm15, %%xmm6 ;\n"+ "pand %%xmm15, %%xmm7 ;\n"+ "pand %%xmm15, %%xmm8 ;\n"+ "pand %%xmm15, %%xmm9 ;\n"+ "pand %%xmm15, %%xmm10 ;\n"+ "pand %%xmm15, %%xmm11 ;\n"+ "por %%xmm6, %%xmm0 ;\n"+ "por %%xmm7, %%xmm1 ;\n"+ "por %%xmm8, %%xmm2 ;\n"+ "por %%xmm9, %%xmm3 ;\n"+ "por %%xmm10, %%xmm4 ;\n"+ "por %%xmm11, %%xmm5 ;\n"++ /* 7 */+ "movq $7, %%rax ;\n"+ "movd %%rax, %%xmm15 ;\n"+ "pshufd $0x00, %%xmm15, %%xmm15 ;\n"+ "pcmpeqd %%xmm14, %%xmm15 ;\n"+ "movdqa 576(%1), %%xmm6 ;\n"+ "movdqa 592(%1), %%xmm7 ;\n"+ "movdqa 608(%1), %%xmm8 ;\n"+ "movdqa 624(%1), %%xmm9 ;\n"+ "movdqa 640(%1), %%xmm10 ;\n"+ "movdqa 656(%1), %%xmm11 ;\n"+ "pand %%xmm15, %%xmm6 ;\n"+ "pand %%xmm15, %%xmm7 ;\n"+ "pand %%xmm15, %%xmm8 ;\n"+ "pand %%xmm15, %%xmm9 ;\n"+ "pand %%xmm15, %%xmm10 ;\n"+ "pand %%xmm15, %%xmm11 ;\n"+ "por %%xmm6, %%xmm0 ;\n"+ "por %%xmm7, %%xmm1 ;\n"+ "por %%xmm8, %%xmm2 ;\n"+ "por %%xmm9, %%xmm3 ;\n"+ "por %%xmm10, %%xmm4 ;\n"+ "por %%xmm11, %%xmm5 ;\n"++ /* 8 */+ "movq $8, %%rax ;\n"+ "movd %%rax, %%xmm15 ;\n"+ "pshufd $0x00, %%xmm15, %%xmm15 ;\n"+ "pcmpeqd %%xmm14, %%xmm15 ;\n"+ "movdqa 672(%1), %%xmm6 ;\n"+ "movdqa 688(%1), %%xmm7 ;\n"+ "movdqa 704(%1), %%xmm8 ;\n"+ "movdqa 720(%1), %%xmm9 ;\n"+ "movdqa 736(%1), %%xmm10 ;\n"+ "movdqa 752(%1), %%xmm11 ;\n"+ "pand %%xmm15, %%xmm6 ;\n"+ "pand %%xmm15, %%xmm7 ;\n"+ "pand %%xmm15, %%xmm8 ;\n"+ "pand %%xmm15, %%xmm9 ;\n"+ "pand %%xmm15, %%xmm10 ;\n"+ "pand %%xmm15, %%xmm11 ;\n"+ "por %%xmm6, %%xmm0 ;\n"+ "por %%xmm7, %%xmm1 ;\n"+ "por %%xmm8, %%xmm2 ;\n"+ "por %%xmm9, %%xmm3 ;\n"+ "por %%xmm10, %%xmm4 ;\n"+ "por %%xmm11, %%xmm5 ;\n"++ /* conditionally swap ysubx and xaddy */+ "movq %3, %%rax ;\n"+ "xorq $1, %%rax ;\n"+ "movd %%rax, %%xmm14 ;\n"+ "pxor %%xmm15, %%xmm15 ;\n"+ "pshufd $0x00, %%xmm14, %%xmm14 ;\n"+ "pxor %%xmm0, %%xmm2 ;\n"+ "pxor %%xmm1, %%xmm3 ;\n"+ "pcmpeqd %%xmm14, %%xmm15 ;\n"+ "movdqa %%xmm2, %%xmm6 ;\n"+ "movdqa %%xmm3, %%xmm7 ;\n"+ "pand %%xmm15, %%xmm6 ;\n"+ "pand %%xmm15, %%xmm7 ;\n"+ "pxor %%xmm6, %%xmm0 ;\n"+ "pxor %%xmm7, %%xmm1 ;\n"+ "pxor %%xmm0, %%xmm2 ;\n"+ "pxor %%xmm1, %%xmm3 ;\n"++ /* store ysubx */+ "movq $0x7ffffffffffff, %%rax ;\n"+ "movd %%xmm0, %%rcx ;\n"+ "movd %%xmm0, %%r8 ;\n"+ "movd %%xmm1, %%rsi ;\n"+ "pshufd $0xee, %%xmm0, %%xmm0 ;\n"+ "pshufd $0xee, %%xmm1, %%xmm1 ;\n"+ "movd %%xmm0, %%rdx ;\n"+ "movd %%xmm1, %%rdi ;\n"+ "shrdq $51, %%rdx, %%r8 ;\n"+ "shrdq $38, %%rsi, %%rdx ;\n"+ "shrdq $25, %%rdi, %%rsi ;\n"+ "shrq $12, %%rdi ;\n"+ "andq %%rax, %%rcx ;\n"+ "andq %%rax, %%r8 ;\n"+ "andq %%rax, %%rdx ;\n"+ "andq %%rax, %%rsi ;\n"+ "andq %%rax, %%rdi ;\n"+ "movq %%rcx, 0(%2) ;\n"+ "movq %%r8, 8(%2) ;\n"+ "movq %%rdx, 16(%2) ;\n"+ "movq %%rsi, 24(%2) ;\n"+ "movq %%rdi, 32(%2) ;\n"++ /* store xaddy */+ "movq $0x7ffffffffffff, %%rax ;\n"+ "movd %%xmm2, %%rcx ;\n"+ "movd %%xmm2, %%r8 ;\n"+ "movd %%xmm3, %%rsi ;\n"+ "pshufd $0xee, %%xmm2, %%xmm2 ;\n"+ "pshufd $0xee, %%xmm3, %%xmm3 ;\n"+ "movd %%xmm2, %%rdx ;\n"+ "movd %%xmm3, %%rdi ;\n"+ "shrdq $51, %%rdx, %%r8 ;\n"+ "shrdq $38, %%rsi, %%rdx ;\n"+ "shrdq $25, %%rdi, %%rsi ;\n"+ "shrq $12, %%rdi ;\n"+ "andq %%rax, %%rcx ;\n"+ "andq %%rax, %%r8 ;\n"+ "andq %%rax, %%rdx ;\n"+ "andq %%rax, %%rsi ;\n"+ "andq %%rax, %%rdi ;\n"+ "movq %%rcx, 40(%2) ;\n"+ "movq %%r8, 48(%2) ;\n"+ "movq %%rdx, 56(%2) ;\n"+ "movq %%rsi, 64(%2) ;\n"+ "movq %%rdi, 72(%2) ;\n"++ /* extract t2d */+ "movq $0x7ffffffffffff, %%rax ;\n"+ "movd %%xmm4, %%rcx ;\n"+ "movd %%xmm4, %%r8 ;\n"+ "movd %%xmm5, %%rsi ;\n"+ "pshufd $0xee, %%xmm4, %%xmm4 ;\n"+ "pshufd $0xee, %%xmm5, %%xmm5 ;\n"+ "movd %%xmm4, %%rdx ;\n"+ "movd %%xmm5, %%rdi ;\n"+ "shrdq $51, %%rdx, %%r8 ;\n"+ "shrdq $38, %%rsi, %%rdx ;\n"+ "shrdq $25, %%rdi, %%rsi ;\n"+ "shrq $12, %%rdi ;\n"+ "andq %%rax, %%rcx ;\n"+ "andq %%rax, %%r8 ;\n"+ "andq %%rax, %%rdx ;\n"+ "andq %%rax, %%rsi ;\n"+ "andq %%rax, %%rdi ;\n"++ /* conditionally negate t2d */+ "movq %3, %%rax ;\n"+ "movq $0xfffffffffffda, %%r9 ;\n"+ "movq $0xffffffffffffe, %%r10 ;\n"+ "movq %%r10, %%r11 ;\n"+ "movq %%r10, %%r12 ;\n"+ "movq %%r10, %%r13 ;\n"+ "subq %%rcx, %%r9 ;\n"+ "subq %%r8, %%r10 ;\n"+ "subq %%rdx, %%r11 ;\n"+ "subq %%rsi, %%r12 ;\n"+ "subq %%rdi, %%r13 ;\n"+ "cmpq $1, %%rax ;\n"+ "cmove %%r9, %%rcx ;\n"+ "cmove %%r10, %%r8 ;\n"+ "cmove %%r11, %%rdx ;\n"+ "cmove %%r12, %%rsi ;\n"+ "cmove %%r13, %%rdi ;\n"++ /* store t2d */+ "movq %%rcx, 80(%2) ;\n"+ "movq %%r8, 88(%2) ;\n"+ "movq %%rdx, 96(%2) ;\n"+ "movq %%rsi, 104(%2) ;\n"+ "movq %%rdi, 112(%2) ;\n"+ :+ : "m"(u), "r"(&table[pos * 8]), "r"(t), "m"(sign) /* %0 = u, %1 = table, %2 = t, %3 = sign */+ :+ "%rax", "%rcx", "%rdx", "%rdi", "%rsi", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", + "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7", "%xmm8", "%xmm9", "%xmm10", "%xmm11", "%xmm14", "%xmm14",+ "cc", "memory"+ );+}++#endif /* defined(ED25519_GCC_64BIT_X86_CHOOSE) */+
+ cbits/ed25519/ed25519-donna-basepoint-table.h view
@@ -0,0 +1,259 @@+/* multiples of the base point in packed {ysubx, xaddy, t2d} form */+static const uint8_t ALIGN(16) ge25519_niels_base_multiples[256][96] = {+ {0x3e,0x91,0x40,0xd7,0x05,0x39,0x10,0x9d,0xb3,0xbe,0x40,0xd1,0x05,0x9f,0x39,0xfd,0x09,0x8a,0x8f,0x68,0x34,0x84,0xc1,0xa5,0x67,0x12,0xf8,0x98,0x92,0x2f,0xfd,0x44,0x85,0x3b,0x8c,0xf5,0xc6,0x93,0xbc,0x2f,0x19,0x0e,0x8c,0xfb,0xc6,0x2d,0x93,0xcf,0xc2,0x42,0x3d,0x64,0x98,0x48,0x0b,0x27,0x65,0xba,0xd4,0x33,0x3a,0x9d,0xcf,0x07,0x59,0xbb,0x6f,0x4b,0x67,0x15,0xbd,0xdb,0xea,0xa5,0xa2,0xee,0x00,0x3f,0xe1,0x41,0xfa,0xc6,0x57,0xc9,0x1c,0x9d,0xd4,0xcd,0xca,0xec,0x16,0xaf,0x1f,0xbe,0x0e,0x4f},+ {0xa8,0xd5,0xb4,0x42,0x60,0xa5,0x99,0x8a,0xf6,0xac,0x60,0x4e,0x0c,0x81,0x2b,0x8f,0xaa,0x37,0x6e,0xb1,0x6b,0x23,0x9e,0xe0,0x55,0x25,0xc9,0x69,0xa6,0x95,0xb5,0x6b,0xd7,0x71,0x3c,0x93,0xfc,0xe7,0x24,0x92,0xb5,0xf5,0x0f,0x7a,0x96,0x9d,0x46,0x9f,0x02,0x07,0xd6,0xe1,0x65,0x9a,0xa6,0x5a,0x2e,0x2e,0x7d,0xa8,0x3f,0x06,0x0c,0x59,0x02,0x68,0xd3,0xda,0xaa,0x7e,0x34,0x6e,0x05,0x48,0xee,0x83,0x93,0x59,0xf3,0xba,0x26,0x68,0x07,0xe6,0x10,0xbe,0xca,0x3b,0xb8,0xd1,0x5e,0x16,0x0a,0x4f,0x31,0x49},+ {0x65,0xd2,0xfc,0xa4,0xe8,0x1f,0x61,0x56,0x7d,0xba,0xc1,0xe5,0xfd,0x53,0xd3,0x3b,0xbd,0xd6,0x4b,0x21,0x1a,0xf3,0x31,0x81,0x62,0xda,0x5b,0x55,0x87,0x15,0xb9,0x2a,0x30,0x97,0xee,0x4c,0xa8,0xb0,0x25,0xaf,0x8a,0x4b,0x86,0xe8,0x30,0x84,0x5a,0x02,0x32,0x67,0x01,0x9f,0x02,0x50,0x1b,0xc1,0xf4,0xf8,0x80,0x9a,0x1b,0x4e,0x16,0x7a,0x34,0x48,0x67,0xf1,0xf4,0x11,0xf2,0x9b,0x95,0xf8,0x2d,0xf6,0x17,0x6b,0x4e,0xb8,0x4e,0x2a,0x72,0x5b,0x07,0x6f,0xde,0xd7,0x21,0x2a,0xbb,0x63,0xb9,0x04,0x9a,0x54},+ {0xbf,0x18,0x68,0x05,0x0a,0x05,0xfe,0x95,0xa9,0xfa,0x60,0x56,0x71,0x89,0x7e,0x32,0x73,0x50,0xa0,0x06,0xcd,0xe3,0xe8,0xc3,0x9a,0xa4,0x45,0x74,0x4c,0x3f,0x93,0x27,0x9f,0x09,0xfc,0x8e,0xb9,0x51,0x73,0x28,0x38,0x25,0xfd,0x7d,0xf4,0xc6,0x65,0x67,0x65,0x92,0x0a,0xfb,0x3d,0x8d,0x34,0xca,0x27,0x87,0xe5,0x21,0x03,0x91,0x0e,0x68,0xb0,0x26,0x14,0xe5,0xec,0x45,0x1e,0xbf,0x94,0x0f,0xba,0x6d,0x3d,0xc6,0x2b,0xe3,0xc0,0x52,0xf8,0x8c,0xd5,0x74,0x29,0xe4,0x18,0x4c,0xe6,0xb0,0xb1,0x79,0xf0,0x44},+ {0xba,0xd6,0x47,0xa4,0xc3,0x82,0x91,0x7f,0xb7,0x29,0x27,0x4b,0xd1,0x14,0x00,0xd5,0x87,0xa0,0x64,0xb8,0x1c,0xf1,0x3c,0xe3,0xf3,0x55,0x1b,0xeb,0x73,0x7e,0x4a,0x15,0x33,0xbb,0xa5,0x08,0x44,0xbc,0x12,0xa2,0x02,0xed,0x5e,0xc7,0xc3,0x48,0x50,0x8d,0x44,0xec,0xbf,0x5a,0x0c,0xeb,0x1b,0xdd,0xeb,0x06,0xe2,0x46,0xf1,0xcc,0x45,0x29,0xb3,0x03,0xd0,0xe7,0x79,0xa1,0x32,0xc8,0x7e,0x4d,0x12,0x00,0x0a,0x9d,0x72,0x5f,0xf3,0x8f,0x6d,0x0e,0xa1,0xd4,0xc1,0x62,0x98,0x7a,0xb2,0x38,0x59,0xac,0xb8,0x68},+ {0xa4,0x8c,0x7d,0x7b,0xb6,0x06,0x98,0x49,0x39,0x27,0xd2,0x27,0x84,0xe2,0x5b,0x57,0xb9,0x53,0x45,0x20,0xe7,0x5c,0x08,0xbb,0x84,0x78,0x41,0xae,0x41,0x4c,0xb6,0x38,0x31,0x71,0x15,0x77,0xeb,0xee,0x0c,0x3a,0x88,0xaf,0xc8,0x00,0x89,0x15,0x27,0x9b,0x36,0xa7,0x59,0xda,0x68,0xb6,0x65,0x80,0xbd,0x38,0xcc,0xa2,0xb6,0x7b,0xe5,0x51,0xa4,0xe3,0x9d,0x68,0x91,0xad,0x9d,0x8f,0x37,0x91,0xfb,0xf8,0x28,0x24,0x5f,0x17,0x88,0xb9,0xcf,0x9f,0x32,0xb5,0x0a,0x05,0x9f,0xc0,0x54,0x13,0xa2,0xdf,0x65,0x78},+ {0xb1,0x21,0x32,0xaa,0x9a,0x2c,0x6f,0xba,0xa7,0x23,0xba,0x3b,0x53,0x21,0xa0,0x6c,0x3a,0x2c,0x19,0x92,0x4f,0x76,0xea,0x9d,0xe0,0x17,0x53,0x2e,0x5d,0xdd,0x6e,0x1d,0xbf,0xa3,0x4e,0x94,0xd0,0x5c,0x1a,0x6b,0xd2,0xc0,0x9d,0xb3,0x3a,0x35,0x70,0x74,0x49,0x2e,0x54,0x28,0x82,0x52,0xb2,0x71,0x7e,0x92,0x3c,0x28,0x69,0xea,0x1b,0x46,0x36,0xda,0x0f,0xab,0xac,0x8a,0x7a,0x21,0xc8,0x49,0x35,0x3d,0x54,0xc6,0x28,0xa5,0x68,0x75,0xab,0x13,0x8b,0x5b,0xd0,0x37,0x37,0xbc,0x2c,0x3a,0x62,0xef,0x3c,0x23},+ {0xd9,0x34,0x92,0xf3,0xed,0x5d,0xa7,0xe2,0xf9,0x58,0xb5,0xe1,0x80,0x76,0x3d,0x96,0xfb,0x23,0x3c,0x6e,0xac,0x41,0x27,0x2c,0xc3,0x01,0x0e,0x32,0xa1,0x24,0x90,0x3a,0x8f,0x3e,0xdd,0x04,0x66,0x59,0xb7,0x59,0x2c,0x70,0x88,0xe2,0x77,0x03,0xb3,0x6c,0x23,0xc3,0xd9,0x5e,0x66,0x9c,0x33,0xb1,0x2f,0xe5,0xbc,0x61,0x60,0xe7,0x15,0x09,0x7e,0xa3,0x34,0xa8,0x35,0xe8,0x7d,0xdf,0xea,0x57,0x98,0x68,0xda,0x9c,0xe1,0x8b,0x26,0xb3,0x67,0x71,0x36,0x85,0x11,0x2c,0xc2,0xd5,0xef,0xdb,0xd9,0xb3,0x9e,0x58},+ {0x5e,0x51,0xaa,0x49,0x54,0x63,0x5b,0xed,0x3a,0x82,0xc6,0x0b,0x9f,0xc4,0x65,0xa8,0xc4,0xd1,0x42,0x5b,0xe9,0x1f,0x0c,0x85,0xb9,0x15,0xd3,0x03,0x6f,0x6d,0xd7,0x30,0x1d,0x9c,0x2f,0x63,0x0e,0xdd,0xcc,0x2e,0x15,0x31,0x89,0x76,0x96,0xb6,0xd0,0x51,0x58,0x7a,0x63,0xa8,0x6b,0xb7,0xdf,0x52,0x39,0xef,0x0e,0xa0,0x49,0x7d,0xd3,0x6d,0xc7,0xe4,0x06,0x21,0x17,0x44,0x44,0x6c,0x69,0x7f,0x8d,0x92,0x80,0xd6,0x53,0xfb,0x26,0x3f,0x4d,0x69,0xa4,0x9e,0x73,0xb4,0xb0,0x4b,0x86,0x2e,0x11,0x97,0xc6,0x10},+ {0xde,0x5f,0xbe,0x7d,0x27,0xc4,0x93,0x64,0xa2,0x7e,0xad,0x19,0xad,0x4f,0x5d,0x26,0x90,0x45,0x30,0x46,0xc8,0xdf,0x00,0x0e,0x09,0xfe,0x66,0xed,0xab,0x1c,0xe6,0x25,0x05,0xc8,0x58,0x83,0xa0,0x2a,0xa6,0x0c,0x47,0x42,0x20,0x7a,0xe3,0x4a,0x3d,0x6a,0xdc,0xed,0x11,0x3b,0xa6,0xd3,0x64,0x74,0xef,0x06,0x08,0x55,0xaf,0x9b,0xbf,0x03,0x04,0x66,0x58,0xcc,0x28,0xe1,0x13,0x3f,0x7e,0x74,0x59,0xb4,0xec,0x73,0x58,0x6f,0xf5,0x68,0x12,0xcc,0xed,0x3d,0xb6,0xa0,0x2c,0xe2,0x86,0x45,0x63,0x78,0x6d,0x56},+ {0x34,0x08,0xc1,0x9c,0x9f,0xa4,0x37,0x16,0x51,0xc4,0x9b,0xa8,0xd5,0x56,0x8e,0xbc,0xdb,0xd2,0x7f,0x7f,0x0f,0xec,0xb5,0x1c,0xd9,0x35,0xcc,0x5e,0xca,0x5b,0x97,0x33,0xd0,0x2f,0x5a,0xc6,0x85,0x42,0x05,0xa1,0xc3,0x67,0x16,0xf3,0x2a,0x11,0x64,0x6c,0x58,0xee,0x1a,0x73,0x40,0xe2,0x0a,0x68,0x2a,0xb2,0x93,0x47,0xf3,0xa5,0xfb,0x14,0xd4,0xf7,0x85,0x69,0x16,0x46,0xd7,0x3c,0x57,0x00,0xc8,0xc9,0x84,0x5e,0x3e,0x59,0x1e,0x13,0x61,0x7b,0xb6,0xf2,0xc3,0x2f,0x6c,0x52,0xfc,0x83,0xea,0x9c,0x82,0x14},+ {0xc2,0x95,0xdd,0x97,0x84,0x7b,0x43,0xff,0xa7,0xb5,0x4e,0xaa,0x30,0x4e,0x74,0x6c,0x8b,0xe8,0x85,0x3c,0x61,0x5d,0x0c,0x9e,0x73,0x81,0x75,0x5f,0x1e,0xc7,0xd9,0x2f,0xb8,0xec,0x71,0x4e,0x2f,0x0b,0xe7,0x21,0xe3,0x77,0xa4,0x40,0xb9,0xdd,0x56,0xe6,0x80,0x4f,0x1d,0xce,0xce,0x56,0x65,0xbf,0x7e,0x7b,0x5d,0x53,0xc4,0x3b,0xfc,0x05,0xdd,0xde,0xaf,0x52,0xae,0xb3,0xb8,0x24,0xcf,0x30,0x3b,0xed,0x8c,0x63,0x95,0x34,0x95,0x81,0xbe,0xa9,0x83,0xbc,0xa4,0x33,0x04,0x1f,0x65,0x5c,0x47,0x67,0x37,0x37},+ {0xd9,0xad,0xd1,0x40,0xfd,0x99,0xba,0x2f,0x27,0xd0,0xf4,0x96,0x6f,0x16,0x07,0xb3,0xae,0x3b,0xf0,0x15,0x52,0xf0,0x63,0x43,0x99,0xf9,0x18,0x3b,0x6c,0xa5,0xbe,0x1f,0x90,0x65,0x24,0x14,0xcb,0x95,0x40,0x63,0x35,0x55,0xc1,0x16,0x40,0x14,0x12,0xef,0x60,0xbc,0x10,0x89,0x0c,0x14,0x38,0x9e,0x8c,0x7c,0x90,0x30,0x57,0x90,0xf5,0x6b,0x8a,0x5b,0x41,0xe1,0xf1,0x78,0xa7,0x0f,0x7e,0xa7,0xc3,0xba,0xf7,0x9f,0x40,0x06,0x50,0x9a,0xa2,0x9a,0xb8,0xd7,0x52,0x6f,0x56,0x5a,0x63,0x7a,0xf6,0x1c,0x52,0x02},+ {0x94,0x52,0x9d,0x0a,0x0b,0xee,0x3f,0x51,0x66,0x5a,0xdf,0x0f,0x5c,0xe7,0x98,0x8f,0xce,0x07,0xe1,0xbf,0x88,0x86,0x61,0xd4,0xed,0x2c,0x38,0x71,0x7e,0x0a,0xa0,0x3f,0xe4,0x5e,0x2f,0x77,0x20,0x67,0x14,0xb1,0xce,0x9a,0x07,0x96,0xb1,0x94,0xf8,0xe8,0x4a,0x82,0xac,0x00,0x4d,0x22,0xf8,0x4a,0xc4,0x6c,0xcd,0xf7,0xd9,0x53,0x17,0x00,0x34,0xdb,0x3d,0x96,0x2d,0x23,0x69,0x3c,0x58,0x38,0x97,0xb4,0xda,0x87,0xde,0x1d,0x85,0xf2,0x91,0xa0,0xf9,0xd1,0xd7,0xaa,0xb6,0xed,0x48,0xa0,0x2f,0xfe,0xb5,0x12},+ {0x4d,0xe3,0xfc,0x96,0xc4,0xfb,0xf0,0x71,0xed,0x5b,0xf3,0xad,0x6b,0x82,0xb9,0x73,0x61,0xc5,0x28,0xff,0x61,0x72,0x04,0xd2,0x6f,0x20,0xb1,0x6f,0xf9,0x76,0x9b,0x74,0x92,0x1e,0x6f,0xad,0x26,0x7c,0x2b,0xdf,0x13,0x89,0x4b,0x50,0x23,0xd3,0x66,0x4b,0xc3,0x8b,0x1c,0x75,0xc0,0x9d,0x40,0x8c,0xb8,0xc7,0x96,0x07,0xc2,0x93,0x7e,0x6f,0x05,0xae,0xa6,0xae,0x04,0xf6,0x5a,0x1f,0x99,0x9c,0xe4,0xbe,0xf1,0x51,0x23,0xc1,0x66,0x6b,0xff,0xee,0xb5,0x08,0xa8,0x61,0x51,0x21,0xe0,0x01,0x0f,0xc1,0xce,0x0f},+ {0x44,0x1e,0xfe,0x49,0xa6,0x58,0x4d,0x64,0x7e,0x77,0xad,0x31,0xa2,0xae,0xfc,0x21,0xd2,0xd0,0x7f,0x88,0x5a,0x1c,0x44,0x02,0xf3,0x11,0xc5,0x83,0x71,0xaa,0x01,0x49,0x45,0x4e,0x24,0xc4,0x9d,0xd2,0xf2,0x3d,0x0a,0xde,0xd8,0x93,0x74,0x0e,0x02,0x2b,0x4d,0x21,0x0c,0x82,0x7e,0x06,0xc8,0x6c,0x0a,0xb9,0xea,0x6f,0x16,0x79,0x37,0x41,0xf0,0xf8,0x1a,0x8c,0x54,0xb7,0xb1,0x08,0xb4,0x99,0x62,0x24,0x7c,0x7a,0x0f,0xce,0x39,0xd9,0x06,0x1e,0xf9,0xb0,0x60,0xf7,0x13,0x12,0x6d,0x72,0x7b,0x88,0xbb,0x41},+ {0xbe,0x46,0x43,0x74,0x44,0x7d,0xe8,0x40,0x25,0x2b,0xb5,0x15,0xd4,0xda,0x48,0x1d,0x3e,0x60,0x3b,0xa1,0x18,0x8a,0x3a,0x7c,0xf7,0xbd,0xcd,0x2f,0xc1,0x28,0xb7,0x4e,0xae,0x91,0x66,0x7c,0x59,0x4c,0x23,0x7e,0xc8,0xb4,0x85,0x0a,0x3d,0x9d,0x88,0x64,0xe7,0xfa,0x4a,0x35,0x0c,0xc9,0xe2,0xda,0x1d,0x9e,0x6a,0x0c,0x07,0x1e,0x87,0x0a,0x89,0x89,0xbc,0x4b,0x99,0xb5,0x01,0x33,0x60,0x42,0xdd,0x5b,0x3a,0xae,0x6b,0x73,0x3c,0x9e,0xd5,0x19,0xe2,0xad,0x61,0x0d,0x64,0xd4,0x85,0x26,0x0f,0x30,0xe7,0x3e},+ {0xb7,0xd6,0x7d,0x9e,0xe4,0x55,0xd2,0xf5,0xac,0x1e,0x0b,0x61,0x5c,0x11,0x16,0x80,0xca,0x87,0xe1,0x92,0x5d,0x97,0x99,0x3c,0xc2,0x25,0x91,0x97,0x62,0x57,0x81,0x13,0x18,0x75,0x1e,0x84,0x47,0x79,0xfa,0x43,0xd7,0x46,0x9c,0x63,0x59,0xfa,0xc6,0xe5,0x74,0x2b,0x05,0xe3,0x1d,0x5e,0x06,0xa1,0x30,0x90,0xb8,0xcf,0xa2,0xc6,0x47,0x7d,0xe0,0xd6,0xf0,0x8e,0x14,0xd0,0xda,0x3f,0x3c,0x6f,0x54,0x91,0x9a,0x74,0x3e,0x9d,0x57,0x81,0xbb,0x26,0x10,0x62,0xec,0x71,0x80,0xec,0xc9,0x34,0x8d,0xf5,0x8c,0x14},+ {0x27,0xf0,0x34,0x79,0xf6,0x92,0xa4,0x46,0xa9,0x0a,0x84,0xf6,0xbe,0x84,0x99,0x46,0x54,0x18,0x61,0x89,0x2a,0xbc,0xa1,0x5c,0xd4,0xbb,0x5d,0xbd,0x1e,0xfa,0xf2,0x3f,0x6d,0x75,0xe4,0x9a,0x7d,0x2f,0x57,0xe2,0x7f,0x48,0xf3,0x88,0xbb,0x45,0xc3,0x56,0x8d,0xa8,0x60,0x69,0x6d,0x0b,0xd1,0x9f,0xb9,0xa1,0xae,0x4e,0xad,0xeb,0x8f,0x27,0x66,0x39,0x93,0x8c,0x1f,0x68,0xaa,0xb1,0x98,0x0c,0x29,0x20,0x9c,0x94,0x21,0x8c,0x52,0x3c,0x9d,0x21,0x91,0x52,0x11,0x39,0x7b,0x67,0x9c,0xfe,0x02,0xdd,0x04,0x41},+ {0x2a,0x42,0x24,0x11,0x5e,0xbf,0xb2,0x72,0xb5,0x3a,0xa3,0x98,0x33,0x0c,0xfa,0xa1,0x66,0xb6,0x52,0xfa,0x01,0x61,0xcb,0x94,0xd5,0x53,0xaf,0xaf,0x00,0x3b,0x86,0x2c,0xb8,0x6a,0x09,0xdb,0x06,0x4e,0x21,0x81,0x35,0x4f,0xe4,0x0c,0xc9,0xb6,0xa8,0x21,0xf5,0x2a,0x9e,0x40,0x2a,0xc1,0x24,0x65,0x81,0xa4,0xfc,0x8e,0xa4,0xb5,0x65,0x01,0x76,0x6a,0x84,0xa0,0x74,0xa4,0x90,0xf1,0xc0,0x7c,0x2f,0xcd,0x84,0xf9,0xef,0x12,0x8f,0x2b,0xaa,0x58,0x06,0x29,0x5e,0x69,0xb8,0xc8,0xfe,0xbf,0xd9,0x67,0x1b,0x59},+ {0xfa,0x9b,0xb4,0x80,0x1c,0x0d,0x2f,0x31,0x8a,0xec,0xf3,0xab,0x5e,0x51,0x79,0x59,0x88,0x1c,0xf0,0x9e,0xc0,0x33,0x70,0x72,0xcb,0x7b,0x8f,0xca,0xc7,0x2e,0xe0,0x3d,0x5d,0xb5,0x18,0x9f,0x71,0xb3,0xb9,0x99,0x1e,0x64,0x8c,0xa1,0xfa,0xe5,0x65,0xe4,0xed,0x05,0x9f,0xc2,0x36,0x11,0x08,0x61,0x8b,0x12,0x30,0x70,0x86,0x4f,0x9b,0x48,0xef,0x92,0xeb,0x3a,0x2d,0x10,0x32,0xd2,0x61,0xa8,0x16,0x61,0xb4,0x53,0x62,0xe1,0x24,0xaa,0x0b,0x19,0xe7,0xab,0x7e,0x3d,0xbf,0xbe,0x6c,0x49,0xba,0xfb,0xf5,0x49},+ {0xd4,0xcf,0x5b,0x8a,0x10,0x9a,0x94,0x30,0xeb,0x73,0x64,0xbc,0x70,0xdd,0x40,0xdc,0x1c,0x0d,0x7c,0x30,0xc1,0x94,0xc2,0x92,0x74,0x6e,0xfa,0xcb,0x6d,0xa8,0x04,0x56,0x2e,0x57,0x9c,0x1e,0x8c,0x62,0x5d,0x15,0x41,0x47,0x88,0xc5,0xac,0x86,0x4d,0x8a,0xeb,0x63,0x57,0x51,0xf6,0x52,0xa3,0x91,0x5b,0x51,0x67,0x88,0xc2,0xa6,0xa1,0x06,0xb6,0x64,0x17,0x7c,0xd4,0xd1,0x88,0x72,0x51,0x8b,0x41,0xe0,0x40,0x11,0x54,0x72,0xd1,0xf6,0xac,0x18,0x60,0x1a,0x03,0x9f,0xc6,0x42,0x27,0xfe,0x89,0x9e,0x98,0x20},+ {0x7f,0xcc,0x2d,0x3a,0xfd,0x77,0x97,0x49,0x92,0xd8,0x4f,0xa5,0x2c,0x7c,0x85,0x32,0xa0,0xe3,0x07,0xd2,0x64,0xd8,0x79,0xa2,0x29,0x7e,0xa6,0x0c,0x1d,0xed,0x03,0x04,0x2e,0xec,0xea,0x85,0x8b,0x27,0x74,0x16,0xdf,0x2b,0xcb,0x7a,0x07,0xdc,0x21,0x56,0x5a,0xf4,0xcb,0x61,0x16,0x4c,0x0a,0x64,0xd3,0x95,0x05,0xf7,0x50,0x99,0x0b,0x73,0x52,0xc5,0x4e,0x87,0x35,0x2d,0x4b,0xc9,0x8d,0x6f,0x24,0x98,0xcf,0xc8,0xe6,0xc5,0xce,0x35,0xc0,0x16,0xfa,0x46,0xcb,0xf7,0xcc,0x3d,0x30,0x08,0x43,0x45,0xd7,0x5b},+ {0xc2,0x4c,0xb2,0x28,0x95,0xd1,0x9a,0x7f,0x81,0xc1,0x35,0x63,0x65,0x54,0x6b,0x7f,0x36,0x72,0xc0,0x4f,0x6e,0xb6,0xb8,0x66,0x83,0xad,0x80,0x73,0x00,0x78,0x3a,0x13,0x2a,0x79,0xe7,0x15,0x21,0x93,0xc4,0x85,0xc9,0xdd,0xcd,0xbd,0xa2,0x89,0x4c,0xc6,0x62,0xd7,0xa3,0xad,0xa8,0x3d,0x1e,0x9d,0x2c,0xf8,0x67,0x30,0x12,0xdb,0xb7,0x5b,0xbe,0x62,0xca,0xc6,0x67,0xf4,0x61,0x09,0xee,0x52,0x19,0x21,0xd6,0x21,0xec,0x04,0x70,0x47,0xd5,0x9b,0x77,0x60,0x23,0x18,0xd2,0xe0,0xf0,0x58,0x6d,0xca,0x0d,0x74},+ {0x4e,0xce,0xcf,0x52,0x07,0xee,0x48,0xdf,0xb7,0x08,0xec,0x06,0xf3,0xfa,0xff,0xc3,0xc4,0x59,0x54,0xb9,0x2a,0x0b,0x71,0x05,0x8d,0xa3,0x3e,0x96,0xfa,0x25,0x1d,0x16,0x3c,0x43,0x78,0x04,0x57,0x8c,0x1a,0x23,0x9d,0x43,0x81,0xc2,0x0e,0x27,0xb5,0xb7,0x9f,0x07,0xd9,0xe3,0xea,0x99,0xaa,0xdb,0xd9,0x03,0x2b,0x6c,0x25,0xf5,0x03,0x2c,0x7d,0xa4,0x53,0x7b,0x75,0x18,0x0f,0x79,0x79,0x58,0x0c,0xcf,0x30,0x01,0x7b,0x30,0xf9,0xf7,0x7e,0x25,0x77,0x3d,0x90,0x31,0xaf,0xbb,0x96,0xbd,0xbd,0x68,0x94,0x69},+ {0xcf,0xfe,0xda,0xf4,0x46,0x2f,0x1f,0xbd,0xf7,0xd6,0x7f,0xa4,0x14,0x01,0xef,0x7c,0x7f,0xb3,0x47,0x4a,0xda,0xfd,0x1f,0xd3,0x85,0x57,0x90,0x73,0xa4,0x19,0x52,0x52,0x48,0x19,0xa9,0x6a,0xe6,0x3d,0xdd,0xd8,0xcc,0xd2,0xc0,0x2f,0xc2,0x64,0x50,0x48,0x2f,0xea,0xfd,0x34,0x66,0x24,0x48,0x9b,0x3a,0x2e,0x4a,0x6c,0x4e,0x1c,0x3e,0x29,0xe1,0x12,0x51,0x92,0x4b,0x13,0x6e,0x37,0xa0,0x5d,0xa1,0xdc,0xb5,0x78,0x37,0x70,0x11,0x31,0x1c,0x46,0xaf,0x89,0x45,0xb0,0x23,0x28,0x03,0x7f,0x44,0x5c,0x60,0x5b},+ {0x89,0x7c,0xc4,0x20,0x59,0x80,0x65,0xb9,0xcc,0x8f,0x3b,0x92,0x0c,0x10,0xf0,0xe7,0x77,0xef,0xe2,0x02,0x65,0x25,0x01,0x00,0xee,0xb3,0xae,0xa8,0xce,0x6d,0xa7,0x24,0x4c,0xf0,0xe7,0xf0,0xc6,0xfe,0xe9,0x3b,0x62,0x49,0xe3,0x75,0x9e,0x57,0x6a,0x86,0x1a,0xe6,0x1d,0x1e,0x16,0xef,0x42,0x55,0xd5,0xbd,0x5a,0xcc,0xf4,0xfe,0x12,0x2f,0x40,0xc7,0xc0,0xdf,0xb2,0x22,0x45,0x0a,0x07,0xa4,0xc9,0x40,0x7f,0x6e,0xd0,0x10,0x68,0xf6,0xcf,0x78,0x41,0x14,0xcf,0xc6,0x90,0x37,0xa4,0x18,0x25,0x7b,0x60,0x5e},+ {0x18,0x18,0xdf,0x6c,0x8f,0x1d,0xb3,0x58,0xa2,0x58,0x62,0xc3,0x4f,0xa7,0xcf,0x35,0x6e,0x1d,0xe6,0x66,0x4f,0xff,0xb3,0xe1,0xf7,0xd5,0xcd,0x6c,0xab,0xac,0x67,0x50,0x14,0xcf,0x96,0xa5,0x1c,0x43,0x2c,0xa0,0x00,0xe4,0xd3,0xae,0x40,0x2d,0xc4,0xe3,0xdb,0x26,0x0f,0x2e,0x80,0x26,0x45,0xd2,0x68,0x70,0x45,0x9e,0x13,0x33,0x1f,0x20,0x51,0x9d,0x03,0x08,0x6b,0x7f,0x52,0xfd,0x06,0x00,0x7c,0x01,0x64,0x49,0xb1,0x18,0xa8,0xa4,0x25,0x2e,0xb0,0x0e,0x22,0xd5,0x75,0x03,0x46,0x62,0x88,0xba,0x7c,0x39},+ {0xb2,0x59,0x59,0xf0,0x93,0x30,0xc1,0x30,0x76,0x79,0xa9,0xe9,0x8d,0xa1,0x3a,0xe2,0x26,0x5e,0x1d,0x72,0x91,0xd4,0x2f,0x22,0x3a,0x6c,0x6e,0x76,0x20,0xd3,0x39,0x23,0xe7,0x79,0x13,0xc8,0xfb,0xc3,0x15,0x78,0xf1,0x2a,0xe1,0xdd,0x20,0x94,0x61,0xa6,0xd5,0xfd,0xa8,0x85,0xf8,0xc0,0xa9,0xff,0x52,0xc2,0xe1,0xc1,0x22,0x40,0x1b,0x77,0xa7,0x2f,0x3a,0x51,0x86,0xd9,0x7d,0xd8,0x08,0xcf,0xd4,0xf9,0x71,0x9b,0xac,0xf5,0xb3,0x83,0xa2,0x1e,0x1b,0xc3,0x6b,0xd0,0x76,0x1a,0x97,0x19,0x92,0x18,0x1a,0x33},+ {0xc6,0x80,0x4f,0xfb,0x45,0x6f,0x16,0xf5,0xcf,0x75,0xc7,0x61,0xde,0xc7,0x36,0x9c,0x1c,0xd9,0x41,0x90,0x1b,0xe8,0xd4,0xe3,0x21,0xfe,0xbd,0x83,0x6b,0x7c,0x16,0x31,0xaf,0x72,0x75,0x9d,0x3a,0x2f,0x51,0x26,0x9e,0x4a,0x07,0x68,0x88,0xe2,0xcb,0x5b,0xc4,0xf7,0x80,0x11,0xc1,0xc1,0xed,0x84,0x7b,0xa6,0x49,0xf6,0x9f,0x61,0xc9,0x1a,0x68,0x10,0x4b,0x52,0x42,0x38,0x2b,0xf2,0x87,0xe9,0x9c,0xee,0x3b,0x34,0x68,0x50,0xc8,0x50,0x62,0x4a,0x84,0x71,0x9d,0xfc,0x11,0xb1,0x08,0x1f,0x34,0x36,0x24,0x61},+ {0x8d,0x89,0x4e,0x87,0xdb,0x41,0x9d,0xd9,0x20,0xdc,0x07,0x6c,0xf1,0xa5,0xfe,0x09,0xbc,0x9b,0x0f,0xd0,0x67,0x2c,0x3d,0x79,0x40,0xff,0x5e,0x9e,0x30,0xe2,0xeb,0x46,0x38,0x26,0x2d,0x1a,0xe3,0x49,0x63,0x8b,0x35,0xfd,0xd3,0x9b,0x00,0xb7,0xdf,0x9d,0xa4,0x6b,0xa0,0xa3,0xb8,0xf1,0x8b,0x7f,0x45,0x04,0xd9,0x78,0x31,0xaa,0x22,0x15,0x38,0x49,0x61,0x69,0x53,0x2f,0x38,0x2c,0x10,0x6d,0x2d,0xb7,0x9a,0x40,0xfe,0xda,0x27,0xf2,0x46,0xb6,0x91,0x33,0xc8,0xe8,0x6c,0x30,0x24,0x05,0xf5,0x70,0xfe,0x45},+ {0x8c,0x0b,0x0c,0x96,0xa6,0x75,0x48,0xda,0x20,0x2f,0x0e,0xef,0x76,0xd0,0x68,0x5b,0xd4,0x8f,0x0b,0x3d,0xcf,0x51,0xfb,0x07,0xd4,0x92,0xe3,0xa0,0x23,0x16,0x8d,0x42,0x91,0x14,0x95,0xc8,0x20,0x49,0xf2,0x62,0xa2,0x0c,0x63,0x3f,0xc8,0x07,0xf0,0x05,0xb8,0xd4,0xc9,0xf5,0xd2,0x45,0xbb,0x6f,0x45,0x22,0x7a,0xb5,0x6d,0x9f,0x61,0x16,0xfd,0x08,0xa3,0x01,0x44,0x4a,0x4f,0x08,0xac,0xca,0xa5,0x76,0xc3,0x19,0x22,0xa8,0x7d,0xbc,0xd1,0x43,0x46,0xde,0xb8,0xde,0xc6,0x38,0xbd,0x60,0x2d,0x59,0x81,0x1d},+ {0x5f,0xac,0x0d,0xa6,0x56,0x87,0x36,0x61,0x57,0xdc,0xab,0xeb,0x6a,0x2f,0xe0,0x17,0x7d,0x0f,0xce,0x4c,0x2d,0x3f,0x19,0x7f,0xf0,0xdc,0xec,0x89,0x77,0x4a,0x23,0x20,0xe8,0xc5,0x85,0x7b,0x9f,0xb6,0x65,0x87,0xb2,0xba,0x68,0xd1,0x8b,0x67,0xf0,0x6f,0x9b,0x0f,0x33,0x1d,0x7c,0xe7,0x70,0x3a,0x7c,0x8e,0xaf,0xb0,0x51,0x6d,0x5f,0x3a,0x52,0xb2,0x78,0x71,0xb6,0x0d,0xd2,0x76,0x60,0xd1,0x1e,0xd5,0xf9,0x34,0x1c,0x07,0x70,0x11,0xe4,0xb3,0x20,0x4a,0x2a,0xf6,0x66,0xe3,0xff,0x3c,0x35,0x82,0xd6,0x7c},+ {0xb6,0xfa,0x87,0xd8,0x5b,0xa4,0xe1,0x0b,0x6e,0x3b,0x40,0xba,0x32,0x6a,0x84,0x2a,0x00,0x60,0x6e,0xe9,0x12,0x10,0x92,0xd9,0x43,0x09,0xdc,0x3b,0x86,0xc8,0x38,0x28,0xf3,0xf4,0xac,0x68,0x60,0xcd,0x65,0xa6,0xd3,0xe3,0xd7,0x3c,0x18,0x2d,0xd9,0x42,0xd9,0x25,0x60,0x33,0x9d,0x38,0x59,0x57,0xff,0xd8,0x2c,0x2b,0x3b,0x25,0xf0,0x3e,0x30,0x50,0x46,0x4a,0xcf,0xb0,0x6b,0xd1,0xab,0x77,0xc5,0x15,0x41,0x6b,0x49,0xfa,0x9d,0x41,0xab,0xf4,0x8a,0xae,0xcf,0x82,0x12,0x28,0xa8,0x06,0xa6,0xb8,0xdc,0x21},+ {0xc8,0x9f,0x9d,0x8c,0x46,0x04,0x60,0x5c,0xcb,0xa3,0x2a,0xd4,0x6e,0x09,0x40,0x25,0x9c,0x2f,0xee,0x12,0x4c,0x4d,0x5b,0x12,0xab,0x1d,0xa3,0x94,0x81,0xd0,0xc3,0x0b,0xba,0x31,0x77,0xbe,0xfa,0x00,0x8d,0x9a,0x89,0x18,0x9e,0x62,0x7e,0x60,0x03,0x82,0x7f,0xd9,0xf3,0x43,0x37,0x02,0xcc,0xb2,0x8b,0x67,0x6f,0x6c,0xbf,0x0d,0x84,0x5d,0x8b,0xe1,0x9f,0x30,0x0d,0x38,0x6e,0x70,0xc7,0x65,0xe1,0xb9,0xa6,0x2d,0xb0,0x6e,0xab,0x20,0xae,0x7d,0x99,0xba,0xbb,0x57,0xdd,0x96,0xc1,0x2a,0x23,0x76,0x42,0x3a},+ {0xfa,0x84,0x70,0x8a,0x2c,0x43,0x42,0x4b,0x45,0xe5,0xb9,0xdf,0xe3,0x19,0x8a,0x89,0x5d,0xe4,0x58,0x9c,0x21,0x00,0x9f,0xbe,0xd1,0xeb,0x6d,0xa1,0xce,0x77,0xf1,0x1f,0xcb,0x7e,0x44,0xdb,0x72,0xc1,0xf8,0x3b,0xbd,0x2d,0x28,0xc6,0x1f,0xc4,0xcf,0x5f,0xfe,0x15,0xaa,0x75,0xc0,0xff,0xac,0x80,0xf9,0xa9,0xe1,0x24,0xe8,0xc9,0x70,0x07,0xfd,0xb5,0xb5,0x45,0x9a,0xd9,0x61,0xcf,0x24,0x79,0x3a,0x1b,0xe9,0x84,0x09,0x86,0x89,0x3e,0x3e,0x30,0x19,0x09,0x30,0xe7,0x1e,0x0b,0x50,0x41,0xfd,0x64,0xf2,0x39},+ {0x9c,0xe2,0xe7,0xdb,0x17,0x34,0xad,0xa7,0x9c,0x13,0x9c,0x2b,0x6a,0x37,0x94,0xbd,0xa9,0x7b,0x59,0x93,0x8e,0x1b,0xe9,0xa0,0x40,0x98,0x88,0x68,0x34,0xd7,0x12,0x17,0xe1,0x7b,0x09,0xfe,0xab,0x4a,0x9b,0xd1,0x29,0x19,0xe0,0xdf,0xe1,0xfc,0x6d,0xa4,0xff,0xf1,0xa6,0x2c,0x94,0x08,0xc9,0xc3,0x4e,0xf1,0x35,0x2c,0x27,0x21,0xc6,0x65,0xdd,0x93,0x31,0xce,0xf8,0x89,0x2b,0xe7,0xbb,0xc0,0x25,0xa1,0x56,0x33,0x10,0x4d,0x83,0xfe,0x1c,0x2e,0x3d,0xa9,0x19,0x04,0x72,0xe2,0x9c,0xb1,0x0a,0x80,0xf9,0x22},+ {0xcb,0xf8,0x9e,0x3e,0x8a,0x36,0x5a,0x60,0x15,0x47,0x50,0xa5,0x22,0xc0,0xe9,0xe3,0x8f,0x24,0x24,0x5f,0xb0,0x48,0x3d,0x55,0xe5,0x26,0x76,0x64,0xcd,0x16,0xf4,0x13,0xac,0xfd,0x6e,0x9a,0xdd,0x9f,0x02,0x42,0x41,0x49,0xa5,0x34,0xbe,0xce,0x12,0xb9,0x7b,0xf3,0xbd,0x87,0xb9,0x64,0x0f,0x64,0xb4,0xca,0x98,0x85,0xd3,0xa4,0x71,0x41,0x8c,0x4c,0xc9,0x99,0xaa,0x58,0x27,0xfa,0x07,0xb8,0x00,0xb0,0x6f,0x6f,0x00,0x23,0x92,0x53,0xda,0xad,0xdd,0x91,0xd2,0xfb,0xab,0xd1,0x4b,0x57,0xfa,0x14,0x82,0x50},+ {0x4b,0xfe,0xd6,0x3e,0x15,0x69,0x02,0xc2,0xc4,0x77,0x1d,0x51,0x39,0x67,0x5a,0xa6,0x94,0xaf,0x14,0x2c,0x46,0x26,0xde,0xcb,0x4b,0xa7,0xab,0x6f,0xec,0x60,0xf9,0x22,0xd6,0x03,0xd0,0x53,0xbb,0x15,0x1a,0x46,0x65,0xc9,0xf3,0xbc,0x88,0x28,0x10,0xb2,0x5a,0x3a,0x68,0x6c,0x75,0x76,0xc5,0x27,0x47,0xb4,0x6c,0xc8,0xa4,0x58,0x77,0x3a,0x76,0x50,0xae,0x93,0xf6,0x11,0x81,0x54,0xa6,0x54,0xfd,0x1d,0xdf,0x21,0xae,0x1d,0x65,0x5e,0x11,0xf3,0x90,0x8c,0x24,0x12,0x94,0xf4,0xe7,0x8d,0x5f,0xd1,0x9f,0x5d},+ {0x7f,0x72,0x63,0x6d,0xd3,0x08,0x14,0x03,0x33,0xb5,0xc7,0xd7,0xef,0x9a,0x37,0x6a,0x4b,0xe2,0xae,0xcc,0xc5,0x8f,0xe1,0xa9,0xd3,0xbe,0x8f,0x4f,0x91,0x35,0x2f,0x33,0x1e,0x52,0xd7,0xee,0x2a,0x4d,0x24,0x3f,0x15,0x96,0x2e,0x43,0x28,0x90,0x3a,0x8e,0xd4,0x16,0x9c,0x2e,0x77,0xba,0x64,0xe1,0xd8,0x98,0xeb,0x47,0xfa,0x87,0xc1,0x3b,0x0c,0xc2,0x86,0xea,0x15,0x01,0x47,0x6d,0x25,0xd1,0x46,0x6c,0xcb,0xb7,0x8a,0x99,0x88,0x01,0x66,0x3a,0xb5,0x32,0x78,0xd7,0x03,0xba,0x6f,0x90,0xce,0x81,0x0d,0x45},+ {0x75,0x52,0x20,0xa6,0xa1,0xb6,0x7b,0x6e,0x83,0x8e,0x3c,0x41,0xd7,0x21,0x4f,0xaa,0xb2,0x5c,0x8f,0xe8,0x55,0xd1,0x56,0x6f,0xe1,0x5b,0x34,0xa6,0x4b,0x5d,0xe2,0x2d,0x3f,0x74,0xae,0x1c,0x96,0xd8,0x74,0xd0,0xed,0x63,0x1c,0xee,0xf5,0x18,0x6d,0xf8,0x29,0xed,0xf4,0xe7,0x5b,0xc5,0xbd,0x97,0x08,0xb1,0x3a,0x66,0x79,0xd2,0xba,0x4c,0xcd,0x1f,0xd7,0xa0,0x24,0x90,0xd1,0x80,0xf8,0x8a,0x28,0xfb,0x0a,0xc2,0x25,0xc5,0x19,0x64,0x3a,0x5f,0x4b,0x97,0xa3,0xb1,0x33,0x72,0x00,0xe2,0xef,0xbc,0x7f,0x7d},+ {0x01,0x28,0x6b,0x26,0x6a,0x1e,0xef,0xfa,0x16,0x9f,0x73,0xd5,0xc4,0x68,0x6c,0x86,0x2c,0x76,0x03,0x1b,0xbc,0x2f,0x8a,0xf6,0x8d,0x5a,0xb7,0x87,0x5e,0x43,0x75,0x59,0x94,0x90,0xc2,0xf3,0xc5,0x5d,0x7c,0xcd,0xab,0x05,0x91,0x2a,0x9a,0xa2,0x81,0xc7,0x58,0x30,0x1c,0x42,0x36,0x1d,0xc6,0x80,0xd7,0xd4,0xd8,0xdc,0x96,0xd1,0x9c,0x4f,0x68,0x37,0x7b,0x6a,0xd8,0x97,0x92,0x19,0x63,0x7a,0xd1,0x1a,0x24,0x58,0xd0,0xd0,0x17,0x0c,0x1c,0x5c,0xad,0x9c,0x02,0xba,0x07,0x03,0x7a,0x38,0x84,0xd0,0xcd,0x7c},+ {0x17,0x04,0x26,0x6d,0x2c,0x42,0xa6,0xdc,0xbd,0x40,0x82,0x94,0x50,0x3d,0x15,0xae,0x77,0xc6,0x68,0xfb,0xb4,0xc1,0xc0,0xa9,0x53,0xcf,0xd0,0x61,0xed,0xd0,0x8b,0x42,0x93,0xcc,0x60,0x67,0x18,0x84,0x0c,0x9b,0x99,0x2a,0xb3,0x1a,0x7a,0x00,0xae,0xcd,0x18,0xda,0x0b,0x62,0x86,0xec,0x8d,0xa8,0x44,0xca,0x90,0x81,0x84,0xca,0x93,0x35,0xa7,0x9a,0x84,0x5e,0x9a,0x18,0x13,0x92,0xcd,0xfa,0xd8,0x65,0x35,0xc3,0xd8,0xd4,0xd1,0xbb,0xfd,0x53,0x5b,0x54,0x52,0x8c,0xe6,0x63,0x2d,0xda,0x08,0x83,0x39,0x27},+ {0x13,0xd4,0x5e,0x43,0x28,0x8d,0xc3,0x42,0xc9,0xcc,0x78,0x32,0x60,0xf3,0x50,0xbd,0xef,0x03,0xda,0x79,0x1a,0xab,0x07,0xbb,0x55,0x33,0x8c,0xbe,0xae,0x97,0x95,0x26,0x53,0x24,0x70,0x0a,0x4c,0x0e,0xa1,0xb9,0xde,0x1b,0x7d,0xd5,0x66,0x58,0xa2,0x0f,0xf7,0xda,0x27,0xcd,0xb5,0xd9,0xb9,0xff,0xfd,0x33,0x2c,0x49,0x45,0x29,0x2c,0x57,0xbe,0x30,0xcd,0xd6,0x45,0xc7,0x7f,0xc7,0xfb,0xae,0xba,0xe3,0xd3,0xe8,0xdf,0xe4,0x0c,0xda,0x5d,0xaa,0x30,0x88,0x2c,0xa2,0x80,0xca,0x5b,0xc0,0x98,0x54,0x98,0x7f},+ {0x17,0xe1,0x0b,0x9f,0x88,0xce,0x49,0x38,0x88,0xa2,0x54,0x7b,0x1b,0xad,0x05,0x80,0x1c,0x92,0xfc,0x23,0x9f,0xc3,0xa3,0x3d,0x04,0xf3,0x31,0x0a,0x47,0xec,0xc2,0x76,0x63,0x63,0xbf,0x0f,0x52,0x15,0x56,0xd3,0xa6,0xfb,0x4d,0xcf,0x45,0x5a,0x04,0x08,0xc2,0xa0,0x3f,0x87,0xbc,0x4f,0xc2,0xee,0xe7,0x12,0x9b,0xd6,0x3c,0x65,0xf2,0x30,0x85,0x0c,0xc1,0xaa,0x38,0xc9,0x08,0x8a,0xcb,0x6b,0x27,0xdb,0x60,0x9b,0x17,0x46,0x70,0xac,0x6f,0x0e,0x1e,0xc0,0x20,0xa9,0xda,0x73,0x64,0x59,0xf1,0x73,0x12,0x2f},+ {0x11,0x1e,0xe0,0x8a,0x7c,0xfc,0x39,0x47,0x9f,0xab,0x6a,0x4a,0x90,0x74,0x52,0xfd,0x2e,0x8f,0x72,0x87,0x82,0x8a,0xd9,0x41,0xf2,0x69,0x5b,0xd8,0x2a,0x57,0x9e,0x5d,0xc0,0x0b,0xa7,0x55,0xd7,0x8b,0x48,0x30,0xe7,0x42,0xd4,0xf1,0xa4,0xb5,0xd6,0x06,0x62,0x61,0x59,0xbc,0x9e,0xa6,0xd1,0xea,0x84,0xf7,0xc5,0xed,0x97,0x19,0xac,0x38,0x3b,0xb1,0x51,0xa7,0x17,0xb5,0x66,0x06,0x8c,0x85,0x9b,0x7e,0x86,0x06,0x7d,0x74,0x49,0xde,0x4d,0x45,0x11,0xc0,0xac,0xac,0x9c,0xe6,0xe9,0xbf,0x9c,0xcd,0xdf,0x22},+ {0xd9,0x0c,0x0d,0xc3,0xe0,0xd2,0xdb,0x8d,0x33,0x43,0xbb,0xac,0x5f,0x66,0x8e,0xad,0x1f,0x96,0x2a,0x32,0x8c,0x25,0x6b,0x8f,0xc7,0xc1,0x48,0x54,0xc0,0x16,0x29,0x6b,0xa1,0xe0,0x3b,0x10,0xb4,0x59,0xec,0x56,0x69,0xf9,0x59,0xd2,0xec,0xba,0xe3,0x2e,0x32,0xcd,0xf5,0x13,0x94,0xb2,0x7c,0x79,0x72,0xe4,0xcd,0x24,0x78,0x87,0xe9,0x0f,0x3b,0x91,0xba,0x0a,0xd1,0x34,0xdb,0x7e,0x0e,0xac,0x6d,0x2e,0x82,0xcd,0xa3,0x4e,0x15,0xf8,0x78,0x65,0xff,0x3d,0x08,0x66,0x17,0x0a,0xf0,0x7f,0x30,0x3f,0x30,0x4c},+ {0x85,0x8c,0xb2,0x17,0xd6,0x3b,0x0a,0xd3,0xea,0x3b,0x77,0x39,0xb7,0x77,0xd3,0xc5,0xbf,0x5c,0x6a,0x1e,0x8c,0xe7,0xc6,0xc6,0xc4,0xb7,0x2a,0x8b,0xf7,0xb8,0x61,0x0d,0x00,0x45,0xd9,0x0d,0x58,0x03,0xfc,0x29,0x93,0xec,0xbb,0x6f,0xa4,0x7a,0xd2,0xec,0xf8,0xa7,0xe2,0xc2,0x5f,0x15,0x0a,0x13,0xd5,0xa1,0x06,0xb7,0x1a,0x15,0x6b,0x41,0xb0,0x36,0xc1,0xe9,0xef,0xd7,0xa8,0x56,0x20,0x4b,0xe4,0x58,0xcd,0xe5,0x07,0xbd,0xab,0xe0,0x57,0x1b,0xda,0x2f,0xe6,0xaf,0xd2,0xe8,0x77,0x42,0xf7,0x2a,0x1a,0x19},+ {0x31,0x14,0x3c,0xc5,0x4b,0xf7,0x16,0xce,0xde,0xed,0x72,0x20,0xce,0x25,0x97,0x2b,0xe7,0x3e,0xb2,0xb5,0x6f,0xc3,0xb9,0xb8,0x08,0xc9,0x5c,0x0b,0x45,0x0e,0x2e,0x7e,0xfb,0x0e,0x46,0x4f,0x43,0x2b,0xe6,0x9f,0xd6,0x07,0x36,0xa6,0xd4,0x03,0xd3,0xde,0x24,0xda,0xa0,0xb7,0x0e,0x21,0x52,0xf0,0x93,0x5b,0x54,0x00,0xbe,0x7d,0x7e,0x23,0x30,0xb4,0x01,0x67,0xed,0x75,0x35,0x01,0x10,0xfd,0x0b,0x9f,0xe6,0x94,0x10,0x23,0x22,0x7f,0xe4,0x83,0x15,0x0f,0x32,0x75,0xe3,0x55,0x11,0xb1,0x99,0xa6,0xaf,0x71},+ {0x1d,0xb6,0x53,0x39,0x9b,0x6f,0xce,0x65,0xe6,0x41,0xa1,0xaf,0xea,0x39,0x58,0xc6,0xfe,0x59,0xf7,0xa9,0xfd,0x5f,0x43,0x0f,0x8e,0xc2,0xb1,0xc2,0xe9,0x42,0x11,0x02,0xd6,0x50,0x3b,0x47,0x1c,0x3c,0x42,0xea,0x10,0xef,0x38,0x3b,0x1f,0x7a,0xe8,0x51,0x95,0xbe,0xc9,0xb2,0x5f,0xbf,0x84,0x9b,0x1c,0x9a,0xf8,0x78,0xbc,0x1f,0x73,0x00,0x80,0x18,0xf8,0x48,0x18,0xc7,0x30,0xe4,0x19,0xc1,0xce,0x5e,0x22,0x0c,0x96,0xbf,0xe3,0x15,0xba,0x6b,0x83,0xe0,0xda,0xb6,0x08,0x58,0xe1,0x47,0x33,0x6f,0x4d,0x4c},+ {0xc9,0x1f,0x7d,0xc1,0xcf,0xec,0xf7,0x18,0x14,0x3c,0x40,0x51,0xa6,0xf5,0x75,0x6c,0xdf,0x0c,0xee,0xf7,0x2b,0x71,0xde,0xdb,0x22,0x7a,0xe4,0xa7,0xaa,0xdd,0x3f,0x19,0x70,0x19,0x8f,0x98,0xfc,0xdd,0x0c,0x2f,0x1b,0xf5,0xb9,0xb0,0x27,0x62,0x91,0x6b,0xbe,0x76,0x91,0x77,0xc4,0xb6,0xc7,0x6e,0xa8,0x9f,0x8f,0xa8,0x00,0x95,0xbf,0x38,0x6f,0x87,0xe8,0x37,0x3c,0xc9,0xd2,0x1f,0x2c,0x46,0xd1,0x18,0x5a,0x1e,0xf6,0xa2,0x76,0x12,0x24,0x39,0x82,0xf5,0x80,0x50,0x69,0x49,0x0d,0xbf,0x9e,0xb9,0x6f,0x6a},+ {0xeb,0x55,0x08,0x56,0xbb,0xc1,0x46,0x6a,0x9d,0xf0,0x93,0xf8,0x38,0xbb,0x16,0x24,0xc1,0xac,0x71,0x8f,0x37,0x11,0x1d,0xd7,0xea,0x96,0x18,0xa3,0x14,0x69,0xf7,0x75,0xc6,0x23,0xe4,0xb6,0xb5,0x22,0xb1,0xee,0x8e,0xff,0x86,0xf2,0x10,0x70,0x9d,0x93,0x8c,0x5d,0xcf,0x1d,0x83,0x2a,0xa9,0x90,0x10,0xeb,0xc5,0x42,0x9f,0xda,0x6f,0x13,0xd1,0xbd,0x05,0xa3,0xb1,0xdf,0x4c,0xf9,0x08,0x2c,0xf8,0x9f,0x9d,0x4b,0x36,0x0f,0x8a,0x58,0xbb,0xc3,0xa5,0xd8,0x87,0x2a,0xba,0xdc,0xe8,0x0b,0x51,0x83,0x21,0x02},+ {0x14,0x2d,0xad,0x5e,0x38,0x66,0xf7,0x4a,0x30,0x58,0x7c,0xca,0x80,0xd8,0x8e,0xa0,0x3d,0x1e,0x21,0x10,0xe6,0xa6,0x13,0x0d,0x03,0x6c,0x80,0x7b,0xe1,0x1c,0x07,0x6a,0x7f,0x7a,0x30,0x43,0x01,0x71,0x5a,0x9d,0x5f,0xa4,0x7d,0xc4,0x9e,0xde,0x63,0xb0,0xd3,0x7a,0x92,0xbe,0x52,0xfe,0xbb,0x22,0x6c,0x42,0x40,0xfd,0x41,0xc4,0x87,0x13,0xf8,0x8a,0x97,0x87,0xd1,0xc3,0xd3,0xb5,0x13,0x44,0x0e,0x7f,0x3d,0x5a,0x2b,0x72,0xa0,0x7c,0x47,0xbb,0x48,0x48,0x7b,0x0d,0x92,0xdc,0x1e,0xaf,0x6a,0xb2,0x71,0x31},+ {0xa8,0x4c,0x56,0x97,0x90,0x31,0x2f,0xa9,0x19,0xe1,0x75,0x22,0x4c,0xb8,0x7b,0xff,0x50,0x51,0x87,0xa4,0x37,0xfe,0x55,0x4f,0x5a,0x83,0xf0,0x3c,0x87,0xd4,0x1f,0x22,0xd1,0x47,0x8a,0xb2,0xd8,0xb7,0x0d,0xa6,0xf1,0xa4,0x70,0x17,0xd6,0x14,0xbf,0xa6,0x58,0xbd,0xdd,0x53,0x93,0xf8,0xa1,0xd4,0xe9,0x43,0x42,0x34,0x63,0x4a,0x51,0x6c,0x41,0x63,0x15,0x3a,0x4f,0x20,0x22,0x23,0x2d,0x03,0x0a,0xba,0xe9,0xe0,0x73,0xfb,0x0e,0x03,0x0f,0x41,0x4c,0xdd,0xe0,0xfc,0xaa,0x4a,0x92,0xfb,0x96,0xa5,0xda,0x48},+ {0xc7,0x9c,0xa5,0x5c,0x66,0x8e,0xca,0x6e,0xa0,0xac,0x38,0x2e,0x4b,0x25,0x47,0xa8,0xce,0x17,0x1e,0xd2,0x08,0xc7,0xaf,0x31,0xf7,0x4a,0xd8,0xca,0xfc,0xd6,0x6d,0x67,0x93,0x97,0x4c,0xc8,0x5d,0x1d,0xf6,0x14,0x06,0x82,0x41,0xef,0xe3,0xf9,0x41,0x99,0xac,0x77,0x62,0x34,0x8f,0xb8,0xf5,0xcd,0xa9,0x79,0x8a,0x0e,0xfa,0x37,0xc8,0x58,0x58,0x90,0xfc,0x96,0x85,0x68,0xf9,0x0c,0x1b,0xa0,0x56,0x7b,0xf3,0xbb,0xdc,0x1d,0x6a,0xd6,0x35,0x49,0x7d,0xe7,0xc2,0xdc,0x0a,0x7f,0xa5,0xc6,0xf2,0x73,0x4f,0x1c},+ {0xbb,0xa0,0x5f,0x30,0xbd,0x4f,0x7a,0x0e,0xad,0x63,0xc6,0x54,0xe0,0x4c,0x9d,0x82,0x48,0x38,0xe3,0x2f,0x83,0xc3,0x21,0xf4,0x42,0x4c,0xf6,0x1b,0x0d,0xc8,0x5a,0x79,0x84,0x34,0x7c,0xfc,0x6e,0x70,0x6e,0xb3,0x61,0xcf,0xc1,0xc3,0xb4,0xc9,0xdf,0x73,0xe5,0xc7,0x1c,0x78,0xc9,0x79,0x1d,0xeb,0x5c,0x67,0xaf,0x7d,0xdb,0x9a,0x45,0x70,0xb3,0x2b,0xb4,0x91,0x49,0xdb,0x91,0x1b,0xca,0xdc,0x02,0x4b,0x23,0x96,0x26,0x57,0xdc,0x78,0x8c,0x1f,0xe5,0x9e,0xdf,0x9f,0xd3,0x1f,0xe2,0x8c,0x84,0x62,0xe1,0x5f},+ {0x1a,0x96,0x94,0xe1,0x4f,0x21,0x59,0x4e,0x4f,0xcd,0x71,0x0d,0xc7,0x7d,0xbe,0x49,0x2d,0xf2,0x50,0x3b,0xd2,0xcf,0x00,0x93,0x32,0x72,0x91,0xfc,0x46,0xd4,0x89,0x47,0x08,0xb2,0x7c,0x5d,0x2d,0x85,0x79,0x28,0xe7,0xf2,0x7d,0x68,0x70,0xdd,0xde,0xb8,0x91,0x78,0x68,0x21,0xab,0xff,0x0b,0xdc,0x35,0xaa,0x7d,0x67,0x43,0xc0,0x44,0x2b,0x8e,0xb7,0x4e,0x07,0xab,0x87,0x1c,0x1a,0x67,0xf4,0xda,0x99,0x8e,0xd1,0xc6,0xfa,0x67,0x90,0x4f,0x48,0xcd,0xbb,0xac,0x3e,0xe4,0xa4,0xb9,0x2b,0xef,0x2e,0xc5,0x60},+ {0xf1,0x8b,0xfd,0x3b,0xbc,0x89,0x5d,0x0b,0x1a,0x55,0xf3,0xc9,0x37,0x92,0x6b,0xb0,0xf5,0x28,0x30,0xd5,0xb0,0x16,0x4c,0x0e,0xab,0xca,0xcf,0x2c,0x31,0x9c,0xbc,0x10,0x11,0x6d,0xae,0x7c,0xc2,0xc5,0x2b,0x70,0xab,0x8c,0xa4,0x54,0x9b,0x69,0xc7,0x44,0xb2,0x2e,0x49,0xba,0x56,0x40,0xbc,0xef,0x6d,0x67,0xb6,0xd9,0x48,0x72,0xd7,0x70,0x5b,0xa0,0xc2,0x3e,0x4b,0xe8,0x8a,0xaa,0xe0,0x81,0x17,0xed,0xf4,0x9e,0x69,0x98,0xd1,0x85,0x8e,0x70,0xe4,0x13,0x45,0x79,0x13,0xf4,0x76,0xa9,0xd3,0x5b,0x75,0x63},+ {0x53,0x08,0xd1,0x2a,0x3e,0xa0,0x5f,0xb5,0x69,0x35,0xe6,0x9e,0x90,0x75,0x6f,0x35,0x90,0xb8,0x69,0xbe,0xfd,0xf1,0xf9,0x9f,0x84,0x6f,0xc1,0x8b,0xc4,0xc1,0x8c,0x0d,0xb7,0xac,0xf1,0x97,0x18,0x10,0xc7,0x3d,0xd8,0xbb,0x65,0xc1,0x5e,0x7d,0xda,0x5d,0x0f,0x02,0xa1,0x0f,0x9c,0x5b,0x8e,0x50,0x56,0x2a,0xc5,0x37,0x17,0x75,0x63,0x27,0xa9,0x19,0xb4,0x6e,0xd3,0x02,0x94,0x02,0xa5,0x60,0xb4,0x77,0x7e,0x4e,0xb4,0xf0,0x56,0x49,0x3c,0xd4,0x30,0x62,0xa8,0xcf,0xe7,0x66,0xd1,0x7a,0x8a,0xdd,0xc2,0x70},+ {0x0e,0xec,0x6f,0x9f,0x50,0x94,0x61,0x65,0x8d,0x51,0xc6,0x46,0xa9,0x7e,0x2e,0xee,0x5c,0x9b,0xe0,0x67,0xf3,0xc1,0x33,0x97,0x95,0x84,0x94,0x63,0x63,0xac,0x0f,0x2e,0x13,0x7e,0xed,0xb8,0x7d,0x96,0xd4,0x91,0x7a,0x81,0x76,0xd7,0x0a,0x2f,0x25,0x74,0x64,0x25,0x85,0x0d,0xe0,0x82,0x09,0xe4,0xe5,0x3c,0xa5,0x16,0x38,0x61,0xb8,0x32,0x64,0xcd,0x48,0xe4,0xbe,0xf7,0xe7,0x79,0xd0,0x86,0x78,0x08,0x67,0x3a,0xc8,0x6a,0x2e,0xdb,0xe4,0xa0,0xd9,0xd4,0x9f,0xf8,0x41,0x4f,0x5a,0x73,0x5c,0x21,0x79,0x41},+ {0x2a,0xed,0xdc,0xd7,0xe7,0x94,0x70,0x8c,0x70,0x9c,0xd3,0x47,0xc3,0x8a,0xfb,0x97,0x02,0xd9,0x06,0xa9,0x33,0xe0,0x3b,0xe1,0x76,0x9d,0xd9,0x0c,0xa3,0x44,0x03,0x70,0x34,0xcd,0x6b,0x28,0xb9,0x33,0xae,0xe4,0xdc,0xd6,0x9d,0x55,0xb6,0x7e,0xef,0xb7,0x1f,0x8e,0xd3,0xb3,0x1f,0x14,0x8b,0x27,0x86,0xc2,0x41,0x22,0x66,0x85,0xfa,0x31,0xf4,0x22,0x36,0x2e,0x42,0x6c,0x82,0xaf,0x2d,0x50,0x33,0x98,0x87,0x29,0x20,0xc1,0x23,0x91,0x38,0x2b,0xe1,0xb7,0xc1,0x9b,0x89,0x24,0x95,0xa9,0x12,0x23,0xbb,0x24},+ {0xc3,0x67,0xde,0x32,0x17,0xed,0xa8,0xb1,0x48,0x49,0x1b,0x46,0x18,0x94,0xb4,0x3c,0xd2,0xbc,0xcf,0x76,0x43,0x43,0xbd,0x8e,0x08,0x80,0x18,0x1e,0x87,0x3e,0xee,0x0f,0x6b,0x5c,0xf8,0xf5,0x2a,0x0c,0xf8,0x41,0x94,0x67,0xfa,0x04,0xc3,0x84,0x72,0x68,0xad,0x1b,0xba,0xa3,0x99,0xdf,0x45,0x89,0x16,0x5d,0xeb,0xff,0xf9,0x2a,0x1d,0x0d,0xdf,0x1e,0x62,0x32,0xa1,0x8a,0xda,0xa9,0x79,0x65,0x22,0x59,0xa1,0x22,0xb8,0x30,0x93,0xc1,0x9a,0xa7,0x7b,0x19,0x04,0x40,0x76,0x1d,0x53,0x18,0x97,0xd7,0xac,0x16},+ {0x3d,0x1d,0x9b,0x2d,0xaf,0x72,0xdf,0x72,0x5a,0x24,0x32,0xa4,0x36,0x2a,0x46,0x63,0x37,0x96,0xb3,0x16,0x79,0xa0,0xce,0x3e,0x09,0x23,0x30,0xb9,0xf6,0x0e,0x3e,0x12,0xad,0xb6,0x87,0x78,0xc5,0xc6,0x59,0xc9,0xba,0xfe,0x90,0x5f,0xad,0x9e,0xe1,0x94,0x04,0xf5,0x42,0xa3,0x62,0x4e,0xe2,0x16,0x00,0x17,0x16,0x18,0x4b,0xd3,0x4e,0x16,0x9a,0xe6,0x2f,0x19,0x4c,0xd9,0x7e,0x48,0x13,0x15,0x91,0x3a,0xea,0x2c,0xae,0x61,0x27,0xde,0xa4,0xb9,0xd3,0xf6,0x7b,0x87,0xeb,0xf3,0x73,0x10,0xc6,0x0f,0xda,0x78},+ {0x6a,0xc6,0x2b,0xe5,0x28,0x5d,0xf1,0x5b,0x8e,0x1a,0xf0,0x70,0x18,0xe3,0x47,0x2c,0xdd,0x8b,0xc2,0x06,0xbc,0xaf,0x19,0x24,0x3a,0x17,0x6b,0x25,0xeb,0xde,0x25,0x2d,0x94,0x3a,0x0c,0x68,0xf1,0x80,0x9f,0xa2,0xe6,0xe7,0xe9,0x1a,0x15,0x7e,0xf7,0x71,0x73,0x79,0x01,0x48,0x58,0xf1,0x00,0x11,0xdd,0x8d,0xb3,0x16,0xb3,0xa4,0x4a,0x05,0xb8,0x7c,0x26,0x19,0x8d,0x46,0xc8,0xdf,0xaf,0x4d,0xe5,0x66,0x9c,0x78,0x28,0x0b,0x17,0xec,0x6e,0x66,0x2a,0x1d,0xeb,0x2a,0x60,0xa7,0x7d,0xab,0xa6,0x10,0x46,0x13},+ {0xfe,0xb0,0xf6,0x8d,0xc7,0x8e,0x13,0x51,0x1b,0xf5,0x75,0xe5,0x89,0xda,0x97,0x53,0xb9,0xf1,0x7a,0x71,0x1d,0x7a,0x20,0x09,0x50,0xd6,0x20,0x2b,0xba,0xfd,0x02,0x21,0x15,0xf5,0xd1,0x77,0xe7,0x65,0x2a,0xcd,0xf1,0x60,0xaa,0x8f,0x87,0x91,0x89,0x54,0xe5,0x06,0xbc,0xda,0xbc,0x3b,0xb7,0xb1,0xfb,0xc9,0x7c,0xa9,0xcb,0x78,0x48,0x65,0xa1,0xe6,0x5c,0x05,0x05,0xe4,0x9e,0x96,0x29,0xad,0x51,0x12,0x68,0xa7,0xbc,0x36,0x15,0xa4,0x7d,0xaa,0x17,0xf5,0x1a,0x3a,0xba,0xb2,0xec,0x29,0xdb,0x25,0xd7,0x0a},+ {0x57,0x24,0x4e,0x83,0xb1,0x67,0x42,0xdc,0xc5,0x1b,0xce,0x70,0xb5,0x44,0x75,0xb6,0xd7,0x5e,0xd1,0xf7,0x0b,0x7a,0xf0,0x1a,0x50,0x36,0xa0,0x71,0xfb,0xcf,0xef,0x4a,0x85,0x6f,0x05,0x9b,0x0c,0xbc,0xc7,0xfe,0xd7,0xff,0xf5,0xe7,0x68,0x52,0x7d,0x53,0xfa,0xae,0x12,0x43,0x62,0xc6,0xaf,0x77,0xd9,0x9f,0x39,0x02,0x53,0x5f,0x67,0x4f,0x1e,0x17,0x15,0x04,0x36,0x36,0x2d,0xc3,0x3b,0x48,0x98,0x89,0x11,0xef,0x2b,0xcd,0x10,0x51,0x94,0xd0,0xad,0x6e,0x0a,0x87,0x61,0x65,0xa8,0xa2,0x72,0xbb,0xcc,0x0b},+ {0xc8,0xa9,0xb1,0xea,0x2f,0x96,0x5e,0x18,0xcd,0x7d,0x14,0x65,0x35,0xe6,0xe7,0x86,0xf2,0x6d,0x5b,0xbb,0x31,0xe0,0x92,0xb0,0x3e,0xb7,0xd6,0x59,0xab,0xf0,0x24,0x40,0x96,0x12,0xfe,0x50,0x4c,0x5e,0x6d,0x18,0x7e,0x9f,0xe8,0xfe,0x82,0x7b,0x39,0xe0,0xb0,0x31,0x70,0x50,0xc5,0xf6,0xc7,0x3b,0xc2,0x37,0x8f,0x10,0x69,0xfd,0x78,0x66,0xc2,0x63,0x68,0x63,0x31,0xfa,0x86,0x15,0xf2,0x33,0x2d,0x57,0x48,0x8c,0xf6,0x07,0xfc,0xae,0x9e,0x78,0x9f,0xcc,0x73,0x4f,0x01,0x47,0xad,0x8e,0x10,0xe2,0x42,0x2d},+ {0x9b,0xd2,0xdf,0x94,0x15,0x13,0xf5,0x97,0x6a,0x4c,0x3f,0x31,0x5d,0x98,0x55,0x61,0x10,0x50,0x45,0x08,0x07,0x3f,0xa1,0xeb,0x22,0xd3,0xd2,0xb8,0x08,0x26,0x6b,0x67,0x93,0x75,0x53,0x0f,0x0d,0x7b,0x71,0x21,0x4c,0x06,0x1e,0x13,0x0b,0x69,0x4e,0x91,0x9f,0xe0,0x2a,0x75,0xae,0x87,0xb6,0x1b,0x6e,0x3c,0x42,0x9b,0xa7,0xf3,0x0b,0x42,0x47,0x2b,0x5b,0x1c,0x65,0xba,0x38,0x81,0x80,0x1b,0x1b,0x31,0xec,0xb6,0x71,0x86,0xb0,0x35,0x31,0xbc,0xb1,0x0c,0xff,0x7b,0xe0,0xf1,0x0c,0x9c,0xfa,0x2f,0x5d,0x74},+ {0xbd,0xc8,0xc9,0x2b,0x1e,0x5a,0x52,0xbf,0x81,0x9d,0x47,0x26,0x08,0x26,0x5b,0xea,0xdb,0x55,0x01,0xdf,0x0e,0xc7,0x11,0xd5,0xd0,0xf5,0x0c,0x96,0xeb,0x3c,0xe2,0x1a,0x6a,0x4e,0xd3,0x21,0x57,0xdf,0x36,0x60,0xd0,0xb3,0x7b,0x99,0x27,0x88,0xdb,0xb1,0xfa,0x6a,0x75,0xc8,0xc3,0x09,0xc2,0xd3,0x39,0xc8,0x1d,0x4c,0xe5,0x5b,0xe1,0x06,0x4a,0x99,0x32,0x19,0x87,0x5d,0x72,0x5b,0xb0,0xda,0xb1,0xce,0xb5,0x1c,0x35,0x32,0x05,0xca,0xb7,0xda,0x49,0x15,0xc4,0x7d,0xf7,0xc1,0x8e,0x27,0x61,0xd8,0xde,0x58},+ {0x5c,0xc5,0x66,0xf2,0x93,0x37,0x17,0xd8,0x49,0x4e,0x45,0xcc,0xc5,0x76,0xc9,0xc8,0xa8,0xc3,0x26,0xbc,0xf8,0x82,0xe3,0x5c,0xf9,0xf6,0x85,0x54,0xe8,0x9d,0xf3,0x2f,0xa8,0xc9,0xc2,0xb6,0xa8,0x5b,0xfb,0x2d,0x8c,0x59,0x2c,0xf5,0x8e,0xef,0xee,0x48,0x73,0x15,0x2d,0xf1,0x07,0x91,0x80,0x33,0xd8,0x5b,0x1d,0x53,0x6b,0x69,0xba,0x08,0x7a,0xc5,0xef,0xc3,0xee,0x3e,0xed,0x77,0x11,0x48,0xff,0xd4,0x17,0x55,0xe0,0x04,0xcb,0x71,0xa6,0xf1,0x3f,0x7a,0x3d,0xea,0x54,0xfe,0x7c,0x94,0xb4,0x33,0x06,0x12},+ {0x42,0x00,0x61,0x91,0x78,0x98,0x94,0x0b,0xe8,0xfa,0xeb,0xec,0x3c,0xb1,0xe7,0x4e,0xc0,0xa4,0xf0,0x94,0x95,0x73,0xbe,0x70,0x85,0x91,0xd5,0xb4,0x99,0x0a,0xd3,0x35,0x0a,0x10,0x12,0x49,0x47,0x31,0xbd,0x82,0x06,0xbe,0x6f,0x7e,0x6d,0x7b,0x23,0xde,0xc6,0x79,0xea,0x11,0x19,0x76,0x1e,0xe1,0xde,0x3b,0x39,0xcb,0xe3,0x3b,0x43,0x07,0xf4,0x97,0xe9,0x5c,0xc0,0x44,0x79,0xff,0xa3,0x51,0x5c,0xb0,0xe4,0x3d,0x5d,0x57,0x7c,0x84,0x76,0x5a,0xfd,0x81,0x33,0x58,0x9f,0xda,0xf6,0x7a,0xde,0x3e,0x87,0x2d},+ {0x09,0x34,0x37,0x43,0x64,0x31,0x7a,0x15,0xd9,0x81,0xaa,0xf4,0xee,0xb7,0xb8,0xfa,0x06,0x48,0xa6,0xf5,0xe6,0xfe,0x93,0xb0,0xb6,0xa7,0x7f,0x70,0x54,0x36,0x77,0x2e,0x81,0xf9,0x5d,0x4e,0xe1,0x02,0x62,0xaa,0xf5,0xe1,0x15,0x50,0x17,0x59,0x0d,0xa2,0x6c,0x1d,0xe2,0xba,0xd3,0x75,0xa2,0x18,0x53,0x02,0x60,0x01,0x8a,0x61,0x43,0x05,0xc1,0x23,0x4c,0x97,0xf4,0xbd,0xea,0x0d,0x93,0x46,0xce,0x9d,0x25,0x0a,0x6f,0xaa,0x2c,0xba,0x9a,0xa2,0xb8,0x2c,0x20,0x04,0x0d,0x96,0x07,0x2d,0x36,0x43,0x14,0x4b},+ {0x7a,0x1f,0x6e,0xb6,0xc7,0xb7,0xc4,0xcc,0x7e,0x2f,0x0c,0xf5,0x25,0x7e,0x15,0x44,0x1c,0xaf,0x3e,0x71,0xfc,0x6d,0xf0,0x3e,0xf7,0x63,0xda,0x52,0x67,0x44,0x2f,0x58,0xcb,0x9c,0x52,0x1c,0xe9,0x54,0x7c,0x96,0xfb,0x35,0xc6,0x64,0x92,0x26,0xf6,0x30,0x65,0x19,0x12,0x78,0xf4,0xaf,0x47,0x27,0x5c,0x6f,0xf6,0xea,0x18,0x84,0x03,0x17,0xe4,0x4c,0x32,0x20,0xd3,0x7b,0x31,0xc6,0xc4,0x8b,0x48,0xa4,0xe8,0x42,0x10,0xa8,0x64,0x13,0x5a,0x4e,0x8b,0xf1,0x1e,0xb2,0xc9,0x8d,0xa2,0xcd,0x4b,0x1c,0x2a,0x0c},+ {0x47,0x04,0x1f,0x6f,0xd0,0xc7,0x4d,0xd2,0x59,0xc0,0x87,0xdb,0x3e,0x9e,0x26,0xb2,0x8f,0xd2,0xb2,0xfb,0x72,0x02,0x5b,0xd1,0x77,0x48,0xf6,0xc6,0xd1,0x8b,0x55,0x7c,0x45,0x69,0xbd,0x69,0x48,0x81,0xc4,0xed,0x22,0x8d,0x1c,0xbe,0x7d,0x90,0x6d,0x0d,0xab,0xc5,0x5c,0xd5,0x12,0xd2,0x3b,0xc6,0x83,0xdc,0x14,0xa3,0x30,0x9b,0x6a,0x5a,0x3d,0x46,0x96,0xd3,0x24,0x15,0xec,0xd0,0xf0,0x24,0x5a,0xc3,0x8a,0x62,0xbb,0x12,0xa4,0x5f,0xbc,0x1c,0x79,0x3a,0x0c,0xa5,0xc3,0xaf,0xfb,0x0a,0xca,0xa5,0x04,0x04},+ {0xd6,0x43,0xa7,0x0a,0x07,0x40,0x1f,0x8c,0xe8,0x5e,0x26,0x5b,0xcb,0xd0,0xba,0xcc,0xde,0xd2,0x8f,0x66,0x6b,0x04,0x4b,0x57,0x33,0x96,0xdd,0xca,0xfd,0x5b,0x39,0x46,0xd1,0x6f,0x41,0x2a,0x1b,0x9e,0xbc,0x62,0x8b,0x59,0x50,0xe3,0x28,0xf7,0xc6,0xb5,0x67,0x69,0x5d,0x3d,0xd8,0x3f,0x34,0x04,0x98,0xee,0xf8,0xe7,0x16,0x75,0x52,0x39,0x9c,0x9a,0x5d,0x1a,0x2d,0xdb,0x7f,0x11,0x2a,0x5c,0x00,0xd1,0xbc,0x45,0x77,0x9c,0xea,0x6f,0xd5,0x54,0xf1,0xbe,0xd4,0xef,0x16,0xd0,0x22,0xe8,0x29,0x9a,0x57,0x76},+ {0x17,0x2a,0xc0,0x49,0x7e,0x8e,0xb6,0x45,0x7f,0xa3,0xa9,0xbc,0xa2,0x51,0xcd,0x23,0x1b,0x4c,0x22,0xec,0x11,0x5f,0xd6,0x3e,0xb1,0xbd,0x05,0x9e,0xdc,0x84,0xa3,0x43,0xf2,0x34,0xb4,0x52,0x13,0xb5,0x3c,0x33,0xe1,0x80,0xde,0x93,0x49,0x28,0x32,0xd8,0xce,0x35,0x0d,0x75,0x87,0x28,0x51,0xb5,0xc1,0x77,0x27,0x2a,0xbb,0x14,0xc5,0x02,0x45,0xb6,0xf1,0x8b,0xda,0xd5,0x4b,0x68,0x53,0x4b,0xb5,0xf6,0x7e,0xd3,0x8b,0xfb,0x53,0xd2,0xb0,0xa9,0xd7,0x16,0x39,0x31,0x59,0x80,0x54,0x61,0x09,0x92,0x60,0x11},+ {0xaa,0xcf,0xda,0x29,0x69,0x16,0x4d,0xb4,0x8f,0x59,0x13,0x84,0x4c,0x9f,0x52,0xda,0x59,0x55,0x3d,0x45,0xca,0x63,0xef,0xe9,0x0b,0x8e,0x69,0xc5,0x5b,0x12,0x1e,0x35,0xcd,0x4d,0x9b,0x36,0x16,0x56,0x38,0x7a,0x63,0x35,0x5c,0x65,0xa7,0x2c,0xc0,0x75,0x21,0x80,0xf1,0xd4,0xf9,0x1b,0xc2,0x7d,0x42,0xe0,0xe6,0x91,0x74,0x7d,0x63,0x2f,0xbe,0x7b,0xf6,0x1a,0x46,0x9b,0xb4,0xd4,0x61,0x89,0xab,0xc8,0x7a,0x03,0x03,0xd6,0xfb,0x99,0xa6,0xf9,0x9f,0xe1,0xde,0x71,0x9a,0x2a,0xce,0xe7,0x06,0x2d,0x18,0x7f},+ {0xec,0x68,0x01,0xab,0x64,0x8e,0x7c,0x7a,0x43,0xc5,0xed,0x15,0x55,0x4a,0x5a,0xcb,0xda,0x0e,0xcd,0x47,0xd3,0x19,0x55,0x09,0xb0,0x93,0x3e,0x34,0x8c,0xac,0xd4,0x67,0x22,0x75,0x21,0x8e,0x72,0x4b,0x45,0x09,0xd8,0xb8,0x84,0xd4,0xf4,0xe8,0x58,0xaa,0x3c,0x90,0x46,0x7f,0x4d,0x25,0x58,0xd3,0x17,0x52,0x1c,0x24,0x43,0xc0,0xac,0x44,0x77,0x57,0x7a,0x4f,0xbb,0x6b,0x7d,0x1c,0xe1,0x13,0x83,0x91,0xd4,0xfe,0x35,0x8b,0x84,0x46,0x6b,0xc9,0xc6,0xa1,0xdc,0x4a,0xbd,0x71,0xad,0x12,0x83,0x1c,0x6d,0x55},+ {0x82,0x39,0x8d,0x0c,0xe3,0x40,0xef,0x17,0x34,0xfa,0xa3,0x15,0x3e,0x07,0xf7,0x31,0x6e,0x64,0x73,0x07,0xcb,0xf3,0x21,0x4f,0xff,0x4e,0x82,0x1d,0x6d,0x6c,0x6c,0x74,0x21,0xe8,0x1b,0xb1,0x56,0x67,0xf0,0x81,0xdd,0xf3,0xa3,0x10,0x23,0xf8,0xaf,0x0f,0x5d,0x46,0x99,0x6a,0x55,0xd0,0xb2,0xf8,0x05,0x7f,0x8c,0xcc,0x38,0xbe,0x7a,0x09,0xa4,0x2d,0xa5,0x7e,0x87,0xc9,0x49,0x0c,0x43,0x1d,0xdc,0x9b,0x55,0x69,0x43,0x4c,0xd2,0xeb,0xcc,0xf7,0x09,0x38,0x2c,0x02,0xbd,0x84,0xee,0x4b,0xa3,0x14,0x7e,0x57},+ {0x0a,0x3b,0xa7,0x61,0xac,0x68,0xe2,0xf0,0xf5,0xa5,0x91,0x37,0x10,0xfa,0xfa,0xf2,0xe9,0x00,0x6d,0x6b,0x82,0x3e,0xe1,0xc1,0x42,0x8f,0xd7,0x6f,0xe9,0x7e,0xfa,0x60,0x2b,0xd7,0x4d,0xbd,0xbe,0xce,0xfe,0x94,0x11,0x22,0x0f,0x06,0xda,0x4f,0x6a,0xf4,0xff,0xd1,0xc8,0xc0,0x77,0x59,0x4a,0x12,0x95,0x92,0x00,0xfb,0xb8,0x04,0x53,0x70,0xc6,0x6e,0x29,0x4d,0x35,0x1d,0x3d,0xb6,0xd8,0x31,0xad,0x5f,0x3e,0x05,0xc3,0xf3,0xec,0x42,0xbd,0xb4,0x8c,0x95,0x0b,0x67,0xfd,0x53,0x63,0xa1,0x0c,0x8e,0x39,0x21},+ {0xf3,0x33,0x2b,0x38,0x8a,0x05,0xf5,0x89,0xb4,0xc0,0x48,0xad,0x0b,0xba,0xe2,0x5a,0x6e,0xb3,0x3d,0xa5,0x03,0xb5,0x93,0x8f,0xe6,0x32,0xa2,0x95,0x9d,0xed,0xa3,0x5a,0x01,0x56,0xb7,0xb4,0xf9,0xaa,0x98,0x27,0x72,0xad,0x8d,0x5c,0x13,0x72,0xac,0x5e,0x23,0xa0,0xb7,0x61,0x61,0xaa,0xce,0xd2,0x4e,0x7d,0x8f,0xe9,0x84,0xb2,0xbf,0x1b,0x61,0x65,0xd9,0xc7,0xe9,0x77,0x67,0x65,0x36,0x80,0xc7,0x72,0x54,0x12,0x2b,0xcb,0xee,0x6e,0x50,0xd9,0x99,0x32,0x05,0x65,0xcc,0x57,0x89,0x5e,0x4e,0xe1,0x07,0x4a},+ {0x99,0xf9,0x0d,0x98,0xcb,0x12,0xe4,0x4e,0x71,0xc7,0x6e,0x3c,0x6f,0xd7,0x15,0xa3,0xfd,0x77,0x5c,0x92,0xde,0xed,0xa5,0xbb,0x02,0x34,0x31,0x1d,0x39,0xac,0x0b,0x3f,0x9b,0xa4,0x77,0xc4,0xcd,0x58,0x0b,0x24,0x17,0xf0,0x47,0x64,0xde,0xda,0x38,0xfd,0xad,0x6a,0xc8,0xa7,0x32,0x8d,0x92,0x19,0x81,0xa0,0xaf,0x84,0xed,0x7a,0xaf,0x50,0xe5,0x5b,0xf6,0x15,0x01,0xde,0x4f,0x6e,0xb2,0x09,0x61,0x21,0x21,0x26,0x98,0x29,0xd9,0xd6,0xad,0x0b,0x81,0x05,0x02,0x78,0x06,0xd0,0xeb,0xba,0x16,0xa3,0x21,0x19},+ {0xfc,0x70,0xb8,0xdf,0x7e,0x2f,0x42,0x89,0xbd,0xb3,0x76,0x4f,0xeb,0x6b,0x29,0x2c,0xf7,0x4d,0xc2,0x36,0xd4,0xf1,0x38,0x07,0xb0,0xae,0x73,0xe2,0x41,0xdf,0x58,0x64,0x8b,0xc1,0xf3,0xd9,0x9a,0xad,0x5a,0xd7,0x9c,0xc1,0xb1,0x60,0xef,0x0e,0x6a,0x56,0xd9,0x0e,0x5c,0x25,0xac,0x0b,0x9a,0x3e,0xf5,0xc7,0x62,0xa0,0xec,0x9d,0x04,0x7b,0x83,0x44,0x44,0x35,0x7a,0xe3,0xcb,0xdc,0x93,0xbe,0xed,0x0f,0x33,0x79,0x88,0x75,0x87,0xdd,0xc5,0x12,0xc3,0x04,0x60,0x78,0x64,0x0e,0x95,0xc2,0xcb,0xdc,0x93,0x60},+ {0x6d,0x70,0xe0,0x85,0x85,0x9a,0xf3,0x1f,0x33,0x39,0xe7,0xb3,0xd8,0xa5,0xd0,0x36,0x3b,0x45,0x8f,0x71,0xe1,0xf2,0xb9,0x43,0x7c,0xa9,0x27,0x48,0x08,0xea,0xd1,0x57,0x4b,0x03,0x84,0x60,0xbe,0xee,0xde,0x6b,0x54,0xb8,0x0f,0x78,0xb6,0xc2,0x99,0x31,0x95,0x06,0x2d,0xb6,0xab,0x76,0x33,0x97,0x90,0x7d,0x64,0x8b,0xc9,0x80,0x31,0x6e,0x71,0xb0,0x28,0xa1,0xe7,0xb6,0x7a,0xee,0xaa,0x8b,0xa8,0x93,0x6d,0x59,0xc1,0xa4,0x30,0x61,0x21,0xb2,0x82,0xde,0xb4,0xf7,0x18,0xbd,0x97,0xdd,0x9d,0x99,0x3e,0x36},+ {0xc4,0x1f,0xee,0x35,0xc1,0x43,0xa8,0x96,0xcf,0xc8,0xe4,0x08,0x55,0xb3,0x6e,0x97,0x30,0xd3,0x8c,0xb5,0x01,0x68,0x2f,0xb4,0x2b,0x05,0x3a,0x69,0x78,0x9b,0xee,0x48,0xc6,0xae,0x4b,0xe2,0xdc,0x48,0x18,0x2f,0x60,0xaf,0xbc,0xba,0x55,0x72,0x9b,0x76,0x31,0xe9,0xef,0x3c,0x6e,0x3c,0xcb,0x90,0x55,0xb3,0xf9,0xc6,0x9b,0x97,0x1f,0x23,0xc6,0xf3,0x2a,0xcc,0x4b,0xde,0x31,0x5c,0x1f,0x8d,0x20,0xfe,0x30,0xb0,0x4b,0xb0,0x66,0xb4,0x4f,0xc1,0x09,0x70,0x8d,0xb7,0x13,0x24,0x79,0x08,0x9b,0xfa,0x9b,0x07},+ {0xf4,0x0d,0x30,0xda,0x51,0x3a,0x90,0xe3,0xb0,0x5a,0xa9,0x3d,0x23,0x64,0x39,0x84,0x80,0x64,0x35,0x0b,0x2d,0xf1,0x3c,0xed,0x94,0x71,0x81,0x84,0xf6,0x77,0x8c,0x03,0x45,0x42,0xd5,0xa2,0x80,0xed,0xc9,0xf3,0x52,0x39,0xf6,0x77,0x78,0x8b,0xa0,0x0a,0x75,0x54,0x08,0xd1,0x63,0xac,0x6d,0xd7,0x6b,0x63,0x70,0x94,0x15,0xfb,0xf4,0x1e,0xec,0x7b,0x16,0x5b,0xe6,0x5e,0x4e,0x85,0xc2,0xcd,0xd0,0x96,0x42,0x0a,0x59,0x59,0x99,0x21,0x10,0x98,0x34,0xdf,0xb2,0x72,0x56,0xff,0x0b,0x4a,0x2a,0xe9,0x5e,0x57},+ {0xcf,0x2f,0x18,0x8a,0x90,0x80,0xc0,0xd4,0xbd,0x9d,0x48,0x99,0xc2,0x70,0xe1,0x30,0xde,0x33,0xf7,0x52,0x57,0xbd,0xba,0x05,0x00,0xfd,0xd3,0x2c,0x11,0xe7,0xd4,0x43,0x01,0xd8,0xa4,0x0a,0x45,0xbc,0x46,0x5d,0xd8,0xb9,0x33,0xa5,0x27,0x12,0xaf,0xc3,0xc2,0x06,0x89,0x2b,0x26,0x3b,0x9e,0x38,0x1b,0x58,0x2f,0x38,0x7e,0x1e,0x0a,0x20,0xc5,0x3a,0xf9,0xea,0x67,0xb9,0x8d,0x51,0xc0,0x52,0x66,0x05,0x9b,0x98,0xbc,0x71,0xf5,0x97,0x71,0x56,0xd9,0x85,0x2b,0xfe,0x38,0x4e,0x1e,0x65,0x52,0xca,0x0e,0x05},+ {0x9c,0x0c,0x3f,0x45,0xde,0x1a,0x43,0xc3,0x9b,0x3b,0x70,0xff,0x5e,0x04,0xf5,0xe9,0x3d,0x7b,0x84,0xed,0xc9,0x7a,0xd9,0xfc,0xc6,0xf4,0x58,0x1c,0xc2,0xe6,0x0e,0x4b,0xea,0x68,0xe6,0x60,0x76,0x39,0xac,0x97,0x97,0xb4,0x3a,0x15,0xfe,0xbb,0x19,0x9b,0x9f,0xa7,0xec,0x34,0xb5,0x79,0xb1,0x4c,0x57,0xae,0x31,0xa1,0x9f,0xc0,0x51,0x61,0x96,0x5d,0xf0,0xfd,0x0d,0x5c,0xf5,0x3a,0x7a,0xee,0xb4,0x2a,0xe0,0x2e,0x26,0xdd,0x09,0x17,0x17,0x12,0x87,0xbb,0xb2,0x11,0x0b,0x03,0x0f,0x80,0xfa,0x24,0xef,0x1f},+ {0x96,0x31,0xa7,0x1a,0xfb,0x53,0xd6,0x37,0x18,0x64,0xd7,0x3f,0x30,0x95,0x94,0x0f,0xb2,0x17,0x3a,0xfb,0x09,0x0b,0x20,0xad,0x3e,0x61,0xc8,0x2f,0x29,0x49,0x4d,0x54,0x86,0x6b,0x97,0x30,0xf5,0xaf,0xd2,0x22,0x04,0x46,0xd2,0xc2,0x06,0xb8,0x90,0x8d,0xe5,0xba,0xe5,0x4d,0x6c,0x89,0xa1,0xdc,0x17,0x0c,0x34,0xc8,0xe6,0x5f,0x00,0x28,0x88,0x86,0x52,0x34,0x9f,0xba,0xef,0x6a,0xa1,0x7d,0x10,0x25,0x94,0xff,0x1b,0x5c,0x36,0x4b,0xd9,0x66,0xcd,0xbb,0x5b,0xf7,0xfa,0x6d,0x31,0x0f,0x93,0x72,0xe4,0x72},+ {0x4f,0x08,0x81,0x97,0x8c,0x20,0x95,0x26,0xe1,0x0e,0x45,0x23,0x0b,0x2a,0x50,0xb1,0x02,0xde,0xef,0x03,0xa6,0xae,0x9d,0xfd,0x4c,0xa3,0x33,0x27,0x8c,0x2e,0x9d,0x5a,0x27,0x76,0x2a,0xd3,0x35,0xf6,0xf3,0x07,0xf0,0x66,0x65,0x5f,0x86,0x4d,0xaa,0x7a,0x50,0x44,0xd0,0x28,0x97,0xe7,0x85,0x3c,0x38,0x64,0xe0,0x0f,0x00,0x7f,0xee,0x1f,0xe5,0xf7,0xdb,0x03,0xda,0x05,0x53,0x76,0xbd,0xcd,0x34,0x14,0x49,0xf2,0xda,0xa4,0xec,0x88,0x4a,0xd2,0xcd,0xd5,0x4a,0x7b,0x43,0x05,0x04,0xee,0x51,0x40,0xf9,0x00},+ {0xb2,0x30,0xd3,0xc3,0x23,0x6b,0x35,0x8d,0x06,0x1b,0x47,0xb0,0x9b,0x8b,0x1c,0xf2,0x3c,0xb8,0x42,0x6e,0x6c,0x31,0x6c,0xb3,0x0d,0xb1,0xea,0x8b,0x7e,0x9c,0xd7,0x07,0x53,0x97,0xaf,0x07,0xbb,0x93,0xef,0xd7,0xa7,0x66,0xb7,0x3d,0xcf,0xd0,0x3e,0x58,0xc5,0x1e,0x0b,0x6e,0xbf,0x98,0x69,0xce,0x52,0x04,0xd4,0x5d,0xd2,0xff,0xb7,0x47,0x12,0xdd,0x08,0xbc,0x9c,0xfb,0xfb,0x87,0x9b,0xc2,0xee,0xe1,0x3a,0x6b,0x06,0x8a,0xbf,0xc1,0x1f,0xdb,0x2b,0x24,0x57,0x0d,0xb6,0x4b,0xa6,0x5e,0xa3,0x20,0x35,0x1c},+ {0x4a,0xa3,0xcb,0xbc,0xa6,0x53,0xd2,0x80,0x9b,0x21,0x38,0x38,0xa1,0xc3,0x61,0x3e,0x96,0xe3,0x82,0x98,0x01,0xb6,0xc3,0x90,0x6f,0xe6,0x0e,0x5d,0x77,0x05,0x3d,0x1c,0x59,0xc0,0x6b,0x21,0x40,0x6f,0xa8,0xcd,0x7e,0xd8,0xbc,0x12,0x1d,0x23,0xbb,0x1f,0x90,0x09,0xc7,0x17,0x9e,0x6a,0x95,0xb4,0x55,0x2e,0xd1,0x66,0x3b,0x0c,0x75,0x38,0x1a,0xe5,0x22,0x94,0x40,0xf1,0x2e,0x69,0x71,0xf6,0x5d,0x2b,0x3c,0xc7,0xc0,0xcb,0x29,0xe0,0x4c,0x74,0xe7,0x4f,0x01,0x21,0x7c,0x48,0x30,0xd3,0xc7,0xe2,0x21,0x06},+ {0x8d,0x83,0x59,0x82,0xcc,0x60,0x98,0xaf,0xdc,0x9a,0x9f,0xc6,0xc1,0x48,0xea,0x90,0x30,0x1e,0x58,0x65,0x37,0x48,0x26,0x65,0xbc,0xa5,0xd3,0x7b,0x09,0xd6,0x07,0x00,0xf3,0xf0,0xdb,0xb0,0x96,0x17,0xae,0xb7,0x96,0xe1,0x7c,0xe1,0xb9,0xaf,0xdf,0x54,0xb4,0xa3,0xaa,0xe9,0x71,0x30,0x92,0x25,0x9d,0x2e,0x00,0xa1,0x9c,0x58,0x8e,0x5d,0x4b,0xa9,0x42,0x08,0x95,0x1d,0xbf,0xc0,0x3e,0x2e,0x8f,0x58,0x63,0xc3,0xd3,0xb2,0xef,0xe2,0x51,0xbb,0x38,0x14,0x96,0x0a,0x86,0xbf,0x1c,0x3c,0x78,0xd7,0x83,0x15},+ {0xe1,0x7a,0xa2,0x5d,0xef,0xa2,0xee,0xec,0x74,0x01,0x67,0x55,0x14,0x3a,0x7c,0x59,0x7a,0x16,0x09,0x66,0x12,0x2a,0xa6,0xc9,0x70,0x8f,0xed,0x81,0x2e,0x5f,0x2a,0x25,0xc7,0x28,0x9d,0xcc,0x04,0x47,0x03,0x90,0x8f,0xc5,0x2c,0xf7,0x9e,0x67,0x1b,0x1d,0x26,0x87,0x5b,0xbe,0x5f,0x2b,0xe1,0x16,0x0a,0x58,0xc5,0x83,0x4e,0x06,0x58,0x49,0x0d,0xe8,0x66,0x50,0x26,0x94,0x28,0x0d,0x6b,0x8c,0x7c,0x30,0x85,0xf7,0xc3,0xfc,0xfd,0x12,0x11,0x0c,0x78,0xda,0x53,0x1b,0x88,0xb3,0x43,0xd8,0x0b,0x17,0x9c,0x07},+ {0xff,0x6f,0xfa,0x64,0xe4,0xec,0x06,0x05,0x23,0xe5,0x05,0x62,0x1e,0x43,0xe3,0xbe,0x42,0xea,0xb8,0x51,0x24,0x42,0x79,0x35,0x00,0xfb,0xc9,0x4a,0xe3,0x05,0xec,0x6d,0x56,0xd0,0xd5,0xc0,0x50,0xcd,0xd6,0xcd,0x3b,0x57,0x03,0xbb,0x6d,0x68,0xf7,0x9a,0x48,0xef,0xc3,0xf3,0x3f,0x72,0xa6,0x3c,0xcc,0x8a,0x7b,0x31,0xd7,0xc0,0x68,0x67,0xb3,0xc1,0x55,0xf1,0xe5,0x25,0xb6,0x94,0x91,0x7b,0x7b,0x99,0xa7,0xf3,0x7b,0x41,0x00,0x26,0x6b,0x6d,0xdc,0xbd,0x2c,0xc2,0xf4,0x52,0xcd,0xdd,0x14,0x5e,0x44,0x51},+ {0x51,0x49,0x14,0x3b,0x4b,0x2b,0x50,0x57,0xb3,0xbc,0x4b,0x44,0x6b,0xff,0x67,0x8e,0xdb,0x85,0x63,0x16,0x27,0x69,0xbd,0xb8,0xc8,0x95,0x92,0xe3,0x31,0x6f,0x18,0x13,0x55,0xa4,0xbe,0x2b,0xab,0x47,0x31,0x89,0x29,0x91,0x07,0x92,0x4f,0xa2,0x53,0x8c,0xa7,0xf7,0x30,0xbe,0x48,0xf9,0x49,0x4b,0x3d,0xd4,0x4f,0x6e,0x08,0x90,0xe9,0x12,0x2e,0xbb,0xdf,0x7f,0xb3,0x96,0x0c,0xf1,0xf9,0xea,0x1c,0x12,0x5e,0x93,0x9a,0x9f,0x3f,0x98,0x5b,0x3a,0xc4,0x36,0x11,0xdf,0xaf,0x99,0x3e,0x5d,0xf0,0xe3,0xb2,0x77},+ {0xde,0xc4,0x2e,0x9c,0xc5,0xa9,0x6f,0x29,0xcb,0xf3,0x84,0x4f,0xbf,0x61,0x8b,0xbc,0x08,0xf9,0xa8,0x17,0xd9,0x06,0x77,0x1c,0x5d,0x25,0xd3,0x7a,0xfc,0x95,0xb7,0x63,0xa4,0xb0,0xdd,0x12,0x9c,0x63,0x98,0xd5,0x6b,0x86,0x24,0xc0,0x30,0x9f,0xd1,0xa5,0x60,0xe4,0xfc,0x58,0x03,0x2f,0x7c,0xd1,0x8a,0x5e,0x09,0x2e,0x15,0x95,0xa1,0x07,0xc8,0x5f,0x9e,0x38,0x02,0x8f,0x36,0xa8,0x3b,0xe4,0x8d,0xcf,0x02,0x3b,0x43,0x90,0x43,0x26,0x41,0xc5,0x5d,0xfd,0xa1,0xaf,0x37,0x01,0x2f,0x03,0x3d,0xe8,0x8f,0x3e},+ {0x94,0xa2,0x70,0x05,0xb9,0x15,0x8b,0x2f,0x49,0x45,0x08,0x67,0x70,0x42,0xf2,0x94,0x84,0xfd,0xbb,0x61,0xe1,0x5a,0x1c,0xde,0x07,0x40,0xac,0x7f,0x79,0x3b,0xba,0x75,0x3c,0xd1,0xef,0xe8,0x8d,0x4c,0x70,0x08,0x31,0x37,0xe0,0x33,0x8e,0x1a,0xc5,0xdf,0xe3,0xcd,0x60,0x12,0xa5,0x5d,0x9d,0xa5,0x86,0x8c,0x25,0xa6,0x99,0x08,0xd6,0x22,0x96,0xd1,0xcd,0x70,0xc0,0xdb,0x39,0x62,0x9a,0x8a,0x7d,0x6c,0x8b,0x8a,0xfe,0x60,0x60,0x12,0x40,0xeb,0xbc,0x47,0x88,0xb3,0x5e,0x9e,0x77,0x87,0x7b,0xd0,0x04,0x09},+ {0x9c,0x91,0xba,0xdd,0xd4,0x1f,0xce,0xb4,0xaa,0x8d,0x4c,0xc7,0x3e,0xdb,0x31,0xcf,0x51,0xcc,0x86,0xad,0x63,0xcc,0x63,0x2c,0x07,0xde,0x1d,0xbc,0x3f,0x14,0xe2,0x43,0xb9,0x40,0xf9,0x48,0x66,0x2d,0x32,0xf4,0x39,0x0c,0x2d,0xbd,0x0c,0x2f,0x95,0x06,0x31,0xf9,0x81,0xa0,0xad,0x97,0x76,0x16,0x6c,0x2a,0xf7,0xba,0xce,0xaa,0x40,0x62,0xa0,0x95,0xa2,0x5b,0x9c,0x74,0x34,0xf8,0x5a,0xd2,0x37,0xca,0x5b,0x7c,0x94,0xd6,0x6a,0x31,0xc9,0xe7,0xa7,0x3b,0xf1,0x66,0xac,0x0c,0xb4,0x8d,0x23,0xaf,0xbd,0x56},+ {0xeb,0x33,0x35,0xf5,0xe3,0xb9,0x2a,0x36,0x40,0x3d,0xb9,0x6e,0xd5,0x68,0x85,0x33,0x72,0x55,0x5a,0x1d,0x52,0x14,0x0e,0x9e,0x18,0x13,0x74,0x83,0x6d,0xa8,0x24,0x1d,0xb2,0x3b,0x9d,0xc1,0x6c,0xd3,0x10,0x13,0xb9,0x86,0x23,0x62,0xb7,0x6b,0x2a,0x06,0x5c,0x4f,0xa1,0xd7,0x91,0x85,0x9b,0x7c,0x54,0x57,0x1e,0x7e,0x50,0x31,0xaa,0x03,0x1f,0xce,0xd4,0xff,0x48,0x76,0xec,0xf4,0x1c,0x8c,0xac,0x54,0xf0,0xea,0x45,0xe0,0x7c,0x35,0x09,0x1d,0x82,0x25,0xd2,0x88,0x59,0x48,0xeb,0x9a,0xdc,0x61,0xb2,0x43},+ {0xbb,0x79,0xbb,0x88,0x19,0x1e,0x5b,0xe5,0x9d,0x35,0x7a,0xc1,0x7d,0xd0,0x9e,0xa0,0x33,0xea,0x3d,0x60,0xe2,0x2e,0x2c,0xb0,0xc2,0x6b,0x27,0x5b,0xcf,0x55,0x60,0x32,0x64,0x13,0x95,0x6c,0x8b,0x3d,0x51,0x19,0x7b,0xf4,0x0b,0x00,0x26,0x71,0xfe,0x94,0x67,0x95,0x4f,0xd5,0xdd,0x10,0x8d,0x02,0x64,0x09,0x94,0x42,0xe2,0xd5,0xb4,0x02,0xf2,0x8d,0xd1,0x28,0xcb,0x55,0xa1,0xb4,0x08,0xe5,0x6c,0x18,0x46,0x46,0xcc,0xea,0x89,0x43,0x82,0x6c,0x93,0xf4,0x9c,0xc4,0x10,0x34,0x5d,0xae,0x09,0xc8,0xa6,0x27},+ {0x88,0xb1,0x0d,0x1f,0xcd,0xeb,0xa6,0x8b,0xe8,0x5b,0x5a,0x67,0x3a,0xd7,0xd3,0x37,0x5a,0x58,0xf5,0x15,0xa3,0xdf,0x2e,0xf2,0x7e,0xa1,0x60,0xff,0x74,0x71,0xb6,0x2c,0x54,0x69,0x3d,0xc4,0x0a,0x27,0x2c,0xcd,0xb2,0xca,0x66,0x6a,0x57,0x3e,0x4a,0xdd,0x6c,0x03,0xd7,0x69,0x24,0x59,0xfa,0x79,0x99,0x25,0x8c,0x3d,0x60,0x03,0x15,0x22,0xd0,0xe1,0x0b,0x39,0xf9,0xcd,0xee,0x59,0xf1,0xe3,0x8c,0x72,0x44,0x20,0x42,0xa9,0xf4,0xf0,0x94,0x7a,0x66,0x1c,0x89,0x82,0x36,0xf4,0x90,0x38,0xb7,0xf4,0x1d,0x7b},+ {0x24,0xa2,0xb2,0xb3,0xe0,0xf2,0x92,0xe4,0x60,0x11,0x55,0x2b,0x06,0x9e,0x6c,0x7c,0x0e,0x7b,0x7f,0x0d,0xe2,0x8f,0xeb,0x15,0x92,0x59,0xfc,0x58,0x26,0xef,0xfc,0x61,0x8c,0xf5,0xf8,0x07,0x18,0x22,0x2e,0x5f,0xd4,0x09,0x94,0xd4,0x9f,0x5c,0x55,0xe3,0x30,0xa6,0xb6,0x1f,0x8d,0xa8,0xaa,0xb2,0x3d,0xe0,0x52,0xd3,0x45,0x82,0x69,0x68,0x7a,0x18,0x18,0x2a,0x85,0x5d,0xb1,0xdb,0xd7,0xac,0xdd,0x86,0xd3,0xaa,0xe4,0xf3,0x82,0xc4,0xf6,0x0f,0x81,0xe2,0xba,0x44,0xcf,0x01,0xaf,0x3d,0x47,0x4c,0xcf,0x46},+ {0xf9,0xe5,0xc4,0x9e,0xed,0x25,0x65,0x42,0x03,0x33,0x90,0x16,0x01,0xda,0x5e,0x0e,0xdc,0xca,0xe5,0xcb,0xf2,0xa7,0xb1,0x72,0x40,0x5f,0xeb,0x14,0xcd,0x7b,0x38,0x29,0x40,0x81,0x49,0xf1,0xa7,0x6e,0x3c,0x21,0x54,0x48,0x2b,0x39,0xf8,0x7e,0x1e,0x7c,0xba,0xce,0x29,0x56,0x8c,0xc3,0x88,0x24,0xbb,0xc5,0x8c,0x0d,0xe5,0xaa,0x65,0x10,0x57,0x0d,0x20,0xdf,0x25,0x45,0x2c,0x1c,0x4a,0x67,0xca,0xbf,0xd6,0x2d,0x3b,0x5c,0x30,0x40,0x83,0xe1,0xb1,0xe7,0x07,0x0a,0x16,0xe7,0x1c,0x4f,0xe6,0x98,0xa1,0x69},+ {0xbc,0x78,0x1a,0xd9,0xe0,0xb2,0x62,0x90,0x67,0x96,0x50,0xc8,0x9c,0x88,0xc9,0x47,0xb8,0x70,0x50,0x40,0x66,0x4a,0xf5,0x9d,0xbf,0xa1,0x93,0x24,0xa9,0xe6,0x69,0x73,0xed,0xca,0xc5,0xdc,0x34,0x44,0x01,0xe1,0x33,0xfb,0x84,0x3c,0x96,0x5d,0xed,0x47,0xe7,0xa0,0x86,0xed,0x76,0x95,0x01,0x70,0xe4,0xf9,0x67,0xd2,0x7b,0x69,0xb2,0x25,0x64,0x68,0x98,0x13,0xfb,0x3f,0x67,0x9d,0xb8,0xc7,0x5d,0x41,0xd9,0xfb,0xa5,0x3c,0x5e,0x3b,0x27,0xdf,0x3b,0xcc,0x4e,0xe0,0xd2,0x4c,0x4e,0xb5,0x3d,0x68,0x20,0x14},+ {0x97,0xd1,0x9d,0x24,0x1e,0xbd,0x78,0xb4,0x02,0xc1,0x58,0x5e,0x00,0x35,0x0c,0x62,0x5c,0xac,0xba,0xcc,0x2f,0xd3,0x02,0xfb,0x2d,0xa7,0x08,0xf5,0xeb,0x3b,0xb6,0x60,0xd0,0x5a,0xcc,0xc1,0x6f,0xbb,0xee,0x34,0x8b,0xac,0x46,0x96,0xe9,0x0c,0x1b,0x6a,0x53,0xde,0x6b,0xa6,0x49,0xda,0xb0,0xd3,0xc1,0x81,0xd0,0x61,0x41,0x3b,0xe8,0x31,0x4f,0x2b,0x06,0x9e,0x12,0xc7,0xe8,0x97,0xd8,0x0a,0x32,0x29,0x4f,0x8f,0xe4,0x49,0x3f,0x68,0x18,0x6f,0x4b,0xe1,0xec,0x5b,0x17,0x03,0x55,0x2d,0xb6,0x1e,0xcf,0x55},+ {0x58,0x3d,0xc2,0x65,0x10,0x10,0x79,0x58,0x9c,0x81,0x94,0x50,0x6d,0x08,0x9d,0x8b,0xa7,0x5f,0xc5,0x12,0xa9,0x2f,0x40,0xe2,0xd4,0x91,0x08,0x57,0x64,0x65,0x9a,0x66,0x52,0x8c,0xf5,0x7d,0xe3,0xb5,0x76,0x30,0x36,0xcc,0x99,0xe7,0xdd,0xb9,0x3a,0xd7,0x20,0xee,0x13,0x49,0xe3,0x1c,0x83,0xbd,0x33,0x01,0xba,0x62,0xaa,0xfb,0x56,0x1a,0xec,0xc9,0x9d,0x5c,0x50,0x6b,0x3e,0x94,0x1a,0x37,0x7c,0xa7,0xbb,0x57,0x25,0x30,0x51,0x76,0x34,0x41,0x56,0xae,0x73,0x98,0x5c,0x8a,0xc5,0x99,0x67,0x83,0xc4,0x13},+ {0xb9,0xe1,0xb3,0x5a,0x46,0x5d,0x3a,0x42,0x61,0x3f,0xf1,0xc7,0x87,0xc1,0x13,0xfc,0xb6,0xb9,0xb5,0xec,0x64,0x36,0xf8,0x19,0x07,0xb6,0x37,0xa6,0x93,0x0c,0xf8,0x66,0x80,0xd0,0x8b,0x5d,0x6a,0xfb,0xdc,0xc4,0x42,0x48,0x1a,0x57,0xec,0xc4,0xeb,0xde,0x65,0x53,0xe5,0xb8,0x83,0xe8,0xb2,0xd4,0x27,0xb8,0xe5,0xc8,0x7d,0xc8,0xbd,0x50,0x11,0xe1,0xdf,0x6e,0x83,0x37,0x6d,0x60,0xd9,0xab,0x11,0xf0,0x15,0x3e,0x35,0x32,0x96,0x3b,0xb7,0x25,0xc3,0x3a,0xb0,0x64,0xae,0xd5,0x5f,0x72,0x44,0x64,0xd5,0x1d},+ {0x7d,0x12,0x62,0x33,0xf8,0x7f,0xa4,0x8f,0x15,0x7c,0xcd,0x71,0xc4,0x6a,0x9f,0xbc,0x8b,0x0c,0x22,0x49,0x43,0x45,0x71,0x6e,0x2e,0x73,0x9f,0x21,0x12,0x59,0x64,0x0e,0x9a,0xc8,0xba,0x08,0x00,0xe6,0x97,0xc2,0xe0,0xc3,0xe1,0xea,0x11,0xea,0x4c,0x7d,0x7c,0x97,0xe7,0x9f,0xe1,0x8b,0xe3,0xf3,0xcd,0x05,0xa3,0x63,0x0f,0x45,0x3a,0x3a,0x27,0x46,0x39,0xd8,0x31,0x2f,0x8f,0x07,0x10,0xa5,0x94,0xde,0x83,0x31,0x9d,0x38,0x80,0x6f,0x99,0x17,0x6d,0x6c,0xe3,0xd1,0x7b,0xa8,0xa9,0x93,0x93,0x8d,0x8c,0x31},+ {0x19,0xfe,0xff,0x2a,0x03,0x5d,0x74,0xf2,0x66,0xdb,0x24,0x7f,0x49,0x3c,0x9f,0x0c,0xef,0x98,0x85,0xba,0xe3,0xd3,0x98,0xbc,0x14,0x53,0x1d,0x9a,0x67,0x7c,0x4c,0x22,0x98,0xd3,0x1d,0xab,0x29,0x9e,0x66,0x5d,0x3b,0x9e,0x2d,0x34,0x58,0x16,0x92,0xfc,0xcd,0x73,0x59,0xf3,0xfd,0x1d,0x85,0x55,0xf6,0x0a,0x95,0x25,0xc3,0x41,0x9a,0x50,0xe9,0x25,0xf9,0xa6,0xdc,0x6e,0xc0,0xbd,0x33,0x1f,0x1b,0x64,0xf4,0xf3,0x3e,0x79,0x89,0x3e,0x83,0x9d,0x80,0x12,0xec,0x82,0x89,0x13,0xa1,0x28,0x23,0xf0,0xbf,0x05},+ {0x0b,0xe0,0xca,0x23,0x70,0x13,0x32,0x36,0x59,0xcf,0xac,0xd1,0x0a,0xcf,0x4a,0x54,0x88,0x1c,0x1a,0xd2,0x49,0x10,0x74,0x96,0xa7,0x44,0x2a,0xfa,0xc3,0x8c,0x0b,0x78,0xe4,0x12,0xc5,0x0d,0xdd,0xa0,0x81,0x68,0xfe,0xfa,0xa5,0x44,0xc8,0x0d,0xe7,0x4f,0x40,0x52,0x4a,0x8f,0x6b,0x8e,0x74,0x1f,0xea,0xa3,0x01,0xee,0xcd,0x77,0x62,0x57,0x5f,0x30,0x4f,0x23,0xbc,0x8a,0xf3,0x1e,0x08,0xde,0x05,0x14,0xbd,0x7f,0x57,0x9a,0x0d,0x2a,0xe6,0x34,0x14,0xa5,0x82,0x5e,0xa1,0xb7,0x71,0x62,0x72,0x18,0xf4,0x5f},+ {0x9d,0xdb,0x89,0x17,0x0c,0x08,0x8e,0x39,0xf5,0x78,0xe7,0xf3,0x25,0x20,0x60,0xa7,0x5d,0x03,0xbd,0x06,0x4c,0x89,0x98,0xfa,0xbe,0x66,0xa9,0x25,0xdc,0x03,0x6a,0x10,0x40,0x95,0xb6,0x13,0xe8,0x47,0xdb,0xe5,0xe1,0x10,0x26,0x43,0x3b,0x2a,0x5d,0xf3,0x76,0x12,0x78,0x38,0xe9,0x26,0x1f,0xac,0x69,0xcb,0xa0,0xa0,0x8c,0xdb,0xd4,0x29,0xd0,0x53,0x33,0x33,0xaf,0x0a,0xad,0xd9,0xe5,0x09,0xd3,0xac,0xa5,0x9d,0x66,0x38,0xf0,0xf7,0x88,0xc8,0x8a,0x65,0x57,0x3c,0xfa,0xbe,0x2c,0x05,0x51,0x8a,0xb3,0x4a},+ {0x93,0xd5,0x68,0x67,0x25,0x2b,0x7c,0xda,0x13,0xca,0x22,0x44,0x57,0xc0,0xc1,0x98,0x1d,0xce,0x0a,0xca,0xd5,0x0b,0xa8,0xf1,0x90,0xa6,0x88,0xc0,0xad,0xd1,0xcd,0x29,0x9c,0xc0,0xdd,0x5f,0xef,0xd1,0xcf,0xd6,0xce,0x5d,0x57,0xf7,0xfd,0x3e,0x2b,0xe8,0xc2,0x34,0x16,0x20,0x5d,0x6b,0xd5,0x25,0x9b,0x2b,0xed,0x04,0xbb,0xc6,0x41,0x30,0x48,0xe1,0x56,0xd9,0xf9,0xf2,0xf2,0x0f,0x2e,0x6b,0x35,0x9f,0x75,0x97,0xe7,0xad,0x5c,0x02,0x6c,0x5f,0xbb,0x98,0x46,0x1a,0x7b,0x9a,0x04,0x14,0x68,0xbd,0x4b,0x10},+ {0x67,0xed,0xf1,0x68,0x31,0xfd,0xf0,0x51,0xc2,0x3b,0x6f,0xd8,0xcd,0x1d,0x81,0x2c,0xde,0xf2,0xd2,0x04,0x43,0x5c,0xdc,0x44,0x49,0x71,0x2a,0x09,0x57,0xcc,0xe8,0x5b,0x63,0xf1,0x7f,0xd6,0x5f,0x9a,0x5d,0xa9,0x81,0x56,0xc7,0x4c,0x9d,0xe6,0x2b,0xe9,0x57,0xf2,0x20,0xde,0x4c,0x02,0xf8,0xb7,0xf5,0x2d,0x07,0xfb,0x20,0x2a,0x4f,0x20,0x79,0xb0,0xeb,0x30,0x3d,0x3b,0x14,0xc8,0x30,0x2e,0x65,0xbd,0x5a,0x15,0x89,0x75,0x31,0x5c,0x6d,0x8f,0x31,0x3c,0x3c,0x65,0x1f,0x16,0x79,0xc2,0x17,0xfb,0x70,0x25},+ {0x75,0x15,0xb6,0x2c,0x7f,0x36,0xfa,0x3e,0x6c,0x02,0xd6,0x1c,0x76,0x6f,0xf9,0xf5,0x62,0x25,0xb5,0x65,0x2a,0x14,0xc7,0xe8,0xcd,0x0a,0x03,0x53,0xea,0x65,0xcb,0x3d,0x5a,0x24,0xb8,0x0b,0x55,0xa9,0x2e,0x19,0xd1,0x50,0x90,0x8f,0xa8,0xfb,0xe6,0xc8,0x35,0xc9,0xa4,0x88,0x2d,0xea,0x86,0x79,0x68,0x86,0x01,0xde,0x91,0x5f,0x1c,0x24,0xaa,0x6c,0xde,0x40,0x29,0x17,0xd8,0x28,0x3a,0x73,0xd9,0x22,0xf0,0x2c,0xbf,0x8f,0xd1,0x01,0x5b,0x23,0xdd,0xfc,0xd7,0x16,0xe5,0xf0,0xcd,0x5f,0xdd,0x0e,0x42,0x08},+ {0x4a,0xfa,0x62,0x83,0xab,0x20,0xff,0xcd,0x6e,0x3e,0x1a,0xe2,0xd4,0x18,0xe1,0x57,0x2b,0xe6,0x39,0xfc,0x17,0x96,0x17,0xe3,0xfd,0x69,0x17,0xbc,0xef,0x53,0x9a,0x0d,0xce,0x10,0xf4,0x04,0x4e,0xc3,0x58,0x03,0x85,0x06,0x6e,0x27,0x5a,0x5b,0x13,0xb6,0x21,0x15,0xb9,0xeb,0xc7,0x70,0x96,0x5d,0x9c,0x88,0xdb,0x21,0xf3,0x54,0xd6,0x04,0xd5,0xb5,0xbd,0xdd,0x16,0xc1,0x7d,0x5e,0x2d,0xdd,0xa5,0x8d,0xb6,0xde,0x54,0x29,0x92,0xa2,0x34,0x33,0x17,0x08,0xb6,0x1c,0xd7,0x1a,0x99,0x18,0x26,0x4f,0x7a,0x4a},+ {0x95,0x5f,0xb1,0x5f,0x02,0x18,0xa7,0xf4,0x8f,0x1b,0x5c,0x6b,0x34,0x5f,0xf6,0x3d,0x12,0x11,0xe0,0x00,0x85,0xf0,0xfc,0xcd,0x48,0x18,0xd3,0xdd,0x4c,0x0c,0xb5,0x11,0x4b,0x2a,0x37,0xaf,0x91,0xb2,0xc3,0x24,0xf2,0x47,0x81,0x71,0x70,0x82,0xda,0x93,0xf2,0x9e,0x89,0x86,0x64,0x85,0x84,0xdd,0x33,0xee,0xe0,0x23,0x42,0x31,0x96,0x4a,0xd6,0xff,0xa4,0x08,0x44,0x27,0xe8,0xa6,0xd9,0x76,0x15,0x9c,0x7e,0x17,0x8e,0x73,0xf2,0xb3,0x02,0x3d,0xb6,0x48,0x33,0x77,0x51,0xcc,0x6b,0xce,0x4d,0xce,0x4b,0x4f},+ {0x84,0x25,0x24,0xe2,0x5a,0xce,0x1f,0xa7,0x9e,0x8a,0xf5,0x92,0x56,0x72,0xea,0x26,0xf4,0x3c,0xea,0x1c,0xd7,0x09,0x1a,0xd2,0xe6,0x01,0x1c,0xb7,0x14,0xdd,0xfc,0x73,0x6f,0x0b,0x9d,0xc4,0x6e,0x61,0xe2,0x30,0x17,0x23,0xec,0xca,0x8f,0x71,0x56,0xe4,0xa6,0x4f,0x6b,0xf2,0x9b,0x40,0xeb,0x48,0x37,0x5f,0x59,0x61,0xe5,0xce,0x42,0x30,0x41,0xac,0x9b,0x44,0x79,0x70,0x7e,0x42,0x0a,0x31,0xe2,0xbc,0x6d,0xe3,0x5a,0x85,0x7c,0x1a,0x84,0x5f,0x21,0x76,0xae,0x4c,0xd6,0xe1,0x9c,0x9a,0x0c,0x74,0x9e,0x38},+ {0xce,0xb9,0xdc,0x34,0xae,0xb3,0xfc,0x64,0xad,0xd0,0x48,0xe3,0x23,0x03,0x50,0x97,0x1b,0x38,0xc6,0x62,0x7d,0xf0,0xb3,0x45,0x88,0x67,0x5a,0x46,0x79,0x53,0x54,0x61,0x28,0xac,0x0e,0x57,0xf6,0x78,0xbd,0xc9,0xe1,0x9c,0x91,0x27,0x32,0x0b,0x5b,0xe5,0xed,0x91,0x9b,0xa1,0xab,0x3e,0xfc,0x65,0x90,0x36,0x26,0xd6,0xe5,0x25,0xc4,0x25,0x6e,0xde,0xd7,0xf1,0xa6,0x06,0x3e,0x3f,0x08,0x23,0x06,0x8e,0x27,0x76,0xf9,0x3e,0x77,0x6c,0x8a,0x4e,0x26,0xf6,0x14,0x8c,0x59,0x47,0x48,0x15,0x89,0xa0,0x39,0x65},+ {0x73,0xf7,0xd2,0xc3,0x74,0x1f,0xd2,0xe9,0x45,0x68,0xc4,0x25,0x41,0x54,0x50,0xc1,0x33,0x9e,0xb9,0xf9,0xe8,0x5c,0x4e,0x62,0x6c,0x18,0xcd,0xc5,0xaa,0xe4,0xc5,0x11,0x19,0x4a,0xbb,0x14,0xd4,0xdb,0xc4,0xdd,0x8e,0x4f,0x42,0x98,0x3c,0xbc,0xb2,0x19,0x69,0x71,0xca,0x36,0xd7,0x9f,0xa8,0x48,0x90,0xbd,0x19,0xf0,0x0e,0x32,0x65,0x0f,0xc6,0xe0,0xfd,0xca,0xb1,0xd1,0x86,0xd4,0x81,0x51,0x3b,0x16,0xe3,0xe6,0x3f,0x4f,0x9a,0x93,0xf2,0xfa,0x0d,0xaf,0xa8,0x59,0x2a,0x07,0x33,0xec,0xbd,0xc7,0xab,0x4c},+ {0x2e,0x0a,0x9c,0x08,0x24,0x96,0x9e,0x23,0x38,0x47,0xfe,0x3a,0xc0,0xc4,0x48,0xc7,0x2a,0xa1,0x4f,0x76,0x2a,0xed,0xdb,0x17,0x82,0x85,0x1c,0x32,0xf0,0x93,0x9b,0x63,0x89,0xd2,0x78,0x3f,0x8f,0x78,0x8f,0xc0,0x9f,0x4d,0x40,0xa1,0x2c,0xa7,0x30,0xfe,0x9d,0xcc,0x65,0xcf,0xfc,0x8b,0x77,0xf2,0x21,0x20,0xcb,0x5a,0x16,0x98,0xe4,0x7e,0xc3,0xa1,0x11,0x91,0xe3,0x08,0xd5,0x7b,0x89,0x74,0x90,0x80,0xd4,0x90,0x2b,0x2b,0x19,0xfd,0x72,0xae,0xc2,0xae,0xd2,0xe7,0xa6,0x02,0xb6,0x85,0x3c,0x49,0xdf,0x0e},+ {0x68,0x5a,0x9b,0x59,0x58,0x81,0xcc,0xae,0x0e,0xe2,0xad,0xeb,0x0f,0x4f,0x57,0xea,0x07,0x7f,0xb6,0x22,0x74,0x1d,0xe4,0x4f,0xb4,0x4f,0x9d,0x01,0xe3,0x92,0x3b,0x40,0x13,0x41,0x76,0x84,0xd2,0xc4,0x67,0x67,0x35,0xf8,0xf5,0xf7,0x3f,0x40,0x90,0xa0,0xde,0xbe,0xe6,0xca,0xfa,0xcf,0x8f,0x1c,0x69,0xa3,0xdf,0xd1,0x54,0x0c,0xc0,0x04,0xf8,0x5c,0x46,0x8b,0x81,0x2f,0xc2,0x4d,0xf8,0xef,0x80,0x14,0x5a,0xf3,0xa0,0x71,0x57,0xd6,0xc7,0x04,0xad,0xbf,0xe8,0xae,0xf4,0x76,0x61,0xb2,0x2a,0xb1,0x5b,0x35},+ {0xf4,0xbb,0x93,0x74,0xcc,0x64,0x1e,0xa7,0xc3,0xb0,0xa3,0xec,0xd9,0x84,0xbd,0xe5,0x85,0xe7,0x05,0xfa,0x0c,0xc5,0x6b,0x0a,0x12,0xc3,0x2e,0x18,0x32,0x81,0x9b,0x0f,0x18,0x73,0x8c,0x5a,0xc7,0xda,0x01,0xa3,0x11,0xaa,0xce,0xb3,0x9d,0x03,0x90,0xed,0x2d,0x3f,0xae,0x3b,0xbf,0x7c,0x07,0x6f,0x8e,0xad,0x52,0xe0,0xf8,0xea,0x18,0x75,0x32,0x6c,0x7f,0x1b,0xc4,0x59,0x88,0xa4,0x98,0x32,0x38,0xf4,0xbc,0x60,0x2d,0x0f,0xd9,0xd1,0xb1,0xc9,0x29,0xa9,0x15,0x18,0xc4,0x55,0x17,0xbb,0x1b,0x87,0xc3,0x47},+ {0x48,0x4f,0xec,0x71,0x97,0x53,0x44,0x51,0x6e,0x5d,0x8c,0xc9,0x7d,0xb1,0x05,0xf8,0x6b,0xc6,0xc3,0x47,0x1a,0xc1,0x62,0xf7,0xdc,0x99,0x46,0x76,0x85,0x9b,0xb8,0x00,0xb0,0x66,0x50,0xc8,0x50,0x5d,0xe6,0xfb,0xb0,0x99,0xa2,0xb3,0xb0,0xc4,0xec,0x62,0xe0,0xe8,0x1a,0x44,0xea,0x54,0x37,0xe5,0x5f,0x8d,0xd4,0xe8,0x2c,0xa0,0xfe,0x08,0xd0,0xea,0xde,0x68,0x76,0xdd,0x4d,0x82,0x23,0x5d,0x68,0x4b,0x20,0x45,0x64,0xc8,0x65,0xd6,0x89,0x5d,0xcd,0xcf,0x14,0xb5,0x37,0xd5,0x75,0x4f,0xa7,0x29,0x38,0x47},+ {0x18,0xc4,0x79,0x46,0x75,0xda,0xd2,0x82,0xf0,0x8d,0x61,0xb2,0xd8,0xd7,0x3b,0xe6,0x0a,0xeb,0x47,0xac,0x24,0xef,0x5e,0x35,0xb4,0xc6,0x33,0x48,0x4c,0x68,0x78,0x20,0xc9,0x02,0x39,0xad,0x3a,0x53,0xd9,0x23,0x8f,0x58,0x03,0xef,0xce,0xdd,0xc2,0x64,0xb4,0x2f,0xe1,0xcf,0x90,0x73,0x25,0x15,0x90,0xd3,0xe4,0x44,0x4d,0x8b,0x66,0x6c,0x0c,0x82,0x78,0x7a,0x21,0xcf,0x48,0x3b,0x97,0x3e,0x27,0x81,0xb2,0x0a,0x6a,0xf7,0x7b,0xed,0x8e,0x8c,0xa7,0x65,0x6c,0xa9,0x3f,0x43,0x8a,0x4f,0x05,0xa6,0x11,0x74},+ {0x6d,0xc8,0x9d,0xb9,0x32,0x9d,0x65,0x4d,0x15,0xf1,0x3a,0x60,0x75,0xdc,0x4c,0x04,0x88,0xe4,0xc2,0xdc,0x2c,0x71,0x4c,0xb3,0xff,0x34,0x81,0xfb,0x74,0x65,0x13,0x7c,0xb4,0x75,0xb1,0x18,0x3d,0xe5,0x9a,0x57,0x02,0xa1,0x92,0xf3,0x59,0x31,0x71,0x68,0xf5,0x35,0xef,0x1e,0xba,0xec,0x55,0x84,0x8f,0x39,0x8c,0x45,0x72,0xa8,0xc9,0x1e,0x9b,0x50,0xa2,0x00,0xd4,0xa4,0xe6,0xb8,0xb4,0x82,0xc8,0x0b,0x02,0xd7,0x81,0x9b,0x61,0x75,0x95,0xf1,0x9b,0xcc,0xe7,0x57,0x60,0x64,0xcd,0xc7,0xa5,0x88,0xdd,0x3a},+ {0xf2,0xdc,0x35,0xb6,0x70,0x57,0x89,0xab,0xbc,0x1f,0x6c,0xf6,0x6c,0xef,0xdf,0x02,0x87,0xd1,0xb6,0xbe,0x68,0x02,0x53,0x85,0x74,0x9e,0x87,0xcc,0xfc,0x29,0x99,0x24,0x46,0x30,0x39,0x59,0xd4,0x98,0xc2,0x85,0xec,0x59,0xf6,0x5f,0x98,0x35,0x7e,0x8f,0x3a,0x6e,0xf6,0xf2,0x2a,0xa2,0x2c,0x1d,0x20,0xa7,0x06,0xa4,0x31,0x11,0xba,0x61,0x29,0x90,0x95,0x16,0xf1,0xa0,0xd0,0xa3,0x89,0xbd,0x7e,0xba,0x6c,0x6b,0x3b,0x02,0x07,0x33,0x78,0x26,0x3e,0x5a,0xf1,0x7b,0xe7,0xec,0xd8,0xbb,0x0c,0x31,0x20,0x56},+ {0x43,0xd6,0x34,0x49,0x43,0x93,0x89,0x52,0xf5,0x22,0x12,0xa5,0x06,0xf8,0xdb,0xb9,0x22,0x1c,0xf4,0xc3,0x8f,0x87,0x6d,0x8f,0x30,0x97,0x9d,0x4d,0x2a,0x6a,0x67,0x37,0xd6,0x85,0xe2,0x77,0xf4,0xb5,0x46,0x66,0x93,0x61,0x8f,0x6c,0x67,0xff,0xe8,0x40,0xdd,0x94,0xb5,0xab,0x11,0x73,0xec,0xa6,0x4d,0xec,0x8c,0x65,0xf3,0x46,0xc8,0x7e,0xc7,0x2e,0xa2,0x1d,0x3f,0x8f,0x5e,0x9b,0x13,0xcd,0x01,0x6c,0x77,0x1d,0x0f,0x13,0xb8,0x9f,0x98,0xa2,0xcf,0x8f,0x4c,0x21,0xd5,0x9d,0x9b,0x39,0x23,0xf7,0xaa,0x6d},+ {0x47,0xbe,0x3d,0xeb,0x62,0x75,0x3a,0x5f,0xb8,0xa0,0xbd,0x8e,0x54,0x38,0xea,0xf7,0x99,0x72,0x74,0x45,0x31,0xe5,0xc3,0x00,0x51,0xd5,0x27,0x16,0xe7,0xe9,0x04,0x13,0xa2,0x8e,0xad,0xac,0xbf,0x04,0x3b,0x58,0x84,0xe8,0x8b,0x14,0xe8,0x43,0xb7,0x29,0xdb,0xc5,0x10,0x08,0x3b,0x58,0x1e,0x2b,0xaa,0xbb,0xb3,0x8e,0xe5,0x49,0x54,0x2b,0xfe,0x9c,0xdc,0x6a,0xd2,0x14,0x98,0x78,0x0b,0xdd,0x48,0x8b,0x3f,0xab,0x1b,0x3c,0x0a,0xc6,0x79,0xf9,0xff,0xe1,0x0f,0xda,0x93,0xd6,0x2d,0x7c,0x2d,0xde,0x68,0x44},+ {0x9e,0x46,0x19,0x94,0x5e,0x35,0xbb,0x51,0x54,0xc7,0xdd,0x23,0x4c,0xdc,0xe6,0x33,0x62,0x99,0x7f,0x44,0xd6,0xb6,0xa5,0x93,0x63,0xbd,0x44,0xfb,0x6f,0x7c,0xce,0x6c,0xce,0x07,0x63,0xf8,0xc6,0xd8,0x9a,0x4b,0x28,0x0c,0x5d,0x43,0x31,0x35,0x11,0x21,0x2c,0x77,0x7a,0x65,0xc5,0x66,0xa8,0xd4,0x52,0x73,0x24,0x63,0x7e,0x42,0xa6,0x5d,0xca,0x22,0xac,0xde,0x88,0xc6,0x94,0x1a,0xf8,0x1f,0xae,0xbb,0xf7,0x6e,0x06,0xb9,0x0f,0x58,0x59,0x8d,0x38,0x8c,0xad,0x88,0xa8,0x2c,0x9f,0xe7,0xbf,0x9a,0xf2,0x58},+ {0x68,0x3e,0xe7,0x8d,0xab,0xcf,0x0e,0xe9,0xa5,0x76,0x7e,0x37,0x9f,0x6f,0x03,0x54,0x82,0x59,0x01,0xbe,0x0b,0x5b,0x49,0xf0,0x36,0x1e,0xf4,0xa7,0xc4,0x29,0x76,0x57,0xf6,0xcd,0x0e,0x71,0xbf,0x64,0x5a,0x4b,0x3c,0x29,0x2c,0x46,0x38,0xe5,0x4c,0xb1,0xb9,0x3a,0x0b,0xd5,0x56,0xd0,0x43,0x36,0x70,0x48,0x5b,0x18,0x24,0x37,0xf9,0x6a,0x88,0xa8,0xc6,0x09,0x45,0x02,0x20,0x32,0x73,0x89,0x55,0x4b,0x13,0x36,0xe0,0xd2,0x9f,0x28,0x33,0x3c,0x23,0x36,0xe2,0x83,0x8f,0xc1,0xae,0x0c,0xbb,0x25,0x1f,0x70},+ {0xed,0x6c,0x61,0xe4,0xf8,0xb0,0xa8,0xc3,0x7d,0xa8,0x25,0x9e,0x0e,0x66,0x00,0xf7,0x9c,0xa5,0xbc,0xf4,0x1f,0x06,0xe3,0x61,0xe9,0x0b,0xc4,0xbd,0xbf,0x92,0x0c,0x2e,0x13,0xc1,0xbe,0x7c,0xd9,0xf6,0x18,0x9d,0xe4,0xdb,0xbf,0x74,0xe6,0x06,0x4a,0x84,0xd6,0x60,0x4e,0xac,0x22,0xb5,0xf5,0x20,0x51,0x5e,0x95,0x50,0xc0,0x5b,0x0a,0x72,0x35,0x5a,0x80,0x9b,0x43,0x09,0x3f,0x0c,0xfc,0xab,0x42,0x62,0x37,0x8b,0x4e,0xe8,0x46,0x93,0x22,0x5c,0xf3,0x17,0x14,0x69,0xec,0xf0,0x4e,0x14,0xbb,0x9c,0x9b,0x0e},+ {0xad,0x20,0x57,0xfb,0x8f,0xd4,0xba,0xfb,0x0e,0x0d,0xf9,0xdb,0x6b,0x91,0x81,0xee,0xbf,0x43,0x55,0x63,0x52,0x31,0x81,0xd4,0xd8,0x7b,0x33,0x3f,0xeb,0x04,0x11,0x22,0xee,0xbe,0xb1,0x5d,0xd5,0x9b,0xee,0x8d,0xb9,0x3f,0x72,0x0a,0x37,0xab,0xc3,0xc9,0x91,0xd7,0x68,0x1c,0xbf,0xf1,0xa8,0x44,0xde,0x3c,0xfd,0x1c,0x19,0x44,0x6d,0x36,0x14,0x8c,0xbc,0xf2,0x43,0x17,0x3c,0x9e,0x3b,0x6c,0x85,0xb5,0xfc,0x26,0xda,0x2e,0x97,0xfb,0xa7,0x68,0x0e,0x2f,0xb8,0xcc,0x44,0x32,0x59,0xbc,0xe6,0xa4,0x67,0x41},+ {0x00,0x27,0xf6,0x76,0x28,0x9d,0x3b,0x64,0xeb,0x68,0x76,0x0e,0x40,0x9d,0x1d,0x5d,0x84,0x06,0xfc,0x21,0x03,0x43,0x4b,0x1b,0x6a,0x24,0x55,0x22,0x7e,0xbb,0x38,0x79,0xee,0x8f,0xce,0xf8,0x65,0x26,0xbe,0xc2,0x2c,0xd6,0x80,0xe8,0x14,0xff,0x67,0xe9,0xee,0x4e,0x36,0x2f,0x7e,0x6e,0x2e,0xf1,0xf6,0xd2,0x7e,0xcb,0x70,0x33,0xb3,0x34,0xcc,0xd6,0x81,0x86,0xee,0x91,0xc5,0xcd,0x53,0xa7,0x85,0xed,0x9c,0x10,0x02,0xce,0x83,0x88,0x80,0x58,0xc1,0x85,0x74,0xed,0xe4,0x65,0xfe,0x2d,0x6e,0xfc,0x76,0x11},+ {0x9b,0x61,0x9c,0x5b,0xd0,0x6c,0xaf,0xb4,0x80,0x84,0xa5,0xb2,0xf4,0xc9,0xdf,0x2d,0xc4,0x4d,0xe9,0xeb,0x02,0xa5,0x4f,0x3d,0x34,0x5f,0x7d,0x67,0x4c,0x3a,0xfc,0x08,0xb8,0x0e,0x77,0x49,0x89,0xe2,0x90,0xdb,0xa3,0x40,0xf4,0xac,0x2a,0xcc,0xfb,0x98,0x9b,0x87,0xd7,0xde,0xfe,0x4f,0x35,0x21,0xb6,0x06,0x69,0xf2,0x54,0x3e,0x6a,0x1f,0xea,0x34,0x07,0xd3,0x99,0xc1,0xa4,0x60,0xd6,0x5c,0x16,0x31,0xb6,0x85,0xc0,0x40,0x95,0x82,0x59,0xf7,0x23,0x3e,0x33,0xe2,0xd1,0x00,0xb9,0x16,0x01,0xad,0x2f,0x4f},+ {0x54,0x4e,0xae,0x94,0x41,0xb2,0xbe,0x44,0x6c,0xef,0x57,0x18,0x51,0x1c,0x54,0x5f,0x98,0x04,0x8d,0x36,0x2d,0x6b,0x1e,0xa6,0xab,0xf7,0x2e,0x97,0xa4,0x84,0x54,0x44,0x38,0xb6,0x3b,0xb7,0x1d,0xd9,0x2c,0x96,0x08,0x9c,0x12,0xfc,0xaa,0x77,0x05,0xe6,0x89,0x16,0xb6,0xf3,0x39,0x9b,0x61,0x6f,0x81,0xee,0x44,0x29,0x5f,0x99,0x51,0x34,0x7c,0x7d,0xea,0x9f,0xd0,0xfc,0x52,0x91,0xf6,0x5c,0x93,0xb0,0x94,0x6c,0x81,0x4a,0x40,0x5c,0x28,0x47,0xaa,0x9a,0x8e,0x25,0xb7,0x93,0x28,0x04,0xa6,0x9c,0xb8,0x10},+ {0x9c,0x28,0x18,0x97,0x49,0x47,0x59,0x3d,0x26,0x3f,0x53,0x24,0xc5,0xf8,0xeb,0x12,0x15,0xef,0xc3,0x14,0xcb,0xbf,0x62,0x02,0x8e,0x51,0xb7,0x77,0xd5,0x78,0xb8,0x20,0x6e,0xf0,0x45,0x5a,0xbe,0x41,0x39,0x75,0x65,0x5f,0x9c,0x6d,0xed,0xae,0x7c,0xd0,0xb6,0x51,0xff,0x72,0x9c,0x6b,0x77,0x11,0xa9,0x4d,0x0d,0xef,0xd9,0xd1,0xd2,0x17,0x6a,0x3e,0x3f,0x07,0x18,0xaf,0xf2,0x27,0x69,0x10,0x52,0xd7,0x19,0xe5,0x3f,0xfd,0x22,0x00,0xa6,0x3c,0x2c,0xb7,0xe3,0x22,0xa7,0xc6,0x65,0xcc,0x63,0x4f,0x21,0x72},+ {0x93,0xa6,0x07,0x53,0x40,0x7f,0xe3,0xb4,0x95,0x67,0x33,0x2f,0xd7,0x14,0xa7,0xab,0x99,0x10,0x76,0x73,0xa7,0xd0,0xfb,0xd6,0xc9,0xcb,0x71,0x81,0xc5,0x48,0xdf,0x5f,0xc9,0x29,0x3b,0xf4,0xb9,0xb7,0x9d,0x1d,0x75,0x8f,0x51,0x4f,0x4a,0x82,0x05,0xd6,0xc4,0x9d,0x2f,0x31,0xbd,0x72,0xc0,0xf2,0xb0,0x45,0x15,0x5a,0x85,0xac,0x24,0x1f,0xaa,0x05,0x95,0x8e,0x32,0x08,0xd6,0x24,0xee,0x20,0x14,0x0c,0xd1,0xc1,0x48,0x47,0xa2,0x25,0xfb,0x06,0x5c,0xe4,0xff,0xc7,0xe6,0x95,0xe3,0x2a,0x9e,0x73,0xba,0x00},+ {0xd6,0x90,0x87,0x5c,0xde,0x98,0x2e,0x59,0xdf,0xa2,0xc2,0x45,0xd3,0xb7,0xbf,0xe5,0x22,0x99,0xb4,0xf9,0x60,0x3b,0x5a,0x11,0xf3,0x78,0xad,0x67,0x3e,0x3a,0x28,0x03,0x26,0xbb,0x88,0xea,0xf5,0x26,0x44,0xae,0xfb,0x3b,0x97,0x84,0xd9,0x79,0x06,0x36,0x50,0x4e,0x69,0x26,0x0c,0x03,0x9f,0x5c,0x26,0xd2,0x18,0xd5,0xe7,0x7d,0x29,0x72,0x39,0xb9,0x0c,0xbe,0xc7,0x1d,0x24,0x48,0x80,0x30,0x63,0x8b,0x4d,0x9b,0xf1,0x32,0x08,0x93,0x28,0x02,0x0d,0xc9,0xdf,0xd3,0x45,0x19,0x27,0x46,0x68,0x29,0xe1,0x05},+ {0x5a,0x49,0x9c,0x2d,0xb3,0xee,0x82,0xba,0x7c,0xb9,0x2b,0xf1,0xfc,0xc8,0xef,0xce,0xe0,0xd1,0xb5,0x93,0xae,0xab,0x2d,0xb0,0x9b,0x8d,0x69,0x13,0x9c,0x0c,0xc0,0x39,0x50,0x45,0x2c,0x24,0xc8,0xbb,0xbf,0xad,0xd9,0x81,0x30,0xd0,0xec,0x0c,0xc8,0xbc,0x92,0xdf,0xc8,0xf5,0xa6,0x66,0x35,0x84,0x4c,0xce,0x58,0x82,0xd3,0x25,0xcf,0x78,0x68,0x9d,0x48,0x31,0x8e,0x6b,0xae,0x15,0x87,0xf0,0x2b,0x9c,0xab,0x1c,0x85,0xaa,0x05,0xfa,0x4e,0xf0,0x97,0x5a,0xa7,0xc9,0x32,0xf8,0x3f,0x6b,0x07,0x52,0x6b,0x00},+ {0x1c,0x78,0x95,0x9d,0xe1,0xcf,0xe0,0x29,0xe2,0x10,0x63,0x96,0x18,0xdf,0x81,0xb6,0x39,0x6b,0x51,0x70,0xd3,0x39,0xdf,0x57,0x22,0x61,0xc7,0x3b,0x44,0xe3,0x57,0x4d,0x2d,0x08,0xce,0xb9,0x16,0x7e,0xcb,0xf5,0x29,0xbc,0x7a,0x41,0x4c,0xf1,0x07,0x34,0xab,0xa7,0xf4,0x2b,0xce,0x6b,0xb3,0xd4,0xce,0x75,0x9f,0x1a,0x56,0xe9,0xe2,0x7d,0xcb,0x5e,0xa5,0xb6,0xf4,0xd4,0x70,0xde,0x99,0xdb,0x85,0x5d,0x7f,0x52,0x01,0x48,0x81,0x9a,0xee,0xd3,0x40,0xc4,0xc9,0xdb,0xed,0x29,0x60,0x1a,0xaf,0x90,0x2a,0x6b},+ {0x97,0x1e,0xe6,0x9a,0xfc,0xf4,0x23,0x69,0xd1,0x5f,0x3f,0xe0,0x1d,0x28,0x35,0x57,0x2d,0xd1,0xed,0xe6,0x43,0xae,0x64,0xa7,0x4a,0x3e,0x2d,0xd1,0xe9,0xf4,0xd8,0x5f,0x0a,0xd8,0xb2,0x5b,0x24,0xf3,0xeb,0x77,0x9b,0x07,0xb9,0x2f,0x47,0x1b,0x30,0xd8,0x33,0x73,0xee,0x4c,0xf2,0xe6,0x47,0xc6,0x09,0x21,0x6c,0x27,0xc8,0x12,0x58,0x46,0xd9,0x62,0x10,0x2a,0xb2,0xbe,0x43,0x4d,0x16,0xdc,0x31,0x38,0x75,0xfb,0x65,0x70,0xd7,0x68,0x29,0xde,0x7b,0x4a,0x0d,0x18,0x90,0x67,0xb1,0x1c,0x2b,0x2c,0xb3,0x05},+ {0xfd,0xa8,0x4d,0xd2,0xcc,0x5e,0xc0,0xc8,0x83,0xef,0xdf,0x05,0xac,0x1a,0xcf,0xa1,0x61,0xcd,0xf9,0x7d,0xf2,0xef,0xbe,0xdb,0x99,0x1e,0x47,0x7b,0xa3,0x56,0x55,0x3b,0x95,0x81,0xd5,0x7a,0x2c,0xa4,0xfc,0xf7,0xcc,0xf3,0x33,0x43,0x6e,0x28,0x14,0x32,0x9d,0x97,0x0b,0x34,0x0d,0x9d,0xc2,0xb6,0xe1,0x07,0x73,0x56,0x48,0x1a,0x77,0x31,0x82,0xd4,0x4d,0xe1,0x24,0xc5,0xb0,0x32,0xb6,0xa4,0x2b,0x1a,0x54,0x51,0xb3,0xed,0xf3,0x5a,0x2b,0x28,0x48,0x60,0xd1,0xa3,0xeb,0x36,0x73,0x7a,0xd2,0x79,0xc0,0x4f},+ {0x7f,0x2f,0xbf,0x89,0xb0,0x38,0xc9,0x51,0xa7,0xe9,0xdf,0x02,0x65,0xbd,0x97,0x24,0x53,0xe4,0x80,0x78,0x9c,0xc0,0xff,0xff,0x92,0x8e,0xf9,0xca,0xce,0x67,0x45,0x12,0x0d,0xc5,0x86,0x0c,0x44,0x8b,0x34,0xdc,0x51,0xe6,0x94,0xcc,0xc9,0xcb,0x37,0x13,0xb9,0x3c,0x3e,0x64,0x4d,0xf7,0x22,0x64,0x08,0xcd,0xe3,0xba,0xc2,0x70,0x11,0x24,0xb4,0x73,0xc4,0x0a,0x86,0xab,0xf9,0x3f,0x35,0xe4,0x13,0x01,0xee,0x1d,0x91,0xf0,0xaf,0xc4,0xc6,0xeb,0x60,0x50,0xe7,0x4a,0x0d,0x00,0x87,0x6c,0x96,0x12,0x86,0x3f},+ {0xde,0x0d,0x2a,0x78,0xc9,0x0c,0x9a,0x55,0x85,0x83,0x71,0xea,0xb2,0xcd,0x1d,0x55,0x8c,0x23,0xef,0x31,0x5b,0x86,0x62,0x7f,0x3d,0x61,0x73,0x79,0x76,0xa7,0x4a,0x50,0x13,0x8d,0x04,0x36,0xfa,0xfc,0x18,0x9c,0xdd,0x9d,0x89,0x73,0xb3,0x9d,0x15,0x29,0xaa,0xd0,0x92,0x9f,0x0b,0x35,0x9f,0xdc,0xd4,0x19,0x8a,0x87,0xee,0x7e,0xf5,0x26,0xb1,0xef,0x87,0x56,0xd5,0x2c,0xab,0x0c,0x7b,0xf1,0x7a,0x24,0x62,0xd1,0x80,0x51,0x67,0x24,0x5a,0x4f,0x34,0x5a,0xc1,0x85,0x69,0x30,0xba,0x9d,0x3d,0x94,0x41,0x40},+ {0x96,0xcc,0xeb,0x43,0xba,0xee,0xc0,0xc3,0xaf,0x9c,0xea,0x26,0x9c,0x9c,0x74,0x8d,0xc6,0xcc,0x77,0x1c,0xee,0x95,0xfa,0xd9,0x0f,0x34,0x84,0x76,0xd9,0xa1,0x20,0x14,0xdd,0xaa,0x6c,0xa2,0x43,0x77,0x21,0x4b,0xce,0xb7,0x8a,0x64,0x24,0xb4,0xa6,0x47,0xe3,0xc9,0xfb,0x03,0x7a,0x4f,0x1d,0xcb,0x19,0xd0,0x00,0x98,0x42,0x31,0xd9,0x12,0x4f,0x59,0x37,0xd3,0x99,0x77,0xc6,0x00,0x7b,0xa4,0x3a,0xb2,0x40,0x51,0x3c,0x5e,0x95,0xf3,0x5f,0xe3,0x54,0x28,0x18,0x44,0x12,0xa0,0x59,0x43,0x31,0x92,0x4f,0x1b},+ {0x51,0x09,0x15,0x89,0x9d,0x10,0x5c,0x3e,0x6a,0x69,0xe9,0x2d,0x91,0xfa,0xce,0x39,0x20,0x30,0x5f,0x97,0x3f,0xe4,0xea,0x20,0xae,0x2d,0x13,0x7f,0x2a,0x57,0x9b,0x23,0xb1,0x66,0x98,0xa4,0x30,0x30,0xcf,0x33,0x59,0x48,0x5f,0x21,0xd2,0x73,0x1f,0x25,0xf6,0xf4,0xde,0x51,0x40,0xaa,0x82,0xab,0xf6,0x23,0x9a,0x6f,0xd5,0x91,0xf1,0x5f,0x68,0x90,0x2d,0xac,0x33,0xd4,0x9e,0x81,0x23,0x85,0xc9,0x5f,0x79,0xab,0x83,0x28,0x3d,0xeb,0x93,0x55,0x80,0x72,0x45,0xef,0xcb,0x36,0x8f,0x75,0x6a,0x52,0x0c,0x02},+ {0xbc,0xdb,0xd8,0x9e,0xf8,0x34,0x98,0x77,0x6c,0xa4,0x7c,0xdc,0xf9,0xaa,0xf2,0xc8,0x74,0xb0,0xe1,0xa3,0xdc,0x4c,0x52,0xa9,0x77,0x38,0x31,0x15,0x46,0xcc,0xaa,0x02,0x89,0xcc,0x42,0xf0,0x59,0xef,0x31,0xe9,0xb6,0x4b,0x12,0x8e,0x9d,0x9c,0x58,0x2c,0x97,0x59,0xc7,0xae,0x8a,0xe1,0xc8,0xad,0x0c,0xc5,0x02,0x56,0x0a,0xfe,0x2c,0x45,0xdf,0x77,0x78,0x64,0xa0,0xf7,0xa0,0x86,0x9f,0x7c,0x60,0x0e,0x27,0x64,0xc4,0xbb,0xc9,0x11,0xfb,0xf1,0x25,0xea,0x17,0xab,0x7b,0x87,0x4b,0x30,0x7b,0x7d,0xfb,0x4c},+ {0xfe,0x75,0x9b,0xb8,0x6c,0x3d,0xb4,0x72,0x80,0xdc,0x6a,0x9c,0xd9,0x94,0xc6,0x54,0x9f,0x4c,0xe3,0x3e,0x37,0xaa,0xc3,0xb8,0x64,0x53,0x07,0x39,0x2b,0x62,0xb4,0x14,0x12,0xef,0x89,0x97,0xc2,0x99,0x86,0xe2,0x0d,0x19,0x57,0xdf,0x71,0xcd,0x6e,0x2b,0xd0,0x70,0xc9,0xec,0x57,0xc8,0x43,0xc3,0xc5,0x3a,0x4d,0x43,0xbc,0x4c,0x1d,0x5b,0x26,0x9f,0x0a,0xcc,0x15,0x26,0xfb,0xb6,0xe5,0xcc,0x8d,0xb8,0x2b,0x0e,0x4f,0x3a,0x05,0xa7,0x69,0x33,0x8b,0x49,0x01,0x13,0xd1,0x2d,0x59,0x58,0x12,0xf7,0x98,0x2f},+ {0x56,0x9e,0x0f,0xb5,0x4c,0xa7,0x94,0x0c,0x20,0x13,0x8e,0x8e,0xa9,0xf4,0x1f,0x5b,0x67,0x0f,0x30,0x82,0x21,0xcc,0x2a,0x9a,0xf9,0xaa,0x06,0xd8,0x49,0xe2,0x6a,0x3a,0x01,0xa7,0x54,0x4f,0x44,0xae,0x12,0x2e,0xde,0xd7,0xcb,0xa9,0xf0,0x3e,0xfe,0xfc,0xe0,0x5d,0x83,0x75,0x0d,0x89,0xbf,0xce,0x54,0x45,0x61,0xe7,0xe9,0x62,0x80,0x1d,0x5a,0x7c,0x90,0xa9,0x85,0xda,0x7a,0x65,0x62,0x0f,0xb9,0x91,0xb5,0xa8,0x0e,0x1a,0xe9,0xb4,0x34,0xdf,0xfb,0x1d,0x0e,0x8d,0xf3,0x5f,0xf2,0xae,0xe8,0x8c,0x8b,0x29},+ {0xb2,0x0c,0xf7,0xef,0x53,0x79,0x92,0x2a,0x76,0x70,0x15,0x79,0x2a,0xc9,0x89,0x4b,0x6a,0xcf,0xa7,0x30,0x7a,0x45,0x18,0x94,0x85,0xe4,0x5c,0x4d,0x40,0xa8,0xb8,0x34,0xde,0x65,0x21,0x0a,0xea,0x72,0x7a,0x83,0xf6,0x79,0xcf,0x0b,0xb4,0x07,0xab,0x3f,0x70,0xae,0x38,0x77,0xc7,0x36,0x16,0x52,0xdc,0xd7,0xa7,0x03,0x18,0x27,0xa6,0x6b,0x35,0x33,0x69,0x83,0xb5,0xec,0x6e,0xc2,0xfd,0xfe,0xb5,0x63,0xdf,0x13,0xa8,0xd5,0x73,0x25,0xb2,0xa4,0x9a,0xaa,0x93,0xa2,0x6a,0x1c,0x5e,0x46,0xdd,0x2b,0xd6,0x71},+ {0x80,0xdf,0x78,0xd3,0x28,0xcc,0x33,0x65,0xb4,0xa4,0x0f,0x0a,0x79,0x43,0xdb,0xf6,0x5a,0xda,0x01,0xf7,0xf9,0x5f,0x64,0xe3,0xa4,0x2b,0x17,0xf3,0x17,0xf3,0xd5,0x74,0xf5,0x5e,0xf7,0xb1,0xda,0xb5,0x2d,0xcd,0xf5,0x65,0xb0,0x16,0xcf,0x95,0x7f,0xd7,0x85,0xf0,0x49,0x3f,0xea,0x1f,0x57,0x14,0x3d,0x2b,0x2b,0x26,0x21,0x36,0x33,0x1c,0x81,0xca,0xd9,0x67,0x54,0xe5,0x6f,0xa8,0x37,0x8c,0x29,0x2b,0x75,0x7c,0x8b,0x39,0x3b,0x62,0xac,0xe3,0x92,0x08,0x6d,0xda,0x8c,0xd9,0xe9,0x47,0x45,0xcc,0xeb,0x4a},+ {0xc9,0x01,0x6d,0x27,0x1b,0x07,0xf0,0x12,0x70,0x8c,0xc4,0x86,0xc5,0xba,0xb8,0xe7,0xa9,0xfb,0xd6,0x71,0x9b,0x12,0x08,0x53,0x92,0xb7,0x3d,0x5a,0xf9,0xfb,0x88,0x5d,0x10,0xb6,0x54,0x73,0x9e,0x8d,0x40,0x0b,0x6e,0x5b,0xa8,0x5b,0x53,0x32,0x6b,0x80,0x07,0xa2,0x58,0x4a,0x03,0x3a,0xe6,0xdb,0x2c,0xdf,0xa1,0xc9,0xdd,0xd9,0x3b,0x17,0xdf,0x72,0x58,0xfe,0x1e,0x0f,0x50,0x2b,0xc1,0x18,0x39,0xd4,0x2e,0x58,0xd6,0x58,0xe0,0x3a,0x67,0xc9,0x8e,0x27,0xed,0xe6,0x19,0xa3,0x9e,0xb1,0x13,0xcd,0xe1,0x06},+ {0x23,0x6f,0x16,0x6f,0x51,0xad,0xd0,0x40,0xbe,0x6a,0xab,0x1f,0x93,0x32,0x8e,0x11,0x8e,0x08,0x4d,0xa0,0x14,0x5e,0xe3,0x3f,0x66,0x62,0xe1,0x26,0x35,0x60,0x80,0x30,0x53,0x03,0x5b,0x9e,0x62,0xaf,0x2b,0x47,0x47,0x04,0x8d,0x27,0x90,0x0b,0xaa,0x3b,0x27,0xbf,0x43,0x96,0x46,0x5f,0x78,0x0c,0x13,0x7b,0x83,0x8d,0x1a,0x6a,0x3a,0x7f,0x0b,0x80,0x3d,0x5d,0x39,0x44,0xe6,0xf7,0xf6,0xed,0x01,0xc9,0x55,0xd5,0xa8,0x95,0x39,0x63,0x2c,0x59,0x30,0x78,0xcd,0x68,0x7e,0x30,0x51,0x2e,0xed,0xfd,0xd0,0x30},+ {0xb3,0x33,0x12,0xf2,0x1a,0x4d,0x59,0xe0,0x9c,0x4d,0xcc,0xf0,0x8e,0xe7,0xdb,0x1b,0x77,0x9a,0x49,0x8f,0x7f,0x18,0x65,0x69,0x68,0x98,0x09,0x2c,0x20,0x14,0x92,0x0a,0x50,0x47,0xb8,0x68,0x1e,0x97,0xb4,0x9c,0xcf,0xbb,0x64,0x66,0x29,0x72,0x95,0xa0,0x2b,0x41,0xfa,0x72,0x26,0xe7,0x8d,0x5c,0xd9,0x89,0xc5,0x51,0x43,0x08,0x15,0x46,0x2e,0xa0,0xb9,0xae,0xc0,0x19,0x90,0xbc,0xae,0x4c,0x03,0x16,0x0d,0x11,0xc7,0x55,0xec,0x32,0x99,0x65,0x01,0xf5,0x6d,0x0e,0xfe,0x5d,0xca,0x95,0x28,0x0d,0xca,0x3b},+ {0xa4,0x62,0x5d,0x3c,0xbc,0x31,0xf0,0x40,0x60,0x7a,0xf0,0xcf,0x3e,0x8b,0xfc,0x19,0x45,0xb5,0x0f,0x13,0xa2,0x3d,0x18,0x98,0xcd,0x13,0x8f,0xae,0xdd,0xde,0x31,0x56,0xbf,0x01,0xcc,0x9e,0xb6,0x8e,0x68,0x9c,0x6f,0x89,0x44,0xa6,0xad,0x83,0xbc,0xf0,0xe2,0x9f,0x7a,0x5f,0x5f,0x95,0x2d,0xca,0x41,0x82,0xf2,0x8d,0x03,0xb4,0xa8,0x4e,0x02,0xd2,0xca,0xf1,0x0a,0x46,0xed,0x2a,0x83,0xee,0x8c,0xa4,0x05,0x53,0x30,0x46,0x5f,0x1a,0xf1,0x49,0x45,0x77,0x21,0x91,0x63,0xa4,0x2c,0x54,0x30,0x09,0xce,0x24},+ {0x06,0xc1,0x06,0xfd,0xf5,0x90,0xe8,0x1f,0xf2,0x10,0x88,0x5d,0x35,0x68,0xc4,0xb5,0x3e,0xaf,0x8c,0x6e,0xfe,0x08,0x78,0x82,0x4b,0xd7,0x06,0x8a,0xc2,0xe3,0xd4,0x41,0x85,0x0b,0xf3,0xfd,0x55,0xa1,0xcf,0x3f,0xa4,0x2e,0x37,0x36,0x8e,0x16,0xf7,0xd2,0x44,0xf8,0x92,0x64,0xde,0x64,0xe0,0xb2,0x80,0x42,0x4f,0x32,0xa7,0x28,0x99,0x54,0x2e,0x1a,0xee,0x63,0xa7,0x32,0x6e,0xf2,0xea,0xfd,0x5f,0xd2,0xb7,0xe4,0x91,0xae,0x69,0x4d,0x7f,0xd1,0x3b,0xd3,0x3b,0xbc,0x6a,0xff,0xdc,0xc0,0xde,0x66,0x1b,0x49},+ {0xa7,0x32,0xea,0xc7,0x3d,0xb1,0xf5,0x98,0x98,0xdb,0x16,0x7e,0xcc,0xf8,0xd5,0xe3,0x47,0xd9,0xf8,0xcb,0x52,0xbf,0x0a,0xac,0xac,0xe4,0x5e,0xc8,0xd0,0x38,0xf3,0x08,0xa1,0x64,0xda,0xd0,0x8e,0x4a,0xf0,0x75,0x4b,0x28,0xe2,0x67,0xaf,0x2c,0x22,0xed,0xa4,0x7b,0x7b,0x1f,0x79,0xa3,0x34,0x82,0x67,0x8b,0x01,0xb7,0xb0,0xb8,0xf6,0x4c,0xbd,0x73,0x1a,0x99,0x21,0xa8,0x83,0xc3,0x7a,0x0c,0x32,0xdf,0x01,0xbc,0x27,0xab,0x63,0x70,0x77,0x84,0x1b,0x33,0x3d,0xc1,0x99,0x8a,0x07,0xeb,0x82,0x4a,0x0d,0x53},+ {0x25,0x48,0xf9,0xe1,0x30,0x36,0x4c,0x00,0x5a,0x53,0xab,0x8c,0x26,0x78,0x2d,0x7e,0x8b,0xff,0x84,0xcc,0x23,0x23,0x48,0xc7,0xb9,0x70,0x17,0x10,0x3f,0x75,0xea,0x65,0x9e,0xbf,0x9a,0x6c,0x45,0x73,0x69,0x6d,0x80,0xa8,0x00,0x49,0xfc,0xb2,0x7f,0x25,0x50,0xb8,0xcf,0xc8,0x12,0xf4,0xac,0x2b,0x5b,0xbd,0xbf,0x0c,0xe0,0xe7,0xb3,0x0d,0x63,0x63,0x09,0xe2,0x3e,0xfc,0x66,0x3d,0x6b,0xcb,0xb5,0x61,0x7f,0x2c,0xd6,0x81,0x1a,0x3b,0x44,0x13,0x42,0x04,0xbe,0x0f,0xdb,0xa1,0xe1,0x21,0x19,0xec,0xa4,0x02},+ {0xa2,0xb8,0x24,0x3b,0x9a,0x25,0xe6,0x5c,0xb8,0xa0,0xaf,0x45,0xcc,0x7a,0x57,0xb8,0x37,0x70,0xa0,0x8b,0xe8,0xe6,0xcb,0xcc,0xbf,0x09,0x78,0x12,0x51,0x3c,0x14,0x3d,0x5f,0x79,0xcf,0xf1,0x62,0x61,0xc8,0xf5,0xf2,0x57,0xee,0x26,0x19,0x86,0x8c,0x11,0x78,0x35,0x06,0x1c,0x85,0x24,0x21,0x17,0xcf,0x7f,0x06,0xec,0x5d,0x2b,0xd1,0x36,0x57,0x45,0x15,0x79,0x91,0x27,0x6d,0x12,0x0a,0x3a,0x78,0xfc,0x5c,0x8f,0xe4,0xd5,0xac,0x9b,0x17,0xdf,0xe8,0xb6,0xbd,0x36,0x59,0x28,0xa8,0x5b,0x88,0x17,0xf5,0x2e},+ {0xdc,0xae,0x58,0x8c,0x4e,0x97,0x37,0x46,0xa4,0x41,0xf0,0xab,0xfb,0x22,0xef,0xb9,0x8a,0x71,0x80,0xe9,0x56,0xd9,0x85,0xe1,0xa6,0xa8,0x43,0xb1,0xfa,0x78,0x1b,0x2f,0x51,0x2f,0x5b,0x30,0xfb,0xbf,0xee,0x96,0xb8,0x96,0x95,0x88,0xad,0x38,0xf9,0xd3,0x25,0xdd,0xd5,0x46,0xc7,0x2d,0xf5,0xf0,0x95,0x00,0x3a,0xbb,0x90,0x82,0x96,0x57,0x01,0xe1,0x20,0x0a,0x43,0xb8,0x1a,0xf7,0x47,0xec,0xf0,0x24,0x8d,0x65,0x93,0xf3,0xd1,0xee,0xe2,0x6e,0xa8,0x09,0x75,0xcf,0xe1,0xa3,0x2a,0xdc,0x35,0x3e,0xc4,0x7d},+ {0xc3,0xd9,0x7d,0x88,0x65,0x66,0x96,0x85,0x55,0x53,0xb0,0x4b,0x31,0x9b,0x0f,0xc9,0xb1,0x79,0x20,0xef,0xf8,0x8d,0xe0,0xc6,0x2f,0xc1,0x8c,0x75,0x16,0x20,0xf7,0x7e,0x18,0x97,0x3e,0x27,0x5c,0x2a,0x78,0x5a,0x94,0xfd,0x4e,0x5e,0x99,0xc6,0x76,0x35,0x3e,0x7d,0x23,0x1f,0x05,0xd8,0x2e,0x0f,0x99,0x0a,0xd5,0x82,0x1d,0xb8,0x4f,0x04,0xd9,0xe3,0x07,0xa9,0xc5,0x18,0xdf,0xc1,0x59,0x63,0x4c,0xce,0x1d,0x37,0xb3,0x57,0x49,0xbb,0x01,0xb2,0x34,0x45,0x70,0xca,0x2e,0xdd,0x30,0x9c,0x3f,0x82,0x79,0x7f},+ {0xe8,0x13,0xb5,0xa3,0x39,0xd2,0x34,0x83,0xd8,0xa8,0x1f,0xb9,0xd4,0x70,0x36,0xc1,0x33,0xbd,0x90,0xf5,0x36,0x41,0xb5,0x12,0xb4,0xd9,0x84,0xd7,0x73,0x03,0x4e,0x0a,0xba,0x87,0xf5,0x68,0xf0,0x1f,0x9c,0x6a,0xde,0xc8,0x50,0x00,0x4e,0x89,0x27,0x08,0xe7,0x5b,0xed,0x7d,0x55,0x99,0xbf,0x3c,0xf0,0xd6,0x06,0x1c,0x43,0xb0,0xa9,0x64,0x19,0x29,0x7d,0x5b,0xa1,0xd6,0xb3,0x2e,0x35,0x82,0x3a,0xd5,0xa0,0xf6,0xb4,0xb0,0x47,0x5d,0xa4,0x89,0x43,0xce,0x56,0x71,0x6c,0x34,0x18,0xce,0x0a,0x7d,0x1a,0x07},+ {0x0b,0xba,0x87,0xc8,0xaa,0x2d,0x07,0xd3,0xee,0x62,0xa5,0xbf,0x05,0x29,0x26,0x01,0x8b,0x76,0xef,0xc0,0x02,0x30,0x54,0xcf,0x9c,0x7e,0xea,0x46,0x71,0xcc,0x3b,0x2c,0x31,0x44,0xe1,0x20,0x52,0x35,0x0c,0xcc,0x41,0x51,0xb1,0x09,0x07,0x95,0x65,0x0d,0x36,0x5f,0x9d,0x20,0x1b,0x62,0xf5,0x9a,0xd3,0x55,0x77,0x61,0xf7,0xbc,0x69,0x7c,0x5f,0x29,0xe8,0x04,0xeb,0xd7,0xf0,0x07,0x7d,0xf3,0x50,0x2f,0x25,0x18,0xdb,0x10,0xd7,0x98,0x17,0x17,0xa3,0xa9,0x51,0xe9,0x1d,0xa5,0xac,0x22,0x73,0x9a,0x5a,0x6f},+ {0xc5,0xc6,0x41,0x2f,0x0c,0x00,0xa1,0x8b,0x9b,0xfb,0xfe,0x0c,0xc1,0x79,0x9f,0xc4,0x9f,0x1c,0xc5,0x3c,0x70,0x47,0xfa,0x4e,0xca,0xaf,0x47,0xe1,0xa2,0x21,0x4e,0x49,0xbe,0x44,0xd9,0xa3,0xeb,0xd4,0x29,0xe7,0x9e,0xaf,0x78,0x80,0x40,0x09,0x9e,0x8d,0x03,0x9c,0x86,0x47,0x7a,0x56,0x25,0x45,0x24,0x3b,0x8d,0xee,0x80,0x96,0xab,0x02,0x9a,0x0d,0xe5,0xdd,0x85,0x8a,0xa4,0xef,0x49,0xa2,0xb9,0x0f,0x4e,0x22,0x9a,0x21,0xd9,0xf6,0x1e,0xd9,0x1d,0x1f,0x09,0xfa,0x34,0xbb,0x46,0xea,0xcb,0x76,0x5d,0x6b},+ {0x94,0xd9,0x0c,0xec,0x6c,0x55,0x57,0x88,0xba,0x1d,0xd0,0x5c,0x6f,0xdc,0x72,0x64,0x77,0xb4,0x42,0x8f,0x14,0x69,0x01,0xaf,0x54,0x73,0x27,0x85,0xf6,0x33,0xe3,0x0a,0x22,0x25,0x78,0x1e,0x17,0x41,0xf9,0xe0,0xd3,0x36,0x69,0x03,0x74,0xae,0xe6,0xf1,0x46,0xc7,0xfc,0xd0,0xa2,0x3e,0x8b,0x40,0x3e,0x31,0xdd,0x03,0x9c,0x86,0xfb,0x16,0x62,0x09,0xb6,0x33,0x97,0x19,0x8e,0x28,0x33,0xe1,0xab,0xd8,0xb4,0x72,0xfc,0x24,0x3e,0xd0,0x91,0x09,0xed,0xf7,0x11,0x48,0x75,0xd0,0x70,0x8f,0x8b,0xe3,0x81,0x3f},+ {0xfe,0xaf,0xd9,0x7e,0xcc,0x0f,0x91,0x7f,0x4b,0x87,0x65,0x24,0xa1,0xb8,0x5c,0x54,0x04,0x47,0x0c,0x4b,0xd2,0x7e,0x39,0xa8,0x93,0x09,0xf5,0x04,0xc1,0x0f,0x51,0x50,0x24,0xc8,0x17,0x5f,0x35,0x7f,0xdb,0x0a,0xa4,0x99,0x42,0xd7,0xc3,0x23,0xb9,0x74,0xf7,0xea,0xf8,0xcb,0x8b,0x3e,0x7c,0xd5,0x3d,0xdc,0xde,0x4c,0xd3,0xe2,0xd3,0x0a,0x9d,0x24,0x6e,0x33,0xc5,0x0f,0x0c,0x6f,0xd9,0xcf,0x31,0xc3,0x19,0xde,0x5e,0x74,0x1c,0xfe,0xee,0x09,0x00,0xfd,0xd6,0xf2,0xbe,0x1e,0xfa,0xf0,0x8b,0x15,0x7c,0x12},+ {0xa2,0x79,0x98,0x2e,0x42,0x7c,0x19,0xf6,0x47,0x36,0xca,0x52,0xd4,0xdd,0x4a,0xa4,0xcb,0xac,0x4e,0x4b,0xc1,0x3f,0x41,0x9b,0x68,0x4f,0xef,0x07,0x7d,0xf8,0x4e,0x35,0x74,0xb9,0x51,0xae,0xc4,0x8f,0xa2,0xde,0x96,0xfe,0x4d,0x74,0xd3,0x73,0x99,0x1d,0xa8,0x48,0x38,0x87,0x0b,0x68,0x40,0x62,0x95,0xdf,0x67,0xd1,0x79,0x24,0xd8,0x4e,0x75,0xd9,0xc5,0x60,0x22,0xb5,0xe3,0xfe,0xb8,0xb0,0x41,0xeb,0xfc,0x2e,0x35,0x50,0x3c,0x65,0xf6,0xa9,0x30,0xac,0x08,0x88,0x6d,0x23,0x39,0x05,0xd2,0x92,0x2d,0x30},+ {0x3d,0x28,0xa4,0xbc,0xa2,0xc1,0x13,0x78,0xd9,0x3d,0x86,0xa1,0x91,0xf0,0x62,0xed,0x86,0xfa,0x68,0xc2,0xb8,0xbc,0xc7,0xae,0x4c,0xae,0x1c,0x6f,0xb7,0xd3,0xe5,0x10,0x77,0xf1,0xe0,0xe4,0xb6,0x6f,0xbc,0x2d,0x93,0x6a,0xbd,0xa4,0x29,0xbf,0xe1,0x04,0xe8,0xf6,0x7a,0x78,0xd4,0x66,0x19,0x5e,0x60,0xd0,0x26,0xb4,0x5e,0x5f,0xdc,0x0e,0x67,0x8e,0xda,0x53,0xd6,0xbf,0x53,0x54,0x41,0xf6,0xa9,0x24,0xec,0x1e,0xdc,0xe9,0x23,0x8a,0x57,0x03,0x3b,0x26,0x87,0xbf,0x72,0xba,0x1c,0x36,0x51,0x6c,0xb4,0x45},+ {0xa1,0x7f,0x4f,0x31,0xbf,0x2a,0x40,0xa9,0x50,0xf4,0x8c,0x8e,0xdc,0xf1,0x57,0xe2,0x84,0xbe,0xa8,0x23,0x4b,0xd5,0xbb,0x1d,0x3b,0x71,0xcb,0x6d,0xa3,0xbf,0x77,0x21,0xe4,0xe3,0x7f,0x8a,0xdd,0x4d,0x9d,0xce,0x30,0x0e,0x62,0x76,0x56,0x64,0x13,0xab,0x58,0x99,0x0e,0xb3,0x7b,0x4f,0x59,0x4b,0xdf,0x29,0x12,0x32,0xef,0x0a,0x1c,0x5c,0x8f,0xdb,0x79,0xfa,0xbc,0x1b,0x08,0x37,0xb3,0x59,0x5f,0xc2,0x1e,0x81,0x48,0x60,0x87,0x24,0x83,0x9c,0x65,0x76,0x7a,0x08,0xbb,0xb5,0x8a,0x7d,0x38,0x19,0xe6,0x4a},+ {0x2e,0xa3,0x44,0x53,0xaa,0xf6,0xdb,0x8d,0x78,0x40,0x1b,0xb4,0xb4,0xea,0x88,0x7d,0x60,0x0d,0x13,0x4a,0x97,0xeb,0xb0,0x5e,0x03,0x3e,0xbf,0x17,0x1b,0xd9,0x00,0x1a,0x83,0xfb,0x5b,0x98,0x44,0x7e,0x11,0x61,0x36,0x31,0x96,0x71,0x2a,0x46,0xe0,0xfc,0x4b,0x90,0x25,0xd4,0x48,0x34,0xac,0x83,0x64,0x3d,0xa4,0x5b,0xbe,0x5a,0x68,0x75,0xb2,0xf2,0x61,0xeb,0x33,0x09,0x96,0x6e,0x52,0x49,0xff,0xc9,0xa8,0x0f,0x3d,0x54,0x69,0x65,0xf6,0x7a,0x10,0x75,0x72,0xdf,0xaa,0xe6,0xb0,0x23,0xb6,0x29,0x55,0x13},+ {0x18,0xd5,0xd1,0xad,0xd7,0xdb,0xf0,0x18,0x11,0x1f,0xc1,0xcf,0x88,0x78,0x9f,0x97,0x9b,0x75,0x14,0x71,0xf0,0xe1,0x32,0x87,0x01,0x3a,0xca,0x65,0x1a,0xb8,0xb5,0x79,0xfe,0x83,0x2e,0xe2,0xbc,0x16,0xc7,0xf5,0xc1,0x85,0x09,0xe8,0x19,0xeb,0x2b,0xb4,0xae,0x4a,0x25,0x14,0x37,0xa6,0x9d,0xec,0x13,0xa6,0x90,0x15,0x05,0xea,0x72,0x59,0x11,0x78,0x8f,0xdc,0x20,0xac,0xd4,0x0f,0xa8,0x4f,0x4d,0xac,0x94,0xd2,0x9a,0x9a,0x34,0x04,0x36,0xb3,0x64,0x2d,0x1b,0xc0,0xdb,0x3b,0x5f,0x90,0x95,0x9c,0x7e,0x4f},+ {0x2e,0x30,0x81,0x57,0xbc,0x4b,0x67,0x62,0x0f,0xdc,0xad,0x89,0x39,0x0f,0x52,0xd8,0xc6,0xd9,0xfb,0x53,0xae,0x99,0x29,0x8c,0x4c,0x8e,0x63,0x2e,0xd9,0x3a,0x99,0x31,0xfe,0x99,0x52,0x35,0x3d,0x44,0xc8,0x71,0xd7,0xea,0xeb,0xdb,0x1c,0x3b,0xcd,0x8b,0x66,0x94,0xa4,0xf1,0x9e,0x49,0x92,0x80,0xc8,0xad,0x44,0xa1,0xc4,0xee,0x42,0x19,0x92,0x49,0x23,0xae,0x19,0x53,0xac,0x7d,0x92,0x3e,0xea,0x0c,0x91,0x3d,0x1b,0x2c,0x22,0x11,0x3c,0x25,0x94,0xe4,0x3c,0x55,0x75,0xca,0xf9,0x4e,0x31,0x65,0x0a,0x2a},+ {0xc2,0x27,0xf9,0xf7,0x7f,0x93,0xb7,0x2d,0x35,0xa6,0xd0,0x17,0x06,0x1f,0x74,0xdb,0x76,0xaf,0x55,0x11,0xa2,0xf3,0x82,0x59,0xed,0x2d,0x7c,0x64,0x18,0xe2,0xf6,0x4c,0x3a,0x79,0x1c,0x3c,0xcd,0x1a,0x36,0xcf,0x3b,0xbc,0x35,0x5a,0xac,0xbc,0x9e,0x2f,0xab,0xa6,0xcd,0xa8,0xe9,0x60,0xe8,0x60,0x13,0x1a,0xea,0x6d,0x9b,0xc3,0x5d,0x05,0xb6,0x5b,0x8d,0xc2,0x7c,0x22,0x19,0xb1,0xab,0xff,0x4d,0x77,0xbc,0x4e,0xe2,0x07,0x89,0x2c,0xa3,0xe4,0xce,0x78,0x3c,0xa8,0xb6,0x24,0xaa,0x10,0x77,0x30,0x1a,0x12},+ {0x97,0x4a,0x03,0x9f,0x5e,0x5d,0xdb,0xe4,0x2d,0xbc,0x34,0x30,0x09,0xfc,0x53,0xe1,0xb1,0xd3,0x51,0x95,0x91,0x46,0x05,0x46,0x2d,0xe5,0x40,0x7a,0x6c,0xc7,0x3f,0x33,0xc9,0x83,0x74,0xc7,0x3e,0x71,0x59,0xd6,0xaf,0x96,0x2b,0xb8,0x77,0xe0,0xbf,0x88,0xd3,0xbc,0x97,0x10,0x23,0x28,0x9e,0x28,0x9b,0x3a,0xed,0x6c,0x4a,0xb9,0x7b,0x52,0x2e,0x48,0x5b,0x99,0x2a,0x99,0x3d,0x56,0x01,0x38,0x38,0x6e,0x7c,0xd0,0x05,0x34,0xe5,0xd8,0x64,0x2f,0xde,0x35,0x50,0x48,0xf7,0xa9,0xa7,0x20,0x9b,0x06,0x89,0x6b},+ {0x0d,0x22,0x70,0x62,0x41,0xa0,0x2a,0x81,0x4e,0x5b,0x24,0xf9,0xfa,0x89,0x5a,0x99,0x05,0xef,0x72,0x50,0xce,0xc4,0xad,0xff,0x73,0xeb,0x73,0xaa,0x03,0x21,0xbc,0x23,0x77,0xdb,0xc7,0xb5,0x8c,0xfa,0x82,0x40,0x55,0xc1,0x34,0xc7,0xf8,0x86,0x86,0x06,0x7e,0xa5,0xe7,0xf6,0xd9,0xc8,0xe6,0x29,0xcf,0x9b,0x63,0xa7,0x08,0xd3,0x73,0x04,0x05,0x9e,0x58,0x03,0x26,0x79,0xee,0xca,0x92,0xc4,0xdc,0x46,0x12,0x42,0x4b,0x2b,0x4f,0xa9,0x01,0xe6,0x74,0xef,0xa1,0x02,0x1a,0x34,0x04,0xde,0xbf,0x73,0x2f,0x10},+ {0xc6,0x45,0x57,0x7f,0xab,0xb9,0x18,0xeb,0x90,0xc6,0x87,0x57,0xee,0x8a,0x3a,0x02,0xa9,0xaf,0xf7,0x2d,0xda,0x12,0x27,0xb7,0x3d,0x01,0x5c,0xea,0x25,0x7d,0x59,0x36,0x9a,0x1c,0x51,0xb5,0xe0,0xda,0xb4,0xa2,0x06,0xff,0xff,0x2b,0x29,0x60,0xc8,0x7a,0x34,0x42,0x50,0xf5,0x5d,0x37,0x1f,0x98,0x2d,0xa1,0x4e,0xda,0x25,0xd7,0x6b,0x3f,0xac,0x58,0x60,0x10,0x7b,0x8d,0x4d,0x73,0x5f,0x90,0xc6,0x6f,0x9e,0x57,0x40,0xd9,0x2d,0x93,0x02,0x92,0xf9,0xf8,0x66,0x64,0xd0,0xd6,0x60,0xda,0x19,0xcc,0x7e,0x7b},+ {0x0d,0x69,0x5c,0x69,0x3c,0x37,0xc2,0x78,0x6e,0x90,0x42,0x06,0x66,0x2e,0x25,0xdd,0xd2,0x2b,0xe1,0x4a,0x44,0x44,0x1d,0x95,0x56,0x39,0x74,0x01,0x76,0xad,0x35,0x42,0x9b,0xfa,0x7c,0xa7,0x51,0x4a,0xae,0x6d,0x50,0x86,0xa3,0xe7,0x54,0x36,0x26,0x82,0xdb,0x82,0x2d,0x8f,0xcd,0xff,0xbb,0x09,0xba,0xca,0xf5,0x1b,0x66,0xdc,0xbe,0x03,0xf5,0x75,0x89,0x07,0x0d,0xcb,0x58,0x62,0x98,0xf2,0x89,0x91,0x54,0x42,0x29,0x49,0xe4,0x6e,0xe3,0xe2,0x23,0xb4,0xca,0xa0,0xa1,0x66,0xf0,0xcd,0xb0,0xe2,0x7c,0x0e},+ {0xa3,0x85,0x8c,0xc4,0x3a,0x64,0x94,0xc4,0xad,0x39,0x61,0x3c,0xf4,0x1d,0x36,0xfd,0x48,0x4d,0xe9,0x3a,0xdd,0x17,0xdb,0x09,0x4a,0x67,0xb4,0x8f,0x5d,0x0a,0x6e,0x66,0xf9,0x70,0x4b,0xd9,0xdf,0xfe,0xa6,0xfe,0x2d,0xba,0xfc,0xc1,0x51,0xc0,0x30,0xf1,0x89,0xab,0x2f,0x7f,0x7e,0xd4,0x82,0x48,0xb5,0xee,0xec,0x8a,0x13,0x56,0x52,0x61,0x0d,0xcb,0x70,0x48,0x4e,0xf6,0xbb,0x2a,0x6b,0x8b,0x45,0xaa,0xf0,0xbc,0x65,0xcd,0x5d,0x98,0xe8,0x75,0xba,0x4e,0xbe,0x9a,0xe4,0xde,0x14,0xd5,0x10,0xc8,0x0b,0x7f},+ {0x6f,0x13,0xf4,0x26,0xa4,0x6b,0x00,0xb9,0x35,0x30,0xe0,0x57,0x9e,0x36,0x67,0x8d,0x28,0x3c,0x46,0x4f,0xd9,0xdf,0xc8,0xcb,0xf5,0xdb,0xee,0xf8,0xbc,0x8d,0x1f,0x0d,0xa0,0x13,0x72,0x73,0xad,0x9d,0xac,0x83,0x98,0x2e,0xf7,0x2e,0xba,0xf8,0xf6,0x9f,0x57,0x69,0xec,0x43,0xdd,0x2e,0x1e,0x31,0x75,0xab,0xc5,0xde,0x7d,0x90,0x3a,0x1d,0xdc,0x81,0xd0,0x3e,0x31,0x93,0x16,0xba,0x80,0x34,0x1b,0x85,0xad,0x9f,0x32,0x29,0xcb,0x21,0x03,0x03,0x3c,0x01,0x28,0x01,0xe3,0xfd,0x1b,0xa3,0x44,0x1b,0x01,0x00},+ {0x0c,0x6c,0xc6,0x3f,0x6c,0xa0,0xdf,0x3f,0xd2,0x0d,0xd6,0x4d,0x8e,0xe3,0x40,0x5d,0x71,0x4d,0x8e,0x26,0x38,0x8b,0xe3,0x7a,0xe1,0x57,0x83,0x6e,0x91,0x8d,0xc4,0x3a,0x5c,0xa7,0x0a,0x6a,0x69,0x1f,0x56,0x16,0x6a,0xbd,0x52,0x58,0x5c,0x72,0xbf,0xc1,0xad,0x66,0x79,0x9a,0x7f,0xdd,0xa8,0x11,0x26,0x10,0x85,0xd2,0xa2,0x88,0xd9,0x63,0x2e,0x23,0xbd,0xaf,0x53,0x07,0x12,0x00,0x83,0xf6,0xd8,0xfd,0xb8,0xce,0x2b,0xe9,0x91,0x2b,0xe7,0x84,0xb3,0x69,0x16,0xf8,0x66,0xa0,0x68,0x23,0x2b,0xd5,0xfa,0x33},+ {0x16,0x1e,0xe4,0xc5,0xc6,0x49,0x06,0x54,0x35,0x77,0x3f,0x33,0x30,0x64,0xf8,0x0a,0x46,0xe7,0x05,0xf3,0xd2,0xfc,0xac,0xb2,0xa7,0xdc,0x56,0xa2,0x29,0xf4,0xc0,0x16,0xe8,0xcf,0x22,0xc4,0xd0,0xc8,0x2c,0x8d,0xcb,0x3a,0xa1,0x05,0x7b,0x4f,0x2b,0x07,0x6f,0xa5,0xf6,0xec,0xe6,0xb6,0xfe,0xa3,0xe2,0x71,0x0a,0xb9,0xcc,0x55,0xc3,0x3c,0x31,0x91,0x3e,0x90,0x43,0x94,0xb6,0xe9,0xce,0x37,0x56,0x7a,0xcb,0x94,0xa4,0xb8,0x44,0x92,0xba,0xba,0xa4,0xd1,0x7c,0xc8,0x68,0x75,0xae,0x6b,0x42,0xaf,0x1e,0x63},+ {0x9f,0xfe,0x66,0xda,0x10,0x04,0xe9,0xb3,0xa6,0xe5,0x16,0x6c,0x52,0x4b,0xdd,0x85,0x83,0xbf,0xf9,0x1e,0x61,0x97,0x3d,0xbc,0xb5,0x19,0xa9,0x1e,0x8b,0x64,0x99,0x55,0xe8,0x0d,0x70,0xa3,0xb9,0x75,0xd9,0x47,0x52,0x05,0xf8,0xe2,0xfb,0xc5,0x80,0x72,0xe1,0x5d,0xe4,0x32,0x27,0x8f,0x65,0x53,0xb5,0x80,0x5f,0x66,0x7f,0x2c,0x1f,0x43,0x19,0x7b,0x8f,0x85,0x44,0x63,0x02,0xd6,0x4a,0x51,0xea,0xa1,0x2f,0x35,0xab,0x14,0xd7,0xa9,0x90,0x20,0x1a,0x44,0x00,0x89,0x26,0x3b,0x25,0x91,0x5f,0x71,0x04,0x7b},+ {0x43,0xae,0xf6,0xac,0x28,0xbd,0xed,0x83,0xb4,0x7a,0x5c,0x7d,0x8b,0x7c,0x35,0x86,0x44,0x2c,0xeb,0xb7,0x69,0x47,0x40,0xc0,0x3f,0x58,0xf6,0xc2,0xf5,0x7b,0xb3,0x59,0xc6,0xba,0xe6,0xc4,0x80,0xc2,0x76,0xb3,0x0b,0x9b,0x1d,0x6d,0xdd,0xd3,0x0e,0x97,0x44,0xf9,0x0b,0x45,0x58,0x95,0x9a,0xb0,0x23,0xe2,0xcd,0x57,0xfa,0xac,0xd0,0x48,0x71,0xe6,0xab,0x7d,0xe4,0x26,0x0f,0xb6,0x37,0x3a,0x2f,0x62,0x97,0xa1,0xd1,0xf1,0x94,0x03,0x96,0xe9,0x7e,0xce,0x08,0x42,0xdb,0x3b,0x6d,0x33,0x91,0x41,0x23,0x16},+ {0xf6,0x7f,0x26,0xf6,0xde,0x99,0xe4,0xb9,0x43,0x08,0x2c,0x74,0x7b,0xca,0x72,0x77,0xb1,0xf2,0xa4,0xe9,0x3f,0x15,0xa0,0x23,0x06,0x50,0xd0,0xd5,0xec,0xdf,0xdf,0x2c,0x40,0x86,0xf3,0x1f,0xd6,0x9c,0x49,0xdd,0xa0,0x25,0x36,0x06,0xc3,0x9b,0xcd,0x29,0xc3,0x3d,0xd7,0x3d,0x02,0xd8,0xe2,0x51,0x31,0x92,0x3b,0x20,0x7a,0x70,0x25,0x4a,0x6a,0xed,0xf6,0x53,0x8a,0x66,0xb7,0x2a,0xa1,0x70,0xd1,0x1d,0x58,0x42,0x42,0x30,0x61,0x01,0xe2,0x3a,0x4c,0x14,0x00,0x40,0xfc,0x49,0x8e,0x24,0x6d,0x89,0x21,0x57},+ {0xae,0x1b,0x18,0xfd,0x17,0x55,0x6e,0x0b,0xb4,0x63,0xb9,0x2b,0x9f,0x62,0x22,0x90,0x25,0x46,0x06,0x32,0xe9,0xbc,0x09,0x55,0xda,0x13,0x3c,0xf6,0x74,0xdd,0x8e,0x57,0x4e,0xda,0xd0,0xa1,0x91,0x50,0x5d,0x28,0x08,0x3e,0xfe,0xb5,0xa7,0x6f,0xaa,0x4b,0xb3,0x93,0x93,0xe1,0x7c,0x17,0xe5,0x63,0xfd,0x30,0xb0,0xc4,0xaf,0x35,0xc9,0x03,0x3d,0x0c,0x2b,0x49,0xc6,0x76,0x72,0x99,0xfc,0x05,0xe2,0xdf,0xc4,0xc2,0xcc,0x47,0x3c,0x3a,0x62,0xdd,0x84,0x9b,0xd2,0xdc,0xa2,0xc7,0x88,0x02,0x59,0xab,0xc2,0x3e},+ {0xb9,0x7b,0xd8,0xe4,0x7b,0xd2,0xa0,0xa1,0xed,0x1a,0x39,0x61,0xeb,0x4d,0x8b,0xa9,0x83,0x9b,0xcb,0x73,0xd0,0xdd,0xa0,0x99,0xce,0xca,0x0f,0x20,0x5a,0xc2,0xd5,0x2d,0xcb,0xd1,0x32,0xae,0x09,0x3a,0x21,0xa7,0xd5,0xc2,0xf5,0x40,0xdf,0x87,0x2b,0x0f,0x29,0xab,0x1e,0xe8,0xc6,0xa4,0xae,0x0b,0x5e,0xac,0xdb,0x6a,0x6c,0xf6,0x1b,0x0e,0x7e,0x88,0x2c,0x79,0xe9,0xd5,0xab,0xe2,0x5d,0x6d,0x92,0xcb,0x18,0x00,0x02,0x1a,0x1e,0x5f,0xae,0xba,0xcd,0x69,0xba,0xbf,0x5f,0x8f,0xe8,0x5a,0xb3,0x48,0x05,0x73},+ {0xee,0xb8,0xa8,0xcb,0xa3,0x51,0x35,0xc4,0x16,0x5f,0x11,0xb2,0x1d,0x6f,0xa2,0x65,0x50,0x38,0x8c,0xab,0x52,0x4f,0x0f,0x76,0xca,0xb8,0x1d,0x41,0x3b,0x44,0x43,0x30,0x34,0xe3,0xd6,0xa1,0x4b,0x09,0x5b,0x80,0x19,0x3f,0x35,0x09,0x77,0xf1,0x3e,0xbf,0x2b,0x70,0x22,0x06,0xcb,0x06,0x3f,0x42,0xdd,0x45,0x78,0xd8,0x77,0x22,0x5a,0x58,0x62,0x89,0xd4,0x33,0x82,0x5f,0x8a,0xa1,0x7f,0x25,0x78,0xec,0xb5,0xc4,0x98,0x66,0xff,0x41,0x3e,0x37,0xa5,0x6f,0x8e,0xa7,0x1f,0x98,0xef,0x50,0x89,0x27,0x56,0x76},+ {0xc0,0xc8,0x1f,0xd5,0x59,0xcf,0xc3,0x38,0xf2,0xb6,0x06,0x05,0xfd,0xd2,0xed,0x9b,0x8f,0x0e,0x57,0xab,0x9f,0x10,0xbf,0x26,0xa6,0x46,0xb8,0xc1,0xa8,0x60,0x41,0x3f,0x9d,0xcf,0x86,0xea,0xa3,0x73,0x70,0xe1,0xdc,0x5f,0x15,0x07,0xb7,0xfb,0x8c,0x3a,0x8e,0x8a,0x83,0x31,0xfc,0xe7,0x53,0x48,0x16,0xf6,0x13,0xb6,0x84,0xf4,0xbb,0x28,0x7c,0x6c,0x13,0x6f,0x5c,0x2f,0x61,0xf2,0xbe,0x11,0xdd,0xf6,0x07,0xd1,0xea,0xaf,0x33,0x6f,0xde,0x13,0xd2,0x9a,0x7e,0x52,0x5d,0xf7,0x88,0x81,0x35,0xcb,0x79,0x1e},+ {0xf1,0xe3,0xf7,0xee,0xc3,0x36,0x34,0x01,0xf8,0x10,0x9e,0xfe,0x7f,0x6a,0x8b,0x82,0xfc,0xde,0xf9,0xbc,0xe5,0x08,0xf9,0x7f,0x31,0x38,0x3b,0x3a,0x1b,0x95,0xd7,0x65,0x81,0x81,0xe0,0xf5,0xd8,0x53,0xe9,0x77,0xd9,0xde,0x9d,0x29,0x44,0x0c,0xa5,0x84,0xe5,0x25,0x45,0x86,0x0c,0x2d,0x6c,0xdc,0xf4,0xf2,0xd1,0x39,0x2d,0xb5,0x8a,0x47,0x59,0xd1,0x52,0x92,0xd3,0xa4,0xa6,0x66,0x07,0xc8,0x1a,0x87,0xbc,0xe1,0xdd,0xe5,0x6f,0xc9,0xc1,0xa6,0x40,0x6b,0x2c,0xb8,0x14,0x22,0x21,0x1a,0x41,0x7a,0xd8,0x16},+ {0x15,0x62,0x06,0x42,0x5a,0x7e,0xbd,0xb3,0xc1,0x24,0x5a,0x0c,0xcd,0xe3,0x9b,0x87,0xb7,0x94,0xf9,0xd6,0xb1,0x5d,0xc0,0x57,0xa6,0x8c,0xf3,0x65,0x81,0x7c,0xf8,0x28,0x83,0x05,0x4e,0xd5,0xe2,0xd5,0xa4,0xfb,0xfa,0x99,0xbd,0x2e,0xd7,0xaf,0x1f,0xe2,0x8f,0x77,0xe9,0x6e,0x73,0xc2,0x7a,0x49,0xde,0x6d,0x5a,0x7a,0x57,0x0b,0x99,0x1f,0xd6,0xf7,0xe8,0x1b,0xad,0x4e,0x34,0xa3,0x8f,0x79,0xea,0xac,0xeb,0x50,0x1e,0x7d,0x52,0xe0,0x0d,0x52,0x9e,0x56,0xc6,0x77,0x3e,0x6d,0x4d,0x53,0xe1,0x2f,0x88,0x45},+ {0xd6,0x83,0x79,0x75,0x5d,0x34,0x69,0x66,0xa6,0x11,0xaa,0x17,0x11,0xed,0xb6,0x62,0x8f,0x12,0x5e,0x98,0x57,0x18,0xdd,0x7d,0xdd,0xf6,0x26,0xf6,0xb8,0xe5,0x8f,0x68,0xe4,0x6f,0x3c,0x94,0x29,0x99,0xac,0xd8,0xa2,0x92,0x83,0xa3,0x61,0xf1,0xf9,0xb5,0xf3,0x9a,0xc8,0xbe,0x13,0xdb,0x99,0x26,0x74,0xf0,0x05,0xe4,0x3c,0x84,0xcf,0x7d,0xc0,0x32,0x47,0x4a,0x48,0xd6,0x90,0x6c,0x99,0x32,0x56,0xca,0xfd,0x43,0x21,0xd5,0xe1,0xc6,0x5d,0x91,0xc3,0x28,0xbe,0xb3,0x1b,0x19,0x27,0x73,0x7e,0x68,0x39,0x67},+ {0xa6,0x75,0x56,0x38,0x14,0x20,0x78,0xef,0xe8,0xa9,0xfd,0xaa,0x30,0x9f,0x64,0xa2,0xcb,0xa8,0xdf,0x5c,0x50,0xeb,0xd1,0x4c,0xb3,0xc0,0x4d,0x1d,0xba,0x5a,0x11,0x46,0xc0,0x1a,0x0c,0xc8,0x9d,0xcc,0x6d,0xa6,0x36,0xa4,0x38,0x1b,0xf4,0x5c,0xa0,0x97,0xc6,0xd7,0xdb,0x95,0xbe,0xf3,0xeb,0xa7,0xab,0x7d,0x7e,0x8d,0xf6,0xb8,0xa0,0x7d,0x76,0xda,0xb5,0xc3,0x53,0x19,0x0f,0xd4,0x9b,0x9e,0x11,0x21,0x73,0x6f,0xac,0x1d,0x60,0x59,0xb2,0xfe,0x21,0x60,0xcc,0x03,0x4b,0x4b,0x67,0x83,0x7e,0x88,0x5f,0x5a},+ {0x11,0x3d,0xa1,0x70,0xcf,0x01,0x63,0x8f,0xc4,0xd0,0x0d,0x35,0x15,0xb8,0xce,0xcf,0x7e,0xa4,0xbc,0xa4,0xd4,0x97,0x02,0xf7,0x34,0x14,0x4d,0xe4,0x56,0xb6,0x69,0x36,0xb9,0x43,0xa6,0xa0,0xd3,0x28,0x96,0x9e,0x64,0x20,0xc3,0xe6,0x00,0xcb,0xc3,0xb5,0x32,0xec,0x2d,0x7c,0x89,0x02,0x53,0x9b,0x0c,0xc7,0xd1,0xd5,0xe2,0x7a,0xe3,0x43,0x33,0xe1,0xa6,0xed,0x06,0x3f,0x7e,0x38,0xc0,0x3a,0xa1,0x99,0x51,0x1d,0x30,0x67,0x11,0x38,0x26,0x36,0xf8,0xd8,0x5a,0xbd,0xbe,0xe9,0xd5,0x4f,0xcd,0xe6,0x21,0x6a},+ {0x5f,0xe6,0x46,0x30,0x0a,0x17,0xc6,0xf1,0x24,0x35,0xd2,0x00,0x2a,0x2a,0x71,0x58,0x55,0xb7,0x82,0x8c,0x3c,0xbd,0xdb,0x69,0x57,0xff,0x95,0xa1,0xf1,0xf9,0x6b,0x58,0xe3,0xb2,0x99,0x66,0x12,0x29,0x41,0xef,0x01,0x13,0x8d,0x70,0x47,0x08,0xd3,0x71,0xbd,0xb0,0x82,0x11,0xd0,0x32,0x54,0x32,0x36,0x8b,0x1e,0x00,0x07,0x1b,0x37,0x45,0x0b,0x79,0xf8,0x5e,0x8d,0x08,0xdb,0xa6,0xe5,0x37,0x09,0x61,0xdc,0xf0,0x78,0x52,0xb8,0x6e,0xa1,0x61,0xd2,0x49,0x03,0xac,0x79,0x21,0xe5,0x90,0x37,0xb0,0xaf,0x0e},+ {0x2f,0x04,0x48,0x37,0xc1,0x55,0x05,0x96,0x11,0xaa,0x0b,0x82,0xe6,0x41,0x9a,0x21,0x0c,0x6d,0x48,0x73,0x38,0xf7,0x81,0x1c,0x61,0xc6,0x02,0x5a,0x67,0xcc,0x9a,0x30,0x1d,0xae,0x75,0x0f,0x5e,0x80,0x40,0x51,0x30,0xcc,0x62,0x26,0xe3,0xfb,0x02,0xec,0x6d,0x39,0x92,0xea,0x1e,0xdf,0xeb,0x2c,0xb3,0x5b,0x43,0xc5,0x44,0x33,0xae,0x44,0xee,0x43,0xa5,0xbb,0xb9,0x89,0xf2,0x9c,0x42,0x71,0xc9,0x5a,0x9d,0x0e,0x76,0xf3,0xaa,0x60,0x93,0x4f,0xc6,0xe5,0x82,0x1d,0x8f,0x67,0x94,0x7f,0x1b,0x22,0xd5,0x62},+ {0x6d,0x93,0xd0,0x18,0x9c,0x29,0x4c,0x52,0x0c,0x1a,0x0c,0x8a,0x6c,0xb5,0x6b,0xc8,0x31,0x86,0x4a,0xdb,0x2e,0x05,0x75,0xa3,0x62,0x45,0x75,0xbc,0xe4,0xfd,0x0e,0x5c,0x3c,0x7a,0xf7,0x3a,0x26,0xd4,0x85,0x75,0x4d,0x14,0xe9,0xfe,0x11,0x7b,0xae,0xdf,0x3d,0x19,0xf7,0x59,0x80,0x70,0x06,0xa5,0x37,0x20,0x92,0x83,0x53,0x9a,0xf2,0x14,0xf5,0xd7,0xb2,0x25,0xdc,0x7e,0x71,0xdf,0x40,0x30,0xb5,0x99,0xdb,0x70,0xf9,0x21,0x62,0x4c,0xed,0xc3,0xb7,0x34,0x92,0xda,0x3e,0x09,0xee,0x7b,0x5c,0x36,0x72,0x5e},+ {0x7f,0x21,0x71,0x45,0x07,0xfc,0x5b,0x57,0x5b,0xd9,0x94,0x06,0x5d,0x67,0x79,0x37,0x33,0x1e,0x19,0xf4,0xbb,0x37,0x0a,0x9a,0xbc,0xea,0xb4,0x47,0x4c,0x10,0xf1,0x77,0x3e,0xb3,0x08,0x2f,0x06,0x39,0x93,0x7d,0xbe,0x32,0x9f,0xdf,0xe5,0x59,0x96,0x5b,0xfd,0xbd,0x9e,0x1f,0xad,0x3d,0xff,0xac,0xb7,0x49,0x73,0xcb,0x55,0x05,0xb2,0x70,0x4c,0x2c,0x11,0x55,0xc5,0x13,0x51,0xbe,0xcd,0x1f,0x88,0x9a,0x3a,0x42,0x88,0x66,0x47,0x3b,0x50,0x5e,0x85,0x77,0x66,0x44,0x4a,0x40,0x06,0x4a,0x8f,0x39,0x34,0x0e},+ {0xe8,0xbd,0xce,0x3e,0xd9,0x22,0x7d,0xb6,0x07,0x2f,0x82,0x27,0x41,0xe8,0xb3,0x09,0x8d,0x6d,0x5b,0xb0,0x1f,0xa6,0x3f,0x74,0x72,0x23,0x36,0x8a,0x36,0x05,0x54,0x5e,0x28,0x19,0x4b,0x3e,0x09,0x0b,0x93,0x18,0x40,0xf6,0xf3,0x73,0x0e,0xe1,0xe3,0x7d,0x6f,0x5d,0x39,0x73,0xda,0x17,0x32,0xf4,0x3e,0x9c,0x37,0xca,0xd6,0xde,0x8a,0x6f,0x9a,0xb2,0xb7,0xfd,0x3d,0x12,0x40,0xe3,0x91,0xb2,0x1a,0xa2,0xe1,0x97,0x7b,0x48,0x9e,0x94,0xe6,0xfd,0x02,0x7d,0x96,0xf9,0x97,0xde,0xd3,0xc8,0x2e,0xe7,0x0d,0x78},+ {0xbc,0xe7,0x9a,0x08,0x45,0x85,0xe2,0x0a,0x06,0x4d,0x7f,0x1c,0xcf,0xde,0x8d,0x38,0xb8,0x11,0x48,0x0a,0x51,0x15,0xac,0x38,0xe4,0x8c,0x92,0x71,0xf6,0x8b,0xb2,0x0e,0x72,0x27,0xf4,0x00,0xf3,0xea,0x1f,0x67,0xaa,0x41,0x8c,0x2a,0x2a,0xeb,0x72,0x8f,0x92,0x32,0x37,0x97,0xd7,0x7f,0xa1,0x29,0xa6,0x87,0xb5,0x32,0xad,0xc6,0xef,0x1d,0xa7,0x95,0x51,0xef,0x1a,0xbe,0x5b,0xaf,0xed,0x15,0x7b,0x91,0x77,0x12,0x8c,0x14,0x2e,0xda,0xe5,0x7a,0xfb,0xf7,0x91,0x29,0x67,0x28,0xdd,0xf8,0x1b,0x20,0x7d,0x46},+ {0xad,0x4f,0xef,0x74,0x9a,0x91,0xfe,0x95,0xa2,0x08,0xa3,0xf6,0xec,0x7b,0x82,0x3a,0x01,0x7b,0xa4,0x09,0xd3,0x01,0x4e,0x96,0x97,0xc7,0xa3,0x5b,0x4f,0x3c,0xc4,0x71,0xa9,0xe7,0x7a,0x56,0xbd,0xf4,0x1e,0xbc,0xbd,0x98,0x44,0xd6,0xb2,0x4c,0x62,0x3f,0xc8,0x4e,0x1f,0x2c,0xd2,0x64,0x10,0xe4,0x01,0x40,0x38,0xba,0xa5,0xc5,0xf9,0x2e,0xcd,0x74,0x9e,0xfa,0xf6,0x6d,0xfd,0xb6,0x7a,0x26,0xaf,0xe4,0xbc,0x78,0x82,0xf1,0x0e,0x99,0xef,0xf1,0xd0,0xb3,0x55,0x82,0x93,0xf2,0xc5,0x90,0xa3,0x8c,0x75,0x5a},+ {0x95,0x24,0x46,0xd9,0x10,0x27,0xb7,0xa2,0x03,0x50,0x7d,0xd5,0xd2,0xc6,0xa8,0x3a,0xca,0x87,0xb4,0xa0,0xbf,0x00,0xd4,0xe3,0xec,0x72,0xeb,0xb3,0x44,0xe2,0xba,0x2d,0x94,0xdc,0x61,0x1d,0x8b,0x91,0xe0,0x8c,0x66,0x30,0x81,0x9a,0x46,0x36,0xed,0x8d,0xd3,0xaa,0xe8,0xaf,0x29,0xa8,0xe6,0xd4,0x3f,0xd4,0x39,0xf6,0x27,0x80,0x73,0x0a,0xcc,0xe1,0xff,0x57,0x2f,0x4a,0x0f,0x98,0x43,0x98,0x83,0xe1,0x0d,0x0d,0x67,0x00,0xfd,0x15,0xfb,0x49,0x4a,0x3f,0x5c,0x10,0x9c,0xa6,0x26,0x51,0x63,0xca,0x98,0x26},+ {0x78,0xba,0xb0,0x32,0x88,0x31,0x65,0xe7,0x8b,0xff,0x5c,0x92,0xf7,0x31,0x18,0x38,0xcc,0x1f,0x29,0xa0,0x91,0x1b,0xa8,0x08,0x07,0xeb,0xca,0x49,0xcc,0x3d,0xb4,0x1f,0x0e,0xd9,0x3d,0x5e,0x2f,0x70,0x3d,0x2e,0x86,0x53,0xd2,0xe4,0x18,0x09,0x3f,0x9e,0x6a,0xa9,0x4d,0x02,0xf6,0x3e,0x77,0x5e,0x32,0x33,0xfa,0x4a,0x0c,0x4b,0x00,0x3c,0x2b,0xb8,0xf4,0x06,0xac,0x46,0xa9,0x9a,0xf3,0xc4,0x06,0xa8,0xa5,0x84,0xa2,0x1c,0x87,0x47,0xcd,0xc6,0x5f,0x26,0xd3,0x3e,0x17,0xd2,0x1f,0xcd,0x01,0xfd,0x43,0x6b},+ {0x44,0xc5,0x97,0x46,0x4b,0x5d,0xa7,0xc7,0xbf,0xff,0x0f,0xdf,0x48,0xf8,0xfd,0x15,0x5a,0x78,0x46,0xaa,0xeb,0xb9,0x68,0x28,0x14,0xf7,0x52,0x5b,0x10,0xd7,0x68,0x5a,0xf3,0x0e,0x76,0x3e,0x58,0x42,0xc7,0xb5,0x90,0xb9,0x0a,0xee,0xb9,0x52,0xdc,0x75,0x3f,0x92,0x2b,0x07,0xc2,0x27,0x14,0xbf,0xf0,0xd9,0xf0,0x6f,0x2d,0x0b,0x42,0x73,0x06,0x1e,0x85,0x9e,0xcb,0xf6,0x2c,0xaf,0xc4,0x38,0x22,0xc6,0x13,0x39,0x59,0x8f,0x73,0xf3,0xfb,0x99,0x96,0xb8,0x8a,0xda,0x9e,0xbc,0x34,0xea,0x2f,0x63,0xb5,0x3d},+ {0xd8,0xd9,0x5d,0xf7,0x2b,0xee,0x6e,0xf4,0xa5,0x59,0x67,0x39,0xf6,0xb1,0x17,0x0d,0x73,0x72,0x9e,0x49,0x31,0xd1,0xf2,0x1b,0x13,0x5f,0xd7,0x49,0xdf,0x1a,0x32,0x04,0xd5,0x25,0x98,0x82,0xb1,0x90,0x49,0x2e,0x91,0x89,0x9a,0x3e,0x87,0xeb,0xea,0xed,0xf8,0x4a,0x70,0x4c,0x39,0x3d,0xf0,0xee,0x0e,0x2b,0xdf,0x95,0xa4,0x7e,0x19,0x59,0xae,0x5a,0xe5,0xe4,0x19,0x60,0xe1,0x04,0xe9,0x92,0x2f,0x7e,0x7a,0x43,0x7b,0xe7,0xa4,0x9a,0x15,0x6f,0xc1,0x2d,0xce,0xc7,0xc0,0x0c,0xd7,0xf4,0xc1,0xfd,0xea,0x45},+ {0x2b,0xd7,0x45,0x80,0x85,0x01,0x84,0x69,0x51,0x06,0x2f,0xcf,0xa2,0xfa,0x22,0x4c,0xc6,0x2d,0x22,0x6b,0x65,0x36,0x1a,0x94,0xde,0xda,0x62,0x03,0xc8,0xeb,0x5e,0x5a,0xed,0xb1,0xcc,0xcf,0x24,0x46,0x0e,0xb6,0x95,0x03,0x5c,0xbd,0x92,0xc2,0xdb,0x59,0xc9,0x81,0x04,0xdc,0x1d,0x9d,0xa0,0x31,0x40,0xd9,0x56,0x5d,0xea,0xce,0x73,0x3f,0xc6,0x8d,0x4e,0x0a,0xd1,0xbf,0xa7,0xb7,0x39,0xb3,0xc9,0x44,0x7e,0x00,0x57,0xbe,0xfa,0xae,0x57,0x15,0x7f,0x20,0xc1,0x60,0xdb,0x18,0x62,0x26,0x91,0x88,0x05,0x26},+ {0x04,0xff,0x60,0x83,0xa6,0x04,0xf7,0x59,0xf4,0xe6,0x61,0x76,0xde,0x3f,0xd9,0xc3,0x51,0x35,0x87,0x12,0x73,0x2a,0x1b,0x83,0x57,0x5d,0x61,0x4e,0x2e,0x0c,0xad,0x54,0x42,0xe5,0x76,0xc6,0x3c,0x8e,0x81,0x4c,0xad,0xcc,0xce,0x03,0x93,0x2c,0x42,0x5e,0x08,0x9f,0x12,0xb4,0xca,0xcc,0x07,0xec,0xb8,0x43,0x44,0xb2,0x10,0xfa,0xed,0x0d,0x2a,0x52,0x2b,0xb8,0xd5,0x67,0x3b,0xee,0xeb,0xc1,0xa5,0x9f,0x46,0x63,0xf1,0x36,0xd3,0x9f,0xc1,0x6e,0xf2,0xd2,0xb4,0xa5,0x08,0x94,0x7a,0xa7,0xba,0xb2,0xec,0x62},+ {0x3d,0x2b,0x15,0x61,0x52,0x79,0xed,0xe5,0xd1,0xd7,0xdd,0x0e,0x7d,0x35,0x62,0x49,0x71,0x4c,0x6b,0xb9,0xd0,0xc8,0x82,0x74,0xbe,0xd8,0x66,0xa9,0x19,0xf9,0x59,0x2e,0x74,0x28,0xb6,0xaf,0x36,0x28,0x07,0x92,0xa5,0x04,0xe1,0x79,0x85,0x5e,0xcd,0x5f,0x4a,0xa1,0x30,0xc6,0xad,0x01,0xad,0x5a,0x98,0x3f,0x66,0x75,0x50,0x3d,0x91,0x61,0xda,0x31,0x32,0x1a,0x36,0x2d,0xc6,0x0d,0x70,0x02,0x20,0x94,0x32,0x58,0x47,0xfa,0xce,0x94,0x95,0x3f,0x51,0x01,0xd8,0x02,0x5c,0x5d,0xc0,0x31,0xa1,0xc2,0xdb,0x3d},+ {0x4b,0xc5,0x5e,0xce,0xf9,0x0f,0xdc,0x9a,0x0d,0x13,0x2f,0x8c,0x6b,0x2a,0x9c,0x03,0x15,0x95,0xf8,0xf0,0xc7,0x07,0x80,0x02,0x6b,0xb3,0x04,0xac,0x14,0x83,0x96,0x78,0x14,0xbb,0x96,0x27,0xa2,0x57,0xaa,0xf3,0x21,0xda,0x07,0x9b,0xb7,0xba,0x3a,0x88,0x1c,0x39,0xa0,0x31,0x18,0xe2,0x4b,0xe5,0xf9,0x05,0x32,0xd8,0x38,0xfb,0xe7,0x5e,0x8e,0x6a,0x44,0x41,0xcb,0xfd,0x8d,0x53,0xf9,0x37,0x49,0x43,0xa9,0xfd,0xac,0xa5,0x78,0x8c,0x3c,0x26,0x8d,0x90,0xaf,0x46,0x09,0x0d,0xca,0x9b,0x3c,0x63,0xd0,0x61},+ {0x66,0x25,0xdb,0xff,0x35,0x49,0x74,0x63,0xbb,0x68,0x0b,0x78,0x89,0x6b,0xbd,0xc5,0x03,0xec,0x3e,0x55,0x80,0x32,0x1b,0x6f,0xf5,0xd7,0xae,0x47,0xd8,0x5f,0x96,0x6e,0xdf,0x73,0xfc,0xf8,0xbc,0x28,0xa3,0xad,0xfc,0x37,0xf0,0xa6,0x5d,0x69,0x84,0xee,0x09,0xa9,0xc2,0x38,0xdb,0xb4,0x7f,0x63,0xdc,0x7b,0x06,0xf8,0x2d,0xac,0x23,0x5b,0x7b,0x52,0x80,0xee,0x53,0xb9,0xd2,0x9a,0x8d,0x6d,0xde,0xfa,0xaa,0x19,0x8f,0xe8,0xcf,0x82,0x0e,0x15,0x04,0x17,0x71,0x0e,0xdc,0xde,0x95,0xdd,0xb9,0xbb,0xb9,0x79},+ {0xc2,0x26,0x31,0x6a,0x40,0x55,0xb3,0xeb,0x93,0xc3,0xc8,0x68,0xa8,0x83,0x63,0xd2,0x82,0x7a,0xb9,0xe5,0x29,0x64,0x0c,0x6c,0x47,0x21,0xfd,0xc9,0x58,0xf1,0x65,0x50,0x74,0x73,0x9f,0x8e,0xae,0x7d,0x99,0xd1,0x16,0x08,0xbb,0xcf,0xf8,0xa2,0x32,0xa0,0x0a,0x5f,0x44,0x6d,0x12,0xba,0x6c,0xcd,0x34,0xb8,0xcc,0x0a,0x46,0x11,0xa8,0x1b,0x54,0x99,0x42,0x0c,0xfb,0x69,0x81,0x70,0x67,0xcf,0x6e,0xd7,0xac,0x00,0x46,0xe1,0xba,0x45,0xe6,0x70,0x8a,0xb9,0xaa,0x2e,0xf2,0xfa,0xa4,0x58,0x9e,0xf3,0x81,0x39},+ {0x93,0x0a,0x23,0x59,0x75,0x8a,0xfb,0x18,0x5d,0xf4,0xe6,0x60,0x69,0x8f,0x16,0x1d,0xb5,0x3c,0xa9,0x14,0x45,0xa9,0x85,0x3a,0xfd,0xd0,0xac,0x05,0x37,0x08,0xdc,0x38,0xde,0x6f,0xe6,0x6d,0xa5,0xdf,0x45,0xc8,0x3a,0x48,0x40,0x2c,0x00,0xa5,0x52,0xe1,0x32,0xf6,0xb4,0xc7,0x63,0xe1,0xd2,0xe9,0x65,0x1b,0xbc,0xdc,0x2e,0x45,0xf4,0x30,0x40,0x97,0x75,0xc5,0x82,0x27,0x6d,0x85,0xcc,0xbe,0x9c,0xf9,0x69,0x45,0x13,0xfa,0x71,0x4e,0xea,0xc0,0x73,0xfc,0x44,0x88,0x69,0x24,0x3f,0x59,0x1a,0x9a,0x2d,0x63},+ {0xa6,0xcb,0x07,0xb8,0x15,0x6b,0xbb,0xf6,0xd7,0xf0,0x54,0xbc,0xdf,0xc7,0x23,0x18,0x0b,0x67,0x29,0x6e,0x03,0x97,0x1d,0xbb,0x57,0x4a,0xed,0x47,0x88,0xf4,0x24,0x0b,0xa7,0x84,0x0c,0xed,0x11,0xfd,0x09,0xbf,0x3a,0x69,0x9f,0x0d,0x81,0x71,0xf0,0x63,0x79,0x87,0xcf,0x57,0x2d,0x8c,0x90,0x21,0xa2,0x4b,0xf6,0x8a,0xf2,0x7d,0x5a,0x3a,0xc7,0xea,0x1b,0x51,0xbe,0xd4,0xda,0xdc,0xf2,0xcc,0x26,0xed,0x75,0x80,0x53,0xa4,0x65,0x9a,0x5f,0x00,0x9f,0xff,0x9c,0xe1,0x63,0x1f,0x48,0x75,0x44,0xf7,0xfc,0x34},+ {0xca,0x67,0x97,0x78,0x4c,0xe0,0x97,0xc1,0x7d,0x46,0xd9,0x38,0xcb,0x4d,0x71,0xb8,0xa8,0x5f,0xf9,0x83,0x82,0x88,0xde,0x55,0xf7,0x63,0xfa,0x4d,0x16,0xdc,0x3b,0x3d,0x98,0xaa,0xcf,0x78,0xab,0x1d,0xbb,0xa5,0xf2,0x72,0x0b,0x19,0x67,0xa2,0xed,0x5c,0x8e,0x60,0x92,0x0a,0x11,0xc9,0x09,0x93,0xb0,0x74,0xb3,0x2f,0x04,0xa3,0x19,0x01,0x7d,0x17,0xc2,0xe8,0x9c,0xd8,0xa2,0x67,0xc1,0xd0,0x95,0x68,0xf6,0xa5,0x9d,0x66,0xb0,0xa2,0x82,0xb2,0xe5,0x98,0x65,0xf5,0x73,0x0a,0xe2,0xed,0xf1,0x88,0xc0,0x56},+ {0x17,0x6e,0xa8,0x10,0x11,0x3d,0x6d,0x33,0xfa,0xb2,0x75,0x0b,0x32,0x88,0xf3,0xd7,0x88,0x29,0x07,0x25,0x76,0x33,0x15,0xf9,0x87,0x8b,0x10,0x99,0x6b,0x4c,0x67,0x09,0x02,0x8f,0xf3,0x24,0xac,0x5f,0x1b,0x58,0xbd,0x0c,0xe3,0xba,0xfe,0xe9,0x0b,0xa9,0xf0,0x92,0xcf,0x8a,0x02,0x69,0x21,0x9a,0x8f,0x03,0x59,0x83,0xa4,0x7e,0x8b,0x03,0xf8,0x6f,0x31,0x99,0x21,0xf8,0x4e,0x9f,0x4f,0x8d,0xa7,0xea,0x82,0xd2,0x49,0x2f,0x74,0x31,0xef,0x5a,0xab,0xa5,0x71,0x09,0x65,0xeb,0x69,0x59,0x02,0x31,0x5e,0x6e},+ {0xfb,0x93,0xe5,0x87,0xf5,0x62,0x6c,0xb1,0x71,0x3e,0x5d,0xca,0xde,0xed,0x99,0x49,0x6d,0x3e,0xcc,0x14,0xe0,0xc1,0x91,0xb4,0xa8,0xdb,0xa8,0x89,0x47,0x11,0xf5,0x08,0x22,0x62,0x06,0x63,0x0e,0xfb,0x04,0x33,0x3f,0xba,0xac,0x87,0x89,0x06,0x35,0xfb,0xa3,0x61,0x10,0x8c,0x77,0x24,0x19,0xbd,0x20,0x86,0x83,0xd1,0x43,0xad,0x58,0x30,0xd0,0x63,0x76,0xe5,0xfd,0x0f,0x3c,0x32,0x10,0xa6,0x2e,0xa2,0x38,0xdf,0xc3,0x05,0x9a,0x4f,0x99,0xac,0xbd,0x8a,0xc7,0xbd,0x99,0xdc,0xe3,0xef,0xa4,0x9f,0x54,0x26},+ {0xd6,0xf9,0x6b,0x1e,0x46,0x5a,0x1d,0x74,0x81,0xa5,0x77,0x77,0xfc,0xb3,0x05,0x23,0xd9,0xd3,0x74,0x64,0xa2,0x74,0x55,0xd4,0xff,0xe0,0x01,0x64,0xdc,0xe1,0x26,0x19,0x6e,0x66,0x3f,0xaf,0x49,0x85,0x46,0xdb,0xa5,0x0e,0x4a,0xf1,0x04,0xcf,0x7f,0xd7,0x47,0x0c,0xba,0xa4,0xf7,0x3f,0xf2,0x3d,0x85,0x3c,0xce,0x32,0xe1,0xdf,0x10,0x3a,0xa0,0xce,0x17,0xea,0x8a,0x4e,0x7f,0xe0,0xfd,0xc1,0x1f,0x3a,0x46,0x15,0xd5,0x2f,0xf1,0xc0,0xf2,0x31,0xfd,0x22,0x53,0x17,0x15,0x5d,0x1e,0x86,0x1d,0xd0,0xa1,0x1f},+ {0x32,0x98,0x59,0x7d,0x94,0x55,0x80,0xcc,0x20,0x55,0xf1,0x37,0xda,0x56,0x46,0x1e,0x20,0x93,0x05,0x4e,0x74,0xf7,0xf6,0x99,0x33,0xcf,0x75,0x6a,0xbc,0x63,0x35,0x77,0xab,0x94,0xdf,0xd1,0x00,0xac,0xdc,0x38,0xe9,0x0d,0x08,0xd1,0xdd,0x2b,0x71,0x2e,0x62,0xe2,0xd5,0xfd,0x3e,0xe9,0x13,0x7f,0xe5,0x01,0x9a,0xee,0x18,0xed,0xfc,0x73,0xb3,0x9c,0x13,0x63,0x08,0xe9,0xb1,0x06,0xcd,0x3e,0xa0,0xc5,0x67,0xda,0x93,0xa4,0x32,0x89,0x63,0xad,0xc8,0xce,0x77,0x8d,0x44,0x4f,0x86,0x1b,0x70,0x6b,0x42,0x1f},+ {0x01,0x1c,0x91,0x41,0x4c,0x26,0xc9,0xef,0x25,0x2c,0xa2,0x17,0xb8,0xb7,0xa3,0xf1,0x47,0x14,0x0f,0xf3,0x6b,0xda,0x75,0x58,0x90,0xb0,0x31,0x1d,0x27,0xf5,0x1a,0x4e,0x52,0x25,0xa1,0x91,0xc8,0x35,0x7e,0xf1,0x76,0x9c,0x5e,0x57,0x53,0x81,0x6b,0xb7,0x3e,0x72,0x9b,0x0d,0x6f,0x40,0x83,0xfa,0x38,0xe4,0xa7,0x3f,0x1b,0xbb,0x76,0x0b,0x9b,0x93,0x92,0x7f,0xf9,0xc1,0xb8,0x08,0x6e,0xab,0x44,0xd4,0xcb,0x71,0x67,0xbe,0x17,0x80,0xbb,0x99,0x63,0x64,0xe5,0x22,0x55,0xa9,0x72,0xb7,0x1e,0xd6,0x6d,0x7b},+ {0x92,0x3d,0xf3,0x50,0xe8,0xc1,0xad,0xb7,0xcf,0xd5,0x8c,0x60,0x4f,0xfa,0x98,0x79,0xdb,0x5b,0xfc,0x8d,0xbd,0x2d,0x96,0xad,0x4f,0x2f,0x1d,0xaf,0xce,0x9b,0x3e,0x70,0xc7,0xd2,0x01,0xab,0xf9,0xab,0x30,0x57,0x18,0x3b,0x14,0x40,0xdc,0x76,0xfb,0x16,0x81,0xb2,0xcb,0xa0,0x65,0xbe,0x6c,0x86,0xfe,0x6a,0xff,0x9b,0x65,0x9b,0xfa,0x53,0x55,0x54,0x88,0x94,0xe9,0xc8,0x14,0x6c,0xe5,0xd4,0xae,0x65,0x66,0x5d,0x3a,0x84,0xf1,0x5a,0xd6,0xbc,0x3e,0xb7,0x1b,0x18,0x50,0x1f,0xc6,0xc4,0xe5,0x93,0x8d,0x39},+ {0xf3,0x48,0xe2,0x33,0x67,0xd1,0x4b,0x1c,0x5f,0x0a,0xbf,0x15,0x87,0x12,0x9e,0xbd,0x76,0x03,0x0b,0xa1,0xf0,0x8c,0x3f,0xd4,0x13,0x1b,0x19,0xdf,0x5d,0x9b,0xb0,0x53,0xf2,0xe3,0xe7,0xd2,0x60,0x7c,0x87,0xc3,0xb1,0x8b,0x82,0x30,0xa0,0xaa,0x34,0x3b,0x38,0xf1,0x9e,0x73,0xe7,0x26,0x3e,0x28,0x77,0x05,0xc3,0x02,0x90,0x9c,0x9c,0x69,0xcc,0xf1,0x46,0x59,0x23,0xa7,0x06,0xf3,0x7d,0xd9,0xe5,0xcc,0xb5,0x18,0x17,0x92,0x75,0xe9,0xb4,0x81,0x47,0xd2,0xcd,0x28,0x07,0xd9,0xcd,0x6f,0x0c,0xf3,0xca,0x51},+ {0x0a,0xe0,0x74,0x76,0x42,0xa7,0x0b,0xa6,0xf3,0x7b,0x7a,0xa1,0x70,0x85,0x0e,0x63,0xcc,0x24,0x33,0xcf,0x3d,0x56,0x58,0x37,0xaa,0xfd,0x83,0x23,0x29,0xaa,0x04,0x55,0xc7,0x54,0xac,0x18,0x9a,0xf9,0x7a,0x73,0x0f,0xb3,0x1c,0xc5,0xdc,0x78,0x33,0x90,0xc7,0x0c,0xe1,0x4c,0x33,0xbc,0x89,0x2b,0x9a,0xe9,0xf8,0x89,0xc1,0x29,0xae,0x12,0xcf,0x01,0x0d,0x1f,0xcb,0xc0,0x9e,0xa9,0xae,0xf7,0x34,0x3a,0xcc,0xef,0xd1,0x0d,0x22,0x4e,0x9c,0xd0,0x21,0x75,0xca,0x55,0xea,0xa5,0xeb,0x58,0xe9,0x4f,0xd1,0x5f},+ {0x2c,0xab,0x45,0x28,0xdf,0x2d,0xdc,0xb5,0x93,0xe9,0x7f,0x0a,0xb1,0x91,0x94,0x06,0x46,0xe3,0x02,0x40,0xd6,0xf3,0xaa,0x4d,0xd1,0x74,0x64,0x58,0x6e,0xf2,0x3f,0x09,0x8e,0xcb,0x93,0xbf,0x5e,0xfe,0x42,0x3c,0x5f,0x56,0xd4,0x36,0x51,0xa8,0xdf,0xbe,0xe8,0x20,0x42,0x88,0x9e,0x85,0xf0,0xe0,0x28,0xd1,0x25,0x07,0x96,0x3f,0xd7,0x7d,0x29,0x98,0x05,0x68,0xfe,0x24,0x0d,0xb1,0xe5,0x23,0xaf,0xdb,0x72,0x06,0x73,0x75,0x29,0xac,0x57,0xb4,0x3a,0x25,0x67,0x13,0xa4,0x70,0xb4,0x86,0xbc,0xbc,0x59,0x2f},+ {0x5f,0x13,0x17,0x99,0x42,0x7d,0x84,0x83,0xd7,0x03,0x7d,0x56,0x1f,0x91,0x1b,0xad,0xd1,0xaa,0x77,0xbe,0xd9,0x48,0x77,0x7e,0x4a,0xaf,0x51,0x2e,0x2e,0xb4,0x58,0x54,0x01,0xc3,0x91,0xb6,0x60,0xd5,0x41,0x70,0x1e,0xe7,0xd7,0xad,0x3f,0x1b,0x20,0x85,0x85,0x55,0x33,0x11,0x63,0xe1,0xc2,0x16,0xb1,0x28,0x08,0x01,0x3d,0x5e,0xa5,0x2a,0x4f,0x44,0x07,0x0c,0xe6,0x92,0x51,0xed,0x10,0x1d,0x42,0x74,0x2d,0x4e,0xc5,0x42,0x64,0xc8,0xb5,0xfd,0x82,0x4c,0x2b,0x35,0x64,0x86,0x76,0x8a,0x4a,0x00,0xe9,0x13},+ {0xdb,0xce,0x2f,0x83,0x45,0x88,0x9d,0x73,0x63,0xf8,0x6b,0xae,0xc9,0xd6,0x38,0xfa,0xf7,0xfe,0x4f,0xb7,0xca,0x0d,0xbc,0x32,0x5e,0xe4,0xbc,0x14,0x88,0x7e,0x93,0x73,0x7f,0x87,0x3b,0x19,0xc9,0x00,0x2e,0xbb,0x6b,0x50,0xdc,0xe0,0x90,0xa8,0xe3,0xec,0x9f,0x64,0xde,0x36,0xc0,0xb7,0xf3,0xec,0x1a,0x9e,0xde,0x98,0x08,0x04,0x46,0x5f,0x8d,0xf4,0x7b,0x29,0x16,0x71,0x03,0xb9,0x34,0x68,0xf0,0xd4,0x22,0x3b,0xd1,0xa9,0xc6,0xbd,0x96,0x46,0x57,0x15,0x97,0xe1,0x35,0xe8,0xd5,0x91,0xe8,0xa4,0xf8,0x2c},+ {0x67,0x0f,0x11,0x07,0x87,0xfd,0x93,0x6d,0x49,0xb5,0x38,0x7c,0xd3,0x09,0x4c,0xdd,0x86,0x6a,0x73,0xc2,0x4c,0x6a,0xb1,0x7c,0x09,0x2a,0x25,0x58,0x6e,0xbd,0x49,0x20,0xa2,0x6b,0xd0,0x17,0x7e,0x48,0xb5,0x2c,0x6b,0x19,0x50,0x39,0x1c,0x38,0xd2,0x24,0x30,0x8a,0x97,0x85,0x81,0x9c,0x65,0xd7,0xf6,0xa4,0xd6,0x91,0x28,0x7f,0x6f,0x7a,0x49,0xef,0x9a,0x6a,0x8d,0xfd,0x09,0x7d,0x0b,0xb9,0x3d,0x5b,0xbe,0x60,0xee,0xf0,0xd4,0xbf,0x9e,0x51,0x2c,0xb5,0x21,0x4c,0x1d,0x94,0x45,0xc5,0xdf,0xaa,0x11,0x60},+ {0x3c,0xf8,0x95,0xcf,0x6d,0x92,0x67,0x5f,0x71,0x90,0x28,0x71,0x61,0x85,0x7e,0x7c,0x5b,0x7a,0x8f,0x99,0xf3,0xe7,0xa1,0xd6,0xe0,0xf9,0x62,0x0b,0x1b,0xcc,0xc5,0x6f,0x90,0xf8,0xcb,0x02,0xc8,0xd0,0xde,0x63,0xaa,0x6a,0xff,0x0d,0xca,0x98,0xd0,0xfb,0x99,0xed,0xb6,0xb9,0xfd,0x0a,0x4d,0x62,0x1e,0x0b,0x34,0x79,0xb7,0x18,0xce,0x69,0xcb,0x79,0x98,0xb2,0x28,0x55,0xef,0xd1,0x92,0x90,0x7e,0xd4,0x3c,0xae,0x1a,0xdd,0x52,0x23,0x9f,0x18,0x42,0x04,0x7e,0x12,0xf1,0x01,0x71,0xe5,0x3a,0x6b,0x59,0x15},+ {0xa2,0x79,0x91,0x3f,0xd2,0x39,0x27,0x46,0xcf,0xdd,0xd6,0x97,0x31,0x12,0x83,0xff,0x8a,0x14,0xf2,0x53,0xb5,0xde,0x07,0x13,0xda,0x4d,0x5f,0x7b,0x68,0x37,0x22,0x0d,0xca,0x24,0x51,0x7e,0x16,0x31,0xff,0x09,0xdf,0x45,0xc7,0xd9,0x8b,0x15,0xe4,0x0b,0xe5,0x56,0xf5,0x7e,0x22,0x7d,0x2b,0x29,0x38,0xd1,0xb6,0xaf,0x41,0xe2,0xa4,0x3a,0xf5,0x05,0x33,0x2a,0xbf,0x38,0xc1,0x2c,0xc3,0x26,0xe9,0xa2,0x8f,0x3f,0x58,0x48,0xeb,0xd2,0x49,0x55,0xa2,0xb1,0x3a,0x08,0x6c,0xa3,0x87,0x46,0x6e,0xaa,0xfc,0x32},+ {0xf5,0x9a,0x7d,0xc5,0x8d,0x6e,0xc5,0x7b,0xf2,0xbd,0xf0,0x9d,0xed,0xd2,0x0b,0x3e,0xa3,0xe4,0xef,0x22,0xde,0x14,0xc0,0xaa,0x5c,0x6a,0xbd,0xfe,0xce,0xe9,0x27,0x46,0xdf,0xcc,0x87,0x27,0x73,0xa4,0x07,0x32,0xf8,0xe3,0x13,0xf2,0x08,0x19,0xe3,0x17,0x4e,0x96,0x0d,0xf6,0xd7,0xec,0xb2,0xd5,0xe9,0x0b,0x60,0xc2,0x36,0x63,0x6f,0x74,0x1c,0x97,0x6c,0xab,0x45,0xf3,0x4a,0x3f,0x1f,0x73,0x43,0x99,0x72,0xeb,0x88,0xe2,0x6d,0x18,0x44,0x03,0x8a,0x6a,0x59,0x33,0x93,0x62,0xd6,0x7e,0x00,0x17,0x49,0x7b},+ {0x64,0xb0,0x84,0xab,0x5c,0xfb,0x85,0x2d,0x14,0xbc,0xf3,0x89,0xd2,0x10,0x78,0x49,0x0c,0xce,0x15,0x7b,0x44,0xdc,0x6a,0x47,0x7b,0xfd,0x44,0xf8,0x76,0xa3,0x2b,0x12,0xdd,0xa2,0x53,0xdd,0x28,0x1b,0x34,0x54,0x3f,0xfc,0x42,0xdf,0x5b,0x90,0x17,0xaa,0xf4,0xf8,0xd2,0x4d,0xd9,0x92,0xf5,0x0f,0x7d,0xd3,0x8c,0xe0,0x0f,0x62,0x03,0x1d,0x54,0xe5,0xb4,0xa2,0xcd,0x32,0x02,0xc2,0x7f,0x18,0x5d,0x11,0x42,0xfd,0xd0,0x9e,0xd9,0x79,0xd4,0x7d,0xbe,0xb4,0xab,0x2e,0x4c,0xec,0x68,0x2b,0xf5,0x0b,0xc7,0x02},+ {0xbb,0x2f,0x0b,0x5d,0x4b,0xec,0x87,0xa2,0xca,0x82,0x48,0x07,0x90,0x57,0x5c,0x41,0x5c,0x81,0xd0,0xc1,0x1e,0xa6,0x44,0xe0,0xe0,0xf5,0x9e,0x40,0x0a,0x4f,0x33,0x26,0xe1,0x72,0x8d,0x45,0xbf,0x32,0xe5,0xac,0xb5,0x3c,0xb7,0x7c,0xe0,0x68,0xe7,0x5b,0xe7,0xbd,0x8b,0xee,0x94,0x7d,0xcf,0x56,0x03,0x3a,0xb4,0xfe,0xe3,0x97,0x06,0x6b,0xc0,0xa3,0x62,0xdf,0x4a,0xf0,0xc8,0xb6,0x5d,0xa4,0x6d,0x07,0xef,0x00,0xf0,0x3e,0xa9,0xd2,0xf0,0x49,0x58,0xb9,0x9c,0x9c,0xae,0x2f,0x1b,0x44,0x43,0x7f,0xc3,0x1c},+ {0x4f,0x32,0xc7,0x5c,0x5a,0x56,0x8f,0x50,0x22,0xa9,0x06,0xe5,0xc0,0xc4,0x61,0xd0,0x19,0xac,0x45,0x5c,0xdb,0xab,0x18,0xfb,0x4a,0x31,0x80,0x03,0xc1,0x09,0x68,0x6c,0xb9,0xae,0xce,0xc9,0xf1,0x56,0x66,0xd7,0x6a,0x65,0xe5,0x18,0xf8,0x15,0x5b,0x1c,0x34,0x23,0x4c,0x84,0x32,0x28,0xe7,0x26,0x38,0x68,0x19,0x2f,0x77,0x6f,0x34,0x3a,0xc8,0x6a,0xda,0xe2,0x12,0x51,0xd5,0xd2,0xed,0x51,0xe8,0xb1,0x31,0x03,0xbd,0xe9,0x62,0x72,0xc6,0x8e,0xdd,0x46,0x07,0x96,0xd0,0xc5,0xf7,0x6e,0x9f,0x1b,0x91,0x05},+ {0xbb,0x0e,0xdf,0xf5,0x83,0x99,0x33,0xc1,0xac,0x4c,0x2c,0x51,0x8f,0x75,0xf3,0xc0,0xe1,0x98,0xb3,0x0b,0x0a,0x13,0xf1,0x2c,0x62,0x0c,0x27,0xaa,0xf9,0xec,0x3c,0x6b,0xef,0xea,0x2e,0x51,0xf3,0xac,0x49,0x53,0x49,0xcb,0xc1,0x1c,0xd3,0x41,0xc1,0x20,0x8d,0x68,0x9a,0xa9,0x07,0x0c,0x18,0x24,0x17,0x2d,0x4b,0xc6,0xd1,0xf9,0x5e,0x55,0x08,0xbd,0x73,0x3b,0xba,0x70,0xa7,0x36,0x0c,0xbf,0xaf,0xa3,0x08,0xef,0x4a,0x62,0xf2,0x46,0x09,0xb4,0x98,0xff,0x37,0x57,0x9d,0x74,0x81,0x33,0xe1,0x4d,0x5f,0x67},+ {0xfc,0x82,0x17,0x6b,0x03,0x52,0x2c,0x0e,0xb4,0x83,0xad,0x6c,0x81,0x6c,0x81,0x64,0x3e,0x07,0x64,0x69,0xd9,0xbd,0xdc,0xd0,0x20,0xc5,0x64,0x01,0xf7,0x9d,0xd9,0x13,0x1d,0xb3,0xda,0x3b,0xd9,0xf6,0x2f,0xa1,0xfe,0x2d,0x65,0x9d,0x0f,0xd8,0x25,0x07,0x87,0x94,0xbe,0x9a,0xf3,0x4f,0x9c,0x01,0x43,0x3c,0xcd,0x82,0xb8,0x50,0xf4,0x60,0xca,0xc0,0xe5,0x21,0xc3,0x5e,0x4b,0x01,0xa2,0xbf,0x19,0xd7,0xc9,0x69,0xcb,0x4f,0xa0,0x23,0x00,0x75,0x18,0x1c,0x5f,0x4e,0x80,0xac,0xed,0x55,0x9e,0xde,0x06,0x1c},+ {0xe2,0xc4,0x3e,0xa3,0xd6,0x7a,0x0f,0x99,0x8e,0xe0,0x2e,0xbe,0x38,0xf9,0x08,0x66,0x15,0x45,0x28,0x63,0xc5,0x43,0xa1,0x9c,0x0d,0xb6,0x2d,0xec,0x1f,0x8a,0xf3,0x4c,0xaa,0x69,0x6d,0xff,0x40,0x2b,0xd5,0xff,0xbb,0x49,0x40,0xdc,0x18,0x0b,0x53,0x34,0x97,0x98,0x4d,0xa3,0x2f,0x5c,0x4a,0x5e,0x2d,0xba,0x32,0x7d,0x8e,0x6f,0x09,0x78,0xe7,0x5c,0xfa,0x0d,0x65,0xaa,0xaa,0xa0,0x8c,0x47,0xb5,0x48,0x2a,0x9e,0xc4,0xf9,0x5b,0x72,0x03,0x70,0x7d,0xcc,0x09,0x4f,0xbe,0x1a,0x09,0x26,0x3a,0xad,0x3c,0x37},+ {0x7c,0xf5,0xc9,0x82,0x4d,0x63,0x94,0xb2,0x36,0x45,0x93,0x24,0xe1,0xfd,0xcb,0x1f,0x5a,0xdb,0x8c,0x41,0xb3,0x4d,0x9c,0x9e,0xfc,0x19,0x44,0x45,0xd9,0xf3,0x40,0x00,0xad,0xbb,0xdd,0x89,0xfb,0xa8,0xbe,0xf1,0xcb,0xae,0xae,0x61,0xbc,0x2c,0xcb,0x3b,0x9d,0x8d,0x9b,0x1f,0xbb,0xa7,0x58,0x8f,0x86,0xa6,0x12,0x51,0xda,0x7e,0x54,0x21,0xd3,0x86,0x59,0xfd,0x39,0xe9,0xfd,0xde,0x0c,0x38,0x0a,0x51,0x89,0x2c,0x27,0xf4,0xb9,0x19,0x31,0xbb,0x07,0xa4,0x2b,0xb7,0xf4,0x4d,0x25,0x4a,0x33,0x0a,0x55,0x63},+ {0x37,0xcf,0x69,0xb5,0xed,0xd6,0x07,0x65,0xe1,0x2e,0xa5,0x0c,0xb0,0x29,0x84,0x17,0x5d,0xd6,0x6b,0xeb,0x90,0x00,0x7c,0xea,0x51,0x8f,0xf7,0xda,0xc7,0x62,0xea,0x3e,0x49,0x7b,0x54,0x72,0x45,0x58,0xba,0x9b,0xe0,0x08,0xc4,0xe2,0xfa,0xc6,0x05,0xf3,0x8d,0xf1,0x34,0xc7,0x69,0xfa,0xe8,0x60,0x7a,0x76,0x7d,0xaa,0xaf,0x2b,0xa9,0x39,0x4e,0x27,0x93,0xe6,0x13,0xc7,0x24,0x9d,0x75,0xd3,0xdb,0x68,0x77,0x85,0x63,0x5f,0x9a,0xb3,0x8a,0xeb,0x60,0x55,0x52,0x70,0xcd,0xc4,0xc9,0x65,0x06,0x6a,0x43,0x68},+ {0x27,0x3f,0x2f,0x20,0xe8,0x35,0x02,0xbc,0xb0,0x75,0xf9,0x64,0xe2,0x00,0x5c,0xc7,0x16,0x24,0x8c,0xa3,0xd5,0xe9,0xa4,0x91,0xf9,0x89,0xb7,0x8a,0xf6,0xe7,0xb6,0x17,0x7c,0x10,0x20,0xe8,0x17,0xd3,0x56,0x1e,0x65,0xe9,0x0a,0x84,0x44,0x68,0x26,0xc5,0x7a,0xfc,0x0f,0x32,0xc6,0xa1,0xe0,0xc1,0x72,0x14,0x61,0x91,0x9c,0x66,0x73,0x53,0x57,0x52,0x0e,0x9a,0xab,0x14,0x28,0x5d,0xfc,0xb3,0xca,0xc9,0x84,0x20,0x8f,0x90,0xca,0x1e,0x2d,0x5b,0x88,0xf5,0xca,0xaf,0x11,0x7d,0xf8,0x78,0xa6,0xb5,0xb4,0x1c},+ {0x6c,0xfc,0x4a,0x39,0x6b,0xc0,0x64,0xb6,0xb1,0x5f,0xda,0x98,0x24,0xde,0x88,0x0c,0x34,0xd8,0xca,0x4b,0x16,0x03,0x8d,0x4f,0xa2,0x34,0x74,0xde,0x78,0xca,0x0b,0x33,0xe7,0x07,0xa0,0xa2,0x62,0xaa,0x74,0x6b,0xb1,0xc7,0x71,0xf0,0xb0,0xe0,0x11,0xf3,0x23,0xe2,0x0b,0x00,0x38,0xe4,0x07,0x57,0xac,0x6e,0xef,0x82,0x2d,0xfd,0xc0,0x2d,0x4e,0x74,0x19,0x11,0x84,0xff,0x2e,0x98,0x24,0x47,0x07,0x2b,0x96,0x5e,0x69,0xf9,0xfb,0x53,0xc9,0xbf,0x4f,0xc1,0x8a,0xc5,0xf5,0x1c,0x9f,0x36,0x1b,0xbe,0x31,0x3c},+ {0xee,0x8a,0x94,0x08,0x4d,0x86,0xf4,0xb0,0x6f,0x1c,0xba,0x91,0xee,0x19,0xdc,0x07,0x58,0xa1,0xac,0xa6,0xae,0xcd,0x75,0x79,0xbb,0xd4,0x62,0x42,0x13,0x61,0x0b,0x33,0x72,0x42,0xcb,0xf9,0x93,0xbc,0x68,0xc1,0x98,0xdb,0xce,0xc7,0x1f,0x71,0xb8,0xae,0x7a,0x8d,0xac,0x34,0xaa,0x52,0x0e,0x7f,0xbb,0x55,0x7d,0x7e,0x09,0xc1,0xce,0x41,0x8a,0x80,0x6d,0xa2,0xd7,0x19,0x96,0xf7,0x6d,0x15,0x9e,0x1d,0x9e,0xd4,0x1f,0xbb,0x27,0xdf,0xa1,0xdb,0x6c,0xc3,0xd7,0x73,0x7d,0x77,0x28,0x1f,0xd9,0x4c,0xb4,0x26},+ {0x75,0x74,0x38,0x8f,0x47,0x48,0xf0,0x51,0x3c,0xcb,0xbe,0x9c,0xf4,0xbc,0x5d,0xb2,0x55,0x20,0x9f,0xd9,0x44,0x12,0xab,0x9a,0xd6,0xa5,0x10,0x1c,0x6c,0x9e,0x70,0x2c,0x83,0x03,0x73,0x62,0x93,0xf2,0xb7,0xe1,0x2c,0x8a,0xca,0xeb,0xff,0x79,0x52,0x4b,0x14,0x13,0xd4,0xbf,0x8a,0x77,0xfc,0xda,0x0f,0x61,0x72,0x9c,0x14,0x10,0xeb,0x7d,0x7a,0xee,0x66,0x87,0x6a,0xaf,0x62,0xcb,0x0e,0xcd,0x53,0x55,0x04,0xec,0xcb,0x66,0xb5,0xe4,0x0b,0x0f,0x38,0x01,0x80,0x58,0xea,0xe2,0x2c,0xf6,0x9f,0x8e,0xe6,0x08},+ {0xad,0x30,0xc1,0x4b,0x0a,0x50,0xad,0x34,0x9c,0xd4,0x0b,0x3d,0x49,0xdb,0x38,0x8d,0xbe,0x89,0x0a,0x50,0x98,0x3d,0x5c,0xa2,0x09,0x3b,0xba,0xee,0x87,0x3f,0x1f,0x2f,0xf9,0xf2,0xb8,0x0a,0xd5,0x09,0x2d,0x2f,0xdf,0x23,0x59,0xc5,0x8d,0x21,0xb9,0xac,0xb9,0x6c,0x76,0x73,0x26,0x34,0x8f,0x4a,0xf5,0x19,0xf7,0x38,0xd7,0x3b,0xb1,0x4c,0x4a,0xb6,0x15,0xe5,0x75,0x8c,0x84,0xf7,0x38,0x90,0x4a,0xdb,0xba,0x01,0x95,0xa5,0x50,0x1b,0x75,0x3f,0x3f,0x31,0x0d,0xc2,0xe8,0x2e,0xae,0xc0,0x53,0xe3,0xa1,0x19},+ {0xc3,0x05,0xfa,0xba,0x60,0x75,0x1c,0x7d,0x61,0x5e,0xe5,0xc6,0xa0,0xa0,0xe1,0xb3,0x73,0x64,0xd6,0xc0,0x18,0x97,0x52,0xe3,0x86,0x34,0x0c,0xc2,0x11,0x6b,0x54,0x41,0xbd,0xbd,0x96,0xd5,0xcd,0x72,0x21,0xb4,0x40,0xfc,0xee,0x98,0x43,0x45,0xe0,0x93,0xb5,0x09,0x41,0xb4,0x47,0x53,0xb1,0x9f,0x34,0xae,0x66,0x02,0x99,0xd3,0x6b,0x73,0xb4,0xb3,0x34,0x93,0x50,0x2d,0x53,0x85,0x73,0x65,0x81,0x60,0x4b,0x11,0xfd,0x46,0x75,0x83,0x5c,0x42,0x30,0x5f,0x5f,0xcc,0x5c,0xab,0x7f,0xb8,0xa2,0x95,0x22,0x41},+ {0xe9,0xd6,0x7e,0xf5,0x88,0x9b,0xc9,0x19,0x25,0xc8,0xf8,0x6d,0x26,0xcb,0x93,0x53,0x73,0xd2,0x0a,0xb3,0x13,0x32,0xee,0x5c,0x34,0x2e,0x2d,0xb5,0xeb,0x53,0xe1,0x14,0xc6,0xea,0x93,0xe2,0x61,0x52,0x65,0x2e,0xdb,0xac,0x33,0x21,0x03,0x92,0x5a,0x84,0x6b,0x99,0x00,0x79,0xcb,0x75,0x09,0x46,0x80,0xdd,0x5a,0x19,0x8d,0xbb,0x60,0x07,0x8a,0x81,0xe6,0xcd,0x17,0x1a,0x3e,0x41,0x84,0xa0,0x69,0xed,0xa9,0x6d,0x15,0x57,0xb1,0xcc,0xca,0x46,0x8f,0x26,0xbf,0x2c,0xf2,0xc5,0x3a,0xc3,0x9b,0xbe,0x34,0x6b},+ {0xb2,0xc0,0x78,0x3a,0x64,0x2f,0xdf,0xf3,0x7c,0x02,0x2e,0xf2,0x1e,0x97,0x3e,0x4c,0xa3,0xb5,0xc1,0x49,0x5e,0x1c,0x7d,0xec,0x2d,0xdd,0x22,0x09,0x8f,0xc1,0x12,0x20,0xd3,0xf2,0x71,0x65,0x65,0x69,0xfc,0x11,0x7a,0x73,0x0e,0x53,0x45,0xe8,0xc9,0xc6,0x35,0x50,0xfe,0xd4,0xa2,0xe7,0x3a,0xe3,0x0b,0xd3,0x6d,0x2e,0xb6,0xc7,0xb9,0x01,0x29,0x9d,0xc8,0x5a,0xe5,0x55,0x0b,0x88,0x63,0xa7,0xa0,0x45,0x1f,0x24,0x83,0x14,0x1f,0x6c,0xe7,0xc2,0xdf,0xef,0x36,0x3d,0xe8,0xad,0x4b,0x4e,0x78,0x5b,0xaf,0x08},+ {0x33,0x25,0x1f,0x88,0xdc,0x99,0x34,0x28,0xb6,0x23,0x93,0x77,0xda,0x25,0x05,0x9d,0xf4,0x41,0x34,0x67,0xfb,0xdd,0x7a,0x89,0x8d,0x16,0x3a,0x16,0x71,0x9d,0xb7,0x32,0x4b,0x2c,0xcc,0x89,0xd2,0x14,0x73,0xe2,0x8d,0x17,0x87,0xa2,0x11,0xbd,0xe4,0x4b,0xce,0x64,0x33,0xfa,0xd6,0x28,0xd5,0x18,0x6e,0x82,0xd9,0xaf,0xd5,0xc1,0x23,0x64,0x6a,0xb3,0xfc,0xed,0xd9,0xf8,0x85,0xcc,0xf9,0xe5,0x46,0x37,0x8f,0xc2,0xbc,0x22,0xcd,0xd3,0xe5,0xf9,0x38,0xe3,0x9d,0xe4,0xcc,0x2d,0x3e,0xc1,0xfb,0x5e,0x0a,0x48},+ {0x71,0x20,0x62,0x01,0x0b,0xe7,0x51,0x0b,0xc5,0xaf,0x1d,0x8b,0xcf,0x05,0xb5,0x06,0xcd,0xab,0x5a,0xef,0x61,0xb0,0x6b,0x2c,0x31,0xbf,0xb7,0x0c,0x60,0x27,0xaa,0x47,0x1f,0x22,0xce,0x42,0xe4,0x4c,0x61,0xb6,0x28,0x39,0x05,0x4c,0xcc,0x9d,0x19,0x6e,0x03,0xbe,0x1c,0xdc,0xa4,0xb4,0x3f,0x66,0x06,0x8e,0x1c,0x69,0x47,0x1d,0xb3,0x24,0xc3,0xf8,0x15,0xc0,0xed,0x1e,0x54,0x2a,0x7c,0x3f,0x69,0x7c,0x7e,0xfe,0xa4,0x11,0xd6,0x78,0xa2,0x4e,0x13,0x66,0xaf,0xf0,0x94,0xa0,0xdd,0x14,0x5d,0x58,0x5b,0x54},+ {0x0f,0x3a,0xd4,0xa0,0x5e,0x27,0xbf,0x67,0xbe,0xee,0x9b,0x08,0x34,0x8e,0xe6,0xad,0x2e,0xe7,0x79,0xd4,0x4c,0x13,0x89,0x42,0x54,0x54,0xba,0x32,0xc3,0xf9,0x62,0x0f,0xe1,0x21,0xb3,0xe3,0xd0,0xe4,0x04,0x62,0x95,0x1e,0xff,0x28,0x7a,0x63,0xaa,0x3b,0x9e,0xbd,0x99,0x5b,0xfd,0xcf,0x0c,0x0b,0x71,0xd0,0xc8,0x64,0x3e,0xdc,0x22,0x4d,0x39,0x5f,0x3b,0xd6,0x89,0x65,0xb4,0xfc,0x61,0xcf,0xcb,0x57,0x3f,0x6a,0xae,0x5c,0x05,0xfa,0x3a,0x95,0xd2,0xc2,0xba,0xfe,0x36,0x14,0x37,0x36,0x1a,0xa0,0x0f,0x1c},+ {0xff,0x3d,0x94,0x22,0xb6,0x04,0xc6,0xd2,0xa0,0xb3,0xcf,0x44,0xce,0xbe,0x8c,0xbc,0x78,0x86,0x80,0x97,0xf3,0x4f,0x25,0x5d,0xbf,0xa6,0x1c,0x3b,0x4f,0x61,0xa3,0x0f,0x50,0x6a,0x93,0x8c,0x0e,0x2b,0x08,0x69,0xb6,0xc5,0xda,0xc1,0x35,0xa0,0xc9,0xf9,0x34,0xb6,0xdf,0xc4,0x54,0x3e,0xb7,0x6f,0x40,0xc1,0x2b,0x1d,0x9b,0x41,0x05,0x40,0xf0,0x82,0xbe,0xb9,0xbd,0xfe,0x03,0xa0,0x90,0xac,0x44,0x3a,0xaf,0xc1,0x89,0x20,0x8e,0xfa,0x54,0x19,0x91,0x9f,0x49,0xf8,0x42,0xab,0x40,0xef,0x8a,0x21,0xba,0x1f},+ {0x3e,0xf5,0xc8,0xfa,0x48,0x94,0x54,0xab,0x41,0x37,0xa6,0x7b,0x9a,0xe8,0xf6,0x81,0x01,0x5e,0x2b,0x6c,0x7d,0x6c,0xfd,0x74,0x42,0x6e,0xc8,0xa8,0xca,0x3a,0x2e,0x39,0x94,0x01,0x7b,0x3e,0x04,0x57,0x3e,0x4f,0x7f,0xaf,0xda,0x08,0xee,0x3e,0x1d,0xa8,0xf1,0xde,0xdc,0x99,0xab,0xc6,0x39,0xc8,0xd5,0x61,0x77,0xff,0x13,0x5d,0x53,0x6c,0xaf,0x35,0x8a,0x3e,0xe9,0x34,0xbd,0x4c,0x16,0xe8,0x87,0x58,0x44,0x81,0x07,0x2e,0xab,0xb0,0x9a,0xf2,0x76,0x9c,0x31,0x19,0x3b,0xc1,0x0a,0xd5,0xe4,0x7f,0xe1,0x25},+ {0x76,0xf6,0x04,0x1e,0xd7,0x9b,0x28,0x0a,0x95,0x0f,0x42,0xd6,0x52,0x1c,0x8e,0x20,0xab,0x1f,0x69,0x34,0xb0,0xd8,0x86,0x51,0x51,0xb3,0x9f,0x2a,0x44,0x51,0x57,0x25,0xa7,0x21,0xf1,0x76,0xf5,0x7f,0x5f,0x91,0xe3,0x87,0xcd,0x2f,0x27,0x32,0x4a,0xc3,0x26,0xe5,0x1b,0x4d,0xde,0x2f,0xba,0xcc,0x9b,0x89,0x69,0x89,0x8f,0x82,0xba,0x6b,0x01,0x39,0xfe,0x90,0x66,0xbc,0xd1,0xe2,0xd5,0x7a,0x99,0xa0,0x18,0x4a,0xb5,0x4c,0xd4,0x60,0x84,0xaf,0x14,0x69,0x1d,0x97,0xe4,0x7b,0x6b,0x7f,0x4f,0x50,0x9d,0x55},+ {0xd5,0x54,0xeb,0xb3,0x78,0x83,0x73,0xa7,0x7c,0x3c,0x55,0xa5,0x66,0xd3,0x69,0x1d,0xba,0x00,0x28,0xf9,0x62,0xcf,0x26,0x0a,0x17,0x32,0x7e,0x80,0xd5,0x12,0xab,0x01,0xfd,0x66,0xd2,0xf6,0xe7,0x91,0x48,0x9c,0x1b,0x78,0x07,0x03,0x9b,0xa1,0x44,0x07,0x3b,0xe2,0x61,0x60,0x1d,0x8f,0x38,0x88,0x0e,0xd5,0x4b,0x35,0xa3,0xa6,0x3e,0x12,0x96,0x2d,0xe3,0x41,0x90,0x18,0x8d,0x11,0x48,0x58,0x31,0xd8,0xc2,0xe3,0xed,0xb9,0xd9,0x45,0x32,0xd8,0x71,0x42,0xab,0x1e,0x54,0xa1,0x18,0xc9,0xe2,0x61,0x39,0x4a},+ {0xa0,0xbb,0xe6,0xf8,0xe0,0x3b,0xdc,0x71,0x0a,0xe3,0xff,0x7e,0x34,0xf8,0xce,0xd6,0x6a,0x47,0x3a,0xe1,0x5f,0x42,0x92,0xa9,0x63,0xb7,0x1d,0xfb,0xe3,0xbc,0xd6,0x2c,0x1e,0x3f,0x23,0xf3,0x44,0xd6,0x27,0x03,0x16,0xf0,0xfc,0x34,0x0e,0x26,0x9a,0x49,0x79,0xb9,0xda,0xf2,0x16,0xa7,0xb5,0x83,0x1f,0x11,0xd4,0x9b,0xad,0xee,0xac,0x68,0x10,0xc2,0xd7,0xf3,0x0e,0xc9,0xb4,0x38,0x0c,0x04,0xad,0xb7,0x24,0x6e,0x8e,0x30,0x23,0x3e,0xe7,0xb7,0xf1,0xd9,0x60,0x38,0x97,0xf5,0x08,0xb5,0xd5,0x60,0x57,0x59},+ {0x97,0x63,0xaa,0x04,0xe1,0xbf,0x29,0x61,0xcb,0xfc,0xa7,0xa4,0x08,0x00,0x96,0x8f,0x58,0x94,0x90,0x7d,0x89,0xc0,0x8b,0x3f,0xa9,0x91,0xb2,0xdc,0x3e,0xa4,0x9f,0x70,0x90,0x27,0x02,0xfd,0xeb,0xcb,0x2a,0x88,0x60,0x57,0x11,0xc4,0x05,0x33,0xaf,0x89,0xf4,0x73,0x34,0x7d,0xe3,0x92,0xf4,0x65,0x2b,0x5a,0x51,0x54,0xdf,0xc5,0xb2,0x2c,0xca,0x2a,0xfd,0x63,0x8c,0x5d,0x0a,0xeb,0xff,0x4e,0x69,0x2e,0x66,0xc1,0x2b,0xd2,0x3a,0xb0,0xcb,0xf8,0x6e,0xf3,0x23,0x27,0x1f,0x13,0xc8,0xf0,0xec,0x29,0xf0,0x70},+ {0x33,0x3e,0xed,0x2e,0xb3,0x07,0x13,0x46,0xe7,0x81,0x55,0xa4,0x33,0x2f,0x04,0xae,0x66,0x03,0x5f,0x19,0xd3,0x49,0x44,0xc9,0x58,0x48,0x31,0x6c,0x8a,0x5d,0x7d,0x0b,0xb9,0xb0,0x10,0x5e,0xaa,0xaf,0x6a,0x2a,0xa9,0x1a,0x04,0xef,0x70,0xa3,0xf0,0x78,0x1f,0xd6,0x3a,0xaa,0x77,0xfb,0x3e,0x77,0xe1,0xd9,0x4b,0xa7,0xa2,0xa5,0xec,0x44,0x43,0xd5,0x95,0x7b,0x32,0x48,0xd4,0x25,0x1d,0x0f,0x34,0xa3,0x00,0x83,0xd3,0x70,0x2b,0xc5,0xe1,0x60,0x1c,0x53,0x1c,0xde,0xe4,0xe9,0x7d,0x2c,0x51,0x24,0x22,0x27},+ {0x2e,0x34,0xc5,0x49,0xaf,0x92,0xbc,0x1a,0xd0,0xfa,0xe6,0xb2,0x11,0xd8,0xee,0xff,0x29,0x4e,0xc8,0xfc,0x8d,0x8c,0xa2,0xef,0x43,0xc5,0x4c,0xa4,0x18,0xdf,0xb5,0x11,0xfc,0x75,0xa9,0x42,0x8a,0xbb,0x7b,0xbf,0x58,0xa3,0xad,0x96,0x77,0x39,0x5c,0x8c,0x48,0xaa,0xed,0xcd,0x6f,0xc7,0x7f,0xe2,0xa6,0x20,0xbc,0xf6,0xd7,0x5f,0x73,0x19,0x66,0x42,0xc8,0x42,0xd0,0x90,0xab,0xe3,0x7e,0x54,0x19,0x7f,0x0f,0x8e,0x84,0xeb,0xb9,0x97,0xa4,0x65,0xd0,0xa1,0x03,0x25,0x5f,0x89,0xdf,0x91,0x11,0x91,0xef,0x0f}+};
+ cbits/ed25519/ed25519-donna-batchverify.h view
@@ -0,0 +1,275 @@+/*+ Ed25519 batch verification+*/++#define max_batch_size 64+#define heap_batch_size ((max_batch_size * 2) + 1)++/* which limb is the 128th bit in? */+static const size_t limb128bits = (128 + bignum256modm_bits_per_limb - 1) / bignum256modm_bits_per_limb;++typedef size_t heap_index_t;++typedef struct batch_heap_t {+ unsigned char r[heap_batch_size][16]; /* 128 bit random values */+ ge25519 points[heap_batch_size];+ bignum256modm scalars[heap_batch_size];+ heap_index_t heap[heap_batch_size];+ size_t size;+} batch_heap;++/* swap two values in the heap */+static void+heap_swap(heap_index_t *heap, size_t a, size_t b) {+ heap_index_t temp;+ temp = heap[a];+ heap[a] = heap[b];+ heap[b] = temp;+}++/* add the scalar at the end of the list to the heap */+static void+heap_insert_next(batch_heap *heap) {+ size_t node = heap->size, parent;+ heap_index_t *pheap = heap->heap;+ bignum256modm *scalars = heap->scalars;++ /* insert at the bottom */+ pheap[node] = (heap_index_t)node;++ /* sift node up to its sorted spot */+ parent = (node - 1) / 2;+ while (node && lt256_modm_batch(scalars[pheap[parent]], scalars[pheap[node]], bignum256modm_limb_size - 1)) {+ heap_swap(pheap, parent, node);+ node = parent;+ parent = (node - 1) / 2;+ }+ heap->size++;+}++/* update the heap when the root element is updated */+static void+heap_updated_root(batch_heap *heap, size_t limbsize) {+ size_t node, parent, childr, childl;+ heap_index_t *pheap = heap->heap;+ bignum256modm *scalars = heap->scalars;++ /* sift root to the bottom */+ parent = 0;+ node = 1;+ childl = 1;+ childr = 2;+ while ((childr < heap->size)) {+ node = lt256_modm_batch(scalars[pheap[childl]], scalars[pheap[childr]], limbsize) ? childr : childl;+ heap_swap(pheap, parent, node);+ parent = node;+ childl = (parent * 2) + 1;+ childr = childl + 1;+ }++ /* sift root back up to its sorted spot */+ parent = (node - 1) / 2;+ while (node && lte256_modm_batch(scalars[pheap[parent]], scalars[pheap[node]], limbsize)) {+ heap_swap(pheap, parent, node);+ node = parent;+ parent = (node - 1) / 2;+ }+}++/* build the heap with count elements, count must be >= 3 */+static void+heap_build(batch_heap *heap, size_t count) {+ heap->heap[0] = 0;+ heap->size = 0;+ while (heap->size < count)+ heap_insert_next(heap);+}++/* extend the heap to contain new_count elements */+static void+heap_extend(batch_heap *heap, size_t new_count) {+ while (heap->size < new_count)+ heap_insert_next(heap);+}++/* get the top 2 elements of the heap */+static void+heap_get_top2(batch_heap *heap, heap_index_t *max1, heap_index_t *max2, size_t limbsize) {+ heap_index_t h0 = heap->heap[0], h1 = heap->heap[1], h2 = heap->heap[2];+ if (lt256_modm_batch(heap->scalars[h1], heap->scalars[h2], limbsize))+ h1 = h2;+ *max1 = h0;+ *max2 = h1;+}++/* */+static void+ge25519_multi_scalarmult_vartime_final(ge25519 *r, ge25519 *point, bignum256modm scalar) {+ const bignum256modm_element_t topbit = ((bignum256modm_element_t)1 << (bignum256modm_bits_per_limb - 1));+ size_t limb = limb128bits;+ bignum256modm_element_t flag;++ if (isone256_modm_batch(scalar)) {+ /* this will happen most of the time after bos-carter */+ *r = *point;+ return;+ } else if (iszero256_modm_batch(scalar)) {+ /* this will only happen if all scalars == 0 */+ memset(r, 0, sizeof(*r));+ r->y[0] = 1;+ r->z[0] = 1;+ return;+ }++ *r = *point;++ /* find the limb where first bit is set */+ while (!scalar[limb])+ limb--;++ /* find the first bit */+ flag = topbit;+ while ((scalar[limb] & flag) == 0)+ flag >>= 1;++ /* exponentiate */+ for (;;) {+ ge25519_double(r, r);+ if (scalar[limb] & flag)+ ge25519_add(r, r, point);++ flag >>= 1;+ if (!flag) {+ if (!limb--)+ break;+ flag = topbit;+ }+ }+}++/* count must be >= 5 */+static void+ge25519_multi_scalarmult_vartime(ge25519 *r, batch_heap *heap, size_t count) {+ heap_index_t max1, max2;++ /* start with the full limb size */+ size_t limbsize = bignum256modm_limb_size - 1;++ /* whether the heap has been extended to include the 128 bit scalars */+ int extended = 0;++ /* grab an odd number of scalars to build the heap, unknown limb sizes */+ heap_build(heap, ((count + 1) / 2) | 1);++ for (;;) {+ heap_get_top2(heap, &max1, &max2, limbsize);++ /* only one scalar remaining, we're done */+ if (iszero256_modm_batch(heap->scalars[max2]))+ break;++ /* exhausted another limb? */+ if (!heap->scalars[max1][limbsize])+ limbsize -= 1;++ /* can we extend to the 128 bit scalars? */+ if (!extended && isatmost128bits256_modm_batch(heap->scalars[max1])) {+ heap_extend(heap, count);+ heap_get_top2(heap, &max1, &max2, limbsize);+ extended = 1;+ }++ sub256_modm_batch(heap->scalars[max1], heap->scalars[max1], heap->scalars[max2], limbsize);+ ge25519_add(&heap->points[max2], &heap->points[max2], &heap->points[max1]);+ heap_updated_root(heap, limbsize);+ }++ ge25519_multi_scalarmult_vartime_final(r, &heap->points[max1], heap->scalars[max1]);+}++/* not actually used for anything other than testing */+unsigned char batch_point_buffer[3][32];++static int+ge25519_is_neutral_vartime(const ge25519 *p) {+ static const unsigned char zero[32] = {0};+ unsigned char point_buffer[3][32];+ curve25519_contract(point_buffer[0], p->x);+ curve25519_contract(point_buffer[1], p->y);+ curve25519_contract(point_buffer[2], p->z);+ memcpy(batch_point_buffer[1], point_buffer[1], 32);+ return (memcmp(point_buffer[0], zero, 32) == 0) && (memcmp(point_buffer[1], point_buffer[2], 32) == 0);+}++int+ED25519_FN(ed25519_sign_open_batch) (const unsigned char **m, size_t *mlen, const unsigned char **pk, const unsigned char **RS, size_t num, int *valid) {+ batch_heap ALIGN(16) batch;+ ge25519 ALIGN(16) p;+ bignum256modm *r_scalars;+ size_t i, batchsize;+ unsigned char hram[64];+ int ret = 0;++ for (i = 0; i < num; i++)+ valid[i] = 1;++ while (num > 3) {+ batchsize = (num > max_batch_size) ? max_batch_size : num;++ /* generate r (scalars[batchsize+1]..scalars[2*batchsize] */+ ED25519_FN(ed25519_randombytes_unsafe) (batch.r, batchsize * 16);+ r_scalars = &batch.scalars[batchsize + 1];+ for (i = 0; i < batchsize; i++)+ expand256_modm(r_scalars[i], batch.r[i], 16);++ /* compute scalars[0] = ((r1s1 + r2s2 + ...)) */+ for (i = 0; i < batchsize; i++) {+ expand256_modm(batch.scalars[i], RS[i] + 32, 32);+ mul256_modm(batch.scalars[i], batch.scalars[i], r_scalars[i]);+ }+ for (i = 1; i < batchsize; i++)+ add256_modm(batch.scalars[0], batch.scalars[0], batch.scalars[i]);++ /* compute scalars[1]..scalars[batchsize] as r[i]*H(R[i],A[i],m[i]) */+ for (i = 0; i < batchsize; i++) {+ ed25519_hram(hram, RS[i], pk[i], m[i], mlen[i]);+ expand256_modm(batch.scalars[i+1], hram, 64);+ mul256_modm(batch.scalars[i+1], batch.scalars[i+1], r_scalars[i]);+ }++ /* compute points */+ batch.points[0] = ge25519_basepoint;+ for (i = 0; i < batchsize; i++)+ if (!ge25519_unpack_negative_vartime(&batch.points[i+1], pk[i]))+ goto fallback;+ for (i = 0; i < batchsize; i++)+ if (!ge25519_unpack_negative_vartime(&batch.points[batchsize+i+1], RS[i]))+ goto fallback;++ ge25519_multi_scalarmult_vartime(&p, &batch, (batchsize * 2) + 1);+ if (!ge25519_is_neutral_vartime(&p)) {+ ret |= 2;++ fallback:+ for (i = 0; i < batchsize; i++) {+ valid[i] = ED25519_FN(ed25519_sign_open) (m[i], mlen[i], pk[i], RS[i]) ? 0 : 1;+ ret |= (valid[i] ^ 1);+ }+ }++ m += batchsize;+ mlen += batchsize;+ pk += batchsize;+ RS += batchsize;+ num -= batchsize;+ valid += batchsize;+ }++ for (i = 0; i < num; i++) {+ valid[i] = ED25519_FN(ed25519_sign_open) (m[i], mlen[i], pk[i], RS[i]) ? 0 : 1;+ ret |= (valid[i] ^ 1);+ }++ return ret;+}+
+ cbits/ed25519/ed25519-donna-impl-base.h view
@@ -0,0 +1,364 @@+/*+ conversions+*/++DONNA_INLINE static void+ge25519_p1p1_to_partial(ge25519 *r, const ge25519_p1p1 *p) {+ curve25519_mul(r->x, p->x, p->t);+ curve25519_mul(r->y, p->y, p->z);+ curve25519_mul(r->z, p->z, p->t); +}++DONNA_INLINE static void+ge25519_p1p1_to_full(ge25519 *r, const ge25519_p1p1 *p) {+ curve25519_mul(r->x, p->x, p->t);+ curve25519_mul(r->y, p->y, p->z);+ curve25519_mul(r->z, p->z, p->t); + curve25519_mul(r->t, p->x, p->y); +}++static void+ge25519_full_to_pniels(ge25519_pniels *p, const ge25519 *r) {+ curve25519_sub(p->ysubx, r->y, r->x);+ curve25519_add(p->xaddy, r->y, r->x);+ curve25519_copy(p->z, r->z);+ curve25519_mul(p->t2d, r->t, ge25519_ec2d);+}++/*+ adding & doubling+*/++static void+ge25519_add_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519 *q) {+ bignum25519 a,b,c,d,t,u;++ curve25519_sub(a, p->y, p->x);+ curve25519_add(b, p->y, p->x);+ curve25519_sub(t, q->y, q->x);+ curve25519_add(u, q->y, q->x);+ curve25519_mul(a, a, t);+ curve25519_mul(b, b, u);+ curve25519_mul(c, p->t, q->t);+ curve25519_mul(c, c, ge25519_ec2d);+ curve25519_mul(d, p->z, q->z);+ curve25519_add(d, d, d);+ curve25519_sub(r->x, b, a);+ curve25519_add(r->y, b, a);+ curve25519_add_after_basic(r->z, d, c);+ curve25519_sub_after_basic(r->t, d, c);+}+++static void+ge25519_double_p1p1(ge25519_p1p1 *r, const ge25519 *p) {+ bignum25519 a,b,c;++ curve25519_square(a, p->x);+ curve25519_square(b, p->y);+ curve25519_square(c, p->z);+ curve25519_add_reduce(c, c, c);+ curve25519_add(r->x, p->x, p->y);+ curve25519_square(r->x, r->x);+ curve25519_add(r->y, b, a);+ curve25519_sub(r->z, b, a);+ curve25519_sub_after_basic(r->x, r->x, r->y);+ curve25519_sub_after_basic(r->t, c, r->z);+}++static void+ge25519_nielsadd2_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519_niels *q, unsigned char signbit) {+ const bignum25519 *qb = (const bignum25519 *)q;+ bignum25519 *rb = (bignum25519 *)r;+ bignum25519 a,b,c;++ curve25519_sub(a, p->y, p->x);+ curve25519_add(b, p->y, p->x);+ curve25519_mul(a, a, qb[signbit]); /* x for +, y for - */+ curve25519_mul(r->x, b, qb[signbit^1]); /* y for +, x for - */+ curve25519_add(r->y, r->x, a);+ curve25519_sub(r->x, r->x, a);+ curve25519_mul(c, p->t, q->t2d);+ curve25519_add_reduce(r->t, p->z, p->z);+ curve25519_copy(r->z, r->t);+ curve25519_add(rb[2+signbit], rb[2+signbit], c); /* z for +, t for - */+ curve25519_sub(rb[2+(signbit^1)], rb[2+(signbit^1)], c); /* t for +, z for - */+}++static void+ge25519_pnielsadd_p1p1(ge25519_p1p1 *r, const ge25519 *p, const ge25519_pniels *q, unsigned char signbit) {+ const bignum25519 *qb = (const bignum25519 *)q;+ bignum25519 *rb = (bignum25519 *)r;+ bignum25519 a,b,c;++ curve25519_sub(a, p->y, p->x);+ curve25519_add(b, p->y, p->x);+ curve25519_mul(a, a, qb[signbit]); /* ysubx for +, xaddy for - */+ curve25519_mul(r->x, b, qb[signbit^1]); /* xaddy for +, ysubx for - */+ curve25519_add(r->y, r->x, a);+ curve25519_sub(r->x, r->x, a);+ curve25519_mul(c, p->t, q->t2d);+ curve25519_mul(r->t, p->z, q->z);+ curve25519_add_reduce(r->t, r->t, r->t);+ curve25519_copy(r->z, r->t);+ curve25519_add(rb[2+signbit], rb[2+signbit], c); /* z for +, t for - */+ curve25519_sub(rb[2+(signbit^1)], rb[2+(signbit^1)], c); /* t for +, z for - */+}++static void+ge25519_double_partial(ge25519 *r, const ge25519 *p) {+ ge25519_p1p1 t;+ ge25519_double_p1p1(&t, p);+ ge25519_p1p1_to_partial(r, &t);+}++static void+ge25519_double(ge25519 *r, const ge25519 *p) {+ ge25519_p1p1 t;+ ge25519_double_p1p1(&t, p);+ ge25519_p1p1_to_full(r, &t);+}++static void+ge25519_add(ge25519 *r, const ge25519 *p, const ge25519 *q) {+ ge25519_p1p1 t;+ ge25519_add_p1p1(&t, p, q);+ ge25519_p1p1_to_full(r, &t);+}++static void+ge25519_nielsadd2(ge25519 *r, const ge25519_niels *q) {+ bignum25519 a,b,c,e,f,g,h;++ curve25519_sub(a, r->y, r->x);+ curve25519_add(b, r->y, r->x);+ curve25519_mul(a, a, q->ysubx);+ curve25519_mul(e, b, q->xaddy);+ curve25519_add(h, e, a);+ curve25519_sub(e, e, a);+ curve25519_mul(c, r->t, q->t2d);+ curve25519_add(f, r->z, r->z);+ curve25519_add_after_basic(g, f, c);+ curve25519_sub_after_basic(f, f, c);+ curve25519_mul(r->x, e, f);+ curve25519_mul(r->y, h, g);+ curve25519_mul(r->z, g, f);+ curve25519_mul(r->t, e, h);+}++static void+ge25519_pnielsadd(ge25519_pniels *r, const ge25519 *p, const ge25519_pniels *q) {+ bignum25519 a,b,c,x,y,z,t;++ curve25519_sub(a, p->y, p->x);+ curve25519_add(b, p->y, p->x);+ curve25519_mul(a, a, q->ysubx);+ curve25519_mul(x, b, q->xaddy);+ curve25519_add(y, x, a);+ curve25519_sub(x, x, a);+ curve25519_mul(c, p->t, q->t2d);+ curve25519_mul(t, p->z, q->z);+ curve25519_add(t, t, t);+ curve25519_add_after_basic(z, t, c);+ curve25519_sub_after_basic(t, t, c);+ curve25519_mul(r->xaddy, x, t);+ curve25519_mul(r->ysubx, y, z);+ curve25519_mul(r->z, z, t);+ curve25519_mul(r->t2d, x, y);+ curve25519_copy(y, r->ysubx);+ curve25519_sub(r->ysubx, r->ysubx, r->xaddy);+ curve25519_add(r->xaddy, r->xaddy, y);+ curve25519_mul(r->t2d, r->t2d, ge25519_ec2d);+}+++/*+ pack & unpack+*/++static void+ge25519_pack(unsigned char r[32], const ge25519 *p) {+ bignum25519 tx, ty, zi;+ unsigned char parity[32];+ curve25519_recip(zi, p->z);+ curve25519_mul(tx, p->x, zi);+ curve25519_mul(ty, p->y, zi);+ curve25519_contract(r, ty);+ curve25519_contract(parity, tx);+ r[31] ^= ((parity[0] & 1) << 7);+}++static int+ge25519_unpack_negative_vartime(ge25519 *r, const unsigned char p[32]) {+ static const unsigned char zero[32] = {0};+ static const bignum25519 one = {1};+ unsigned char parity = p[31] >> 7;+ unsigned char check[32];+ bignum25519 t, root, num, den, d3;++ curve25519_expand(r->y, p);+ curve25519_copy(r->z, one);+ curve25519_square(num, r->y); /* x = y^2 */+ curve25519_mul(den, num, ge25519_ecd); /* den = dy^2 */+ curve25519_sub_reduce(num, num, r->z); /* x = y^1 - 1 */+ curve25519_add(den, den, r->z); /* den = dy^2 + 1 */++ /* Computation of sqrt(num/den) */+ /* 1.: computation of num^((p-5)/8)*den^((7p-35)/8) = (num*den^7)^((p-5)/8) */+ curve25519_square(t, den);+ curve25519_mul(d3, t, den);+ curve25519_square(r->x, d3);+ curve25519_mul(r->x, r->x, den);+ curve25519_mul(r->x, r->x, num);+ curve25519_pow_two252m3(r->x, r->x);++ /* 2. computation of r->x = num * den^3 * (num*den^7)^((p-5)/8) */+ curve25519_mul(r->x, r->x, d3);+ curve25519_mul(r->x, r->x, num);++ /* 3. Check if either of the roots works: */+ curve25519_square(t, r->x);+ curve25519_mul(t, t, den);+ curve25519_sub_reduce(root, t, num);+ curve25519_contract(check, root);+ if (!ed25519_verify(check, zero, 32)) {+ curve25519_add_reduce(t, t, num);+ curve25519_contract(check, t);+ if (!ed25519_verify(check, zero, 32))+ return 0;+ curve25519_mul(r->x, r->x, ge25519_sqrtneg1);+ }++ curve25519_contract(check, r->x);+ if ((check[0] & 1) == parity) {+ curve25519_copy(t, r->x);+ curve25519_neg(r->x, t);+ }+ curve25519_mul(r->t, r->x, r->y);+ return 1;+}+++/*+ scalarmults+*/++#define S1_SWINDOWSIZE 5+#define S1_TABLE_SIZE (1<<(S1_SWINDOWSIZE-2))+#define S2_SWINDOWSIZE 7+#define S2_TABLE_SIZE (1<<(S2_SWINDOWSIZE-2))++/* computes [s1]p1 + [s2]basepoint */+static void +ge25519_double_scalarmult_vartime(ge25519 *r, const ge25519 *p1, const bignum256modm s1, const bignum256modm s2) {+ signed char slide1[256], slide2[256];+ ge25519_pniels pre1[S1_TABLE_SIZE];+ ge25519 d1;+ ge25519_p1p1 t;+ int32_t i;++ contract256_slidingwindow_modm(slide1, s1, S1_SWINDOWSIZE);+ contract256_slidingwindow_modm(slide2, s2, S2_SWINDOWSIZE);++ ge25519_double(&d1, p1);+ ge25519_full_to_pniels(pre1, p1);+ for (i = 0; i < S1_TABLE_SIZE - 1; i++)+ ge25519_pnielsadd(&pre1[i+1], &d1, &pre1[i]);++ /* set neutral */+ memset(r, 0, sizeof(ge25519));+ r->y[0] = 1;+ r->z[0] = 1;++ i = 255;+ while ((i >= 0) && !(slide1[i] | slide2[i]))+ i--;++ for (; i >= 0; i--) {+ ge25519_double_p1p1(&t, r);++ if (slide1[i]) {+ ge25519_p1p1_to_full(r, &t);+ ge25519_pnielsadd_p1p1(&t, r, &pre1[abs(slide1[i]) / 2], (unsigned char)slide1[i] >> 7);+ }++ if (slide2[i]) {+ ge25519_p1p1_to_full(r, &t);+ ge25519_nielsadd2_p1p1(&t, r, &ge25519_niels_sliding_multiples[abs(slide2[i]) / 2], (unsigned char)slide2[i] >> 7);+ }++ ge25519_p1p1_to_partial(r, &t);+ }+}++++#if !defined(HAVE_GE25519_SCALARMULT_BASE_CHOOSE_NIELS)++static uint32_t+ge25519_windowb_equal(uint32_t b, uint32_t c) {+ return ((b ^ c) - 1) >> 31;+}++static void+ge25519_scalarmult_base_choose_niels(ge25519_niels *t, const uint8_t table[256][96], uint32_t pos, signed char b) {+ bignum25519 neg;+ uint32_t sign = (uint32_t)((unsigned char)b >> 7);+ uint32_t mask = ~(sign - 1);+ uint32_t u = (b + mask) ^ mask;+ uint32_t i;++ /* ysubx, xaddy, t2d in packed form. initialize to ysubx = 1, xaddy = 1, t2d = 0 */+ uint8_t packed[96] = {0};+ packed[0] = 1;+ packed[32] = 1;++ for (i = 0; i < 8; i++)+ curve25519_move_conditional_bytes(packed, table[(pos * 8) + i], ge25519_windowb_equal(u, i + 1));++ /* expand in to t */+ curve25519_expand(t->ysubx, packed + 0);+ curve25519_expand(t->xaddy, packed + 32);+ curve25519_expand(t->t2d , packed + 64);++ /* adjust for sign */+ curve25519_swap_conditional(t->ysubx, t->xaddy, sign);+ curve25519_neg(neg, t->t2d);+ curve25519_swap_conditional(t->t2d, neg, sign);+}++#endif /* HAVE_GE25519_SCALARMULT_BASE_CHOOSE_NIELS */+++/* computes [s]basepoint */+static void+ge25519_scalarmult_base_niels(ge25519 *r, const uint8_t basepoint_table[256][96], const bignum256modm s) {+ signed char b[64];+ uint32_t i;+ ge25519_niels t;++ contract256_window4_modm(b, s);++ ge25519_scalarmult_base_choose_niels(&t, basepoint_table, 0, b[1]);+ curve25519_sub_reduce(r->x, t.xaddy, t.ysubx);+ curve25519_add_reduce(r->y, t.xaddy, t.ysubx);+ memset(r->z, 0, sizeof(bignum25519));+ curve25519_copy(r->t, t.t2d);+ r->z[0] = 2; + for (i = 3; i < 64; i += 2) {+ ge25519_scalarmult_base_choose_niels(&t, basepoint_table, i / 2, b[i]);+ ge25519_nielsadd2(r, &t);+ }+ ge25519_double_partial(r, r);+ ge25519_double_partial(r, r);+ ge25519_double_partial(r, r);+ ge25519_double(r, r);+ ge25519_scalarmult_base_choose_niels(&t, basepoint_table, 0, b[0]);+ curve25519_mul(t.t2d, t.t2d, ge25519_ecd);+ ge25519_nielsadd2(r, &t);+ for(i = 2; i < 64; i += 2) {+ ge25519_scalarmult_base_choose_niels(&t, basepoint_table, i / 2, b[i]);+ ge25519_nielsadd2(r, &t);+ }+}+
+ cbits/ed25519/ed25519-donna-portable-identify.h view
@@ -0,0 +1,103 @@+/* os */+#if defined(_WIN32) || defined(_WIN64) || defined(__TOS_WIN__) || defined(__WINDOWS__)+ #define OS_WINDOWS+#elif defined(sun) || defined(__sun) || defined(__SVR4) || defined(__svr4__)+ #define OS_SOLARIS+#else+ #include <sys/param.h> /* need this to define BSD */+ #define OS_NIX+ #if defined(__linux__)+ #define OS_LINUX+ #elif defined(BSD)+ #define OS_BSD+ #if defined(MACOS_X) || (defined(__APPLE__) & defined(__MACH__))+ #define OS_OSX+ #elif defined(macintosh) || defined(Macintosh)+ #define OS_MAC+ #elif defined(__OpenBSD__)+ #define OS_OPENBSD+ #endif+ #endif+#endif+++/* compiler */+#if defined(_MSC_VER)+ #define COMPILER_MSVC+#endif+#if defined(__ICC)+ #define COMPILER_INTEL+#endif+#if defined(__GNUC__)+ #if (__GNUC__ >= 3)+ #define COMPILER_GCC ((__GNUC__ * 10000) + (__GNUC_MINOR__ * 100) + (__GNUC_PATCHLEVEL__))+ #else+ #define COMPILER_GCC ((__GNUC__ * 10000) + (__GNUC_MINOR__ * 100) )+ #endif+#endif+#if defined(__PATHCC__)+ #define COMPILER_PATHCC+#endif+#if defined(__clang__)+ #define COMPILER_CLANG ((__clang_major__ * 10000) + (__clang_minor__ * 100) + (__clang_patchlevel__))+#endif++++/* cpu */+#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__ ) || defined(_M_X64)+ #define CPU_X86_64+#elif defined(__i586__) || defined(__i686__) || (defined(_M_IX86) && (_M_IX86 >= 500))+ #define CPU_X86 500+#elif defined(__i486__) || (defined(_M_IX86) && (_M_IX86 >= 400))+ #define CPU_X86 400+#elif defined(__i386__) || (defined(_M_IX86) && (_M_IX86 >= 300)) || defined(__X86__) || defined(_X86_) || defined(__I86__)+ #define CPU_X86 300+#elif defined(__ia64__) || defined(_IA64) || defined(__IA64__) || defined(_M_IA64) || defined(__ia64)+ #define CPU_IA64+#endif++#if defined(__sparc__) || defined(__sparc) || defined(__sparcv9)+ #define CPU_SPARC+ #if defined(__sparcv9)+ #define CPU_SPARC64+ #endif+#endif++#if defined(powerpc) || defined(__PPC__) || defined(__ppc__) || defined(_ARCH_PPC) || defined(__powerpc__) || defined(__powerpc) || defined(POWERPC) || defined(_M_PPC)+ #define CPU_PPC+ #if defined(_ARCH_PWR7)+ #define CPU_POWER7+ #elif defined(__64BIT__)+ #define CPU_PPC64+ #else+ #define CPU_PPC32+ #endif+#endif++#if defined(__hppa__) || defined(__hppa)+ #define CPU_HPPA+#endif++#if defined(__alpha__) || defined(__alpha) || defined(_M_ALPHA)+ #define CPU_ALPHA+#endif++/* 64 bit cpu */+#if defined(CPU_X86_64) || defined(CPU_IA64) || defined(CPU_SPARC64) || defined(__64BIT__) || defined(__LP64__) || defined(_LP64) || (defined(_MIPS_SZLONG) && (_MIPS_SZLONG == 64))+ #define CPU_64BITS+#endif++#if defined(COMPILER_MSVC)+ typedef signed char int8_t;+ typedef unsigned char uint8_t;+ typedef signed short int16_t;+ typedef unsigned short uint16_t;+ typedef signed int int32_t;+ typedef unsigned int uint32_t;+ typedef signed __int64 int64_t;+ typedef unsigned __int64 uint64_t;+#else+ #include <stdint.h>+#endif+
+ cbits/ed25519/ed25519-donna-portable.h view
@@ -0,0 +1,138 @@+#include "ed25519-donna-portable-identify.h"++#define mul32x32_64(a,b) (((uint64_t)(a))*(b))++/* platform */+#if defined(COMPILER_MSVC)+ #include <intrin.h>+ #if !defined(_DEBUG)+ #undef mul32x32_64 + #define mul32x32_64(a,b) __emulu(a,b)+ #endif+ #undef inline+ #define inline __forceinline+ #define DONNA_INLINE __forceinline+ #define DONNA_NOINLINE __declspec(noinline)+ #define ALIGN(x) __declspec(align(x))+ #define ROTL32(a,b) _rotl(a,b)+ #define ROTR32(a,b) _rotr(a,b)+#else+ #include <sys/param.h>+ #define DONNA_INLINE inline __attribute__((always_inline))+ #define DONNA_NOINLINE __attribute__((noinline))+ #ifdef ALIGN+ #undef ALIGN+ #endif+ #define ALIGN(x) __attribute__((aligned(x)))+ #define ROTL32(a,b) (((a) << (b)) | ((a) >> (32 - b)))+ #define ROTR32(a,b) (((a) >> (b)) | ((a) << (32 - b)))+#endif++/* uint128_t */+#if defined(CPU_64BITS) && !defined(ED25519_FORCE_32BIT)+ #if defined(COMPILER_CLANG) && (COMPILER_CLANG >= 30100)+ #define HAVE_NATIVE_UINT128+ typedef unsigned __int128 uint128_t;+ #elif defined(COMPILER_MSVC)+ #define HAVE_UINT128+ typedef struct uint128_t {+ uint64_t lo, hi;+ } uint128_t;+ #define mul64x64_128(out,a,b) out.lo = _umul128(a,b,&out.hi);+ #define shr128_pair(out,hi,lo,shift) out = __shiftright128(lo, hi, shift);+ #define shl128_pair(out,hi,lo,shift) out = __shiftleft128(lo, hi, shift);+ #define shr128(out,in,shift) shr128_pair(out, in.hi, in.lo, shift)+ #define shl128(out,in,shift) shl128_pair(out, in.hi, in.lo, shift)+ #define add128(a,b) { uint64_t p = a.lo; a.lo += b.lo; a.hi += b.hi + (a.lo < p); }+ #define add128_64(a,b) { uint64_t p = a.lo; a.lo += b; a.hi += (a.lo < p); }+ #define lo128(a) (a.lo)+ #define hi128(a) (a.hi)+ #elif defined(COMPILER_GCC) && !defined(HAVE_NATIVE_UINT128)+ #if defined(__SIZEOF_INT128__)+ #define HAVE_NATIVE_UINT128+ typedef unsigned __int128 uint128_t;+ #elif (COMPILER_GCC >= 40400)+ #define HAVE_NATIVE_UINT128+ typedef unsigned uint128_t __attribute__((mode(TI)));+ #elif defined(CPU_X86_64)+ #define HAVE_UINT128+ typedef struct uint128_t {+ uint64_t lo, hi;+ } uint128_t;+ #define mul64x64_128(out,a,b) __asm__ ("mulq %3" : "=a" (out.lo), "=d" (out.hi) : "a" (a), "rm" (b));+ #define shr128_pair(out,hi,lo,shift) __asm__ ("shrdq %2,%1,%0" : "+r" (lo) : "r" (hi), "J" (shift)); out = lo;+ #define shl128_pair(out,hi,lo,shift) __asm__ ("shldq %2,%1,%0" : "+r" (hi) : "r" (lo), "J" (shift)); out = hi;+ #define shr128(out,in,shift) shr128_pair(out,in.hi, in.lo, shift)+ #define shl128(out,in,shift) shl128_pair(out,in.hi, in.lo, shift)+ #define add128(a,b) __asm__ ("addq %4,%2; adcq %5,%3" : "=r" (a.hi), "=r" (a.lo) : "1" (a.lo), "0" (a.hi), "rm" (b.lo), "rm" (b.hi) : "cc");+ #define add128_64(a,b) __asm__ ("addq %4,%2; adcq $0,%3" : "=r" (a.hi), "=r" (a.lo) : "1" (a.lo), "0" (a.hi), "rm" (b) : "cc");+ #define lo128(a) (a.lo)+ #define hi128(a) (a.hi)+ #endif+ #endif++ #if defined(HAVE_NATIVE_UINT128)+ #define HAVE_UINT128+ #define mul64x64_128(out,a,b) out = (uint128_t)a * b;+ #define shr128_pair(out,hi,lo,shift) out = (uint64_t)((((uint128_t)hi << 64) | lo) >> (shift));+ #define shl128_pair(out,hi,lo,shift) out = (uint64_t)(((((uint128_t)hi << 64) | lo) << (shift)) >> 64);+ #define shr128(out,in,shift) out = (uint64_t)(in >> (shift));+ #define shl128(out,in,shift) out = (uint64_t)((in << shift) >> 64);+ #define add128(a,b) a += b;+ #define add128_64(a,b) a += (uint64_t)b;+ #define lo128(a) ((uint64_t)a)+ #define hi128(a) ((uint64_t)(a >> 64))+ #endif++ #if !defined(HAVE_UINT128)+ #error Need a uint128_t implementation!+ #endif+#endif++/* endian */+#if !defined(ED25519_OPENSSLRNG)+static inline void U32TO8_LE(unsigned char *p, const uint32_t v) {+ p[0] = (unsigned char)(v );+ p[1] = (unsigned char)(v >> 8);+ p[2] = (unsigned char)(v >> 16);+ p[3] = (unsigned char)(v >> 24);+}+#endif++#if !defined(HAVE_UINT128)+static inline uint32_t U8TO32_LE(const unsigned char *p) {+ return+ (((uint32_t)(p[0]) ) | + ((uint32_t)(p[1]) << 8) |+ ((uint32_t)(p[2]) << 16) |+ ((uint32_t)(p[3]) << 24));+}+#else+static inline uint64_t U8TO64_LE(const unsigned char *p) {+ return+ (((uint64_t)(p[0]) ) |+ ((uint64_t)(p[1]) << 8) |+ ((uint64_t)(p[2]) << 16) |+ ((uint64_t)(p[3]) << 24) |+ ((uint64_t)(p[4]) << 32) |+ ((uint64_t)(p[5]) << 40) |+ ((uint64_t)(p[6]) << 48) |+ ((uint64_t)(p[7]) << 56));+}++static inline void U64TO8_LE(unsigned char *p, const uint64_t v) {+ p[0] = (unsigned char)(v );+ p[1] = (unsigned char)(v >> 8);+ p[2] = (unsigned char)(v >> 16);+ p[3] = (unsigned char)(v >> 24);+ p[4] = (unsigned char)(v >> 32);+ p[5] = (unsigned char)(v >> 40);+ p[6] = (unsigned char)(v >> 48);+ p[7] = (unsigned char)(v >> 56);+}+#endif++#include <stdlib.h>+#include <string.h>++
+ cbits/ed25519/ed25519-donna.h view
@@ -0,0 +1,115 @@+/*+ Public domain by Andrew M. <liquidsun@gmail.com>+ Modified from the amd64-51-30k implementation by+ Daniel J. Bernstein+ Niels Duif+ Tanja Lange+ Peter Schwabe+ Bo-Yin Yang+*/+++#include "ed25519-donna-portable.h"++#if defined(ED25519_SSE2)+#else+ #if defined(HAVE_UINT128) && !defined(ED25519_FORCE_32BIT)+ #define ED25519_64BIT+ #else+ #define ED25519_32BIT+ #endif+#endif++#if !defined(ED25519_NO_INLINE_ASM)+ /* detect extra features first so un-needed functions can be disabled throughout */+ #if defined(ED25519_SSE2)+ #if defined(COMPILER_GCC) && defined(CPU_X86)+ #define ED25519_GCC_32BIT_SSE_CHOOSE+ #elif defined(COMPILER_GCC) && defined(CPU_X86_64)+ #define ED25519_GCC_64BIT_SSE_CHOOSE+ #endif+ #else+ #if defined(CPU_X86_64)+ #if defined(COMPILER_GCC) + #if defined(ED25519_64BIT)+ #define ED25519_GCC_64BIT_X86_CHOOSE+ #else+ #define ED25519_GCC_64BIT_32BIT_CHOOSE+ #endif+ #endif+ #endif+ #endif+#endif++#if defined(ED25519_SSE2)+ #include "curve25519-donna-sse2.h"+#elif defined(ED25519_64BIT)+ #include "curve25519-donna-64bit.h"+#else+ #include "curve25519-donna-32bit.h"+#endif++#include "curve25519-donna-helpers.h"++/* separate uint128 check for 64 bit sse2 */+#if defined(HAVE_UINT128) && !defined(ED25519_FORCE_32BIT)+ #include "modm-donna-64bit.h"+#else+ #include "modm-donna-32bit.h"+#endif++typedef unsigned char hash_512bits[64];++/*+ Timing safe memory compare+*/+static int+ed25519_verify(const unsigned char *x, const unsigned char *y, size_t len) {+ size_t differentbits = 0;+ while (len--)+ differentbits |= (*x++ ^ *y++);+ return (int) (1 & ((differentbits - 1) >> 8));+}+++/*+ * Arithmetic on the twisted Edwards curve -x^2 + y^2 = 1 + dx^2y^2+ * with d = -(121665/121666) = 37095705934669439343138083508754565189542113879843219016388785533085940283555+ * Base point: (15112221349535400772501151409588531511454012693041857206046113283949847762202,46316835694926478169428394003475163141307993866256225615783033603165251855960);+ */++typedef struct ge25519_t {+ bignum25519 x, y, z, t;+} ge25519;++typedef struct ge25519_p1p1_t {+ bignum25519 x, y, z, t;+} ge25519_p1p1;++typedef struct ge25519_niels_t {+ bignum25519 ysubx, xaddy, t2d;+} ge25519_niels;++typedef struct ge25519_pniels_t {+ bignum25519 ysubx, xaddy, z, t2d;+} ge25519_pniels;++#include "ed25519-donna-basepoint-table.h"++#if defined(ED25519_64BIT)+ #include "ed25519-donna-64bit-tables.h"+ #include "ed25519-donna-64bit-x86.h"+#else+ #include "ed25519-donna-32bit-tables.h"+ #include "ed25519-donna-64bit-x86-32bit.h"+#endif+++#if defined(ED25519_SSE2)+ #include "ed25519-donna-32bit-sse2.h"+ #include "ed25519-donna-64bit-sse2.h"+ #include "ed25519-donna-impl-sse2.h"+#else+ #include "ed25519-donna-impl-base.h"+#endif+
+ cbits/ed25519/ed25519-hash.h view
@@ -0,0 +1,26 @@+#include <crypton_sha512.h>+typedef struct sha512_ctx ed25519_hash_context;++static void+ed25519_hash_init(ed25519_hash_context *ctx) {+ crypton_sha512_init(ctx);+}++static void+ed25519_hash_update(ed25519_hash_context *ctx, const uint8_t *in, size_t inlen) {+ crypton_sha512_update(ctx, in, inlen);+}++static void+ed25519_hash_final(ed25519_hash_context *ctx, uint8_t *hash) {+ crypton_sha512_finalize(ctx, hash);+}++static void+ed25519_hash(uint8_t *hash, const uint8_t *in, size_t inlen) {+ ed25519_hash_context ctx;+ crypton_sha512_init(&ctx);+ crypton_sha512_update(&ctx, in, inlen);+ crypton_sha512_finalize(&ctx, hash);+ memset(&ctx, 0, sizeof(ctx));+}
+ cbits/ed25519/ed25519-randombytes.h view
@@ -0,0 +1,4 @@+void+ED25519_FN(ed25519_randombytes_unsafe) (void *p, size_t len) {+ exit(1);+}
+ cbits/ed25519/ed25519.c view
@@ -0,0 +1,159 @@+/*+ Public domain by Andrew M. <liquidsun@gmail.com>++ Ed25519 reference implementation using Ed25519-donna+*/+++#define ED25519_FN(fn) cardano_crypto_##fn++#include "ed25519-donna.h"+#include "ed25519.h"+#include "ed25519-randombytes.h"+#include "ed25519-hash.h"++#define VARIANT_CODE++/*+ Generates a (extsk[0..31]) and aExt (extsk[32..63])+*/++DONNA_INLINE static void+ed25519_extsk(hash_512bits extsk, const ed25519_unextended_secret_key sk) {+ ed25519_hash(extsk, sk, 32);+ extsk[0] &= 248;+ extsk[31] &= 127;+ extsk[31] |= 64;+}++static void+ed25519_hram(hash_512bits hram, const ed25519_signature RS, const ed25519_public_key pk, const unsigned char *m, size_t mlen) {+ ed25519_hash_context ctx;+ ed25519_hash_init(&ctx);+ ed25519_hash_update(&ctx, RS, 32);+ ed25519_hash_update(&ctx, pk, 32);+ ed25519_hash_update(&ctx, m, mlen);+ ed25519_hash_final(&ctx, hram);+}++void+ED25519_FN(ed25519_publickey) (const ed25519_secret_key sk, ed25519_public_key pk) {+ bignum256modm a;+ ge25519 ALIGN(16) A;+ hash_512bits extsk = { 0 };++ /* A = aB */+#ifdef VARIANT_CODE+ /* in variant we don't stretch the key through hashing first */+ memcpy(extsk, sk, 32);+#else+ ed25519_extsk(extsk, sk);+#endif+ expand256_modm(a, extsk, 32);+ ge25519_scalarmult_base_niels(&A, ge25519_niels_base_multiples, a);+ ge25519_pack(pk, &A);+}++void+ED25519_FN(ed25519_sign) (const unsigned char *m, size_t mlen, const unsigned char *salt, size_t slen, const ed25519_secret_key sk, const ed25519_public_key pk, ed25519_signature RS) {+ ed25519_hash_context ctx;+ bignum256modm r, S, a;+ ge25519 ALIGN(16) R;+ hash_512bits extsk, hashr, hram;++#ifdef VARIANT_CODE+ memcpy(extsk, sk, 64);+#else+ ed25519_extsk(extsk, sk);+#endif++ /* r = H(aExt[32..64], m) */+ ed25519_hash_init(&ctx);+ ed25519_hash_update(&ctx, extsk + 32, 32);+ ed25519_hash_update(&ctx, m, mlen);+ ed25519_hash_final(&ctx, hashr);+ expand256_modm(r, hashr, 64);++ /* R = rB */+ ge25519_scalarmult_base_niels(&R, ge25519_niels_base_multiples, r);+ ge25519_pack(RS, &R);++ /* S = H(R,A,m).. */+ ed25519_hram(hram, RS, pk, m, mlen);+ expand256_modm(S, hram, 64);++ /* S = H(R,A,m)a */+ expand256_modm(a, extsk, 32);+ mul256_modm(S, S, a);++ /* S = (r + H(R,A,m)a) */+ add256_modm(S, S, r);++ /* S = (r + H(R,A,m)a) mod L */+ contract256_modm(RS + 32, S);+}++int+ED25519_FN(ed25519_sign_open) (const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS) {+ ge25519 ALIGN(16) R, A;+ hash_512bits hash;+ bignum256modm hram, S;+ unsigned char checkR[32];++ if ((RS[63] & 224) || !ge25519_unpack_negative_vartime(&A, pk))+ return -1;++ /* hram = H(R,A,m) */+ ed25519_hram(hash, RS, pk, m, mlen);+ expand256_modm(hram, hash, 64);++ /* S */+ expand256_modm(S, RS + 32, 32);++ /* SB - H(R,A,m)A */+ ge25519_double_scalarmult_vartime(&R, &A, hram, S);+ ge25519_pack(checkR, &R);++ /* check that R = SB - H(R,A,m)A */+ return ed25519_verify(RS, checkR, 32) ? 0 : -1;+}++/* we only need the leftmost 32 bytes of the extended secret key */+int+ED25519_FN(ed25519_scalar_add) (const ed25519_secret_key sk1, const ed25519_secret_key sk2, ed25519_secret_key res)+{+ bignum256modm s1, s2;+ expand256_modm(s1, sk1, 32);+ expand256_modm(s2, sk2, 32);+ add256_modm(s1, s1, s2);+ contract256_modm(res, s1);+ return 0;+}++int+ED25519_FN(ed25519_point_add) (const ed25519_public_key pk1, const ed25519_public_key pk2, ed25519_public_key res)+{+ ge25519 ALIGN(16) R, P, Q;++ if (!ge25519_unpack_negative_vartime(&P, pk1))+ return -1;+ if (!ge25519_unpack_negative_vartime(&Q, pk2))+ return -1;++ ge25519_add(&R, &P, &Q);+ ge25519_pack(res, &R);++ res[31] ^= 0x80;+ return 0;+}++int+ED25519_FN(ed25519_extend) (const ed25519_unextended_secret_key seed, ed25519_secret_key secret)+{+ ed25519_extsk(secret, seed);++ /* invalid if 3rd highest bit set */+ if (secret[31] & 0x20)+ return 1;+ return 0;+}
+ cbits/ed25519/ed25519.h view
@@ -0,0 +1,26 @@+#ifndef ED25519_H+#define ED25519_H++#include <stdlib.h>++#if defined(__cplusplus)+extern "C" {+#endif++typedef unsigned char ed25519_signature[64];+typedef unsigned char ed25519_public_key[32];+typedef unsigned char ed25519_unextended_secret_key[32]; // this is the UNEXTENDED SECRET KEY+typedef unsigned char ed25519_secret_key[64]; // this is the EXTENDED SECRET KEY++void cardano_crypto_ed25519_publickey(const ed25519_secret_key sk, ed25519_public_key pk);+int cardano_crypto_ed25519_sign_open(const unsigned char *m, size_t mlen, const ed25519_public_key pk, const ed25519_signature RS);+void cardano_crypto_ed25519_sign (const unsigned char *m, size_t mlen, const unsigned char *salt, size_t slen, const ed25519_secret_key sk, const ed25519_public_key pk, ed25519_signature RS);+int cardano_crypto_ed25519_scalar_add (const ed25519_secret_key sk1, const ed25519_secret_key sk2, ed25519_secret_key res);+int cardano_crypto_ed25519_point_add (const ed25519_public_key pk1, const ed25519_public_key pk2, ed25519_public_key res);+int cardano_crypto_ed25519_extend (const ed25519_unextended_secret_key seed, ed25519_secret_key secret);++#if defined(__cplusplus)+}+#endif++#endif // ED25519_H
+ cbits/ed25519/modm-donna-32bit.h view
@@ -0,0 +1,469 @@+/*+ Public domain by Andrew M. <liquidsun@gmail.com>+*/+++/*+ Arithmetic modulo the group order n = 2^252 + 27742317777372353535851937790883648493 = 7237005577332262213973186563042994240857116359379907606001950938285454250989++ k = 32+ b = 1 << 8 = 256+ m = 2^252 + 27742317777372353535851937790883648493 = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed+ mu = floor( b^(k*2) / m ) = 0xfffffffffffffffffffffffffffffffeb2106215d086329a7ed9ce5a30a2c131b+*/++#define bignum256modm_bits_per_limb 30+#define bignum256modm_limb_size 9++typedef uint32_t bignum256modm_element_t;+typedef bignum256modm_element_t bignum256modm[9];++static const bignum256modm modm_m = {+ 0x1cf5d3ed, 0x20498c69, 0x2f79cd65, 0x37be77a8,+ 0x00000014, 0x00000000, 0x00000000, 0x00000000,+ 0x00001000+};++static const bignum256modm modm_mu = {+ 0x0a2c131b, 0x3673968c, 0x06329a7e, 0x01885742,+ 0x3fffeb21, 0x3fffffff, 0x3fffffff, 0x3fffffff,+ 0x000fffff+};++static bignum256modm_element_t+lt_modm(bignum256modm_element_t a, bignum256modm_element_t b) {+ return (a - b) >> 31;+}++/* see HAC, Alg. 14.42 Step 4 */+static void+reduce256_modm(bignum256modm r) {+ bignum256modm t;+ bignum256modm_element_t b = 0, pb, mask;++ /* t = r - m */+ pb = 0;+ pb += modm_m[0]; b = lt_modm(r[0], pb); t[0] = (r[0] - pb + (b << 30)); pb = b;+ pb += modm_m[1]; b = lt_modm(r[1], pb); t[1] = (r[1] - pb + (b << 30)); pb = b;+ pb += modm_m[2]; b = lt_modm(r[2], pb); t[2] = (r[2] - pb + (b << 30)); pb = b;+ pb += modm_m[3]; b = lt_modm(r[3], pb); t[3] = (r[3] - pb + (b << 30)); pb = b;+ pb += modm_m[4]; b = lt_modm(r[4], pb); t[4] = (r[4] - pb + (b << 30)); pb = b;+ pb += modm_m[5]; b = lt_modm(r[5], pb); t[5] = (r[5] - pb + (b << 30)); pb = b;+ pb += modm_m[6]; b = lt_modm(r[6], pb); t[6] = (r[6] - pb + (b << 30)); pb = b;+ pb += modm_m[7]; b = lt_modm(r[7], pb); t[7] = (r[7] - pb + (b << 30)); pb = b;+ pb += modm_m[8]; b = lt_modm(r[8], pb); t[8] = (r[8] - pb + (b << 16));++ /* keep r if r was smaller than m */+ mask = b - 1;+ r[0] ^= mask & (r[0] ^ t[0]);+ r[1] ^= mask & (r[1] ^ t[1]);+ r[2] ^= mask & (r[2] ^ t[2]);+ r[3] ^= mask & (r[3] ^ t[3]);+ r[4] ^= mask & (r[4] ^ t[4]);+ r[5] ^= mask & (r[5] ^ t[5]);+ r[6] ^= mask & (r[6] ^ t[6]);+ r[7] ^= mask & (r[7] ^ t[7]);+ r[8] ^= mask & (r[8] ^ t[8]);+}++/*+ Barrett reduction, see HAC, Alg. 14.42++ Instead of passing in x, pre-process in to q1 and r1 for efficiency+*/+static void+barrett_reduce256_modm(bignum256modm r, const bignum256modm q1, const bignum256modm r1) {+ bignum256modm q3, r2;+ uint64_t c;+ bignum256modm_element_t f, b, pb;++ /* q1 = x >> 248 = 264 bits = 9 30 bit elements+ q2 = mu * q1+ q3 = (q2 / 256(32+1)) = q2 / (2^8)^(32+1) = q2 >> 264 */+ c = mul32x32_64(modm_mu[0], q1[7]) + mul32x32_64(modm_mu[1], q1[6]) + mul32x32_64(modm_mu[2], q1[5]) + mul32x32_64(modm_mu[3], q1[4]) + mul32x32_64(modm_mu[4], q1[3]) + mul32x32_64(modm_mu[5], q1[2]) + mul32x32_64(modm_mu[6], q1[1]) + mul32x32_64(modm_mu[7], q1[0]); + c >>= 30;+ c += mul32x32_64(modm_mu[0], q1[8]) + mul32x32_64(modm_mu[1], q1[7]) + mul32x32_64(modm_mu[2], q1[6]) + mul32x32_64(modm_mu[3], q1[5]) + mul32x32_64(modm_mu[4], q1[4]) + mul32x32_64(modm_mu[5], q1[3]) + mul32x32_64(modm_mu[6], q1[2]) + mul32x32_64(modm_mu[7], q1[1]) + mul32x32_64(modm_mu[8], q1[0]);+ f = (bignum256modm_element_t)c; q3[0] = (f >> 24) & 0x3f; c >>= 30;+ c += mul32x32_64(modm_mu[1], q1[8]) + mul32x32_64(modm_mu[2], q1[7]) + mul32x32_64(modm_mu[3], q1[6]) + mul32x32_64(modm_mu[4], q1[5]) + mul32x32_64(modm_mu[5], q1[4]) + mul32x32_64(modm_mu[6], q1[3]) + mul32x32_64(modm_mu[7], q1[2]) + mul32x32_64(modm_mu[8], q1[1]);+ f = (bignum256modm_element_t)c; q3[0] |= (f << 6) & 0x3fffffff; q3[1] = (f >> 24) & 0x3f; c >>= 30;+ c += mul32x32_64(modm_mu[2], q1[8]) + mul32x32_64(modm_mu[3], q1[7]) + mul32x32_64(modm_mu[4], q1[6]) + mul32x32_64(modm_mu[5], q1[5]) + mul32x32_64(modm_mu[6], q1[4]) + mul32x32_64(modm_mu[7], q1[3]) + mul32x32_64(modm_mu[8], q1[2]);+ f = (bignum256modm_element_t)c; q3[1] |= (f << 6) & 0x3fffffff; q3[2] = (f >> 24) & 0x3f; c >>= 30;+ c += mul32x32_64(modm_mu[3], q1[8]) + mul32x32_64(modm_mu[4], q1[7]) + mul32x32_64(modm_mu[5], q1[6]) + mul32x32_64(modm_mu[6], q1[5]) + mul32x32_64(modm_mu[7], q1[4]) + mul32x32_64(modm_mu[8], q1[3]);+ f = (bignum256modm_element_t)c; q3[2] |= (f << 6) & 0x3fffffff; q3[3] = (f >> 24) & 0x3f; c >>= 30;+ c += mul32x32_64(modm_mu[4], q1[8]) + mul32x32_64(modm_mu[5], q1[7]) + mul32x32_64(modm_mu[6], q1[6]) + mul32x32_64(modm_mu[7], q1[5]) + mul32x32_64(modm_mu[8], q1[4]);+ f = (bignum256modm_element_t)c; q3[3] |= (f << 6) & 0x3fffffff; q3[4] = (f >> 24) & 0x3f; c >>= 30;+ c += mul32x32_64(modm_mu[5], q1[8]) + mul32x32_64(modm_mu[6], q1[7]) + mul32x32_64(modm_mu[7], q1[6]) + mul32x32_64(modm_mu[8], q1[5]);+ f = (bignum256modm_element_t)c; q3[4] |= (f << 6) & 0x3fffffff; q3[5] = (f >> 24) & 0x3f; c >>= 30;+ c += mul32x32_64(modm_mu[6], q1[8]) + mul32x32_64(modm_mu[7], q1[7]) + mul32x32_64(modm_mu[8], q1[6]);+ f = (bignum256modm_element_t)c; q3[5] |= (f << 6) & 0x3fffffff; q3[6] = (f >> 24) & 0x3f; c >>= 30;+ c += mul32x32_64(modm_mu[7], q1[8]) + mul32x32_64(modm_mu[8], q1[7]);+ f = (bignum256modm_element_t)c; q3[6] |= (f << 6) & 0x3fffffff; q3[7] = (f >> 24) & 0x3f; c >>= 30;+ c += mul32x32_64(modm_mu[8], q1[8]);+ f = (bignum256modm_element_t)c; q3[7] |= (f << 6) & 0x3fffffff; q3[8] = (bignum256modm_element_t)(c >> 24);++ /* r1 = (x mod 256^(32+1)) = x mod (2^8)(31+1) = x & ((1 << 264) - 1)+ r2 = (q3 * m) mod (256^(32+1)) = (q3 * m) & ((1 << 264) - 1) */+ c = mul32x32_64(modm_m[0], q3[0]);+ r2[0] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30;+ c += mul32x32_64(modm_m[0], q3[1]) + mul32x32_64(modm_m[1], q3[0]);+ r2[1] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30;+ c += mul32x32_64(modm_m[0], q3[2]) + mul32x32_64(modm_m[1], q3[1]) + mul32x32_64(modm_m[2], q3[0]);+ r2[2] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30;+ c += mul32x32_64(modm_m[0], q3[3]) + mul32x32_64(modm_m[1], q3[2]) + mul32x32_64(modm_m[2], q3[1]) + mul32x32_64(modm_m[3], q3[0]);+ r2[3] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30;+ c += mul32x32_64(modm_m[0], q3[4]) + mul32x32_64(modm_m[1], q3[3]) + mul32x32_64(modm_m[2], q3[2]) + mul32x32_64(modm_m[3], q3[1]) + mul32x32_64(modm_m[4], q3[0]);+ r2[4] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30;+ c += mul32x32_64(modm_m[0], q3[5]) + mul32x32_64(modm_m[1], q3[4]) + mul32x32_64(modm_m[2], q3[3]) + mul32x32_64(modm_m[3], q3[2]) + mul32x32_64(modm_m[4], q3[1]) + mul32x32_64(modm_m[5], q3[0]);+ r2[5] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30;+ c += mul32x32_64(modm_m[0], q3[6]) + mul32x32_64(modm_m[1], q3[5]) + mul32x32_64(modm_m[2], q3[4]) + mul32x32_64(modm_m[3], q3[3]) + mul32x32_64(modm_m[4], q3[2]) + mul32x32_64(modm_m[5], q3[1]) + mul32x32_64(modm_m[6], q3[0]);+ r2[6] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30;+ c += mul32x32_64(modm_m[0], q3[7]) + mul32x32_64(modm_m[1], q3[6]) + mul32x32_64(modm_m[2], q3[5]) + mul32x32_64(modm_m[3], q3[4]) + mul32x32_64(modm_m[4], q3[3]) + mul32x32_64(modm_m[5], q3[2]) + mul32x32_64(modm_m[6], q3[1]) + mul32x32_64(modm_m[7], q3[0]);+ r2[7] = (bignum256modm_element_t)(c & 0x3fffffff); c >>= 30;+ c += mul32x32_64(modm_m[0], q3[8]) + mul32x32_64(modm_m[1], q3[7]) + mul32x32_64(modm_m[2], q3[6]) + mul32x32_64(modm_m[3], q3[5]) + mul32x32_64(modm_m[4], q3[4]) + mul32x32_64(modm_m[5], q3[3]) + mul32x32_64(modm_m[6], q3[2]) + mul32x32_64(modm_m[7], q3[1]) + mul32x32_64(modm_m[8], q3[0]);+ r2[8] = (bignum256modm_element_t)(c & 0xffffff);++ /* r = r1 - r2+ if (r < 0) r += (1 << 264) */+ pb = 0;+ pb += r2[0]; b = lt_modm(r1[0], pb); r[0] = (r1[0] - pb + (b << 30)); pb = b;+ pb += r2[1]; b = lt_modm(r1[1], pb); r[1] = (r1[1] - pb + (b << 30)); pb = b;+ pb += r2[2]; b = lt_modm(r1[2], pb); r[2] = (r1[2] - pb + (b << 30)); pb = b;+ pb += r2[3]; b = lt_modm(r1[3], pb); r[3] = (r1[3] - pb + (b << 30)); pb = b;+ pb += r2[4]; b = lt_modm(r1[4], pb); r[4] = (r1[4] - pb + (b << 30)); pb = b;+ pb += r2[5]; b = lt_modm(r1[5], pb); r[5] = (r1[5] - pb + (b << 30)); pb = b;+ pb += r2[6]; b = lt_modm(r1[6], pb); r[6] = (r1[6] - pb + (b << 30)); pb = b;+ pb += r2[7]; b = lt_modm(r1[7], pb); r[7] = (r1[7] - pb + (b << 30)); pb = b;+ pb += r2[8]; b = lt_modm(r1[8], pb); r[8] = (r1[8] - pb + (b << 24));++ reduce256_modm(r);+ reduce256_modm(r);+}++/* addition modulo m */+static void+add256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) {+ bignum256modm_element_t c;++ c = x[0] + y[0]; r[0] = c & 0x3fffffff; c >>= 30;+ c += x[1] + y[1]; r[1] = c & 0x3fffffff; c >>= 30;+ c += x[2] + y[2]; r[2] = c & 0x3fffffff; c >>= 30;+ c += x[3] + y[3]; r[3] = c & 0x3fffffff; c >>= 30;+ c += x[4] + y[4]; r[4] = c & 0x3fffffff; c >>= 30;+ c += x[5] + y[5]; r[5] = c & 0x3fffffff; c >>= 30;+ c += x[6] + y[6]; r[6] = c & 0x3fffffff; c >>= 30;+ c += x[7] + y[7]; r[7] = c & 0x3fffffff; c >>= 30;+ c += x[8] + y[8]; r[8] = c;++ reduce256_modm(r);+}++/* multiplication modulo m */+static void +mul256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) {+ bignum256modm r1, q1;+ uint64_t c;+ bignum256modm_element_t f;++ /* r1 = (x mod 256^(32+1)) = x mod (2^8)(31+1) = x & ((1 << 264) - 1)+ q1 = x >> 248 = 264 bits = 9 30 bit elements */+ c = mul32x32_64(x[0], y[0]);+ f = (bignum256modm_element_t)c; r1[0] = (f & 0x3fffffff); c >>= 30;+ c += mul32x32_64(x[0], y[1]) + mul32x32_64(x[1], y[0]);+ f = (bignum256modm_element_t)c; r1[1] = (f & 0x3fffffff); c >>= 30;+ c += mul32x32_64(x[0], y[2]) + mul32x32_64(x[1], y[1]) + mul32x32_64(x[2], y[0]);+ f = (bignum256modm_element_t)c; r1[2] = (f & 0x3fffffff); c >>= 30;+ c += mul32x32_64(x[0], y[3]) + mul32x32_64(x[1], y[2]) + mul32x32_64(x[2], y[1]) + mul32x32_64(x[3], y[0]);+ f = (bignum256modm_element_t)c; r1[3] = (f & 0x3fffffff); c >>= 30;+ c += mul32x32_64(x[0], y[4]) + mul32x32_64(x[1], y[3]) + mul32x32_64(x[2], y[2]) + mul32x32_64(x[3], y[1]) + mul32x32_64(x[4], y[0]);+ f = (bignum256modm_element_t)c; r1[4] = (f & 0x3fffffff); c >>= 30;+ c += mul32x32_64(x[0], y[5]) + mul32x32_64(x[1], y[4]) + mul32x32_64(x[2], y[3]) + mul32x32_64(x[3], y[2]) + mul32x32_64(x[4], y[1]) + mul32x32_64(x[5], y[0]);+ f = (bignum256modm_element_t)c; r1[5] = (f & 0x3fffffff); c >>= 30;+ c += mul32x32_64(x[0], y[6]) + mul32x32_64(x[1], y[5]) + mul32x32_64(x[2], y[4]) + mul32x32_64(x[3], y[3]) + mul32x32_64(x[4], y[2]) + mul32x32_64(x[5], y[1]) + mul32x32_64(x[6], y[0]);+ f = (bignum256modm_element_t)c; r1[6] = (f & 0x3fffffff); c >>= 30;+ c += mul32x32_64(x[0], y[7]) + mul32x32_64(x[1], y[6]) + mul32x32_64(x[2], y[5]) + mul32x32_64(x[3], y[4]) + mul32x32_64(x[4], y[3]) + mul32x32_64(x[5], y[2]) + mul32x32_64(x[6], y[1]) + mul32x32_64(x[7], y[0]);+ f = (bignum256modm_element_t)c; r1[7] = (f & 0x3fffffff); c >>= 30;+ c += mul32x32_64(x[0], y[8]) + mul32x32_64(x[1], y[7]) + mul32x32_64(x[2], y[6]) + mul32x32_64(x[3], y[5]) + mul32x32_64(x[4], y[4]) + mul32x32_64(x[5], y[3]) + mul32x32_64(x[6], y[2]) + mul32x32_64(x[7], y[1]) + mul32x32_64(x[8], y[0]);+ f = (bignum256modm_element_t)c; r1[8] = (f & 0x00ffffff); q1[0] = (f >> 8) & 0x3fffff; c >>= 30;+ c += mul32x32_64(x[1], y[8]) + mul32x32_64(x[2], y[7]) + mul32x32_64(x[3], y[6]) + mul32x32_64(x[4], y[5]) + mul32x32_64(x[5], y[4]) + mul32x32_64(x[6], y[3]) + mul32x32_64(x[7], y[2]) + mul32x32_64(x[8], y[1]);+ f = (bignum256modm_element_t)c; q1[0] = (q1[0] | (f << 22)) & 0x3fffffff; q1[1] = (f >> 8) & 0x3fffff; c >>= 30; + c += mul32x32_64(x[2], y[8]) + mul32x32_64(x[3], y[7]) + mul32x32_64(x[4], y[6]) + mul32x32_64(x[5], y[5]) + mul32x32_64(x[6], y[4]) + mul32x32_64(x[7], y[3]) + mul32x32_64(x[8], y[2]);+ f = (bignum256modm_element_t)c; q1[1] = (q1[1] | (f << 22)) & 0x3fffffff; q1[2] = (f >> 8) & 0x3fffff; c >>= 30; + c += mul32x32_64(x[3], y[8]) + mul32x32_64(x[4], y[7]) + mul32x32_64(x[5], y[6]) + mul32x32_64(x[6], y[5]) + mul32x32_64(x[7], y[4]) + mul32x32_64(x[8], y[3]);+ f = (bignum256modm_element_t)c; q1[2] = (q1[2] | (f << 22)) & 0x3fffffff; q1[3] = (f >> 8) & 0x3fffff; c >>= 30; + c += mul32x32_64(x[4], y[8]) + mul32x32_64(x[5], y[7]) + mul32x32_64(x[6], y[6]) + mul32x32_64(x[7], y[5]) + mul32x32_64(x[8], y[4]);+ f = (bignum256modm_element_t)c; q1[3] = (q1[3] | (f << 22)) & 0x3fffffff; q1[4] = (f >> 8) & 0x3fffff; c >>= 30; + c += mul32x32_64(x[5], y[8]) + mul32x32_64(x[6], y[7]) + mul32x32_64(x[7], y[6]) + mul32x32_64(x[8], y[5]);+ f = (bignum256modm_element_t)c; q1[4] = (q1[4] | (f << 22)) & 0x3fffffff; q1[5] = (f >> 8) & 0x3fffff; c >>= 30;+ c += mul32x32_64(x[6], y[8]) + mul32x32_64(x[7], y[7]) + mul32x32_64(x[8], y[6]);+ f = (bignum256modm_element_t)c; q1[5] = (q1[5] | (f << 22)) & 0x3fffffff; q1[6] = (f >> 8) & 0x3fffff; c >>= 30;+ c += mul32x32_64(x[7], y[8]) + mul32x32_64(x[8], y[7]);+ f = (bignum256modm_element_t)c; q1[6] = (q1[6] | (f << 22)) & 0x3fffffff; q1[7] = (f >> 8) & 0x3fffff; c >>= 30;+ c += mul32x32_64(x[8], y[8]);+ f = (bignum256modm_element_t)c; q1[7] = (q1[7] | (f << 22)) & 0x3fffffff; q1[8] = (f >> 8) & 0x3fffff;++ barrett_reduce256_modm(r, q1, r1);+}++static void+expand256_modm(bignum256modm out, const unsigned char *in, size_t len) {+ unsigned char work[64] = {0};+ bignum256modm_element_t x[16];+ bignum256modm q1;++ memcpy(work, in, len);+ x[0] = U8TO32_LE(work + 0);+ x[1] = U8TO32_LE(work + 4);+ x[2] = U8TO32_LE(work + 8);+ x[3] = U8TO32_LE(work + 12);+ x[4] = U8TO32_LE(work + 16);+ x[5] = U8TO32_LE(work + 20);+ x[6] = U8TO32_LE(work + 24);+ x[7] = U8TO32_LE(work + 28);+ x[8] = U8TO32_LE(work + 32);+ x[9] = U8TO32_LE(work + 36);+ x[10] = U8TO32_LE(work + 40);+ x[11] = U8TO32_LE(work + 44);+ x[12] = U8TO32_LE(work + 48);+ x[13] = U8TO32_LE(work + 52);+ x[14] = U8TO32_LE(work + 56);+ x[15] = U8TO32_LE(work + 60);++ /* r1 = (x mod 256^(32+1)) = x mod (2^8)(31+1) = x & ((1 << 264) - 1) */+ out[0] = ( x[0]) & 0x3fffffff;+ out[1] = ((x[ 0] >> 30) | (x[ 1] << 2)) & 0x3fffffff;+ out[2] = ((x[ 1] >> 28) | (x[ 2] << 4)) & 0x3fffffff;+ out[3] = ((x[ 2] >> 26) | (x[ 3] << 6)) & 0x3fffffff;+ out[4] = ((x[ 3] >> 24) | (x[ 4] << 8)) & 0x3fffffff;+ out[5] = ((x[ 4] >> 22) | (x[ 5] << 10)) & 0x3fffffff;+ out[6] = ((x[ 5] >> 20) | (x[ 6] << 12)) & 0x3fffffff;+ out[7] = ((x[ 6] >> 18) | (x[ 7] << 14)) & 0x3fffffff;+ out[8] = ((x[ 7] >> 16) | (x[ 8] << 16)) & 0x00ffffff;++ /* 8*31 = 248 bits, no need to reduce */+ if (len < 32)+ return;++ /* q1 = x >> 248 = 264 bits = 9 30 bit elements */+ q1[0] = ((x[ 7] >> 24) | (x[ 8] << 8)) & 0x3fffffff;+ q1[1] = ((x[ 8] >> 22) | (x[ 9] << 10)) & 0x3fffffff;+ q1[2] = ((x[ 9] >> 20) | (x[10] << 12)) & 0x3fffffff;+ q1[3] = ((x[10] >> 18) | (x[11] << 14)) & 0x3fffffff;+ q1[4] = ((x[11] >> 16) | (x[12] << 16)) & 0x3fffffff;+ q1[5] = ((x[12] >> 14) | (x[13] << 18)) & 0x3fffffff;+ q1[6] = ((x[13] >> 12) | (x[14] << 20)) & 0x3fffffff;+ q1[7] = ((x[14] >> 10) | (x[15] << 22)) & 0x3fffffff;+ q1[8] = ((x[15] >> 8) ); ++ barrett_reduce256_modm(out, q1, out);+}++static void+expand_raw256_modm(bignum256modm out, const unsigned char in[32]) {+ bignum256modm_element_t x[8];++ x[0] = U8TO32_LE(in + 0);+ x[1] = U8TO32_LE(in + 4);+ x[2] = U8TO32_LE(in + 8);+ x[3] = U8TO32_LE(in + 12);+ x[4] = U8TO32_LE(in + 16);+ x[5] = U8TO32_LE(in + 20);+ x[6] = U8TO32_LE(in + 24);+ x[7] = U8TO32_LE(in + 28);++ out[0] = ( x[0]) & 0x3fffffff;+ out[1] = ((x[ 0] >> 30) | (x[ 1] << 2)) & 0x3fffffff;+ out[2] = ((x[ 1] >> 28) | (x[ 2] << 4)) & 0x3fffffff;+ out[3] = ((x[ 2] >> 26) | (x[ 3] << 6)) & 0x3fffffff;+ out[4] = ((x[ 3] >> 24) | (x[ 4] << 8)) & 0x3fffffff;+ out[5] = ((x[ 4] >> 22) | (x[ 5] << 10)) & 0x3fffffff;+ out[6] = ((x[ 5] >> 20) | (x[ 6] << 12)) & 0x3fffffff;+ out[7] = ((x[ 6] >> 18) | (x[ 7] << 14)) & 0x3fffffff;+ out[8] = ((x[ 7] >> 16) ) & 0x0000ffff;+}++static void+contract256_modm(unsigned char out[32], const bignum256modm in) {+ U32TO8_LE(out + 0, (in[0] ) | (in[1] << 30));+ U32TO8_LE(out + 4, (in[1] >> 2) | (in[2] << 28));+ U32TO8_LE(out + 8, (in[2] >> 4) | (in[3] << 26));+ U32TO8_LE(out + 12, (in[3] >> 6) | (in[4] << 24));+ U32TO8_LE(out + 16, (in[4] >> 8) | (in[5] << 22));+ U32TO8_LE(out + 20, (in[5] >> 10) | (in[6] << 20));+ U32TO8_LE(out + 24, (in[6] >> 12) | (in[7] << 18));+ U32TO8_LE(out + 28, (in[7] >> 14) | (in[8] << 16));+}++++static void+contract256_window4_modm(signed char r[64], const bignum256modm in) {+ char carry;+ signed char *quads = r;+ bignum256modm_element_t i, j, v;++ for (i = 0; i < 8; i += 2) {+ v = in[i];+ for (j = 0; j < 7; j++) {+ *quads++ = (v & 15);+ v >>= 4;+ }+ v |= (in[i+1] << 2);+ for (j = 0; j < 8; j++) {+ *quads++ = (v & 15);+ v >>= 4;+ }+ }+ v = in[8];+ *quads++ = (v & 15); v >>= 4;+ *quads++ = (v & 15); v >>= 4;+ *quads++ = (v & 15); v >>= 4;+ *quads++ = (v & 15); v >>= 4;++ /* making it signed */+ carry = 0;+ for(i = 0; i < 63; i++) {+ r[i] += carry;+ r[i+1] += (r[i] >> 4);+ r[i] &= 15;+ carry = (r[i] >> 3);+ r[i] -= (carry << 4);+ }+ r[63] += carry;+}++static void+contract256_slidingwindow_modm(signed char r[256], const bignum256modm s, int windowsize) {+ int i,j,k,b;+ int m = (1 << (windowsize - 1)) - 1, soplen = 256;+ signed char *bits = r;+ bignum256modm_element_t v;++ /* first put the binary expansion into r */+ for (i = 0; i < 8; i++) {+ v = s[i];+ for (j = 0; j < 30; j++, v >>= 1)+ *bits++ = (v & 1);+ }+ v = s[8];+ for (j = 0; j < 16; j++, v >>= 1)+ *bits++ = (v & 1);++ /* Making it sliding window */+ for (j = 0; j < soplen; j++) {+ if (!r[j])+ continue;++ for (b = 1; (b < (soplen - j)) && (b <= 6); b++) {+ if ((r[j] + (r[j + b] << b)) <= m) {+ r[j] += r[j + b] << b;+ r[j + b] = 0;+ } else if ((r[j] - (r[j + b] << b)) >= -m) {+ r[j] -= r[j + b] << b;+ for (k = j + b; k < soplen; k++) {+ if (!r[k]) {+ r[k] = 1;+ break;+ }+ r[k] = 0;+ }+ } else if (r[j + b]) {+ break;+ }+ }+ }+}+++/*+ helpers for batch verifcation, are allowed to be vartime+*/++/* out = a - b, a must be larger than b */+static void+sub256_modm_batch(bignum256modm out, const bignum256modm a, const bignum256modm b, size_t limbsize) {+ size_t i = 0;+ bignum256modm_element_t carry = 0;+ switch (limbsize) {+ case 8: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++;+ case 7: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++;+ case 6: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++;+ case 5: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++;+ case 4: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++;+ case 3: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++;+ case 2: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++;+ case 1: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 31); out[i] &= 0x3fffffff; i++;+ case 0: + default: out[i] = (a[i] - b[i]) - carry;+ }+}+++/* is a < b */+static int+lt256_modm_batch(const bignum256modm a, const bignum256modm b, size_t limbsize) {+ switch (limbsize) {+ case 8: if (a[8] > b[8]) return 0; if (a[8] < b[8]) return 1;+ case 7: if (a[7] > b[7]) return 0; if (a[7] < b[7]) return 1;+ case 6: if (a[6] > b[6]) return 0; if (a[6] < b[6]) return 1;+ case 5: if (a[5] > b[5]) return 0; if (a[5] < b[5]) return 1;+ case 4: if (a[4] > b[4]) return 0; if (a[4] < b[4]) return 1;+ case 3: if (a[3] > b[3]) return 0; if (a[3] < b[3]) return 1;+ case 2: if (a[2] > b[2]) return 0; if (a[2] < b[2]) return 1;+ case 1: if (a[1] > b[1]) return 0; if (a[1] < b[1]) return 1;+ case 0: if (a[0] > b[0]) return 0; if (a[0] < b[0]) return 1;+ }+ return 0;+}++/* is a <= b */+static int+lte256_modm_batch(const bignum256modm a, const bignum256modm b, size_t limbsize) {+ switch (limbsize) {+ case 8: if (a[8] > b[8]) return 0; if (a[8] < b[8]) return 1;+ case 7: if (a[7] > b[7]) return 0; if (a[7] < b[7]) return 1;+ case 6: if (a[6] > b[6]) return 0; if (a[6] < b[6]) return 1;+ case 5: if (a[5] > b[5]) return 0; if (a[5] < b[5]) return 1;+ case 4: if (a[4] > b[4]) return 0; if (a[4] < b[4]) return 1;+ case 3: if (a[3] > b[3]) return 0; if (a[3] < b[3]) return 1;+ case 2: if (a[2] > b[2]) return 0; if (a[2] < b[2]) return 1;+ case 1: if (a[1] > b[1]) return 0; if (a[1] < b[1]) return 1;+ case 0: if (a[0] > b[0]) return 0; if (a[0] < b[0]) return 1;+ }+ return 1;+}+++/* is a == 0 */+static int+iszero256_modm_batch(const bignum256modm a) {+ size_t i;+ for (i = 0; i < 9; i++)+ if (a[i])+ return 0;+ return 1;+}++/* is a == 1 */+static int+isone256_modm_batch(const bignum256modm a) {+ size_t i;+ if (a[0] != 1)+ return 0;+ for (i = 1; i < 9; i++)+ if (a[i])+ return 0;+ return 1;+}++/* can a fit in to (at most) 128 bits */+static int+isatmost128bits256_modm_batch(const bignum256modm a) {+ uint32_t mask =+ ((a[8] ) | /* 16 */+ (a[7] ) | /* 46 */+ (a[6] ) | /* 76 */+ (a[5] ) | /* 106 */+ (a[4] & 0x3fffff00)); /* 128 */++ return (mask == 0);+}
+ cbits/ed25519/modm-donna-64bit.h view
@@ -0,0 +1,361 @@+/*+ Public domain by Andrew M. <liquidsun@gmail.com>+*/+++/*+ Arithmetic modulo the group order n = 2^252 + 27742317777372353535851937790883648493 = 7237005577332262213973186563042994240857116359379907606001950938285454250989++ k = 32+ b = 1 << 8 = 256+ m = 2^252 + 27742317777372353535851937790883648493 = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed+ mu = floor( b^(k*2) / m ) = 0xfffffffffffffffffffffffffffffffeb2106215d086329a7ed9ce5a30a2c131b+*/++#define bignum256modm_bits_per_limb 56+#define bignum256modm_limb_size 5++typedef uint64_t bignum256modm_element_t;+typedef bignum256modm_element_t bignum256modm[5];++static const bignum256modm modm_m = {+ 0x12631a5cf5d3ed, + 0xf9dea2f79cd658, + 0x000000000014de, + 0x00000000000000, + 0x00000010000000+};++static const bignum256modm modm_mu = {+ 0x9ce5a30a2c131b,+ 0x215d086329a7ed,+ 0xffffffffeb2106,+ 0xffffffffffffff,+ 0x00000fffffffff+};++static bignum256modm_element_t+lt_modm(bignum256modm_element_t a, bignum256modm_element_t b) {+ return (a - b) >> 63;+}++static void+reduce256_modm(bignum256modm r) {+ bignum256modm t;+ bignum256modm_element_t b = 0, pb, mask;++ /* t = r - m */+ pb = 0;+ pb += modm_m[0]; b = lt_modm(r[0], pb); t[0] = (r[0] - pb + (b << 56)); pb = b;+ pb += modm_m[1]; b = lt_modm(r[1], pb); t[1] = (r[1] - pb + (b << 56)); pb = b;+ pb += modm_m[2]; b = lt_modm(r[2], pb); t[2] = (r[2] - pb + (b << 56)); pb = b;+ pb += modm_m[3]; b = lt_modm(r[3], pb); t[3] = (r[3] - pb + (b << 56)); pb = b;+ pb += modm_m[4]; b = lt_modm(r[4], pb); t[4] = (r[4] - pb + (b << 32)); ++ /* keep r if r was smaller than m */+ mask = b - 1;++ r[0] ^= mask & (r[0] ^ t[0]);+ r[1] ^= mask & (r[1] ^ t[1]);+ r[2] ^= mask & (r[2] ^ t[2]);+ r[3] ^= mask & (r[3] ^ t[3]);+ r[4] ^= mask & (r[4] ^ t[4]);+}++static void+barrett_reduce256_modm(bignum256modm r, const bignum256modm q1, const bignum256modm r1) {+ bignum256modm q3, r2;+ uint128_t c, mul;+ bignum256modm_element_t f, b, pb;++ /* q1 = x >> 248 = 264 bits = 5 56 bit elements+ q2 = mu * q1+ q3 = (q2 / 256(32+1)) = q2 / (2^8)^(32+1) = q2 >> 264 */+ mul64x64_128(c, modm_mu[0], q1[3]) mul64x64_128(mul, modm_mu[3], q1[0]) add128(c, mul) mul64x64_128(mul, modm_mu[1], q1[2]) add128(c, mul) mul64x64_128(mul, modm_mu[2], q1[1]) add128(c, mul) shr128(f, c, 56);+ mul64x64_128(c, modm_mu[0], q1[4]) add128_64(c, f) mul64x64_128(mul, modm_mu[4], q1[0]) add128(c, mul) mul64x64_128(mul, modm_mu[3], q1[1]) add128(c, mul) mul64x64_128(mul, modm_mu[1], q1[3]) add128(c, mul) mul64x64_128(mul, modm_mu[2], q1[2]) add128(c, mul)+ f = lo128(c); q3[0] = (f >> 40) & 0xffff; shr128(f, c, 56);+ mul64x64_128(c, modm_mu[4], q1[1]) add128_64(c, f) mul64x64_128(mul, modm_mu[1], q1[4]) add128(c, mul) mul64x64_128(mul, modm_mu[2], q1[3]) add128(c, mul) mul64x64_128(mul, modm_mu[3], q1[2]) add128(c, mul)+ f = lo128(c); q3[0] |= (f << 16) & 0xffffffffffffff; q3[1] = (f >> 40) & 0xffff; shr128(f, c, 56);+ mul64x64_128(c, modm_mu[4], q1[2]) add128_64(c, f) mul64x64_128(mul, modm_mu[2], q1[4]) add128(c, mul) mul64x64_128(mul, modm_mu[3], q1[3]) add128(c, mul)+ f = lo128(c); q3[1] |= (f << 16) & 0xffffffffffffff; q3[2] = (f >> 40) & 0xffff; shr128(f, c, 56);+ mul64x64_128(c, modm_mu[4], q1[3]) add128_64(c, f) mul64x64_128(mul, modm_mu[3], q1[4]) add128(c, mul)+ f = lo128(c); q3[2] |= (f << 16) & 0xffffffffffffff; q3[3] = (f >> 40) & 0xffff; shr128(f, c, 56);+ mul64x64_128(c, modm_mu[4], q1[4]) add128_64(c, f)+ f = lo128(c); q3[3] |= (f << 16) & 0xffffffffffffff; q3[4] = (f >> 40) & 0xffff; shr128(f, c, 56);+ q3[4] |= (f << 16);++ mul64x64_128(c, modm_m[0], q3[0]) + r2[0] = lo128(c) & 0xffffffffffffff; shr128(f, c, 56);+ mul64x64_128(c, modm_m[0], q3[1]) add128_64(c, f) mul64x64_128(mul, modm_m[1], q3[0]) add128(c, mul)+ r2[1] = lo128(c) & 0xffffffffffffff; shr128(f, c, 56);+ mul64x64_128(c, modm_m[0], q3[2]) add128_64(c, f) mul64x64_128(mul, modm_m[2], q3[0]) add128(c, mul) mul64x64_128(mul, modm_m[1], q3[1]) add128(c, mul)+ r2[2] = lo128(c) & 0xffffffffffffff; shr128(f, c, 56);+ mul64x64_128(c, modm_m[0], q3[3]) add128_64(c, f) mul64x64_128(mul, modm_m[3], q3[0]) add128(c, mul) mul64x64_128(mul, modm_m[1], q3[2]) add128(c, mul) mul64x64_128(mul, modm_m[2], q3[1]) add128(c, mul)+ r2[3] = lo128(c) & 0xffffffffffffff; shr128(f, c, 56);+ mul64x64_128(c, modm_m[0], q3[4]) add128_64(c, f) mul64x64_128(mul, modm_m[4], q3[0]) add128(c, mul) mul64x64_128(mul, modm_m[3], q3[1]) add128(c, mul) mul64x64_128(mul, modm_m[1], q3[3]) add128(c, mul) mul64x64_128(mul, modm_m[2], q3[2]) add128(c, mul)+ r2[4] = lo128(c) & 0x0000ffffffffff;++ pb = 0;+ pb += r2[0]; b = lt_modm(r1[0], pb); r[0] = (r1[0] - pb + (b << 56)); pb = b;+ pb += r2[1]; b = lt_modm(r1[1], pb); r[1] = (r1[1] - pb + (b << 56)); pb = b;+ pb += r2[2]; b = lt_modm(r1[2], pb); r[2] = (r1[2] - pb + (b << 56)); pb = b;+ pb += r2[3]; b = lt_modm(r1[3], pb); r[3] = (r1[3] - pb + (b << 56)); pb = b;+ pb += r2[4]; b = lt_modm(r1[4], pb); r[4] = (r1[4] - pb + (b << 40)); ++ reduce256_modm(r);+ reduce256_modm(r);+}+++static void+add256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) {+ bignum256modm_element_t c;++ c = x[0] + y[0]; r[0] = c & 0xffffffffffffff; c >>= 56;+ c += x[1] + y[1]; r[1] = c & 0xffffffffffffff; c >>= 56;+ c += x[2] + y[2]; r[2] = c & 0xffffffffffffff; c >>= 56;+ c += x[3] + y[3]; r[3] = c & 0xffffffffffffff; c >>= 56;+ c += x[4] + y[4]; r[4] = c;++ reduce256_modm(r);+}++static void+mul256_modm(bignum256modm r, const bignum256modm x, const bignum256modm y) {+ bignum256modm q1, r1;+ uint128_t c, mul;+ bignum256modm_element_t f;++ mul64x64_128(c, x[0], y[0])+ f = lo128(c); r1[0] = f & 0xffffffffffffff; shr128(f, c, 56);+ mul64x64_128(c, x[0], y[1]) add128_64(c, f) mul64x64_128(mul, x[1], y[0]) add128(c, mul) + f = lo128(c); r1[1] = f & 0xffffffffffffff; shr128(f, c, 56);+ mul64x64_128(c, x[0], y[2]) add128_64(c, f) mul64x64_128(mul, x[2], y[0]) add128(c, mul) mul64x64_128(mul, x[1], y[1]) add128(c, mul) + f = lo128(c); r1[2] = f & 0xffffffffffffff; shr128(f, c, 56);+ mul64x64_128(c, x[0], y[3]) add128_64(c, f) mul64x64_128(mul, x[3], y[0]) add128(c, mul) mul64x64_128(mul, x[1], y[2]) add128(c, mul) mul64x64_128(mul, x[2], y[1]) add128(c, mul) + f = lo128(c); r1[3] = f & 0xffffffffffffff; shr128(f, c, 56);+ mul64x64_128(c, x[0], y[4]) add128_64(c, f) mul64x64_128(mul, x[4], y[0]) add128(c, mul) mul64x64_128(mul, x[3], y[1]) add128(c, mul) mul64x64_128(mul, x[1], y[3]) add128(c, mul) mul64x64_128(mul, x[2], y[2]) add128(c, mul) + f = lo128(c); r1[4] = f & 0x0000ffffffffff; q1[0] = (f >> 24) & 0xffffffff; shr128(f, c, 56);+ mul64x64_128(c, x[4], y[1]) add128_64(c, f) mul64x64_128(mul, x[1], y[4]) add128(c, mul) mul64x64_128(mul, x[2], y[3]) add128(c, mul) mul64x64_128(mul, x[3], y[2]) add128(c, mul) + f = lo128(c); q1[0] |= (f << 32) & 0xffffffffffffff; q1[1] = (f >> 24) & 0xffffffff; shr128(f, c, 56);+ mul64x64_128(c, x[4], y[2]) add128_64(c, f) mul64x64_128(mul, x[2], y[4]) add128(c, mul) mul64x64_128(mul, x[3], y[3]) add128(c, mul) + f = lo128(c); q1[1] |= (f << 32) & 0xffffffffffffff; q1[2] = (f >> 24) & 0xffffffff; shr128(f, c, 56);+ mul64x64_128(c, x[4], y[3]) add128_64(c, f) mul64x64_128(mul, x[3], y[4]) add128(c, mul) + f = lo128(c); q1[2] |= (f << 32) & 0xffffffffffffff; q1[3] = (f >> 24) & 0xffffffff; shr128(f, c, 56);+ mul64x64_128(c, x[4], y[4]) add128_64(c, f)+ f = lo128(c); q1[3] |= (f << 32) & 0xffffffffffffff; q1[4] = (f >> 24) & 0xffffffff; shr128(f, c, 56);+ q1[4] |= (f << 32);++ barrett_reduce256_modm(r, q1, r1);+}++static void+expand256_modm(bignum256modm out, const unsigned char *in, size_t len) {+ unsigned char work[64] = {0};+ bignum256modm_element_t x[16];+ bignum256modm q1;++ memcpy(work, in, len);+ x[0] = U8TO64_LE(work + 0);+ x[1] = U8TO64_LE(work + 8);+ x[2] = U8TO64_LE(work + 16);+ x[3] = U8TO64_LE(work + 24);+ x[4] = U8TO64_LE(work + 32);+ x[5] = U8TO64_LE(work + 40);+ x[6] = U8TO64_LE(work + 48);+ x[7] = U8TO64_LE(work + 56);++ /* r1 = (x mod 256^(32+1)) = x mod (2^8)(31+1) = x & ((1 << 264) - 1) */+ out[0] = ( x[0]) & 0xffffffffffffff;+ out[1] = ((x[ 0] >> 56) | (x[ 1] << 8)) & 0xffffffffffffff;+ out[2] = ((x[ 1] >> 48) | (x[ 2] << 16)) & 0xffffffffffffff;+ out[3] = ((x[ 2] >> 40) | (x[ 3] << 24)) & 0xffffffffffffff;+ out[4] = ((x[ 3] >> 32) | (x[ 4] << 32)) & 0x0000ffffffffff;++ /* under 252 bits, no need to reduce */+ if (len < 32)+ return;++ /* q1 = x >> 248 = 264 bits */+ q1[0] = ((x[ 3] >> 56) | (x[ 4] << 8)) & 0xffffffffffffff;+ q1[1] = ((x[ 4] >> 48) | (x[ 5] << 16)) & 0xffffffffffffff;+ q1[2] = ((x[ 5] >> 40) | (x[ 6] << 24)) & 0xffffffffffffff;+ q1[3] = ((x[ 6] >> 32) | (x[ 7] << 32)) & 0xffffffffffffff;+ q1[4] = ((x[ 7] >> 24) );++ barrett_reduce256_modm(out, q1, out);+}++static void+expand_raw256_modm(bignum256modm out, const unsigned char in[32]) {+ bignum256modm_element_t x[4];++ x[0] = U8TO64_LE(in + 0);+ x[1] = U8TO64_LE(in + 8);+ x[2] = U8TO64_LE(in + 16);+ x[3] = U8TO64_LE(in + 24);++ out[0] = ( x[0]) & 0xffffffffffffff;+ out[1] = ((x[ 0] >> 56) | (x[ 1] << 8)) & 0xffffffffffffff;+ out[2] = ((x[ 1] >> 48) | (x[ 2] << 16)) & 0xffffffffffffff;+ out[3] = ((x[ 2] >> 40) | (x[ 3] << 24)) & 0xffffffffffffff;+ out[4] = ((x[ 3] >> 32) ) & 0x000000ffffffff;+}++static void+contract256_modm(unsigned char out[32], const bignum256modm in) {+ U64TO8_LE(out + 0, (in[0] ) | (in[1] << 56));+ U64TO8_LE(out + 8, (in[1] >> 8) | (in[2] << 48));+ U64TO8_LE(out + 16, (in[2] >> 16) | (in[3] << 40));+ U64TO8_LE(out + 24, (in[3] >> 24) | (in[4] << 32));+}++static void+contract256_window4_modm(signed char r[64], const bignum256modm in) {+ char carry;+ signed char *quads = r;+ bignum256modm_element_t i, j, v, m;++ for (i = 0; i < 5; i++) {+ v = in[i];+ m = (i == 4) ? 8 : 14;+ for (j = 0; j < m; j++) {+ *quads++ = (v & 15);+ v >>= 4;+ }+ }++ /* making it signed */+ carry = 0;+ for(i = 0; i < 63; i++) {+ r[i] += carry;+ r[i+1] += (r[i] >> 4);+ r[i] &= 15;+ carry = (r[i] >> 3);+ r[i] -= (carry << 4);+ }+ r[63] += carry;+}++static void+contract256_slidingwindow_modm(signed char r[256], const bignum256modm s, int windowsize) {+ int i,j,k,b;+ int m = (1 << (windowsize - 1)) - 1, soplen = 256;+ signed char *bits = r;+ bignum256modm_element_t v;++ /* first put the binary expansion into r */+ for (i = 0; i < 4; i++) {+ v = s[i];+ for (j = 0; j < 56; j++, v >>= 1)+ *bits++ = (v & 1);+ }+ v = s[4];+ for (j = 0; j < 32; j++, v >>= 1)+ *bits++ = (v & 1);++ /* Making it sliding window */+ for (j = 0; j < soplen; j++) {+ if (!r[j])+ continue;++ for (b = 1; (b < (soplen - j)) && (b <= 6); b++) {+ if ((r[j] + (r[j + b] << b)) <= m) {+ r[j] += r[j + b] << b;+ r[j + b] = 0;+ } else if ((r[j] - (r[j + b] << b)) >= -m) {+ r[j] -= r[j + b] << b;+ for (k = j + b; k < soplen; k++) {+ if (!r[k]) {+ r[k] = 1;+ break;+ }+ r[k] = 0;+ }+ } else if (r[j + b]) {+ break;+ }+ }+ }+}++/*+ helpers for batch verifcation, are allowed to be vartime+*/++/* out = a - b, a must be larger than b */+static void+sub256_modm_batch(bignum256modm out, const bignum256modm a, const bignum256modm b, size_t limbsize) {+ size_t i = 0;+ bignum256modm_element_t carry = 0;+ switch (limbsize) {+ case 4: out[i] = (a[i] - b[i]) ; carry = (out[i] >> 63); out[i] &= 0xffffffffffffff; i++;+ case 3: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 63); out[i] &= 0xffffffffffffff; i++;+ case 2: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 63); out[i] &= 0xffffffffffffff; i++;+ case 1: out[i] = (a[i] - b[i]) - carry; carry = (out[i] >> 63); out[i] &= 0xffffffffffffff; i++;+ case 0: + default: out[i] = (a[i] - b[i]) - carry;+ }+}+++/* is a < b */+static int+lt256_modm_batch(const bignum256modm a, const bignum256modm b, size_t limbsize) {+ size_t i = 0;+ bignum256modm_element_t t, carry = 0;+ switch (limbsize) {+ case 4: t = (a[i] - b[i]) ; carry = (t >> 63); i++;+ case 3: t = (a[i] - b[i]) - carry; carry = (t >> 63); i++;+ case 2: t = (a[i] - b[i]) - carry; carry = (t >> 63); i++;+ case 1: t = (a[i] - b[i]) - carry; carry = (t >> 63); i++;+ case 0: t = (a[i] - b[i]) - carry; carry = (t >> 63);+ }+ return (int)carry;+}++/* is a <= b */+static int+lte256_modm_batch(const bignum256modm a, const bignum256modm b, size_t limbsize) {+ size_t i = 0;+ bignum256modm_element_t t, carry = 0;+ switch (limbsize) {+ case 4: t = (b[i] - a[i]) ; carry = (t >> 63); i++;+ case 3: t = (b[i] - a[i]) - carry; carry = (t >> 63); i++;+ case 2: t = (b[i] - a[i]) - carry; carry = (t >> 63); i++;+ case 1: t = (b[i] - a[i]) - carry; carry = (t >> 63); i++;+ case 0: t = (b[i] - a[i]) - carry; carry = (t >> 63);+ }+ return (int)!carry;+}++/* is a == 0 */+static int+iszero256_modm_batch(const bignum256modm a) {+ size_t i;+ for (i = 0; i < 5; i++)+ if (a[i])+ return 0;+ return 1;+}++/* is a == 1 */+static int+isone256_modm_batch(const bignum256modm a) {+ size_t i;+ for (i = 0; i < 5; i++)+ if (a[i] != ((i) ? 0 : 1))+ return 0;+ return 1;+}++/* can a fit in to (at most) 128 bits */+static int+isatmost128bits256_modm_batch(const bignum256modm a) {+ uint64_t mask =+ ((a[4] ) | /* 32 */+ (a[3] ) | /* 88 */+ (a[2] & 0xffffffffff0000));++ return (mask == 0);+}
+ cbits/encrypted_sign.c view
@@ -0,0 +1,401 @@+#include <assert.h>+#include <stdint.h>+#include <string.h>++#include <ed25519.h>+#include <hmac.h>++#include "crypton_pbkdf2.h"++typedef uint8_t crypton_chacha_context[131];++extern void crypton_chacha_init(crypton_chacha_context *ctx, uint8_t nb_rounds, uint32_t keylen, const uint8_t *key, uint32_t ivlen, const uint8_t *iv);+extern void crypton_chacha_combine(uint8_t *dst, crypton_chacha_context *st, const uint8_t *src, uint32_t bytes);++void clear(void *buf, uint32_t const sz)+{+ /* FIXME - HERE we need to make sure the compiler is not going to remove the call */+ memset(buf, 0, sz);+}++#define NB_ITERATIONS 15000++static+void stretch(uint8_t *buf, uint32_t const buf_len, uint8_t const *pass, uint32_t const pass_len)+{+ const uint8_t salt[] = "encrypted wallet salt";+ assert(pass_len > 0);+ crypton_fastpbkdf2_hmac_sha512(pass, pass_len, salt, sizeof(salt), NB_ITERATIONS, buf, buf_len);+}++#define SYM_KEY_SIZE 32+#define SYM_NONCE_SIZE 8+#define SYM_BUF_SIZE (SYM_KEY_SIZE+SYM_NONCE_SIZE)++#define SECRET_KEY_SEED_SIZE 32+#define ENCRYPTED_KEY_SIZE 64+#define PUBLIC_KEY_SIZE 32+#define CHAIN_CODE_SIZE 32++#define FULL_KEY_SIZE (ENCRYPTED_KEY_SIZE + PUBLIC_KEY_SIZE + CHAIN_CODE_SIZE)++typedef struct {+ uint8_t ekey[ENCRYPTED_KEY_SIZE];+ uint8_t pkey[PUBLIC_KEY_SIZE];+ uint8_t cc[CHAIN_CODE_SIZE];+} encrypted_key;++typedef struct {+ uint8_t pkey[PUBLIC_KEY_SIZE];+ uint8_t cc[CHAIN_CODE_SIZE];+} public_key;++static void memory_combine(uint8_t const *pass, uint32_t const pass_len, uint8_t const *source, uint8_t *dest, uint32_t sz)+{+ uint8_t buf[SYM_BUF_SIZE];+ crypton_chacha_context ctx;+ static uint8_t const CHACHA_NB_ROUNDS = 20;++ if (pass_len) {+ memset(&ctx, 0, sizeof(crypton_chacha_context));++ /* generate BUF_SIZE bytes where first KEY_SIZE bytes is the key and NONCE_SIZE remaining bytes the nonce */+ stretch(buf, SYM_BUF_SIZE, pass, pass_len);+ crypton_chacha_init(&ctx, CHACHA_NB_ROUNDS, SYM_KEY_SIZE, buf, SYM_NONCE_SIZE, buf + SYM_KEY_SIZE);+ clear(buf, SYM_BUF_SIZE);+ crypton_chacha_combine(dest, &ctx, source, sz);+ clear(&ctx, sizeof(crypton_chacha_context));+ } else {+ memcpy(dest, source, sz);+ }+}++static void unencrypt_start+ (uint8_t const* pass,+ uint32_t const pass_len,+ encrypted_key const *encrypted_key /* in */,+ ed25519_secret_key decrypted_key /* out */)+{+ memory_combine(pass, pass_len, encrypted_key->ekey, decrypted_key, ENCRYPTED_KEY_SIZE);+}++static void unencrypt_stop(ed25519_secret_key decrypted_key)+{+ clear(decrypted_key, sizeof(ed25519_secret_key));+}++static void wallet_encrypted_initialize+ (uint8_t const *pass, uint32_t const pass_len,+ const ed25519_secret_key secret_key,+ const uint8_t cc[CHAIN_CODE_SIZE],+ encrypted_key *encrypted_key)+{+ ed25519_public_key pub_key;++ cardano_crypto_ed25519_publickey(secret_key, pub_key);++ memory_combine(pass, pass_len, secret_key, encrypted_key->ekey, ENCRYPTED_KEY_SIZE);+ memcpy(encrypted_key->pkey, pub_key, PUBLIC_KEY_SIZE);+ memcpy(encrypted_key->cc, cc, CHAIN_CODE_SIZE);+}+++int wallet_encrypted_from_secret+ (uint8_t const *pass, uint32_t const pass_len,+ const uint8_t seed[SECRET_KEY_SEED_SIZE],+ const uint8_t cc[CHAIN_CODE_SIZE],+ encrypted_key *encrypted_key)+{+ ed25519_secret_key secret_key;+ if (cardano_crypto_ed25519_extend(seed, secret_key))+ return 1;+ wallet_encrypted_initialize(pass, pass_len, secret_key, cc, encrypted_key);+ return 0;+}++int wallet_encrypted_new_from_mkg+ (uint8_t const *pass, uint32_t const pass_len,+ const uint8_t master_key[96],+ encrypted_key *encrypted_key)+{+ ed25519_secret_key secret_key;+ memcpy(secret_key, master_key, 64);+ secret_key[0] &= 248; /* clears the bottom 3 bits */+ secret_key[31] &= 0x1F; /* clears the 3 highest bits */+ secret_key[31] |= 64; /* set the 2nd highest bit */++ wallet_encrypted_initialize(pass, pass_len, secret_key, master_key + 64, encrypted_key);+ return 0;+}++void wallet_encrypted_sign+ (encrypted_key const *encrypted_key, uint8_t const* pass, uint32_t const pass_len,+ uint8_t const *data, uint32_t const data_len,+ ed25519_signature signature)+{+ ed25519_secret_key priv_key;+ ed25519_public_key pub_key;++ unencrypt_start(pass, pass_len, encrypted_key, priv_key);+ cardano_crypto_ed25519_publickey(priv_key, pub_key);+ cardano_crypto_ed25519_sign(data, data_len, encrypted_key->cc, CHAIN_CODE_SIZE, priv_key, pub_key, signature);+ unencrypt_stop(priv_key);+}++void wallet_encrypted_change_pass+ (encrypted_key const *in, uint8_t const *old_pass, uint32_t const old_pass_len,+ uint8_t const *new_pass, uint32_t const new_pass_len, encrypted_key *out)+{+ ed25519_secret_key priv_key;+ unencrypt_start(old_pass, old_pass_len, in, priv_key);+ memory_combine(new_pass, new_pass_len, priv_key, out->ekey, ENCRYPTED_KEY_SIZE);+ unencrypt_stop(priv_key);+ memcpy(out->pkey, in->pkey, PUBLIC_KEY_SIZE);+ memcpy(out->cc, in->cc, CHAIN_CODE_SIZE);+}++DECL_HMAC(sha512,+ SHA512_BLOCK_SIZE,+ SHA512_DIGEST_SIZE,+ struct sha512_ctx,+ crypton_sha512_init,+ crypton_sha512_update,+ crypton_sha512_finalize);++typedef enum {+ DERIVATION_V1 = 1,+ DERIVATION_V2 = 2,+} derivation_scheme_mode;++static void multiply8_v1(uint8_t *dst, uint8_t *src, int bytes)+{+ int i;+ uint8_t prev_acc = 0;+ for (i = 0; i < bytes; i++) {+ dst[i] = (src[i] << 3) + (prev_acc & 0x8);+ prev_acc = src[i] >> 5;+ }+}++static void multiply8_v2(uint8_t *dst, uint8_t *src, int bytes)+{+ int i;+ uint8_t prev_acc = 0;+ for (i = 0; i < bytes; i++) {+ dst[i] = (src[i] << 3) + (prev_acc & 0x7);+ prev_acc = src[i] >> 5;+ }+ dst[bytes] = src[bytes-1] >> 5;+}++static void add_256bits_v1(uint8_t *dst, uint8_t *src1, uint8_t *src2)+{+ int i;+ for (i = 0; i < 32; i++) {+ uint8_t a = src1[i];+ uint8_t b = src2[i];+ uint16_t r = a + b;+ dst[i] = r & 0xff;+ }+}++static void add_256bits_v2(uint8_t *dst, uint8_t *src1, uint8_t *src2)+{+ int i; uint8_t carry = 0;+ for (i = 0; i < 32; i++) {+ uint8_t a = src1[i];+ uint8_t b = src2[i];+ uint16_t r = (uint16_t) a + (uint16_t) b + (uint16_t) carry;+ dst[i] = r & 0xff;+ carry = (r >= 0x100) ? 1 : 0;+ }+}++#define TAG_DERIVE_Z_NORMAL "\x2"+#define TAG_DERIVE_Z_HARDENED "\x0"+#define TAG_DERIVE_CC_NORMAL "\x3"+#define TAG_DERIVE_CC_HARDENED "\x1"++static int index_is_hardened(uint32_t index)+{+ return (index & (1 << 31));+}++/* sk1 is zl8 and contains only 29 bytes of active data,+ * so it's not going to overflow when adding to sk2 */+void scalar_add_no_overflow(const ed25519_secret_key sk1, const ed25519_secret_key sk2, ed25519_secret_key res)+{+ uint16_t r = 0; int i;+ for (i = 0; i < 32; i++) {+ r = (uint16_t) sk1[i] + (uint16_t) sk2[i] + r;+ res[i] = (uint8_t) r;+ r >>= 8;+ }+}++static void serialize_index32(uint8_t *out, uint32_t index, derivation_scheme_mode mode)+{+ switch (mode) {+ case DERIVATION_V1: /* BIG ENDIAN */+ out[0] = index >> 24;+ out[1] = index >> 16;+ out[2] = index >> 8;+ out[3] = index;+ break;+ case DERIVATION_V2: /* LITTLE ENDIAN */+ out[3] = index >> 24;+ out[2] = index >> 16;+ out[1] = index >> 8;+ out[0] = index;+ break;+ }+}++static void add_left(ed25519_secret_key res_key, uint8_t *z, ed25519_secret_key priv_key, derivation_scheme_mode mode)+{+ ed25519_secret_key zl8;++ memset(zl8, 0, 64);+ switch (mode) {+ case DERIVATION_V1:+ /* get 8 * Zl */+ multiply8_v1(zl8, z, 32);++ /* Kl = 8*Zl + parent(K)l */+ cardano_crypto_ed25519_scalar_add(zl8, priv_key, res_key);+ break;+ case DERIVATION_V2:+ /* get 8 * Zl */+ multiply8_v2(zl8, z, 28);+ /* Kl = 8*Zl + parent(K)l */+ scalar_add_no_overflow(zl8, priv_key, res_key);+ break;+ }+}++static void add_right(ed25519_secret_key res_key, uint8_t *z, ed25519_secret_key priv_key, derivation_scheme_mode mode)+{+ switch (mode) {+ case DERIVATION_V1:+ add_256bits_v1(res_key + 32, z+32, priv_key+32);+ break;+ case DERIVATION_V2:+ add_256bits_v2(res_key + 32, z+32, priv_key+32);+ break;+ }+}++static void add_left_public(uint8_t *out, uint8_t *z, uint8_t *in, derivation_scheme_mode mode)+{+ ed25519_secret_key zl8;+ ed25519_public_key pub_zl8;++ memset(zl8, 0, 64);+ switch (mode) {+ case DERIVATION_V1:+ multiply8_v1(zl8, z, 32);+ break;+ case DERIVATION_V2:+ multiply8_v2(zl8, z, 28);+ break;+ }++ /* Kl = 8*Zl*B + Al */+ cardano_crypto_ed25519_publickey(zl8, pub_zl8);+ cardano_crypto_ed25519_point_add(pub_zl8, in, out);+}++void wallet_encrypted_derive_private+ (encrypted_key const *in,+ uint8_t const *pass, uint32_t const pass_len,+ uint32_t index,+ encrypted_key *out,+ derivation_scheme_mode mode)+{+ ed25519_secret_key priv_key;+ ed25519_secret_key res_key;+ HMAC_sha512_ctx hmac_ctx;+ uint8_t idxBuf[4];+ uint8_t z[64];+ uint8_t hmac_out[64];++ serialize_index32(idxBuf, index, mode);++ unencrypt_start(pass, pass_len, in, priv_key);++ /* calculate Z */+ HMAC_sha512_init(&hmac_ctx, in->cc, CHAIN_CODE_SIZE);+ if (index_is_hardened(index)) {+ HMAC_sha512_update(&hmac_ctx, TAG_DERIVE_Z_HARDENED, 1);+ HMAC_sha512_update(&hmac_ctx, priv_key, ENCRYPTED_KEY_SIZE);+ } else {+ HMAC_sha512_update(&hmac_ctx, TAG_DERIVE_Z_NORMAL, 1);+ HMAC_sha512_update(&hmac_ctx, in->pkey, PUBLIC_KEY_SIZE);+ }+ HMAC_sha512_update(&hmac_ctx, idxBuf, 4);+ HMAC_sha512_final(&hmac_ctx, z);++ add_left(res_key, z, priv_key, mode);++ /* Kr = Zr + parent(K)r */+ add_right(res_key, z, priv_key, mode);++ /* calculate the new chain code */+ HMAC_sha512_init(&hmac_ctx, in->cc, CHAIN_CODE_SIZE);+ if (index_is_hardened(index)) {+ HMAC_sha512_update(&hmac_ctx, TAG_DERIVE_CC_HARDENED, 1);+ HMAC_sha512_update(&hmac_ctx, priv_key, ENCRYPTED_KEY_SIZE);+ } else {+ HMAC_sha512_update(&hmac_ctx, TAG_DERIVE_CC_NORMAL, 1);+ HMAC_sha512_update(&hmac_ctx, in->pkey, PUBLIC_KEY_SIZE);+ }+ HMAC_sha512_update(&hmac_ctx, idxBuf, 4);+ HMAC_sha512_final(&hmac_ctx, hmac_out);++ unencrypt_stop(priv_key);++ wallet_encrypted_initialize(pass, pass_len, res_key, hmac_out + 32, out);+ clear(res_key, ENCRYPTED_KEY_SIZE);+ clear(hmac_out, 64);+}++int wallet_encrypted_derive_public+ (uint8_t *pub_in,+ uint8_t *cc_in,+ uint32_t index,+ uint8_t *pub_out,+ uint8_t *cc_out,+ derivation_scheme_mode mode)+{+ HMAC_sha512_ctx hmac_ctx;+ uint8_t idxBuf[4];+ uint8_t z[64];+ uint8_t hmac_out[64];++ /* cannot derive hardened key using public bits */+ if (index_is_hardened(index))+ return 1;++ serialize_index32(idxBuf, index, mode);++ /* calculate Z */+ HMAC_sha512_init(&hmac_ctx, cc_in, CHAIN_CODE_SIZE);+ HMAC_sha512_update(&hmac_ctx, TAG_DERIVE_Z_NORMAL, 1);+ HMAC_sha512_update(&hmac_ctx, pub_in, PUBLIC_KEY_SIZE);+ HMAC_sha512_update(&hmac_ctx, idxBuf, 4);+ HMAC_sha512_final(&hmac_ctx, z);++ /* get 8 * Zl */+ add_left_public(pub_out, z, pub_in, mode);++ /* calculate the new chain code */+ HMAC_sha512_init(&hmac_ctx, cc_in, CHAIN_CODE_SIZE);+ HMAC_sha512_update(&hmac_ctx, TAG_DERIVE_CC_NORMAL, 1);+ HMAC_sha512_update(&hmac_ctx, pub_in, PUBLIC_KEY_SIZE);+ HMAC_sha512_update(&hmac_ctx, idxBuf, 4);+ HMAC_sha512_final(&hmac_ctx, hmac_out);++ memcpy(cc_out, hmac_out + (sizeof(hmac_out) - CHAIN_CODE_SIZE), CHAIN_CODE_SIZE);++ return 0;+}
+ cbits/hmac.h view
@@ -0,0 +1,76 @@+#ifndef HMAC_H+#define HMAC_H++#include "crypton_sha512.h"++#define HMAC_CTX(_name) HMAC_ ## _name ## _ctx+#define HMAC_INIT(_name) HMAC_ ## _name ## _init+#define HMAC_UPDATE(_name) HMAC_ ## _name ## _update+#define HMAC_FINAL(_name) HMAC_ ## _name ## _final++#define DECL_HMAC(_name, _blocksz, _hashsz, _ctx, _init, _update, _final) \+ typedef struct { \+ _ctx inner; \+ _ctx outer; \+ } HMAC_CTX(_name); \+ \+ static inline void HMAC_INIT(_name)(HMAC_CTX(_name) *ctx, \+ const uint8_t *key, size_t nkey) \+ { \+ /* Prepare key: */ \+ uint8_t k[_blocksz]; \+ uint8_t blk_inner[_blocksz]; \+ uint8_t blk_outer[_blocksz]; \+ size_t i; \+ \+ /* Shorten long keys. */ \+ if (nkey > _blocksz) \+ { \+ _init(&ctx->inner); \+ _update(&ctx->inner, key, nkey); \+ _final(&ctx->inner, k); \+ \+ key = k; \+ nkey = _hashsz; \+ } \+ \+ /* Standard doesn't cover case where blocksz < hashsz. */ \+ assert(nkey <= _blocksz); \+ \+ /* Right zero-pad short keys. */ \+ if (k != key) \+ memcpy(k, key, nkey); \+ if (_blocksz > nkey) \+ memset(k + nkey, 0, _blocksz - nkey); \+ \+ /* Start inner hash computation */ \+ for (i = 0; i < _blocksz; i++) \+ { \+ blk_inner[i] = 0x36 ^ k[i]; \+ blk_outer[i] = 0x5c ^ k[i]; \+ } \+ \+ _init(&ctx->inner); \+ _update(&ctx->inner, blk_inner, sizeof blk_inner); \+ \+ /* And outer. */ \+ _init(&ctx->outer); \+ _update(&ctx->outer, blk_outer, sizeof blk_outer); \+ } \+ \+ static inline void HMAC_UPDATE(_name)(HMAC_CTX(_name) *ctx, \+ const void *data, size_t ndata) \+ { \+ _update(&ctx->inner, data, ndata); \+ } \+ \+ static inline void HMAC_FINAL(_name)(HMAC_CTX(_name) *ctx, \+ uint8_t out[_hashsz]) \+ { \+ _final(&ctx->inner, out); \+ _update(&ctx->outer, out, _hashsz); \+ _final(&ctx->outer, out); \+ }+++#endif
+ src/Cardano/Crypto/Encoding/BIP39.hs view
@@ -0,0 +1,43 @@+{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}++module Cardano.Crypto.Encoding.BIP39+ ( cardanoSlSeed+ , module X+ ) where++import Data.Proxy (Proxy)+import Data.ByteString (ByteString)+import qualified Data.ByteArray as BA+import Crypto.Hash (Blake2b_256, Digest, hash)++import Crypto.Encoding.BIP39 as X++-- | **this is not a BIP39 function**+--+-- This function is the function used in `cardano-sl` (and Daedalus) to+-- generate a seed from a given mnemonic list.+--+-- https://github.com/input-output-hk/cardano-sl/blob/f5b8073b92b8219ae5fbb038c0ceb4a19502a86b/wallet/src/Pos/Util/BackupPhrase.hs#L59-L65+-- https://github.com/input-output-hk/cardano-sl/blob/429efc2426c63802ae86789f5b828dcbb42de88a/wallet/src/Pos/Util/Mnemonics.hs#L66-L87+--+cardanoSlSeed :: forall n csz mw . ConsistentEntropy n mw csz+ => Proxy n+ -> MnemonicSentence mw+ -> Maybe Seed+cardanoSlSeed _ mw =+ case wordsToEntropy @n @csz @mw mw of+ Left _ -> Nothing+ Right e -> Just $ BA.convert $ toCbor $ blake2b $ toCbor (entropyRaw e)+ where blake2b :: ByteString -> Digest Blake2b_256+ blake2b = hash++ toCbor :: BA.ByteArrayAccess ba => ba -> ByteString+ toCbor bs+ | len < 24 = BA.cons (0x40 + fromIntegral len) $ BA.convert bs+ | len < 0x100 = BA.cons 0x58 $ BA.cons (fromIntegral len) $ BA.convert bs+ | otherwise = error "we do not support entropy of length > 256 bytes"+ where+ len = BA.length bs
+ src/Cardano/Crypto/Encoding/Seed.hs view
@@ -0,0 +1,179 @@+-- |+-- Module : Cardano.Crypto.Encoding.Seed+-- Description : tools relating to Paper Wallet+-- Maintainer : nicolas.diprima@iohk.io+--+-- implementation of the proposal specification for Paper Wallet+-- see https://github.com/input-output-hk/cardano-specs/blob/master/proposals/0001-PaperWallet.md+--+-- however we allow more genericity in the implementation to allow+-- not only 12 mnemonic words to freeze but also 15, 18 and 21.+--+-- because the output mnemonic words are always 3 words longer (for the IV)+-- we cannot use 24 words long mnemonic sentence.+--+-- assumption:+--+-- * we use 'PBKDF2' with 'HMAC 512' to generate the OTP.+-- * we use 10000 iteration for the PBKDF2+-- * we use the 4 bytes "IOHK" for the CONSTANT+--++{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}++module Cardano.Crypto.Encoding.Seed+ ( Entropy+ , Passphrase+ , MnemonicSentence+ , ConsistentEntropy+ , ScrambleIV+ , mkScrambleIV+ , scramble+ , unscramble++ , IVSizeWords+ , IVSizeBits++ , -- helpers+ scrambleMnemonic+ ) where++import Foundation+import Foundation.Check+import Basement.Nat+import Crypto.Error++import Data.ByteArray (xor, ScrubbedBytes)+import Crypto.Encoding.BIP39+import qualified Crypto.KDF.PBKDF2 as PBKDF2+import Basement.Sized.List (ListN)+import qualified Basement.Sized.List as ListN+import Data.ByteArray (ByteArrayAccess)++import Data.ByteString (ByteString)+import qualified Data.ByteString as B++type IVSizeWords = 6+type IVSizeBytes = 8+type IVSizeBits = 64++ivSizeBytes :: Int+ivSizeBytes = 8++-- | Number of iteration of the PBKDF2+iterations :: Int+iterations = 10000++newtype ScrambleIV = ScrambleIV ByteString+ deriving (Eq,Ord,Show,Typeable,ByteArrayAccess)+instance Arbitrary ScrambleIV where+ arbitrary = do+ l <- arbitrary :: Gen (ListN IVSizeBytes Word8)+ pure $ throwCryptoError $ mkScrambleIV $ B.pack $ ListN.unListN l++mkScrambleIV :: ByteString -> CryptoFailable ScrambleIV+mkScrambleIV bs+ | B.length bs == ivSizeBytes = CryptoPassed (ScrambleIV bs)+ | otherwise = CryptoFailed CryptoError_IvSizeInvalid++-- | scramble the given entropy into an entropy slighly larger.+--+-- This entropy can then be converted to a mnemonic sentence:+--+-- @+-- freeze iv mnemonics passphrase = entropyToWords . scramble iv entropy passphrase+-- where+-- entropy = case wordsToEntropy mnemonics of+-- Nothing -> error "mnemonic to entropy failed"+-- Just e -> e+-- @+scramble :: forall entropysizeI entropysizeO mnemonicsize scramblesize csI csO+ . ( ConsistentEntropy entropysizeI mnemonicsize csI+ , ConsistentEntropy entropysizeO scramblesize csO+ , (mnemonicsize + IVSizeWords) ~ scramblesize+ , (entropysizeI + IVSizeBits) ~ entropysizeO+ )+ => ScrambleIV+ -> Entropy entropysizeI+ -> Passphrase+ -> Entropy entropysizeO+scramble (ScrambleIV iv) e passphrase =+ let salt = iv+ otp :: ScrubbedBytes+ otp = PBKDF2.fastPBKDF2_SHA512+ (PBKDF2.Parameters iterations entropySize)+ passphrase+ salt+ ee = xor otp (entropyRaw e)+ in case toEntropy @entropysizeO (iv <> ee) of+ Left err -> error $ "scramble: the function BIP39.toEntropy returned an error: " <> show err+ Right e' -> e'+ where+ entropySize = fromIntegral (natVal (Proxy @entropysizeI)) `div` 8++-- | helper function to scramble mnemonics+scrambleMnemonic :: forall entropysizeI entropysizeO mnemonicsize scramblesize csI csO+ . ( ConsistentEntropy entropysizeI mnemonicsize csI+ , ConsistentEntropy entropysizeO scramblesize csO+ , (mnemonicsize + IVSizeWords) ~ scramblesize+ , (entropysizeI + IVSizeBits) ~ entropysizeO+ )+ => Proxy entropysizeI+ -> ScrambleIV+ -> MnemonicSentence mnemonicsize+ -> Passphrase+ -> MnemonicSentence scramblesize+scrambleMnemonic _ iv mw passphrase =+ entropyToWords @entropysizeO+ $ scramble @entropysizeI @entropysizeO iv entropy passphrase+ where+ entropy = case wordsToEntropy @entropysizeI mw of+ Left err -> error $ "mnemonic to entropy failed: " <> show err+ Right e -> e++-- |+-- The reverse operation of 'scramble'+--+-- This function recovers the original entropy from the given scrambled entropy+-- and the associated password.+--+-- @+-- recover scrambled passphrase = entropyToWords @entropysizeO .+-- unscramble @entropysizeI @entropysizeO entropyScrambled passphrase+-- where+-- entropyScrambled = case wordsToEntropy @entropysizeI scrambled of+-- Nothing -> error "mnemonic to entropy failed"+-- Just e -> e+-- @+--+unscramble :: forall entropysizeI entropysizeO mnemonicsize scramblesize csI csO+ . ( ConsistentEntropy entropysizeI scramblesize csI+ , ConsistentEntropy entropysizeO mnemonicsize csO+ , (mnemonicsize + IVSizeWords) ~ scramblesize+ , (entropysizeO + IVSizeBits) ~ entropysizeI+ )+ => Entropy entropysizeI+ -> Passphrase+ -> Entropy entropysizeO+unscramble e passphrase =+ let ee = xor otp eraw :: ByteString+ in case toEntropy @entropysizeO ee of+ Left err -> error $ "unscramble: the function BIP39.toEntropy returned an error: " <> show err+ Right e' -> e'+ where+ (iv, eraw) = B.splitAt ivSizeBytes (entropyRaw e) :: (ByteString, ByteString)+ salt = iv+ otp :: ScrubbedBytes+ otp = PBKDF2.fastPBKDF2_SHA512+ (PBKDF2.Parameters iterations entropySize)+ passphrase+ salt+ entropySize = fromIntegral (natVal (Proxy @entropysizeO)) `div` 8
+ src/Cardano/Crypto/Wallet.hs view
@@ -0,0 +1,202 @@+-- |+-- Module : Cardano.Crypto.Wallet+-- Description : HD Wallet routines+-- Maintainer : vincent@typed.io+--+-- This provides similar functionality to BIP32 but using+-- Ed25519 arithmetic instead of P256K1 arithmethic.+--+-- Key can be hierarchically derived from private key in two+-- fashions: Hardened or Normal.+--+-- In the hardened scheme, the child secret key is not linearly+-- derived, so that the child public key has no way+-- to be efficiently computed from the parent public key.+--+-- The normal scheme allows anyone to derive public keys from+-- public key.+--+{-# LANGUAGE GADTs #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE PatternSynonyms #-}++module Cardano.Crypto.Wallet+ ( ChainCode(..)+ , DerivationScheme(..)+ , DerivationIndex+ , pattern LatestScheme+ -- * Extended Private & Public types+ , XPrv+ , XPub(..)+ , XSignature+ , generate+ , generateNew+ , xprv+ , xpub+ , xsignature+ , unXPrv+ , unXPub+ , unXSignature+ , toXPub+ , xPubGetPublicKey+ , xPrvChangePass+ -- * Derivation function+ , deriveXPrv+ , deriveXPub+ -- * Signature & Verification from extended types+ , sign+ , verify+ ) where++import Basement.Compat.Typeable+import Control.DeepSeq (NFData)+import Control.Arrow (second)+import Crypto.Error (throwCryptoError, CryptoFailable(..), CryptoError(..))+import qualified Crypto.MAC.HMAC as HMAC+import qualified Crypto.PubKey.Ed25519 as Ed25519+import Crypto.KDF.PBKDF2 (fastPBKDF2_SHA512, Parameters(..))+import Data.ByteArray (ByteArrayAccess, convert)+import qualified Data.ByteArray as B (append, length, splitAt)+import Data.ByteString (ByteString)+import qualified Data.ByteString.Char8 as BC+import Data.Hashable (Hashable)+import Data.Word+import GHC.Generics (Generic)++import Cardano.Crypto.Wallet.Encrypted+import Cardano.Crypto.Wallet.Pure ({-XPub (..),-} hFinalize,+ hInitSeed)+import Cardano.Crypto.Wallet.Types++import GHC.Stack++newtype XPrv = XPrv EncryptedKey+ deriving (NFData, Typeable, ByteArrayAccess)++data XPub = XPub+ { xpubPublicKey :: !ByteString+ , xpubChaincode :: !ChainCode+ } deriving (Eq, Show, Ord, Typeable, Generic)++instance NFData XPub+instance Hashable XPub++newtype XSignature = XSignature+ { unXSignature :: ByteString+ } deriving (Show, Eq, Ord, NFData, Hashable, ByteArrayAccess)++-- | Generate a new XPrv+--+-- The seed needs to be at least 32 bytes, otherwise an asynchronous error is thrown+generate :: (ByteArrayAccess passPhrase, ByteArrayAccess seed)+ => seed+ -> passPhrase+ -> XPrv+generate seed passPhrase+ | B.length seed < 32 = error ("Wallet.generate: seed needs to be >= 32 bytes, got : " ++ show (B.length seed))+ | otherwise = loop 1+ where+ phrase :: Int -> ByteString+ phrase i = "Root Seed Chain " `B.append` BC.pack (show i)++ -- repeatdly try to generate from a seed, if we reach 1000th iteration we just bail+ -- this should find a candidate after 2 tries on average+ loop i+ | i > 1000 = error "internal error: Wallet.generate looping forever"+ | otherwise =+ case encryptedCreate iL passPhrase iR of+ CryptoPassed k -> XPrv k+ CryptoFailed err+ | err == CryptoError_SecretKeyStructureInvalid -> loop (i+1)+ | otherwise -> error "internal error: Wallet.generate: got error from encryptedCreate"+ where (iL, iR) = hFinalize+ $ flip HMAC.update (phrase i)+ $ hInitSeed seed++-- | Generate a new XPrv from an entropy seed+--+-- The seed should be at least 16 bytes, although it is not enforced+--+-- The passphrase encrypt the secret key in memory+generateNew :: (ByteArrayAccess keyPassPhrase, ByteArrayAccess generationPassPhrase, ByteArrayAccess seed)+ => seed -- ^ Raw entropy used as source of randomness for this algorithm+ -> generationPassPhrase -- ^ User chosen passphrase for the generation phase+ -> keyPassPhrase -- ^ Symmetric encryption key passphrase used for the in-memory security+ -> XPrv+generateNew seed genPassPhrase memPassPhrase =+ XPrv $ encryptedCreateDirectWithTweak out memPassPhrase+ where+ out :: ByteString+ out = fastPBKDF2_SHA512 (Parameters 4096 96) genPassPhrase seed++-- | Simple constructor+xprv :: ByteArrayAccess bin => bin -> Either String XPrv+xprv bs =+ maybe (Left "error: xprv needs to be 128 bytes") (Right . XPrv)+ $ encryptedKey+ $ convert bs++unXPrv :: XPrv -> ByteString+unXPrv (XPrv e) = unEncryptedKey e++xpub :: ByteString -> Either String XPub+xpub bs+ | B.length bs /= 64 = Left ("error: xprv needs to be 64 bytes: got " ++ show (B.length bs) ++ " bytes")+ | otherwise =+ let (b1, b2) = B.splitAt 32 bs+ in Right $ XPub b1 (ChainCode $ convert b2)++unXPub :: XPub -> ByteString+unXPub (XPub pub (ChainCode cc)) = B.append pub cc++xsignature :: ByteString -> Either String XSignature+xsignature bs+ | B.length bs /= 64 = Left ("error: xsignature needs to be 64 bytes: got " ++ show (B.length bs) ++ " bytes")+ | otherwise = Right $ XSignature bs++-- | Generate extended public key from private key+toXPub :: HasCallStack => XPrv -> XPub+toXPub (XPrv ekey) = XPub pub (ChainCode cc)+ where (_,r) = B.splitAt 64 $ convert ekey+ (pub, cc) = B.splitAt 32 r++-- | Return the Ed25519 public key associated with a XPub context+xPubGetPublicKey :: XPub -> Ed25519.PublicKey+xPubGetPublicKey (XPub pub _) =+ throwCryptoError $ Ed25519.publicKey pub++xPrvChangePass :: (ByteArrayAccess oldPassPhrase, ByteArrayAccess newPassPhrase)+ => oldPassPhrase -- ^ passphrase to decrypt the current encrypted key+ -> newPassPhrase -- ^ new passphrase to use for the new encrypted key+ -> XPrv+ -> XPrv+xPrvChangePass oldPass newPass (XPrv ekey) =+ XPrv $ encryptedChangePass oldPass newPass ekey++-- | Derive a child extended private key from an extended private key+deriveXPrv :: ByteArrayAccess passPhrase => DerivationScheme -> passPhrase -> XPrv -> Word32 -> XPrv+deriveXPrv ds passPhrase (XPrv ekey) n =+ XPrv (encryptedDerivePrivate ds ekey passPhrase n)++-- | Derive a child extended public key from an extended public key+deriveXPub :: DerivationScheme -> XPub -> Word32 -> Maybe XPub+deriveXPub ds (XPub pub (ChainCode cc)) n+ | n >= 0x80000000 = Nothing+ | otherwise = Just $ uncurry XPub $ second ChainCode $ encryptedDerivePublic ds (pub,cc) n++sign :: (ByteArrayAccess passPhrase, ByteArrayAccess msg)+ => passPhrase+ -> XPrv+ -> msg+ -> XSignature+sign passphrase (XPrv ekey) ba =+ XSignature $ let (Signature sig) = encryptedSign ekey passphrase ba in sig++verify :: ByteArrayAccess msg => XPub -> msg -> XSignature -> Bool+verify (XPub point _) ba (XSignature signature) =+ let pub = throwCryptoError $ Ed25519.publicKey point+ sig = throwCryptoError $ Ed25519.signature signature+ in Ed25519.verify pub ba sig
+ src/Cardano/Crypto/Wallet/Encrypted.hs view
@@ -0,0 +1,226 @@+module Cardano.Crypto.Wallet.Encrypted+ ( EncryptedKey+ , encryptedKey+ , unEncryptedKey+ , Signature(..)+ -- * Methods+ , encryptedCreate+ , encryptedCreateDirectWithTweak+ , encryptedChangePass+ , encryptedSign+ , encryptedPublic+ , encryptedChainCode+ , encryptedDerivePrivate+ , encryptedDerivePublic+ ) where++import Control.DeepSeq+import Data.Word+import Foreign.C.Types+import Foreign.Ptr++import Crypto.Error+import Data.ByteArray (ByteArrayAccess, withByteArray)+import qualified Data.ByteArray as B+import Data.ByteString (ByteString)+import System.IO.Unsafe++import Cardano.Crypto.Wallet.Types (DerivationScheme(..), DerivationIndex)++totalKeySize :: Int+totalKeySize = encryptedKeySize + publicKeySize + ccSize++--totalPublicKeySize :: Int+--totalPublicKeySize = publicKeySize + ccSize++encryptedKeySize :: Int+encryptedKeySize = 64++publicKeySize :: Int+publicKeySize = 32++ccSize :: Int+ccSize = 32++signatureSize :: Int+signatureSize = 64++publicKeyOffset :: Int+publicKeyOffset = encryptedKeySize++ccOffset :: Int+ccOffset = publicKeyOffset + publicKeySize++newtype Signature = Signature ByteString+ deriving (NFData)++newtype EncryptedKey = EncryptedKey ByteString+ deriving (NFData, ByteArrayAccess)++type PublicKey = ByteString+type ChainCode = ByteString++data PassPhrase++-- | Create an encryped key from binary representation.+--+-- If the binary is not of the right size, Nothing is returned+encryptedKey :: ByteString -> Maybe EncryptedKey+encryptedKey ba+ | B.length ba == totalKeySize = Just $ EncryptedKey ba+ | otherwise = Nothing++unEncryptedKey :: EncryptedKey -> ByteString+unEncryptedKey (EncryptedKey e) = e++-- | Create a new encrypted key from the secret, encrypting the secret in memory+-- using the passphrase.+encryptedCreate :: (ByteArrayAccess passphrase, ByteArrayAccess secret, ByteArrayAccess cc)+ => secret+ -> passphrase+ -> cc+ -> CryptoFailable EncryptedKey+encryptedCreate sec pass cc+ | B.length sec /= 32 = CryptoFailed CryptoError_SecretKeySizeInvalid+ | otherwise = unsafePerformIO $ do+ (r, k) <- B.allocRet totalKeySize $ \ekey ->+ withByteArray sec $ \psec ->+ withByteArray pass $ \ppass ->+ withByteArray cc $ \pcc ->+ wallet_encrypted_from_secret ppass (fromIntegral $ B.length pass) psec pcc ekey+ if r == 0+ then return $ CryptoPassed $ EncryptedKey k+ else return $ CryptoFailed CryptoError_SecretKeyStructureInvalid++-- | Create a new encrypted key using the output of the masterKeyGeneration directly (96 bytes)+-- using the encryption passphrase.+encryptedCreateDirectWithTweak :: (ByteArrayAccess passphrase, ByteArrayAccess secret)+ => secret+ -> passphrase+ -> EncryptedKey+encryptedCreateDirectWithTweak sec pass =+ EncryptedKey $ B.allocAndFreeze totalKeySize $ \ekey ->+ withByteArray sec $ \psec ->+ withByteArray pass $ \ppass ->+ wallet_encrypted_new_from_mkg ppass (fromIntegral $ B.length pass) psec ekey++-- | Create a new encrypted key that uses a different passphrase+encryptedChangePass :: (ByteArrayAccess oldPassPhrase, ByteArrayAccess newPassPhrase)+ => oldPassPhrase -- ^ passphrase to decrypt the current encrypted key+ -> newPassPhrase -- ^ new passphrase to use for the new encrypted key+ -> EncryptedKey -- ^ Key using the old pass phrase+ -> EncryptedKey -- ^ Key using the new pass phrase+encryptedChangePass oldPass newPass (EncryptedKey okey) =+ EncryptedKey $ B.allocAndFreeze totalKeySize $ \ekey ->+ withByteArray oldPass $ \opass ->+ withByteArray newPass $ \npass ->+ withByteArray okey $ \oldkey ->+ wallet_encrypted_change_pass oldkey+ opass (fromIntegral $ B.length oldPass)+ npass (fromIntegral $ B.length newPass)+ ekey++-- | Sign using the encrypted keys and temporarly decrypt the secret in memory+-- with a minimal memory footprint.+encryptedSign :: (ByteArrayAccess passphrase, ByteArrayAccess msg)+ => EncryptedKey+ -> passphrase+ -> msg+ -> Signature+encryptedSign (EncryptedKey ekey) pass msg =+ Signature $ B.allocAndFreeze signatureSize $ \sig ->+ withByteArray ekey $ \k ->+ withByteArray pass $ \p ->+ withByteArray msg $ \m ->+ wallet_encrypted_sign k p (fromIntegral $ B.length pass) m (fromIntegral $ B.length msg) sig++encryptedDerivePrivate :: (ByteArrayAccess passphrase)+ => DerivationScheme+ -> EncryptedKey+ -> passphrase+ -> DerivationIndex+ -> EncryptedKey+encryptedDerivePrivate dscheme (EncryptedKey parent) pass childIndex =+ EncryptedKey $ B.allocAndFreeze totalKeySize $ \ekey ->+ withByteArray pass $ \ppass ->+ withByteArray parent $ \pparent ->+ wallet_encrypted_derive_private pparent ppass (fromIntegral $ B.length pass) childIndex ekey (dschemeToC dscheme)++encryptedDerivePublic :: DerivationScheme+ -> (PublicKey, ChainCode)+ -> DerivationIndex+ -> (PublicKey, ChainCode)+encryptedDerivePublic dscheme (pub, cc) childIndex+ | childIndex >= 0x80000000 = error "cannot derive hardened in derive public"+ | otherwise = unsafePerformIO $ do+ (newCC, newPub) <-+ B.allocRet publicKeySize $ \outPub ->+ B.alloc ccSize $ \outCc ->+ withByteArray pub $ \ppub ->+ withByteArray cc $ \pcc -> do+ r <- wallet_encrypted_derive_public ppub pcc childIndex outPub outCc (dschemeToC dscheme)+ if r /= 0 then error "encrypted derive public assumption about index failed" else return ()+ return (newPub, newCC)++-- | Get the public part of an encrypted key+encryptedPublic :: EncryptedKey -> ByteString+encryptedPublic (EncryptedKey ekey) = sub publicKeyOffset publicKeySize ekey++-- | Get the chain code part of an encrypted key+encryptedChainCode :: EncryptedKey -> ByteString+encryptedChainCode (EncryptedKey ekey) = sub ccOffset ccSize ekey++sub :: B.ByteArray c => Int -> Int -> c -> c+sub ofs sz = B.take sz . B.drop ofs++-- map to the C enum : derivation_scheme_mode+type CDerivationScheme = CInt++dschemeToC :: DerivationScheme -> CDerivationScheme+dschemeToC DerivationScheme1 = 1+dschemeToC DerivationScheme2 = 2++-- return 0 if success, otherwise 1 if structure of seed not proper+foreign import ccall "wallet_encrypted_from_secret"+ wallet_encrypted_from_secret :: Ptr PassPhrase -> Word32+ -> Ptr Word8 -- 32 bytes "seed secret key" (non extended)+ -> Ptr Word8 -- 32 bytes ChainCode+ -> Ptr EncryptedKey+ -> IO CInt++foreign import ccall "wallet_encrypted_new_from_mkg"+ wallet_encrypted_new_from_mkg :: Ptr PassPhrase -> Word32+ -> Ptr Word8 -- 96 bytes master key generation+ -> Ptr EncryptedKey+ -> IO ()++foreign import ccall "wallet_encrypted_sign"+ wallet_encrypted_sign :: Ptr EncryptedKey+ -> Ptr PassPhrase -> Word32+ -> Ptr Word8 -> Word32+ -> Ptr Signature+ -> IO ()++foreign import ccall "wallet_encrypted_derive_private"+ wallet_encrypted_derive_private :: Ptr EncryptedKey+ -> Ptr PassPhrase -> Word32+ -> DerivationIndex -- index+ -> Ptr EncryptedKey+ -> CDerivationScheme+ -> IO ()++foreign import ccall "wallet_encrypted_derive_public"+ wallet_encrypted_derive_public :: Ptr PublicKey+ -> Ptr ChainCode+ -> DerivationIndex+ -> Ptr PublicKey+ -> Ptr ChainCode+ -> CDerivationScheme+ -> IO CInt++foreign import ccall "wallet_encrypted_change_pass"+ wallet_encrypted_change_pass :: Ptr EncryptedKey+ -> Ptr PassPhrase -> Word32+ -> Ptr PassPhrase -> Word32+ -> Ptr EncryptedKey+ -> IO ()
+ src/Cardano/Crypto/Wallet/Pure.hs view
@@ -0,0 +1,108 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}++module Cardano.Crypto.Wallet.Pure+ ( XPrv(..)+ , XPub(..)+ , xprvPub+ , deriveXPrv+ , deriveXPrvHardened+ , deriveXPub+ , hInitSeed+ , hFinalize+ ) where++import Control.DeepSeq (NFData)+import qualified Crypto.Math.Edwards25519 as Edwards25519+import Crypto.Hash (SHA512)+import qualified Crypto.MAC.HMAC as HMAC+--import qualified Crypto.PubKey.Ed25519 as Ed25519+import Data.Bits+import Data.ByteArray (ByteArrayAccess, convert)+import qualified Data.ByteArray as B (splitAt)+import Data.ByteString (ByteString)+import qualified Data.ByteString as B (pack)+import Data.Hashable (Hashable)+import Data.Word+import GHC.Generics (Generic)++import Cardano.Crypto.Wallet.Types++data XPrv = XPrv !Edwards25519.Scalar !ChainCode++data XPub = XPub !Edwards25519.PointCompressed !ChainCode+ deriving (Eq, Ord, Show, Generic)++instance NFData XPub+instance Hashable XPub++xprvPub :: XPrv -> ByteString+xprvPub (XPrv s _) =+ Edwards25519.unPointCompressed $ Edwards25519.scalarToPoint s++deriveXPrv :: XPrv -> Word32 -> XPrv+deriveXPrv (XPrv sec ccode) n =+ let !pub = Edwards25519.scalarToPoint sec+ (iL, iR) = walletHash $ DerivationHashNormal pub ccode n+ !derived = Edwards25519.scalar iL+ in XPrv (Edwards25519.scalarAdd sec derived) iR++deriveXPrvHardened :: XPrv -> Word32 -> XPrv+deriveXPrvHardened (XPrv sec ccode) n =+ let (iL, iR) = walletHash $ DerivationHashHardened sec ccode n+ in XPrv (Edwards25519.scalar iL) iR++-- | Derive a child public from an extended public key+deriveXPub :: XPub -> Word32 -> XPub+deriveXPub (XPub pub ccode) n =+ let (iL, iR) = walletHash $ DerivationHashNormal pub ccode n+ !derived = Edwards25519.scalarToPoint $ Edwards25519.scalar iL+ in XPub (Edwards25519.pointAdd pub derived) iR+++-- hashing methods either hardened or normal+data DerivationHash where+ DerivationHashHardened :: Edwards25519.Scalar -> ChainCode -> Word32 -> DerivationHash+ DerivationHashNormal :: Edwards25519.PointCompressed -> ChainCode -> Word32 -> DerivationHash++walletHash :: DerivationHash -> (ByteString, ChainCode)+walletHash (DerivationHashHardened sec cc w) =+ hFinalize+ $ flip HMAC.update (encodeIndex w)+ $ flip HMAC.update (Edwards25519.unScalar sec)+ $ flip HMAC.update hardenedTag+ $ hInit cc+walletHash (DerivationHashNormal pub cc w) =+ hFinalize+ $ flip HMAC.update (encodeIndex w)+ $ flip HMAC.update (Edwards25519.unPointCompressed pub)+ $ flip HMAC.update normalTag+ $ hInit cc++hardenedTag :: ByteString+hardenedTag = B.pack $ map (fromIntegral . fromEnum) "HARD"+normalTag :: ByteString+normalTag = B.pack $ map (fromIntegral . fromEnum) "NORM"++-- | Encode a Word32 in Big endian+encodeIndex :: Word32 -> ByteString+encodeIndex w = B.pack [d,c,b,a]+ where+ a = fromIntegral w+ b = fromIntegral (w `shiftR` 8)+ c = fromIntegral (w `shiftR` 16)+ d = fromIntegral (w `shiftR` 24)++hInit :: ChainCode -> HMAC.Context SHA512+hInit (ChainCode key) = HMAC.initialize key++hInitSeed :: ByteArrayAccess seed => seed -> HMAC.Context SHA512+hInitSeed seed = HMAC.initialize seed++hFinalize :: HMAC.Context SHA512 -> (ByteString, ChainCode)+hFinalize ctx =+ let (b1, b2) = B.splitAt 32 $ convert $ HMAC.finalize ctx+ in (b1, ChainCode b2)
+ src/Cardano/Crypto/Wallet/Types.hs view
@@ -0,0 +1,29 @@+{-# LANGUAGE PatternSynonyms #-}+module Cardano.Crypto.Wallet.Types+ ( ChainCode(..)+ , DerivationScheme(..)+ , DerivationIndex+ , pattern LatestScheme+ ) where++import Control.DeepSeq (NFData)+import Data.ByteArray (ByteArrayAccess)+import Data.ByteString (ByteString)+import Data.Hashable (Hashable)++import Foundation+import Foundation.Collection (nonEmpty_)+import Foundation.Check (Arbitrary(..), frequency)++type DerivationIndex = Word32++data DerivationScheme = DerivationScheme1 | DerivationScheme2+ deriving (Show, Eq, Ord, Enum, Bounded, Typeable)+instance Arbitrary DerivationScheme where+ arbitrary = frequency $ nonEmpty_ [ (1, pure DerivationScheme1), (1, pure DerivationScheme2) ]++pattern LatestScheme :: DerivationScheme+pattern LatestScheme = DerivationScheme2++newtype ChainCode = ChainCode ByteString+ deriving (Show, Eq, Ord, ByteArrayAccess, NFData, Hashable)
+ src/Cardano/Internal/Compat.hs view
@@ -0,0 +1,11 @@+{-# LANGUAGE CPP #-}+module Cardano.Internal.Compat (fromRight) where+#if MIN_VERSION_base(4, 10, 0)+import Data.Either(fromRight)+#endif++#if !MIN_VERSION_base(4, 10, 0)+fromRight :: b -> Either a b -> b+fromRight _ (Right b) = b+fromRight b _ = b+#endif
+ src/Crypto/ECC/Ed25519BIP32.hs view
@@ -0,0 +1,313 @@+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE GADTs #-}+module Crypto.ECC.Ed25519BIP32 where++import qualified Crypto.Hash as C (SHA512, SHA256)+import qualified Crypto.MAC.HMAC as C+import qualified Data.ByteArray as B+import qualified Data.ByteString as BS+import Data.Bits+import Data.Kind (Type)+import Data.Word+import Data.Proxy+import qualified Crypto.Math.Edwards25519 as ED25519+import Data.Type.Bool+import Data.Type.Equality+import GHC.TypeLits+import Data.Function (on)+import Unsafe.Coerce (unsafeCoerce)++import Crypto.Math.Bits+import Crypto.Math.Bytes (Bytes)+import qualified Crypto.Math.Bytes as Bytes++-- | A Master secret is a 256 bits random quantity+type MasterSecret = FBits 256++-- | A child key is similar to the key in structure+-- except it has an additional annotation representing+-- the indexes for the hierarchy derivation indexes from+-- a base 'Key' (usually the root key)+type ChildKey (didxs :: DerivationHier) = Key++-- | A key is a 512 bit random value and a chaincode+--+-- Left half need to have:+-- * Lowest 3 bits clear+-- * Highest bit clear+-- * Second highest bit set+-- * Third highest bit clear+--+-- Right half doesn't have any particular structure.+type Key = (FBits 256, FBits 256, ChainCode)++-- | A public part of a key+type Public = (PointCompressed, ChainCode)++-- | A point is 1 bit of x sign and 255 bit of y coordinate (y's 256th bit is always 0)+type PointCompressed = FBits 256++-- | A 256 bits chain code+newtype ChainCode = ChainCode { unChainCode :: Bytes 32 }+ deriving (Eq)++-- | A n bits Digest+newtype Hash n = Hash { unHash :: FBits n }+ deriving (Eq)++-- | A Serialized tag used during HMAC+type Tag = Bytes 1++-- | Serialized Index+newtype SerializedIndex = SerializedIndex (Bytes 4)+ deriving (Eq)++type HMAC_SHA512 = Bytes 64++data DerivationType = Hard | Soft+data DerivationMaterial = ChainCodeMaterial | KeyMaterial++data DerivationIndex (k :: DerivationType) (n :: Nat) = DerivationIndex++data DerivationHier = (:>) Nat DerivationHier | DerivationEnd++type MaxHardIndex = 0xffffffff+type MinHardIndex = 0x80000000+type MaxSoftIndex = MinHardIndex - 1+type MinSoftIndex = 0++data ValidIndex :: Nat -> Type where+ IsValidIndex :: (ValidDerivationIndex n :~: 'True) -> ValidIndex n+ IsNotValidIndex :: (ValidDerivationIndex n :~: 'False) -> ValidIndex n++data ValidHardIndex :: Nat -> Type where+ IsValidHardIndex :: (ValidDerivationHardIndex n :~: 'True) -> ValidHardIndex n+ IsNotValidHardIndex :: (ValidDerivationHardIndex n :~: 'False) -> ValidHardIndex n++data ValidSoftIndex :: Nat -> Type where+ IsValidSoftIndex :: (ValidDerivationSoftIndex n :~: 'True) -> ValidSoftIndex n+ IsNotValidSoftIndex :: (ValidDerivationSoftIndex n :~: 'False) -> ValidSoftIndex n++getValidIndex :: KnownNat n => Proxy n -> Maybe (ValidDerivationIndex n :~: 'True)+getValidIndex n = case isValidIndex n of+ IsValidIndex Refl -> Just Refl+ _ -> Nothing++isValidIndex :: KnownNat n => Proxy n -> ValidIndex n+isValidIndex n+ | natVal (Proxy @MinSoftIndex) <= natVal n+ && natVal n <= natVal (Proxy @MaxHardIndex) = IsValidIndex (unsafeCoerce Refl)+ | otherwise = IsNotValidIndex (unsafeCoerce Refl)++getValidHardIndex :: KnownNat n => Proxy n -> Maybe (ValidDerivationHardIndex n :~: 'True)+getValidHardIndex n = case isValidHardIndex n of+ IsValidHardIndex Refl -> Just Refl+ _ -> Nothing++isValidHardIndex :: KnownNat n => Proxy n -> ValidHardIndex n+isValidHardIndex n+ | natVal (Proxy @MinHardIndex) <= natVal n+ && natVal n <= natVal (Proxy @MaxHardIndex) = IsValidHardIndex (unsafeCoerce Refl)+ | otherwise = IsNotValidHardIndex (unsafeCoerce Refl)++getValidSoftIndex :: KnownNat n => Proxy n -> Maybe (ValidDerivationSoftIndex n :~: 'True)+getValidSoftIndex n = case isValidSoftIndex n of+ IsValidSoftIndex Refl -> Just Refl+ _ -> Nothing++isValidSoftIndex :: KnownNat n => Proxy n -> ValidSoftIndex n+isValidSoftIndex n+ | natVal (Proxy @MinSoftIndex) <= natVal n+ && natVal n <= natVal (Proxy @MaxSoftIndex) = IsValidSoftIndex (unsafeCoerce Refl)+ | otherwise = IsNotValidSoftIndex (unsafeCoerce Refl)++type ValidDerivationIndex (n :: Nat) = (MinSoftIndex <=? n) && (n <=? MaxHardIndex)+type ValidDerivationHardIndex (n :: Nat) = (MinHardIndex <=? n) && (n <=? MaxHardIndex)+type ValidDerivationSoftIndex (n :: Nat) = (MinSoftIndex <=? n) && (n <=? MaxSoftIndex)++type family ValidDerivationIndexForType (k :: DerivationType) (n :: Nat) :: Bool where+ ValidDerivationIndexForType 'Hard n = ValidDerivationHardIndex n+ ValidDerivationIndexForType 'Soft n = ValidDerivationSoftIndex n++type family DerivationTag (ty :: DerivationType) (material :: DerivationMaterial) :: Nat where+ DerivationTag 'Hard 'KeyMaterial = 0x0+ DerivationTag 'Hard 'ChainCodeMaterial = 0x1+ DerivationTag 'Soft 'KeyMaterial = 0x2+ DerivationTag 'Soft 'ChainCodeMaterial = 0x3++-- | Check if the left half is valid+leftHalfValid :: FBits 256 -> Bool+leftHalfValid v =+ and [ testBit v 0 == False+ , testBit v 1 == False+ , testBit v 2 == False+ , testBit v 29 == False+ , testBit v 28 == True+ , testBit v 31 == False+ ]++toPublic :: Key -> Public+toPublic (kl, _, cc) = (kToPoint kl, cc)++kToPoint :: FBits 256 -> PointCompressed+kToPoint k = pointFromRepr $ ED25519.scalarToPoint r+ where r = ED25519.scalarP $ Bytes.fromBits Bytes.LittleEndian k++pointAdd :: PointCompressed -> PointCompressed -> PointCompressed+pointAdd = ((pointFromRepr . ) . ED25519.pointAdd) `on` pointToRepr++pointToRepr :: PointCompressed -> ED25519.PointCompressed+pointToRepr a = ED25519.pointCompressedP $ Bytes.fromBits Bytes.LittleEndian a++pointFromRepr :: ED25519.PointCompressed -> PointCompressed+pointFromRepr =+ Bytes.toBits Bytes.LittleEndian+ . ED25519.unPointCompressedP++type family BitsToHashScheme (n :: Nat) where+ BitsToHashScheme 256 = C.SHA256+ BitsToHashScheme 512 = C.SHA512++type ValidTag tag = (0 <= tag, tag <= 3)++-- | Compute the HMAC-SHA512 using the ChainCode as the key+fcp :: forall tag idx deriveType deriveMaterial+ . ( KnownNat (DerivationTag deriveType deriveMaterial)+ , KnownNat idx+ , (DerivationTag deriveType deriveMaterial) ~ tag+ , ValidDerivationIndex idx ~ 'True+ , ValidDerivationIndexForType deriveType idx ~ 'True+ )+ => Proxy deriveMaterial+ -> Proxy deriveType+ -> Proxy idx+ -> ChainCode+ -> DerivationIndex deriveType idx+ -> [Word8]+ -> HMAC_SHA512+fcp _ _ pidx c _ input =+ hmacSHA512 key `Bytes.packSome` (Bytes.unpack tagValue ++ input ++ Bytes.unpack idx)+ where+ key = unChainCode c++ (SerializedIndex idx) = indexSerialized pidx++ tagValue :: Tag+ tagValue = Bytes.pack [fromIntegral $ natVal (Proxy :: Proxy tag)]++hmacSHA512 :: Bytes keyLength -> Bytes input -> HMAC_SHA512+hmacSHA512 key ({-Bytes.trace "hmac-input" ->-} msg) =+ Bytes.pack $ B.unpack $ C.hmacGetDigest computed+ where+ computed :: C.HMAC C.SHA512+ computed = C.hmac (BS.pack $ Bytes.unpack key) (BS.pack $ Bytes.unpack msg)++class GetDerivationMaterial (dtype :: DerivationType) mat where+ getDerivationMaterial :: Proxy dtype -> mat -> [Word8]+instance GetDerivationMaterial 'Soft Key where+ getDerivationMaterial p key = getDerivationMaterial p (fst $ toPublic key)+instance GetDerivationMaterial 'Hard Key where+ getDerivationMaterial _ (kl,kr,_) =+ Bytes.unpack $ Bytes.append (Bytes.fromBits Bytes.LittleEndian kl)+ (Bytes.fromBits Bytes.LittleEndian kr)+instance GetDerivationMaterial 'Soft PointCompressed where+ getDerivationMaterial _ p = Bytes.unpack $ Bytes.fromBits Bytes.LittleEndian p++derive :: forall dtype idx .+ ( KnownNat (DerivationTag dtype 'KeyMaterial)+ , KnownNat (DerivationTag dtype 'ChainCodeMaterial)+ , KnownNat idx+ , ValidDerivationIndex idx ~ 'True+ , ValidDerivationIndexForType dtype idx ~ 'True+ , GetDerivationMaterial dtype Key)+ => DerivationIndex dtype idx+ -> Key+ -> Key+derive idx key@(kl, kr, c) = (kl', kr', c')+ where+ dtype = Proxy :: Proxy dtype+ matKeyProxy = Proxy :: Proxy 'KeyMaterial+ matCCProxy = Proxy :: Proxy 'ChainCodeMaterial+ -- 1) Z+ z = fcp matKeyProxy dtype (Proxy :: Proxy idx) c idx+ (getDerivationMaterial dtype key)++ -- 2) produce kl' and kr'+ (zl8, zr) = step2 z++ kl' = zl8 + kl+ kr' = zr + kr++ -- 3) child chain code+ untrimmedCC = fcp matCCProxy dtype (Proxy :: Proxy idx) c idx+ (getDerivationMaterial dtype key)+ c' = ChainCode $ Bytes.drop untrimmedCC++derivePublic :: forall idx dtype .+ ( dtype ~ 'Soft -- can only derive public stuff with Soft Derivation+ , KnownNat (DerivationTag dtype 'KeyMaterial)+ , KnownNat (DerivationTag dtype 'ChainCodeMaterial)+ , KnownNat idx+ , ValidDerivationIndex idx ~ 'True+ , ValidDerivationIndexForType dtype idx ~ 'True+ , GetDerivationMaterial dtype PointCompressed)+ => DerivationIndex 'Soft idx+ -> PointCompressed+ -> ChainCode+ -> (PointCompressed, ChainCode)+derivePublic idx p c = (p', c')+ where+ dtype = Proxy :: Proxy dtype+ matKeyProxy = Proxy :: Proxy 'KeyMaterial+ matCCProxy = Proxy :: Proxy 'ChainCodeMaterial+ -- 1) Z+ z = fcp matKeyProxy dtype (Proxy :: Proxy idx) c idx (getDerivationMaterial dtype p)++ -- 2) produce kl' and kr'+ (zl8, _) = step2 z++ p' = kToPoint zl8 `pointAdd` p++ -- 3) child chain code+ untrimmedCC = fcp matCCProxy dtype (Proxy :: Proxy idx) c idx+ (getDerivationMaterial dtype p)+ c' = ChainCode $ Bytes.drop untrimmedCC++-- | Given Z, return 8*ZL(28Bytes) and ZR+step2 :: Bytes 64 -> (FBits 256, FBits 256)+step2 z = (8 * zeroExtendedZl, Bytes.toBits Bytes.LittleEndian zRight)+ where+ (zLeft32, zRight) = Bytes.splitHalf z++ -- step+ -- * take 28 bytes of zLeft32 (zl)+ -- * extend back to 32 bytes+ -- * multiply this number by 8+ zeroExtendedZl = zeroExtender `append` Bytes.toBits Bytes.LittleEndian zl++ zl :: Bytes 28 -- only take 28 bytes+ zl = Bytes.take zLeft32++ zeroExtender :: FBits (4*8) -- re-extend by 4 bytes+ zeroExtender = 0++-- | Serialized index+indexSerialized :: forall idx . (KnownNat idx, ValidDerivationIndex idx ~ 'True)+ => Proxy idx+ -> SerializedIndex+indexSerialized idx = SerializedIndex $ Bytes.fromBits Bytes.LittleEndian (fromInteger n :: FBits 32)+ where n = natVal idx
+ src/Crypto/ECC/Ed25519Donna.hs view
@@ -0,0 +1,183 @@+-- |+-- Module : Crypto.PubKey.Ed25519+-- License : BSD-style+-- Maintainer : Vincent Hanquez <vincent@snarc.org>+-- Stability : experimental+-- Portability : unknown+--+-- Ed25519 support+--+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE BangPatterns #-}+module Crypto.ECC.Ed25519Donna+ ( SecretKey(..)+ , PublicKey(..)+ , Signature+ -- * Smart constructors+ , signature+ , publicKey+ , secretKey+ -- * methods+ , toPublic+ , sign+ , verify+ , publicAdd+ , secretAdd+ ) where++import Control.DeepSeq+import Data.Word+import Foreign.Ptr+import Foreign.C.Types++import Data.ByteArray (ByteArrayAccess, withByteArray, ScrubbedBytes, Bytes)+import qualified Data.ByteArray as B+import Crypto.Error+import Foreign.Storable+import System.IO.Unsafe+import Crypto.Hash (hashWith, SHA512(..))+import Data.ByteArray (alloc)+import Data.Bits+import Control.Monad++unsafeDoIO :: IO a -> a+unsafeDoIO = unsafeDupablePerformIO+{-# NOINLINE unsafeDoIO #-}++-- | An Ed25519 Secret key+newtype SecretKey = SecretKey ScrubbedBytes+ deriving (Eq,ByteArrayAccess,NFData)++-- | An Ed25519 public key+newtype PublicKey = PublicKey Bytes+ deriving (Show,Eq,ByteArrayAccess,NFData)++-- | An Ed25519 signature+newtype Signature = Signature Bytes+ deriving (Show,Eq,ByteArrayAccess,NFData)++-- | Try to build a public key from a bytearray+publicKey :: ByteArrayAccess ba => ba -> CryptoFailable PublicKey+publicKey bs+ | B.length bs == publicKeySize =+ CryptoPassed $ PublicKey $ B.copyAndFreeze bs (\_ -> return ())+ | otherwise =+ CryptoFailed $ CryptoError_PublicKeySizeInvalid++-- | Try to build a secret key from a bytearray+secretKey :: ByteArrayAccess ba => ba -> CryptoFailable SecretKey+secretKey bs+ | B.length bs == 32 = unsafePerformIO verifyAndTweak+ | otherwise = CryptoFailed CryptoError_SecretKeySizeInvalid+ where+ k = hashWith SHA512 bs+ verifyAndTweak :: IO (CryptoFailable SecretKey)+ verifyAndTweak = withByteArray k $ \inp -> do+ b0 <- peekElemOff inp 0 :: IO Word8+ b31 <- peekElemOff inp 31+ if testBit b31 5+ then return $ CryptoFailed CryptoError_SecretKeyStructureInvalid+ else CryptoPassed . SecretKey <$> (alloc 64 $ \outp -> do+ pokeElemOff outp 0 (b0 .&. 0xf8) -- clear lowest 3 bits+ forM_ [1..30] $ \i -> peekElemOff inp i >>= pokeElemOff outp i+ pokeElemOff outp 31 ((b31 .&. 0x1f) .|. 0x40) -- clear highest bit and 3rd bit, and set 2nd highest.+ forM_ [32..63] $ \i -> peekElemOff inp i >>= pokeElemOff outp i+ )++-- | Try to build a signature from a bytearray+signature :: ByteArrayAccess ba => ba -> CryptoFailable Signature+signature bs+ | B.length bs == signatureSize =+ CryptoPassed $ Signature $ B.copyAndFreeze bs (\_ -> return ())+ | otherwise =+ -- missing a SignatureSizeInvalid error, so use another one+ CryptoFailed $ CryptoError_SecretKeySizeInvalid++-- | Create a public key from a secret key+toPublic :: SecretKey -> PublicKey+toPublic (SecretKey sec) = PublicKey $+ B.allocAndFreeze publicKeySize $ \result ->+ withByteArray sec $ \psec ->+ ccryptonite_ed25519_publickey psec result+{-# NOINLINE toPublic #-}++publicAdd :: PublicKey -> PublicKey -> PublicKey+publicAdd p1 p2 =+ PublicKey $ B.allocAndFreeze publicKeySize $ \result ->+ withByteArray p1 $ \v1 ->+ withByteArray p2 $ \v2 ->+ ccryptonite_ed25519_point_add v1 v2 result++secretAdd :: SecretKey -> SecretKey -> SecretKey+secretAdd p1 p2 =+ SecretKey $ B.allocAndFreeze secretKeySize $ \result ->+ withByteArray p1 $ \v1 ->+ withByteArray p2 $ \v2 ->+ ccryptonite_ed25519_scalar_add v1 v2 result++-- | Sign a message using the key pair+sign :: (ByteArrayAccess msg, ByteArrayAccess salt) => SecretKey -> salt -> PublicKey -> msg -> Signature+sign secret salt public message =+ Signature $ B.allocAndFreeze signatureSize $ \sig ->+ withByteArray secret $ \sec ->+ withByteArray public $ \pub ->+ withByteArray salt $ \saltP ->+ withByteArray message $ \msg ->+ ccryptonite_ed25519_sign msg (fromIntegral msgLen) saltP (fromIntegral saltLen) sec pub sig+ where+ !msgLen = B.length message+ !saltLen = B.length salt++-- | Verify a message+verify :: ByteArrayAccess ba => PublicKey -> ba -> Signature -> Bool+verify public message signatureVal = unsafeDoIO $+ withByteArray signatureVal $ \sig ->+ withByteArray public $ \pub ->+ withByteArray message $ \msg -> do+ r <- ccryptonite_ed25519_sign_open msg (fromIntegral msgLen) pub sig+ return (r == 0)+ where+ !msgLen = B.length message++publicKeySize :: Int+publicKeySize = 32++secretKeySize :: Int+secretKeySize = 64++signatureSize :: Int+signatureSize = 64++foreign import ccall "cardano_crypto_ed25519_publickey"+ ccryptonite_ed25519_publickey :: Ptr SecretKey -- secret key+ -> Ptr PublicKey -- public key+ -> IO ()++foreign import ccall "cardano_crypto_ed25519_sign_open"+ ccryptonite_ed25519_sign_open :: Ptr Word8 -- message+ -> CSize -- message len+ -> Ptr PublicKey -- public+ -> Ptr Signature -- signature+ -> IO CInt++foreign import ccall "cardano_crypto_ed25519_sign"+ ccryptonite_ed25519_sign :: Ptr Word8 -- message+ -> CSize -- message len+ -> Ptr Word8 -- salt+ -> CSize -- salt len+ -> Ptr SecretKey -- secret+ -> Ptr PublicKey -- public+ -> Ptr Signature -- signature+ -> IO ()++foreign import ccall "cardano_crypto_ed25519_point_add"+ ccryptonite_ed25519_point_add :: Ptr PublicKey -- p1+ -> Ptr PublicKey -- p2+ -> Ptr PublicKey -- p1 + p2+ -> IO ()++foreign import ccall "cardano_crypto_ed25519_scalar_add"+ ccryptonite_ed25519_scalar_add :: Ptr SecretKey -- s1+ -> Ptr SecretKey -- s2+ -> Ptr SecretKey -- s1 + s2+ -> IO ()
+ src/Crypto/Encoding/BIP39.hs view
@@ -0,0 +1,440 @@+{-# LANGUAGE GADTs #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+module Crypto.Encoding.BIP39+ ( -- * Entropy+ Entropy+ , ValidEntropySize+ , Checksum+ , ValidChecksumSize+ , MnemonicWords+ , EntropySize+ , toEntropy+ , entropyRaw+ , entropyChecksum++ , entropyToWords+ , wordsToEntropy++ , -- * Seed+ Seed+ , Passphrase+ , sentenceToSeed+ , phraseToSeed++ , -- * Mnemonic Sentence+ MnemonicSentence+ , MnemonicPhrase+ , ValidMnemonicSentence+ , mnemonicPhrase+ , checkMnemonicPhrase+ , mnemonicPhraseToMnemonicSentence+ , mnemonicSentenceToMnemonicPhrase+ , mnemonicSentenceToString+ , mnemonicSentenceToListN+ , mnemonicPhraseToString+ , translateTo+ , -- ** Dictionary+ Dictionary(..)+ , WordIndex+ , wordIndex+ , unWordIndex++ , -- * helpers+ ConsistentEntropy+ , CheckSumBits+ , Elem++ , -- * Errors+ DictionaryError(..)+ , EntropyError(..)+ , MnemonicWordsError(..)+ ) where++import Prelude ((-), (*), (+), div, divMod, (^), fromIntegral)++import qualified Basement.String as String+import Basement.Nat+import qualified Basement.Sized.List as ListN+import Basement.Sized.List (ListN)+import Basement.NormalForm+import Basement.Compat.Typeable+import Basement.Numerical.Number (IsIntegral(..))+import Basement.Imports++import Foundation.Check++import Control.Monad (replicateM, (<=<))+import Data.Bits+import Data.Maybe (fromMaybe)+import Data.List (reverse, intersperse, length)+import Data.Kind (Constraint)+import Data.ByteArray (ByteArrayAccess, ByteArray)+import qualified Data.ByteArray as BA+import Data.ByteString (ByteString)+import qualified Data.ByteString as BS++import Data.Proxy++import GHC.TypeLits++import Crypto.Hash (hashWith, SHA256(..))+import Crypto.Number.Serialize (os2ip, i2ospOf_)+import qualified Crypto.KDF.PBKDF2 as PBKDF2++import Crypto.Encoding.BIP39.Dictionary+import Cardano.Internal.Compat (fromRight)++-- -------------------------------------------------------------------------- --+-- Entropy+-- -------------------------------------------------------------------------- --++-- | this is the `Checksum` of a given 'Entropy'+--+-- the 'Nat' type parameter represent the size, in bits, of this checksum.+newtype Checksum (bits :: Nat) = Checksum Word8+ deriving (Show, Eq, Typeable, NormalForm)++checksum :: forall csz ba . (KnownNat csz, ByteArrayAccess ba)+ => ba -> Checksum csz+checksum bs = Checksum $ (hashWith SHA256 bs `BA.index` 0) `shiftR` (8 - csz)+ where+ csz = fromInteger $ natVal (Proxy @csz)++type ValidChecksumSize (ent :: Nat) (csz :: Nat) =+ ( KnownNat csz, NatWithinBound Int csz+ , Elem csz '[3, 4, 5, 6, 7, 8]+ , CheckSumBits ent ~ csz+ )++-- | Number of bits of checksum related to a specific entropy size in bits+type family CheckSumBits (n :: Nat) :: Nat where+ CheckSumBits 96 = 3+ CheckSumBits 128 = 4+ CheckSumBits 160 = 5+ CheckSumBits 192 = 6+ CheckSumBits 224 = 7+ CheckSumBits 256 = 8++-- | BIP39's entropy is a byte array of a given size (in bits, see+-- 'ValidEntropySize' for the valid size).+--+-- To it is associated+data Entropy (n :: Nat) = Entropy+ { entropyRaw :: !ByteString+ -- ^ Get the raw binary associated with the entropy+ , entropyChecksum :: !(Checksum (CheckSumBits n))+ -- ^ Get the checksum of the Entropy+ }+ deriving (Show, Eq, Typeable)+instance NormalForm (Entropy n) where+ toNormalForm (Entropy !_ cs) = toNormalForm cs+instance Arbitrary (Entropy 96) where+ arbitrary = fromRight (error "arbitrary (Entropy 96)") . toEntropy . BS.pack <$> replicateM 12 arbitrary+instance Arbitrary (Entropy 128) where+ arbitrary = fromRight (error "arbitrary (Entropy 128)") . toEntropy . BS.pack <$> replicateM 16 arbitrary+instance Arbitrary (Entropy 160) where+ arbitrary = fromRight (error "arbitrary (Entropy 160)") . toEntropy . BS.pack <$> replicateM 20 arbitrary+instance Arbitrary (Entropy 192) where+ arbitrary = fromRight (error "arbitrary (Entropy 192)") . toEntropy . BS.pack <$> replicateM 24 arbitrary+instance Arbitrary (Entropy 224) where+ arbitrary = fromRight (error "arbitrary (Entropy 224)") . toEntropy . BS.pack <$> replicateM 28 arbitrary+instance Arbitrary (Entropy 256) where+ arbitrary = fromRight (error "arbitrary (Entropy 256)") . toEntropy . BS.pack <$> replicateM 32 arbitrary++-- | Type Constraint Alias to check a given 'Nat' is valid for an entropy size+--+-- i.e. it must be one of the following: 96, 128, 160, 192, 224, 256.+--+type ValidEntropySize (n :: Nat) =+ ( KnownNat n, NatWithinBound Int n+ , Elem n '[96, 128, 160, 192, 224, 256]+ )++-- | Create a specific entropy type of known size from a raw bytestring+toEntropy :: forall n csz ba+ . (ValidEntropySize n, ValidChecksumSize n csz, ByteArrayAccess ba)+ => ba+ -> Either (EntropyError csz) (Entropy n)+toEntropy bs+ | actual == expected = Right $ Entropy (BA.convert bs) (checksum @csz bs)+ | otherwise = Left $ ErrInvalidEntropyLength actual expected+ where+ actual = BA.length bs*8+ expected = natValInt (Proxy @n)++toEntropyCheck :: forall n csz ba+ . (ValidEntropySize n, ValidChecksumSize n csz, ByteArrayAccess ba)+ => ba+ -> Checksum csz+ -> Either (EntropyError csz) (Entropy n)+toEntropyCheck bs s = case toEntropy bs of+ Left err -> Left err+ Right e@(Entropy _ cs) | cs == s -> Right e+ | otherwise -> Left $ ErrInvalidEntropyChecksum cs s++-- | Number of Words related to a specific entropy size in bits+type family MnemonicWords (n :: Nat) :: Nat where+ MnemonicWords 96 = 9+ MnemonicWords 128 = 12+ MnemonicWords 160 = 15+ MnemonicWords 192 = 18+ MnemonicWords 224 = 21+ MnemonicWords 256 = 24++-- | Corresponding entropy size in bits for a given number of words+type family EntropySize (n :: Nat) :: Nat where+ EntropySize 9 = 96+ EntropySize 12 = 128+ EntropySize 15 = 160+ EntropySize 18 = 192+ EntropySize 21 = 224+ EntropySize 24 = 256+++-- | Type Constraint Alias to check the entropy size, the number of mnemonic+-- words and the checksum size is consistent. i.e. that the following is true:+--+-- | entropysize | checksumsize | entropysize + checksumsize | mnemonicsize |+-- +---------------+--------------+----------------------------+--------------++-- | 96 | 3 | 99 | 9 |+-- | 128 | 4 | 132 | 12 |+-- | 160 | 5 | 165 | 15 |+-- | 192 | 6 | 198 | 18 |+-- | 224 | 7 | 231 | 21 |+-- | 256 | 8 | 264 | 24 |+--+-- This type constraint alias also perform all the GHC's cumbersome type level+-- literal handling.+--+type ConsistentEntropy ent mw csz =+ ( ValidEntropySize ent+ , ValidChecksumSize ent csz+ , ValidMnemonicSentence mw+ , MnemonicWords ent ~ mw+ )++-- | retrieve the initial entropy from a given 'MnemonicSentence'+--+-- This function validate the retrieved 'Entropy' is valid, i.e. that the+-- checksum is correct.+-- This means you should not create a new 'Entropy' from a 'MnemonicSentence',+-- instead, you should use a Random Number Generator to create a new 'Entropy'.+--+wordsToEntropy :: forall ent csz mw+ . ConsistentEntropy ent mw csz+ => MnemonicSentence mw+ -> Either (EntropyError csz) (Entropy ent)+wordsToEntropy (MnemonicSentence ms) =+ let -- we don't revese the list here, we know that the first word index+ -- is the highest first 11 bits of the entropy.+ entropy = ListN.foldl' (\acc x -> acc `shiftL` 11 + toInteger (unWordIndex x)) 0 ms+ initialEntropy :: ByteString+ initialEntropy = i2ospOf_ nb (entropy `shiftR` fromInteger checksumsize)+ cs = Checksum $ fromInteger (entropy .&. mask)+ in toEntropyCheck initialEntropy cs+ where+ checksumsize = natVal (Proxy @csz)+ entropysize = natVal (Proxy @ent)+ nb = fromInteger entropysize `div` 8+ mask = 2 ^ checksumsize - 1++-- | Given an entropy of size n, Create a list+--+entropyToWords :: forall n csz mw . ConsistentEntropy n mw csz+ => Entropy n+ -> MnemonicSentence mw+entropyToWords (Entropy bs (Checksum w)) =+ fromList $ reverse $ loop mw g+ where+ g = (os2ip bs `shiftL` fromIntegral csz) .|. fromIntegral w+ csz = natVal (Proxy @csz)+ mw = natVal (Proxy @mw)+ loop nbWords acc+ | nbWords == 0 = []+ | otherwise =+ let (acc', d) = acc `divMod` 2048+ in wordIndex (fromIntegral d) : loop (nbWords - 1) acc'++-- -------------------------------------------------------------------------- --+-- Seed+-- -------------------------------------------------------------------------- --++newtype Seed = Seed ByteString+ deriving (Show, Eq, Ord, Typeable, Semigroup, Monoid, ByteArrayAccess, ByteArray, IsString)++type Passphrase = String++-- | Create a seed from 'MmemonicSentence' and 'Passphrase' using the BIP39+-- algorithm.+sentenceToSeed :: ValidMnemonicSentence mw+ => MnemonicSentence mw -- ^ 'MmenomicPhrase' of mw words+ -> Dictionary -- ^ Dictionary' of words/indexes+ -> Passphrase -- ^ 'Passphrase' used to generate+ -> Seed+sentenceToSeed mw dic =+ phraseToSeed (mnemonicSentenceToMnemonicPhrase dic mw) dic++-- | Create a seed from 'MmemonicPhrase' and 'Passphrase' using the BIP39+-- algorithm.+phraseToSeed :: ValidMnemonicSentence mw+ => MnemonicPhrase mw -- ^ 'MmenomicPhrase' of mw words+ -> Dictionary -- ^ Dictionary' of words/indexes+ -> Passphrase -- ^ 'Passphrase' used to generate+ -> Seed+phraseToSeed mw dic passphrase =+ PBKDF2.fastPBKDF2_SHA512+ (PBKDF2.Parameters 2048 64)+ sentence+ (toData ("mnemonic" `mappend` passphrase))+ where+ sentence = toData $ mnemonicPhraseToString dic mw+ toData = String.toBytes String.UTF8+++-- -------------------------------------------------------------------------- --+-- Mnemonic Sentence and Mnemonic Phrase+-- -------------------------------------------------------------------------- --++-- | Mnemonic Sentence is a list of 'WordIndex'.+--+-- This is the generic representation of a mnemonic phrase that can be used for+-- transalating to a different dictionary (example: English to Japanese).+--+-- This is mainly used to convert from/to the 'Entropy' and for 'cardanoSlSeed'+--+newtype MnemonicSentence (mw :: Nat) = MnemonicSentence+ { mnemonicSentenceToListN :: ListN mw WordIndex+ }+ deriving (Show, Eq, Ord, Typeable, NormalForm)+instance ValidMnemonicSentence mw => IsList (MnemonicSentence mw) where+ type Item (MnemonicSentence mw) = WordIndex+ fromList = MnemonicSentence . fromMaybe (error "invalid mnemonic size") . ListN.toListN+ toList = ListN.unListN . mnemonicSentenceToListN++-- | Type Constraint to validate the given 'Nat' is valid for the supported+-- 'MnemonicSentence'+type ValidMnemonicSentence (mw :: Nat) =+ ( KnownNat mw+ , NatWithinBound Int mw+ , Elem mw '[9, 12, 15, 18, 21, 24]+ )++-- | Human readable representation of a 'MnemonicSentence'+--+newtype MnemonicPhrase (mw :: Nat) = MnemonicPhrase+ { mnemonicPhraseToListN :: ListN mw String+ }+ deriving (Show, Eq, Ord, Typeable, NormalForm)+instance ValidMnemonicSentence mw => IsList (MnemonicPhrase mw) where+ type Item (MnemonicPhrase mw) = String+ fromList = fromRight (error "invalid mnemonic phrase") . mnemonicPhrase+ toList = ListN.unListN . mnemonicPhraseToListN++mnemonicPhrase :: forall mw . ValidMnemonicSentence mw => [String] -> Either MnemonicWordsError (MnemonicPhrase mw)+mnemonicPhrase l = MnemonicPhrase <$> maybe+ (Left $ ErrWrongNumberOfWords (length l) (natValInt @mw Proxy))+ Right+ (ListN.toListN l)+{-# INLINABLE mnemonicPhrase #-}++-- | check a given 'MnemonicPhrase' is valid for the given 'Dictionary'+--+checkMnemonicPhrase :: forall mw . ValidMnemonicSentence mw+ => Dictionary+ -> MnemonicPhrase mw+ -> Bool+checkMnemonicPhrase dic (MnemonicPhrase ln) =+ ListN.foldl' (\acc s -> (dictionaryTestWord dic s && acc)) True ln++-- | convert the given 'MnemonicPhrase' to a generic 'MnemonicSentence'+-- with the given 'Dictionary'.+--+-- This function assumes the 'Dictionary' and the 'MnemonicPhrase' are+-- compatible (see 'checkMnemonicPhrase').+--+mnemonicPhraseToMnemonicSentence :: forall mw . ValidMnemonicSentence mw+ => Dictionary+ -> MnemonicPhrase mw+ -> Either DictionaryError (MnemonicSentence mw)+mnemonicPhraseToMnemonicSentence dic (MnemonicPhrase ln) = MnemonicSentence <$>+ ListN.mapM (dictionaryWordToIndex dic) ln++-- | convert the given generic 'MnemonicSentence' to a human readable+-- 'MnemonicPhrase' targetting the language of the given 'Dictionary'.+mnemonicSentenceToMnemonicPhrase :: forall mw . ValidMnemonicSentence mw+ => Dictionary+ -> MnemonicSentence mw+ -> MnemonicPhrase mw+mnemonicSentenceToMnemonicPhrase dic (MnemonicSentence ln) = MnemonicPhrase $+ ListN.map (dictionaryIndexToWord dic) ln++mnemonicPhraseToString :: forall mw . ValidMnemonicSentence mw+ => Dictionary+ -> MnemonicPhrase mw+ -> String+mnemonicPhraseToString dic (MnemonicPhrase ln) = mconcat $+ intersperse (dictionaryWordSeparator dic) (ListN.unListN ln)++mnemonicSentenceToString :: forall mw . ValidMnemonicSentence mw+ => Dictionary+ -> MnemonicSentence mw+ -> String+mnemonicSentenceToString dic = mnemonicPhraseToString dic+ . mnemonicSentenceToMnemonicPhrase dic++-- | translate the given 'MnemonicPhrase' from one dictionary into another.+--+-- This function assumes the source dictionary is compatible with the given+-- 'MnemonicPhrase' (see 'checkMnemonicPhrase')+--+translateTo :: forall mw . ValidMnemonicSentence mw+ => Dictionary -- ^ source dictionary+ -> Dictionary -- ^ destination dictionary+ -> MnemonicPhrase mw+ -> Either DictionaryError (MnemonicPhrase mw)+translateTo dicSrc dicDst (MnemonicPhrase ln) = MnemonicPhrase <$>+ ListN.mapM (return . dictionaryIndexToWord dicDst <=< dictionaryWordToIndex dicSrc) ln++------------------------------------------------------------------------+-- Helpers+------------------------------------------------------------------------++-- | convenient type level constraint to validate a given 'Nat' e is an elemnt+-- of the list of 'Nat' l.+type family Elem (e :: Nat) (l :: [Nat]) :: Constraint where+ Elem e '[] = TypeError ('Text "offset: field "+ ':<>: 'ShowType e+ ':<>: 'Text " not elements of valids values")+ Elem e (e ': _) = ()+ Elem e (_ ': xs) = Elem e xs++-- -------------------------------------------------------------------------- --+-- Errors+-- -------------------------------------------------------------------------- --++data EntropyError csz+ = ErrInvalidEntropyLength+ Int -- Actual length in bits+ Int -- Expected length in bits+ | ErrInvalidEntropyChecksum+ (Checksum csz) -- Actual checksum+ (Checksum csz) -- Expected checksum+ deriving (Show)++data MnemonicWordsError+ = ErrWrongNumberOfWords+ Int -- Actual number of words+ Int -- Expected number of words+ deriving (Show)
+ src/Crypto/Encoding/BIP39/Dictionary.hs view
@@ -0,0 +1,88 @@+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE OverloadedStrings #-}++module Crypto.Encoding.BIP39.Dictionary+ ( -- ** Dictionary+ Dictionary(..)+ , WordIndex+ , wordIndex+ , unWordIndex++ , DictionaryError(..)+ ) where++import Basement.NormalForm+import Basement.Compat.Typeable+import Basement.Types.OffsetSize (Offset(..))+import Basement.From (TryFrom(..))+import Basement.Imports++-- | this discribe the property of the Dictionary and will alllow to+-- convert from a mnemonic phrase to 'MnemonicSentence'+--+-- This is especially needed to build the BIP39 'Seed'+--+data Dictionary = Dictionary+ { dictionaryIndexToWord :: WordIndex -> String+ -- ^ This function will retrieve the mnemonic word associated to the+ -- given 'WordIndex'.+ , dictionaryWordToIndex :: String -> Either DictionaryError WordIndex+ -- ^ This function will retrieve the 'WordIndex' from a given mnemonic+ -- word.+ , dictionaryTestWord :: String -> Bool+ -- ^ test a given word is in the dictionary+ , dictionaryWordSeparator :: String+ -- ^ joining string (e.g. space for english)+ }+ deriving (Typeable)++-- | Index of the mnemonic word in the 'Dictionary'+--+-- 'WordIndex' are within range of [0..2047]+--+newtype WordIndex = WordIndex { unWordIndex :: Offset String }+ deriving (Show, Eq, Ord, Typeable, NormalForm)+instance Enum WordIndex where+ toEnum = wordIndex . toEnum+ fromEnum = fromEnum . unWordIndex+ succ (WordIndex (Offset v))+ | v < 2047 = WordIndex (Offset (succ v))+ | otherwise = error "WordIndex out of bound"+ pred (WordIndex (Offset v))+ | v <= 0 = error "WordIndex out of bound"+ | otherwise = WordIndex (Offset (pred v))+instance Bounded WordIndex where+ minBound = WordIndex (Offset 0)+ maxBound = WordIndex (Offset 2047)+instance TryFrom (Offset String) WordIndex where+ tryFrom w+ | w < 2048 = Just (WordIndex w)+ | otherwise = Nothing+instance TryFrom Int WordIndex where+ tryFrom v+ | v >= 0 = tryFrom (Offset v :: Offset String)+ | otherwise = Nothing++wordIndex :: Offset String -> WordIndex+wordIndex w = case tryFrom w of+ Nothing -> error ("Error: word index should be between 0 to 2047. " <> show w)+ Just wi -> wi++-- -------------------------------------------------------------------------- --+-- Errors+-- -------------------------------------------------------------------------- --++data DictionaryError+ = ErrInvalidDictionaryWord String+ deriving (Show)+
+ src/Crypto/Encoding/BIP39/English.hs view
@@ -0,0 +1,2081 @@+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE DataKinds #-}+module Crypto.Encoding.BIP39.English ( english ) where++import Basement.Imports+import Basement.Sized.Vect++import Data.Maybe (fromMaybe)+import qualified Data.List++import Crypto.Encoding.BIP39.Dictionary (Dictionary (..), WordIndex,+ unWordIndex, DictionaryError (..))++english :: Dictionary+english = Dictionary+ { dictionaryWordToIndex = \word -> case Data.List.lookup word list of+ Just x -> Right x+ Nothing -> Left $ ErrInvalidDictionaryWord word+ , dictionaryTestWord = flip Data.List.elem wordList+ , dictionaryIndexToWord = index words . unWordIndex+ , dictionaryWordSeparator = " "+ }++words :: Vect 2048 String+words = fromMaybe (error "invalid vector length") $ toVect $ fromList wordList++list :: [(String, WordIndex)]+list = Data.List.zip wordList [minBound..maxBound]++wordList :: [String]+wordList =+ [ "abandon"+ , "ability"+ , "able"+ , "about"+ , "above"+ , "absent"+ , "absorb"+ , "abstract"+ , "absurd"+ , "abuse"+ , "access"+ , "accident"+ , "account"+ , "accuse"+ , "achieve"+ , "acid"+ , "acoustic"+ , "acquire"+ , "across"+ , "act"+ , "action"+ , "actor"+ , "actress"+ , "actual"+ , "adapt"+ , "add"+ , "addict"+ , "address"+ , "adjust"+ , "admit"+ , "adult"+ , "advance"+ , "advice"+ , "aerobic"+ , "affair"+ , "afford"+ , "afraid"+ , "again"+ , "age"+ , "agent"+ , "agree"+ , "ahead"+ , "aim"+ , "air"+ , "airport"+ , "aisle"+ , "alarm"+ , "album"+ , "alcohol"+ , "alert"+ , "alien"+ , "all"+ , "alley"+ , "allow"+ , "almost"+ , "alone"+ , "alpha"+ , "already"+ , "also"+ , "alter"+ , "always"+ , "amateur"+ , "amazing"+ , "among"+ , "amount"+ , "amused"+ , "analyst"+ , "anchor"+ , "ancient"+ , "anger"+ , "angle"+ , "angry"+ , "animal"+ , "ankle"+ , "announce"+ , "annual"+ , "another"+ , "answer"+ , "antenna"+ , "antique"+ , "anxiety"+ , "any"+ , "apart"+ , "apology"+ , "appear"+ , "apple"+ , "approve"+ , "april"+ , "arch"+ , "arctic"+ , "area"+ , "arena"+ , "argue"+ , "arm"+ , "armed"+ , "armor"+ , "army"+ , "around"+ , "arrange"+ , "arrest"+ , "arrive"+ , "arrow"+ , "art"+ , "artefact"+ , "artist"+ , "artwork"+ , "ask"+ , "aspect"+ , "assault"+ , "asset"+ , "assist"+ , "assume"+ , "asthma"+ , "athlete"+ , "atom"+ , "attack"+ , "attend"+ , "attitude"+ , "attract"+ , "auction"+ , "audit"+ , "august"+ , "aunt"+ , "author"+ , "auto"+ , "autumn"+ , "average"+ , "avocado"+ , "avoid"+ , "awake"+ , "aware"+ , "away"+ , "awesome"+ , "awful"+ , "awkward"+ , "axis"+ , "baby"+ , "bachelor"+ , "bacon"+ , "badge"+ , "bag"+ , "balance"+ , "balcony"+ , "ball"+ , "bamboo"+ , "banana"+ , "banner"+ , "bar"+ , "barely"+ , "bargain"+ , "barrel"+ , "base"+ , "basic"+ , "basket"+ , "battle"+ , "beach"+ , "bean"+ , "beauty"+ , "because"+ , "become"+ , "beef"+ , "before"+ , "begin"+ , "behave"+ , "behind"+ , "believe"+ , "below"+ , "belt"+ , "bench"+ , "benefit"+ , "best"+ , "betray"+ , "better"+ , "between"+ , "beyond"+ , "bicycle"+ , "bid"+ , "bike"+ , "bind"+ , "biology"+ , "bird"+ , "birth"+ , "bitter"+ , "black"+ , "blade"+ , "blame"+ , "blanket"+ , "blast"+ , "bleak"+ , "bless"+ , "blind"+ , "blood"+ , "blossom"+ , "blouse"+ , "blue"+ , "blur"+ , "blush"+ , "board"+ , "boat"+ , "body"+ , "boil"+ , "bomb"+ , "bone"+ , "bonus"+ , "book"+ , "boost"+ , "border"+ , "boring"+ , "borrow"+ , "boss"+ , "bottom"+ , "bounce"+ , "box"+ , "boy"+ , "bracket"+ , "brain"+ , "brand"+ , "brass"+ , "brave"+ , "bread"+ , "breeze"+ , "brick"+ , "bridge"+ , "brief"+ , "bright"+ , "bring"+ , "brisk"+ , "broccoli"+ , "broken"+ , "bronze"+ , "broom"+ , "brother"+ , "brown"+ , "brush"+ , "bubble"+ , "buddy"+ , "budget"+ , "buffalo"+ , "build"+ , "bulb"+ , "bulk"+ , "bullet"+ , "bundle"+ , "bunker"+ , "burden"+ , "burger"+ , "burst"+ , "bus"+ , "business"+ , "busy"+ , "butter"+ , "buyer"+ , "buzz"+ , "cabbage"+ , "cabin"+ , "cable"+ , "cactus"+ , "cage"+ , "cake"+ , "call"+ , "calm"+ , "camera"+ , "camp"+ , "can"+ , "canal"+ , "cancel"+ , "candy"+ , "cannon"+ , "canoe"+ , "canvas"+ , "canyon"+ , "capable"+ , "capital"+ , "captain"+ , "car"+ , "carbon"+ , "card"+ , "cargo"+ , "carpet"+ , "carry"+ , "cart"+ , "case"+ , "cash"+ , "casino"+ , "castle"+ , "casual"+ , "cat"+ , "catalog"+ , "catch"+ , "category"+ , "cattle"+ , "caught"+ , "cause"+ , "caution"+ , "cave"+ , "ceiling"+ , "celery"+ , "cement"+ , "census"+ , "century"+ , "cereal"+ , "certain"+ , "chair"+ , "chalk"+ , "champion"+ , "change"+ , "chaos"+ , "chapter"+ , "charge"+ , "chase"+ , "chat"+ , "cheap"+ , "check"+ , "cheese"+ , "chef"+ , "cherry"+ , "chest"+ , "chicken"+ , "chief"+ , "child"+ , "chimney"+ , "choice"+ , "choose"+ , "chronic"+ , "chuckle"+ , "chunk"+ , "churn"+ , "cigar"+ , "cinnamon"+ , "circle"+ , "citizen"+ , "city"+ , "civil"+ , "claim"+ , "clap"+ , "clarify"+ , "claw"+ , "clay"+ , "clean"+ , "clerk"+ , "clever"+ , "click"+ , "client"+ , "cliff"+ , "climb"+ , "clinic"+ , "clip"+ , "clock"+ , "clog"+ , "close"+ , "cloth"+ , "cloud"+ , "clown"+ , "club"+ , "clump"+ , "cluster"+ , "clutch"+ , "coach"+ , "coast"+ , "coconut"+ , "code"+ , "coffee"+ , "coil"+ , "coin"+ , "collect"+ , "color"+ , "column"+ , "combine"+ , "come"+ , "comfort"+ , "comic"+ , "common"+ , "company"+ , "concert"+ , "conduct"+ , "confirm"+ , "congress"+ , "connect"+ , "consider"+ , "control"+ , "convince"+ , "cook"+ , "cool"+ , "copper"+ , "copy"+ , "coral"+ , "core"+ , "corn"+ , "correct"+ , "cost"+ , "cotton"+ , "couch"+ , "country"+ , "couple"+ , "course"+ , "cousin"+ , "cover"+ , "coyote"+ , "crack"+ , "cradle"+ , "craft"+ , "cram"+ , "crane"+ , "crash"+ , "crater"+ , "crawl"+ , "crazy"+ , "cream"+ , "credit"+ , "creek"+ , "crew"+ , "cricket"+ , "crime"+ , "crisp"+ , "critic"+ , "crop"+ , "cross"+ , "crouch"+ , "crowd"+ , "crucial"+ , "cruel"+ , "cruise"+ , "crumble"+ , "crunch"+ , "crush"+ , "cry"+ , "crystal"+ , "cube"+ , "culture"+ , "cup"+ , "cupboard"+ , "curious"+ , "current"+ , "curtain"+ , "curve"+ , "cushion"+ , "custom"+ , "cute"+ , "cycle"+ , "dad"+ , "damage"+ , "damp"+ , "dance"+ , "danger"+ , "daring"+ , "dash"+ , "daughter"+ , "dawn"+ , "day"+ , "deal"+ , "debate"+ , "debris"+ , "decade"+ , "december"+ , "decide"+ , "decline"+ , "decorate"+ , "decrease"+ , "deer"+ , "defense"+ , "define"+ , "defy"+ , "degree"+ , "delay"+ , "deliver"+ , "demand"+ , "demise"+ , "denial"+ , "dentist"+ , "deny"+ , "depart"+ , "depend"+ , "deposit"+ , "depth"+ , "deputy"+ , "derive"+ , "describe"+ , "desert"+ , "design"+ , "desk"+ , "despair"+ , "destroy"+ , "detail"+ , "detect"+ , "develop"+ , "device"+ , "devote"+ , "diagram"+ , "dial"+ , "diamond"+ , "diary"+ , "dice"+ , "diesel"+ , "diet"+ , "differ"+ , "digital"+ , "dignity"+ , "dilemma"+ , "dinner"+ , "dinosaur"+ , "direct"+ , "dirt"+ , "disagree"+ , "discover"+ , "disease"+ , "dish"+ , "dismiss"+ , "disorder"+ , "display"+ , "distance"+ , "divert"+ , "divide"+ , "divorce"+ , "dizzy"+ , "doctor"+ , "document"+ , "dog"+ , "doll"+ , "dolphin"+ , "domain"+ , "donate"+ , "donkey"+ , "donor"+ , "door"+ , "dose"+ , "double"+ , "dove"+ , "draft"+ , "dragon"+ , "drama"+ , "drastic"+ , "draw"+ , "dream"+ , "dress"+ , "drift"+ , "drill"+ , "drink"+ , "drip"+ , "drive"+ , "drop"+ , "drum"+ , "dry"+ , "duck"+ , "dumb"+ , "dune"+ , "during"+ , "dust"+ , "dutch"+ , "duty"+ , "dwarf"+ , "dynamic"+ , "eager"+ , "eagle"+ , "early"+ , "earn"+ , "earth"+ , "easily"+ , "east"+ , "easy"+ , "echo"+ , "ecology"+ , "economy"+ , "edge"+ , "edit"+ , "educate"+ , "effort"+ , "egg"+ , "eight"+ , "either"+ , "elbow"+ , "elder"+ , "electric"+ , "elegant"+ , "element"+ , "elephant"+ , "elevator"+ , "elite"+ , "else"+ , "embark"+ , "embody"+ , "embrace"+ , "emerge"+ , "emotion"+ , "employ"+ , "empower"+ , "empty"+ , "enable"+ , "enact"+ , "end"+ , "endless"+ , "endorse"+ , "enemy"+ , "energy"+ , "enforce"+ , "engage"+ , "engine"+ , "enhance"+ , "enjoy"+ , "enlist"+ , "enough"+ , "enrich"+ , "enroll"+ , "ensure"+ , "enter"+ , "entire"+ , "entry"+ , "envelope"+ , "episode"+ , "equal"+ , "equip"+ , "era"+ , "erase"+ , "erode"+ , "erosion"+ , "error"+ , "erupt"+ , "escape"+ , "essay"+ , "essence"+ , "estate"+ , "eternal"+ , "ethics"+ , "evidence"+ , "evil"+ , "evoke"+ , "evolve"+ , "exact"+ , "example"+ , "excess"+ , "exchange"+ , "excite"+ , "exclude"+ , "excuse"+ , "execute"+ , "exercise"+ , "exhaust"+ , "exhibit"+ , "exile"+ , "exist"+ , "exit"+ , "exotic"+ , "expand"+ , "expect"+ , "expire"+ , "explain"+ , "expose"+ , "express"+ , "extend"+ , "extra"+ , "eye"+ , "eyebrow"+ , "fabric"+ , "face"+ , "faculty"+ , "fade"+ , "faint"+ , "faith"+ , "fall"+ , "false"+ , "fame"+ , "family"+ , "famous"+ , "fan"+ , "fancy"+ , "fantasy"+ , "farm"+ , "fashion"+ , "fat"+ , "fatal"+ , "father"+ , "fatigue"+ , "fault"+ , "favorite"+ , "feature"+ , "february"+ , "federal"+ , "fee"+ , "feed"+ , "feel"+ , "female"+ , "fence"+ , "festival"+ , "fetch"+ , "fever"+ , "few"+ , "fiber"+ , "fiction"+ , "field"+ , "figure"+ , "file"+ , "film"+ , "filter"+ , "final"+ , "find"+ , "fine"+ , "finger"+ , "finish"+ , "fire"+ , "firm"+ , "first"+ , "fiscal"+ , "fish"+ , "fit"+ , "fitness"+ , "fix"+ , "flag"+ , "flame"+ , "flash"+ , "flat"+ , "flavor"+ , "flee"+ , "flight"+ , "flip"+ , "float"+ , "flock"+ , "floor"+ , "flower"+ , "fluid"+ , "flush"+ , "fly"+ , "foam"+ , "focus"+ , "fog"+ , "foil"+ , "fold"+ , "follow"+ , "food"+ , "foot"+ , "force"+ , "forest"+ , "forget"+ , "fork"+ , "fortune"+ , "forum"+ , "forward"+ , "fossil"+ , "foster"+ , "found"+ , "fox"+ , "fragile"+ , "frame"+ , "frequent"+ , "fresh"+ , "friend"+ , "fringe"+ , "frog"+ , "front"+ , "frost"+ , "frown"+ , "frozen"+ , "fruit"+ , "fuel"+ , "fun"+ , "funny"+ , "furnace"+ , "fury"+ , "future"+ , "gadget"+ , "gain"+ , "galaxy"+ , "gallery"+ , "game"+ , "gap"+ , "garage"+ , "garbage"+ , "garden"+ , "garlic"+ , "garment"+ , "gas"+ , "gasp"+ , "gate"+ , "gather"+ , "gauge"+ , "gaze"+ , "general"+ , "genius"+ , "genre"+ , "gentle"+ , "genuine"+ , "gesture"+ , "ghost"+ , "giant"+ , "gift"+ , "giggle"+ , "ginger"+ , "giraffe"+ , "girl"+ , "give"+ , "glad"+ , "glance"+ , "glare"+ , "glass"+ , "glide"+ , "glimpse"+ , "globe"+ , "gloom"+ , "glory"+ , "glove"+ , "glow"+ , "glue"+ , "goat"+ , "goddess"+ , "gold"+ , "good"+ , "goose"+ , "gorilla"+ , "gospel"+ , "gossip"+ , "govern"+ , "gown"+ , "grab"+ , "grace"+ , "grain"+ , "grant"+ , "grape"+ , "grass"+ , "gravity"+ , "great"+ , "green"+ , "grid"+ , "grief"+ , "grit"+ , "grocery"+ , "group"+ , "grow"+ , "grunt"+ , "guard"+ , "guess"+ , "guide"+ , "guilt"+ , "guitar"+ , "gun"+ , "gym"+ , "habit"+ , "hair"+ , "half"+ , "hammer"+ , "hamster"+ , "hand"+ , "happy"+ , "harbor"+ , "hard"+ , "harsh"+ , "harvest"+ , "hat"+ , "have"+ , "hawk"+ , "hazard"+ , "head"+ , "health"+ , "heart"+ , "heavy"+ , "hedgehog"+ , "height"+ , "hello"+ , "helmet"+ , "help"+ , "hen"+ , "hero"+ , "hidden"+ , "high"+ , "hill"+ , "hint"+ , "hip"+ , "hire"+ , "history"+ , "hobby"+ , "hockey"+ , "hold"+ , "hole"+ , "holiday"+ , "hollow"+ , "home"+ , "honey"+ , "hood"+ , "hope"+ , "horn"+ , "horror"+ , "horse"+ , "hospital"+ , "host"+ , "hotel"+ , "hour"+ , "hover"+ , "hub"+ , "huge"+ , "human"+ , "humble"+ , "humor"+ , "hundred"+ , "hungry"+ , "hunt"+ , "hurdle"+ , "hurry"+ , "hurt"+ , "husband"+ , "hybrid"+ , "ice"+ , "icon"+ , "idea"+ , "identify"+ , "idle"+ , "ignore"+ , "ill"+ , "illegal"+ , "illness"+ , "image"+ , "imitate"+ , "immense"+ , "immune"+ , "impact"+ , "impose"+ , "improve"+ , "impulse"+ , "inch"+ , "include"+ , "income"+ , "increase"+ , "index"+ , "indicate"+ , "indoor"+ , "industry"+ , "infant"+ , "inflict"+ , "inform"+ , "inhale"+ , "inherit"+ , "initial"+ , "inject"+ , "injury"+ , "inmate"+ , "inner"+ , "innocent"+ , "input"+ , "inquiry"+ , "insane"+ , "insect"+ , "inside"+ , "inspire"+ , "install"+ , "intact"+ , "interest"+ , "into"+ , "invest"+ , "invite"+ , "involve"+ , "iron"+ , "island"+ , "isolate"+ , "issue"+ , "item"+ , "ivory"+ , "jacket"+ , "jaguar"+ , "jar"+ , "jazz"+ , "jealous"+ , "jeans"+ , "jelly"+ , "jewel"+ , "job"+ , "join"+ , "joke"+ , "journey"+ , "joy"+ , "judge"+ , "juice"+ , "jump"+ , "jungle"+ , "junior"+ , "junk"+ , "just"+ , "kangaroo"+ , "keen"+ , "keep"+ , "ketchup"+ , "key"+ , "kick"+ , "kid"+ , "kidney"+ , "kind"+ , "kingdom"+ , "kiss"+ , "kit"+ , "kitchen"+ , "kite"+ , "kitten"+ , "kiwi"+ , "knee"+ , "knife"+ , "knock"+ , "know"+ , "lab"+ , "label"+ , "labor"+ , "ladder"+ , "lady"+ , "lake"+ , "lamp"+ , "language"+ , "laptop"+ , "large"+ , "later"+ , "latin"+ , "laugh"+ , "laundry"+ , "lava"+ , "law"+ , "lawn"+ , "lawsuit"+ , "layer"+ , "lazy"+ , "leader"+ , "leaf"+ , "learn"+ , "leave"+ , "lecture"+ , "left"+ , "leg"+ , "legal"+ , "legend"+ , "leisure"+ , "lemon"+ , "lend"+ , "length"+ , "lens"+ , "leopard"+ , "lesson"+ , "letter"+ , "level"+ , "liar"+ , "liberty"+ , "library"+ , "license"+ , "life"+ , "lift"+ , "light"+ , "like"+ , "limb"+ , "limit"+ , "link"+ , "lion"+ , "liquid"+ , "list"+ , "little"+ , "live"+ , "lizard"+ , "load"+ , "loan"+ , "lobster"+ , "local"+ , "lock"+ , "logic"+ , "lonely"+ , "long"+ , "loop"+ , "lottery"+ , "loud"+ , "lounge"+ , "love"+ , "loyal"+ , "lucky"+ , "luggage"+ , "lumber"+ , "lunar"+ , "lunch"+ , "luxury"+ , "lyrics"+ , "machine"+ , "mad"+ , "magic"+ , "magnet"+ , "maid"+ , "mail"+ , "main"+ , "major"+ , "make"+ , "mammal"+ , "man"+ , "manage"+ , "mandate"+ , "mango"+ , "mansion"+ , "manual"+ , "maple"+ , "marble"+ , "march"+ , "margin"+ , "marine"+ , "market"+ , "marriage"+ , "mask"+ , "mass"+ , "master"+ , "match"+ , "material"+ , "math"+ , "matrix"+ , "matter"+ , "maximum"+ , "maze"+ , "meadow"+ , "mean"+ , "measure"+ , "meat"+ , "mechanic"+ , "medal"+ , "media"+ , "melody"+ , "melt"+ , "member"+ , "memory"+ , "mention"+ , "menu"+ , "mercy"+ , "merge"+ , "merit"+ , "merry"+ , "mesh"+ , "message"+ , "metal"+ , "method"+ , "middle"+ , "midnight"+ , "milk"+ , "million"+ , "mimic"+ , "mind"+ , "minimum"+ , "minor"+ , "minute"+ , "miracle"+ , "mirror"+ , "misery"+ , "miss"+ , "mistake"+ , "mix"+ , "mixed"+ , "mixture"+ , "mobile"+ , "model"+ , "modify"+ , "mom"+ , "moment"+ , "monitor"+ , "monkey"+ , "monster"+ , "month"+ , "moon"+ , "moral"+ , "more"+ , "morning"+ , "mosquito"+ , "mother"+ , "motion"+ , "motor"+ , "mountain"+ , "mouse"+ , "move"+ , "movie"+ , "much"+ , "muffin"+ , "mule"+ , "multiply"+ , "muscle"+ , "museum"+ , "mushroom"+ , "music"+ , "must"+ , "mutual"+ , "myself"+ , "mystery"+ , "myth"+ , "naive"+ , "name"+ , "napkin"+ , "narrow"+ , "nasty"+ , "nation"+ , "nature"+ , "near"+ , "neck"+ , "need"+ , "negative"+ , "neglect"+ , "neither"+ , "nephew"+ , "nerve"+ , "nest"+ , "net"+ , "network"+ , "neutral"+ , "never"+ , "news"+ , "next"+ , "nice"+ , "night"+ , "noble"+ , "noise"+ , "nominee"+ , "noodle"+ , "normal"+ , "north"+ , "nose"+ , "notable"+ , "note"+ , "nothing"+ , "notice"+ , "novel"+ , "now"+ , "nuclear"+ , "number"+ , "nurse"+ , "nut"+ , "oak"+ , "obey"+ , "object"+ , "oblige"+ , "obscure"+ , "observe"+ , "obtain"+ , "obvious"+ , "occur"+ , "ocean"+ , "october"+ , "odor"+ , "off"+ , "offer"+ , "office"+ , "often"+ , "oil"+ , "okay"+ , "old"+ , "olive"+ , "olympic"+ , "omit"+ , "once"+ , "one"+ , "onion"+ , "online"+ , "only"+ , "open"+ , "opera"+ , "opinion"+ , "oppose"+ , "option"+ , "orange"+ , "orbit"+ , "orchard"+ , "order"+ , "ordinary"+ , "organ"+ , "orient"+ , "original"+ , "orphan"+ , "ostrich"+ , "other"+ , "outdoor"+ , "outer"+ , "output"+ , "outside"+ , "oval"+ , "oven"+ , "over"+ , "own"+ , "owner"+ , "oxygen"+ , "oyster"+ , "ozone"+ , "pact"+ , "paddle"+ , "page"+ , "pair"+ , "palace"+ , "palm"+ , "panda"+ , "panel"+ , "panic"+ , "panther"+ , "paper"+ , "parade"+ , "parent"+ , "park"+ , "parrot"+ , "party"+ , "pass"+ , "patch"+ , "path"+ , "patient"+ , "patrol"+ , "pattern"+ , "pause"+ , "pave"+ , "payment"+ , "peace"+ , "peanut"+ , "pear"+ , "peasant"+ , "pelican"+ , "pen"+ , "penalty"+ , "pencil"+ , "people"+ , "pepper"+ , "perfect"+ , "permit"+ , "person"+ , "pet"+ , "phone"+ , "photo"+ , "phrase"+ , "physical"+ , "piano"+ , "picnic"+ , "picture"+ , "piece"+ , "pig"+ , "pigeon"+ , "pill"+ , "pilot"+ , "pink"+ , "pioneer"+ , "pipe"+ , "pistol"+ , "pitch"+ , "pizza"+ , "place"+ , "planet"+ , "plastic"+ , "plate"+ , "play"+ , "please"+ , "pledge"+ , "pluck"+ , "plug"+ , "plunge"+ , "poem"+ , "poet"+ , "point"+ , "polar"+ , "pole"+ , "police"+ , "pond"+ , "pony"+ , "pool"+ , "popular"+ , "portion"+ , "position"+ , "possible"+ , "post"+ , "potato"+ , "pottery"+ , "poverty"+ , "powder"+ , "power"+ , "practice"+ , "praise"+ , "predict"+ , "prefer"+ , "prepare"+ , "present"+ , "pretty"+ , "prevent"+ , "price"+ , "pride"+ , "primary"+ , "print"+ , "priority"+ , "prison"+ , "private"+ , "prize"+ , "problem"+ , "process"+ , "produce"+ , "profit"+ , "program"+ , "project"+ , "promote"+ , "proof"+ , "property"+ , "prosper"+ , "protect"+ , "proud"+ , "provide"+ , "public"+ , "pudding"+ , "pull"+ , "pulp"+ , "pulse"+ , "pumpkin"+ , "punch"+ , "pupil"+ , "puppy"+ , "purchase"+ , "purity"+ , "purpose"+ , "purse"+ , "push"+ , "put"+ , "puzzle"+ , "pyramid"+ , "quality"+ , "quantum"+ , "quarter"+ , "question"+ , "quick"+ , "quit"+ , "quiz"+ , "quote"+ , "rabbit"+ , "raccoon"+ , "race"+ , "rack"+ , "radar"+ , "radio"+ , "rail"+ , "rain"+ , "raise"+ , "rally"+ , "ramp"+ , "ranch"+ , "random"+ , "range"+ , "rapid"+ , "rare"+ , "rate"+ , "rather"+ , "raven"+ , "raw"+ , "razor"+ , "ready"+ , "real"+ , "reason"+ , "rebel"+ , "rebuild"+ , "recall"+ , "receive"+ , "recipe"+ , "record"+ , "recycle"+ , "reduce"+ , "reflect"+ , "reform"+ , "refuse"+ , "region"+ , "regret"+ , "regular"+ , "reject"+ , "relax"+ , "release"+ , "relief"+ , "rely"+ , "remain"+ , "remember"+ , "remind"+ , "remove"+ , "render"+ , "renew"+ , "rent"+ , "reopen"+ , "repair"+ , "repeat"+ , "replace"+ , "report"+ , "require"+ , "rescue"+ , "resemble"+ , "resist"+ , "resource"+ , "response"+ , "result"+ , "retire"+ , "retreat"+ , "return"+ , "reunion"+ , "reveal"+ , "review"+ , "reward"+ , "rhythm"+ , "rib"+ , "ribbon"+ , "rice"+ , "rich"+ , "ride"+ , "ridge"+ , "rifle"+ , "right"+ , "rigid"+ , "ring"+ , "riot"+ , "ripple"+ , "risk"+ , "ritual"+ , "rival"+ , "river"+ , "road"+ , "roast"+ , "robot"+ , "robust"+ , "rocket"+ , "romance"+ , "roof"+ , "rookie"+ , "room"+ , "rose"+ , "rotate"+ , "rough"+ , "round"+ , "route"+ , "royal"+ , "rubber"+ , "rude"+ , "rug"+ , "rule"+ , "run"+ , "runway"+ , "rural"+ , "sad"+ , "saddle"+ , "sadness"+ , "safe"+ , "sail"+ , "salad"+ , "salmon"+ , "salon"+ , "salt"+ , "salute"+ , "same"+ , "sample"+ , "sand"+ , "satisfy"+ , "satoshi"+ , "sauce"+ , "sausage"+ , "save"+ , "say"+ , "scale"+ , "scan"+ , "scare"+ , "scatter"+ , "scene"+ , "scheme"+ , "school"+ , "science"+ , "scissors"+ , "scorpion"+ , "scout"+ , "scrap"+ , "screen"+ , "script"+ , "scrub"+ , "sea"+ , "search"+ , "season"+ , "seat"+ , "second"+ , "secret"+ , "section"+ , "security"+ , "seed"+ , "seek"+ , "segment"+ , "select"+ , "sell"+ , "seminar"+ , "senior"+ , "sense"+ , "sentence"+ , "series"+ , "service"+ , "session"+ , "settle"+ , "setup"+ , "seven"+ , "shadow"+ , "shaft"+ , "shallow"+ , "share"+ , "shed"+ , "shell"+ , "sheriff"+ , "shield"+ , "shift"+ , "shine"+ , "ship"+ , "shiver"+ , "shock"+ , "shoe"+ , "shoot"+ , "shop"+ , "short"+ , "shoulder"+ , "shove"+ , "shrimp"+ , "shrug"+ , "shuffle"+ , "shy"+ , "sibling"+ , "sick"+ , "side"+ , "siege"+ , "sight"+ , "sign"+ , "silent"+ , "silk"+ , "silly"+ , "silver"+ , "similar"+ , "simple"+ , "since"+ , "sing"+ , "siren"+ , "sister"+ , "situate"+ , "six"+ , "size"+ , "skate"+ , "sketch"+ , "ski"+ , "skill"+ , "skin"+ , "skirt"+ , "skull"+ , "slab"+ , "slam"+ , "sleep"+ , "slender"+ , "slice"+ , "slide"+ , "slight"+ , "slim"+ , "slogan"+ , "slot"+ , "slow"+ , "slush"+ , "small"+ , "smart"+ , "smile"+ , "smoke"+ , "smooth"+ , "snack"+ , "snake"+ , "snap"+ , "sniff"+ , "snow"+ , "soap"+ , "soccer"+ , "social"+ , "sock"+ , "soda"+ , "soft"+ , "solar"+ , "soldier"+ , "solid"+ , "solution"+ , "solve"+ , "someone"+ , "song"+ , "soon"+ , "sorry"+ , "sort"+ , "soul"+ , "sound"+ , "soup"+ , "source"+ , "south"+ , "space"+ , "spare"+ , "spatial"+ , "spawn"+ , "speak"+ , "special"+ , "speed"+ , "spell"+ , "spend"+ , "sphere"+ , "spice"+ , "spider"+ , "spike"+ , "spin"+ , "spirit"+ , "split"+ , "spoil"+ , "sponsor"+ , "spoon"+ , "sport"+ , "spot"+ , "spray"+ , "spread"+ , "spring"+ , "spy"+ , "square"+ , "squeeze"+ , "squirrel"+ , "stable"+ , "stadium"+ , "staff"+ , "stage"+ , "stairs"+ , "stamp"+ , "stand"+ , "start"+ , "state"+ , "stay"+ , "steak"+ , "steel"+ , "stem"+ , "step"+ , "stereo"+ , "stick"+ , "still"+ , "sting"+ , "stock"+ , "stomach"+ , "stone"+ , "stool"+ , "story"+ , "stove"+ , "strategy"+ , "street"+ , "strike"+ , "strong"+ , "struggle"+ , "student"+ , "stuff"+ , "stumble"+ , "style"+ , "subject"+ , "submit"+ , "subway"+ , "success"+ , "such"+ , "sudden"+ , "suffer"+ , "sugar"+ , "suggest"+ , "suit"+ , "summer"+ , "sun"+ , "sunny"+ , "sunset"+ , "super"+ , "supply"+ , "supreme"+ , "sure"+ , "surface"+ , "surge"+ , "surprise"+ , "surround"+ , "survey"+ , "suspect"+ , "sustain"+ , "swallow"+ , "swamp"+ , "swap"+ , "swarm"+ , "swear"+ , "sweet"+ , "swift"+ , "swim"+ , "swing"+ , "switch"+ , "sword"+ , "symbol"+ , "symptom"+ , "syrup"+ , "system"+ , "table"+ , "tackle"+ , "tag"+ , "tail"+ , "talent"+ , "talk"+ , "tank"+ , "tape"+ , "target"+ , "task"+ , "taste"+ , "tattoo"+ , "taxi"+ , "teach"+ , "team"+ , "tell"+ , "ten"+ , "tenant"+ , "tennis"+ , "tent"+ , "term"+ , "test"+ , "text"+ , "thank"+ , "that"+ , "theme"+ , "then"+ , "theory"+ , "there"+ , "they"+ , "thing"+ , "this"+ , "thought"+ , "three"+ , "thrive"+ , "throw"+ , "thumb"+ , "thunder"+ , "ticket"+ , "tide"+ , "tiger"+ , "tilt"+ , "timber"+ , "time"+ , "tiny"+ , "tip"+ , "tired"+ , "tissue"+ , "title"+ , "toast"+ , "tobacco"+ , "today"+ , "toddler"+ , "toe"+ , "together"+ , "toilet"+ , "token"+ , "tomato"+ , "tomorrow"+ , "tone"+ , "tongue"+ , "tonight"+ , "tool"+ , "tooth"+ , "top"+ , "topic"+ , "topple"+ , "torch"+ , "tornado"+ , "tortoise"+ , "toss"+ , "total"+ , "tourist"+ , "toward"+ , "tower"+ , "town"+ , "toy"+ , "track"+ , "trade"+ , "traffic"+ , "tragic"+ , "train"+ , "transfer"+ , "trap"+ , "trash"+ , "travel"+ , "tray"+ , "treat"+ , "tree"+ , "trend"+ , "trial"+ , "tribe"+ , "trick"+ , "trigger"+ , "trim"+ , "trip"+ , "trophy"+ , "trouble"+ , "truck"+ , "true"+ , "truly"+ , "trumpet"+ , "trust"+ , "truth"+ , "try"+ , "tube"+ , "tuition"+ , "tumble"+ , "tuna"+ , "tunnel"+ , "turkey"+ , "turn"+ , "turtle"+ , "twelve"+ , "twenty"+ , "twice"+ , "twin"+ , "twist"+ , "two"+ , "type"+ , "typical"+ , "ugly"+ , "umbrella"+ , "unable"+ , "unaware"+ , "uncle"+ , "uncover"+ , "under"+ , "undo"+ , "unfair"+ , "unfold"+ , "unhappy"+ , "uniform"+ , "unique"+ , "unit"+ , "universe"+ , "unknown"+ , "unlock"+ , "until"+ , "unusual"+ , "unveil"+ , "update"+ , "upgrade"+ , "uphold"+ , "upon"+ , "upper"+ , "upset"+ , "urban"+ , "urge"+ , "usage"+ , "use"+ , "used"+ , "useful"+ , "useless"+ , "usual"+ , "utility"+ , "vacant"+ , "vacuum"+ , "vague"+ , "valid"+ , "valley"+ , "valve"+ , "van"+ , "vanish"+ , "vapor"+ , "various"+ , "vast"+ , "vault"+ , "vehicle"+ , "velvet"+ , "vendor"+ , "venture"+ , "venue"+ , "verb"+ , "verify"+ , "version"+ , "very"+ , "vessel"+ , "veteran"+ , "viable"+ , "vibrant"+ , "vicious"+ , "victory"+ , "video"+ , "view"+ , "village"+ , "vintage"+ , "violin"+ , "virtual"+ , "virus"+ , "visa"+ , "visit"+ , "visual"+ , "vital"+ , "vivid"+ , "vocal"+ , "voice"+ , "void"+ , "volcano"+ , "volume"+ , "vote"+ , "voyage"+ , "wage"+ , "wagon"+ , "wait"+ , "walk"+ , "wall"+ , "walnut"+ , "want"+ , "warfare"+ , "warm"+ , "warrior"+ , "wash"+ , "wasp"+ , "waste"+ , "water"+ , "wave"+ , "way"+ , "wealth"+ , "weapon"+ , "wear"+ , "weasel"+ , "weather"+ , "web"+ , "wedding"+ , "weekend"+ , "weird"+ , "welcome"+ , "west"+ , "wet"+ , "whale"+ , "what"+ , "wheat"+ , "wheel"+ , "when"+ , "where"+ , "whip"+ , "whisper"+ , "wide"+ , "width"+ , "wife"+ , "wild"+ , "will"+ , "win"+ , "window"+ , "wine"+ , "wing"+ , "wink"+ , "winner"+ , "winter"+ , "wire"+ , "wisdom"+ , "wise"+ , "wish"+ , "witness"+ , "wolf"+ , "woman"+ , "wonder"+ , "wood"+ , "wool"+ , "word"+ , "work"+ , "world"+ , "worry"+ , "worth"+ , "wrap"+ , "wreck"+ , "wrestle"+ , "wrist"+ , "write"+ , "wrong"+ , "yard"+ , "year"+ , "yellow"+ , "you"+ , "young"+ , "youth"+ , "zebra"+ , "zero"+ , "zone"+ , "zoo"+ ]
+ src/Crypto/Math/Bits.hs view
@@ -0,0 +1,110 @@+-- copied & adapted from cryptic+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE GADTs #-}+module Crypto.Math.Bits+ ( FBits(..)+ , FBitsK(..)+ , SizeValid+ , splitHalf+ , append+ , dropBitsOnRight+ , dropBitsOnLeft+ ) where++import Data.Bits+import Data.Proxy+import GHC.Natural+import GHC.TypeLits++-- | Finite Bits+--+-- Sadly Bits is taken by Bits operation+data FBits (n :: Nat) = FBits { unFBits :: Natural }+ deriving (Show,Eq,Ord)++data FBitsK = FBitsK (forall n . (KnownNat n, SizeValid n) => FBits n)++type SizeValid n = (KnownNat n, 1 <= n)++toFBits :: SizeValid n => Natural -> FBits n+toFBits nat = FBits nat .&. allOne++instance SizeValid n => Enum (FBits n) where+ toEnum i | i < 0 && fromIntegral i > unFBits maxi = error "FBits n not within bound"+ | otherwise = FBits (fromIntegral i)+ where maxi = allOne :: FBits n+ fromEnum (FBits n) = fromEnum n++instance SizeValid n => Bounded (FBits n) where+ minBound = FBits 0+ maxBound = allOne++instance SizeValid n => Num (FBits n) where+ fromInteger = toFBits . fromInteger+ (+) (FBits a) (FBits b) = toFBits (a + b)+ (-) (FBits a) (FBits b) = toFBits (a - b)+ (*) (FBits a) (FBits b) = toFBits (a * b)+ abs = id+ signum (FBits a)+ | a == 0 = FBits 0+ | otherwise = FBits 1++instance SizeValid n => Bits (FBits n) where+ (.&.) (FBits a) (FBits b) = FBits (a .&. b)+ (.|.) (FBits a) (FBits b) = FBits (a .|. b)+ xor (FBits a) (FBits b) = FBits (a `xor` b)+ shiftR (FBits a) n = FBits (a `shiftR` n)+ shiftL (FBits a) n = toFBits (a `shiftL` n) -- shiftL can overflow here, so explicit safe reconstruction from natural+ rotateL a i = ((a `shiftL` i) .|. (a `shiftR` (n - i)))+ where n = fromIntegral $ natVal (Proxy :: Proxy n)+ rotateR a i = ((a `shiftR` i) .|. (a `shiftL` (n - i)))+ where n = fromIntegral $ natVal (Proxy :: Proxy n)+ zeroBits = FBits 0+ bit i+ | i < 0 || fromIntegral i >= natVal (Proxy :: Proxy n) = FBits 0+ | otherwise = FBits (2^i)+ testBit (FBits a) i = testBit a i+ bitSize _ = fromIntegral $ natVal (Proxy :: Proxy n)+ bitSizeMaybe _ = Just $ fromIntegral $ natVal (Proxy :: Proxy n)+ isSigned _ = False+ complement a = allOne `xor` a+ popCount (FBits a) = popCount a++allOne :: forall n . SizeValid n => FBits n+allOne = FBits (2 ^ n - 1)+ where n = natVal (Proxy :: Proxy n)++splitHalf :: forall m n . (SizeValid n, (n * 2) ~ m) => FBits m -> (FBits n, FBits n)+splitHalf (FBits a) = (FBits (a `shiftR` n), toFBits a)+ where n = fromIntegral $ natVal (Proxy :: Proxy n)++-- | Append 2 FBits together where the left member is shifted to make room for the right+-- element.+--+-- e.g. append (0x1 :: FBits 1) (0x70 :: FBits 7) = 0xf0 :: FBits 8+append :: forall m n r . (SizeValid m, SizeValid n, SizeValid r, (m + n) ~ r)+ => FBits n -> FBits m -> FBits r+append (FBits a) (FBits b) =+ FBits ((a `shiftL` m) .|. b)+ where m = fromIntegral $ natVal (Proxy :: Proxy m)++--appendK :: FBitsK -> FBitsK -> FBitsK+--appendK (FBitsK a) (FBitsK b) = FBitsK (a `append` b)+ -- FBits ((a `shiftL` m) .|. b)++dropBitsOnRight :: forall a b diff . (KnownNat diff, b <= a, SizeValid a, SizeValid b, (a - b) ~ diff)+ => FBits a+ -> FBits b+dropBitsOnRight (FBits a) = FBits (a `shiftR` fromInteger (natVal (Proxy :: Proxy diff)))++dropBitsOnLeft :: forall a b . (KnownNat b, b <= a, SizeValid a, SizeValid b)+ => FBits a+ -> FBits b+dropBitsOnLeft (FBits a) = toFBits a
+ src/Crypto/Math/Bytes.hs view
@@ -0,0 +1,104 @@+-- copied & adapted from cryptic+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE ViewPatterns #-}+module Crypto.Math.Bytes+ ( Bytes+ , Endian(..)+ , pack+ , packSome+ , unpack+ , fromBits+ , toBits+ , append+ , take+ , drop+ , splitHalf+ , trace+ ) where++import Data.Proxy+import Data.Word+import Data.List (foldl')+import GHC.Natural+import GHC.TypeLits+import Crypto.Math.NatMath+import Data.Bits (shiftL)+import Crypto.Math.Bits (FBits(..))+import Prelude hiding (take, drop)+import qualified Prelude+import qualified Debug.Trace as Trace++newtype Bytes (n :: Nat) = Bytes { unpack :: [Word8] }+ deriving (Show,Eq)++data Endian = LittleEndian | BigEndian+ deriving (Show,Eq)++pack :: forall n . KnownNat n => [Word8] -> Bytes n+pack l+ | n == len = Bytes l+ | otherwise = error "packing failed: length not as expected"+ where+ len = length l+ n = fromIntegral $ natVal (Proxy :: Proxy n)++packSome :: (forall n . KnownNat n => Bytes n -> a) -> [Word8] -> a+packSome f l = case someNatVal (fromIntegral len) of+ Nothing -> error "impossible"+ Just (SomeNat (_ :: Proxy n)) -> f (pack l :: Bytes n)+ where len = length l++fixupBytes :: Endian -> [Word8] -> [Word8]+fixupBytes LittleEndian = reverse+fixupBytes BigEndian = id++trace :: String -> Bytes n -> Bytes n+trace cmd b@(Bytes l) = Trace.trace (cmd ++ ": " ++ concatMap toHex l) b+ where+ toHex w = let (x,y) = w `divMod` 16 in [hex x, hex y]+ hex i | i < 10 = toEnum (fromEnum '0' + fromIntegral i)+ | otherwise = toEnum (fromEnum 'a' + fromIntegral (i-10))++-- | transform bytes into bits with a specific endianness+toBits :: Endian -> Bytes n -> FBits (n * 8)+toBits endian (Bytes l) = FBits $+ foldl' (\acc i -> (acc `shiftL` 8) + fromIntegral i) 0 (fixupBytes endian l)++-- | transform bits into bytes with a specific endianness+fromBits :: forall n . KnownNat n => Endian -> FBits n -> Bytes (Div8 n)+fromBits endian (unFBits -> allBits) = Bytes $ loop [] (0 :: Word) allBits+ where+ n = natVal (Proxy :: Proxy n)+ loop acc i nat+ | fromIntegral i > n = error "binFromFBits over"+ | fromIntegral i == n = fixupBytes endian acc+ | otherwise =+ let (nat', b) = divMod8 nat+ in loop (b:acc) (i+8) nat'++ divMod8 :: Natural -> (Natural, Word8)+ divMod8 i = let (q,m) = i `divMod` 256 in (q,fromIntegral m)+++splitHalf :: forall m n . (KnownNat n, (n * 2) ~ m) => Bytes m -> (Bytes n, Bytes n)+splitHalf (Bytes l) = (Bytes l1, Bytes l2)+ where+ (l1, l2) = splitAt n l+ n = fromIntegral $ natVal (Proxy :: Proxy n)++append :: forall m n r . ((m + n) ~ r)+ => Bytes n -> Bytes m -> Bytes r+append (Bytes a) (Bytes b) = Bytes (a ++ b)++take :: forall n m .(KnownNat n, n <= m) => Bytes m -> Bytes n+take (Bytes l) = Bytes $ Prelude.take (fromIntegral $ natVal (Proxy :: Proxy n)) l++drop :: forall n m . (KnownNat m, KnownNat n, n <= m) => Bytes m -> Bytes n+drop (Bytes l) = Bytes $ Prelude.drop (fromIntegral diff) l+ where diff = natVal (Proxy :: Proxy m) - natVal (Proxy :: Proxy n)
+ src/Crypto/Math/Edwards25519.hs view
@@ -0,0 +1,268 @@+-- |+-- Module : Crypto.Math.Edwards25519+-- Description : Edwards 25519 arithmetics+-- Maintainer : vincent@typed.io+--+-- Simple module to play with the arithmetics of the twisted edwards curve Ed25519+-- using Extended Twisted Edwards Coordinates. Compared to the normal implementation+-- this allow to use standard DH property:+--+-- for all valid s1 and s2 scalar:+--+-- > scalarToPoint (s1 + s2) = pointAdd (scalarToPoint s1) (scalarToPoint s2)+--+-- For further useful references about Ed25519:+--+-- * RFC 8032+-- * <http://ed25519.cr.yp.to/>+-- * <http://ed25519.cr.yp.to/ed25519-20110926.pdf>+-- * <http://eprint.iacr.org/2008/522.pdf>+--+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE CPP #-}++module Crypto.Math.Edwards25519+ (+ -- * Basic types+ Scalar+ , PointCompressed+ , Signature(..)+ -- * smart constructor & destructor+ , scalar+ , scalarP+ , unScalar+ , pointCompressed+ , pointCompressedP+ , unPointCompressed+ , unPointCompressedP+ -- * Arithmetic+ , scalarFromInteger+ , scalarAdd+ , scalarToPoint+ , pointAdd+ -- * Signature & Verify+ , sign+ , verify+ ) where++import Control.DeepSeq (NFData)+import Crypto.Hash+import Crypto.Number.ModArithmetic+import Crypto.Number.Serialize+import Data.Bits+#if MIN_VERSION_memory(0,14,18)+import qualified Data.ByteArray as B hiding (append, reverse)+#else+import qualified Data.ByteArray as B hiding (append)+#endif+import Data.ByteString (ByteString)+import qualified Data.ByteString as B (append, reverse)+import Data.Hashable (Hashable)+import GHC.Stack++import Crypto.Math.Bytes (Bytes)+import qualified Crypto.Math.Bytes as Bytes++-- | Represent a scalar in the base field+newtype Scalar = Scalar { unScalar :: ByteString }++-- | Represent a point on the Edwards 25519 curve+newtype PointCompressed = PointCompressed { unPointCompressed :: ByteString }+ deriving (Show, Eq, Ord, NFData, Hashable)++-- | Represent a signature+newtype Signature = Signature { unSignature :: ByteString }+ deriving (Show, Eq, Ord, NFData, Hashable)++newtype Fq = Fq { unFq :: Integer }+-- newtype Fp = Fp { unFp :: Integer }++{- for debugging+fq :: HasCallStack => Integer -> Fq+fq n+ | n >= 0 && n < q = Fq n+ | otherwise = error "fq"+-}++fq :: Integer -> Fq+fq = Fq++-- | Create a Ed25519 scalar+--+-- Only check that the length is of expected size (32 bytes), no effort is made for the scalar+-- to be in the right base field range on purpose.+scalar :: ByteString -> Scalar+scalar bs+ | B.length bs /= 32 = error "invalid scalar"+ | otherwise = Scalar bs++scalarP :: Bytes 32 -> Scalar+scalarP = scalar . B.pack . Bytes.unpack+++-- | Check if a scalar is valid and all the bits properly set/cleared+-- scalarValid :: Scalar -> Bool+-- scalarValid _s = True -- TODO++-- | Smart constructor to create a compress point binary+--+-- Check if the length is of expected size+pointCompressed :: HasCallStack => ByteString -> PointCompressed+pointCompressed bs+ | B.length bs /= 32 = error ("invalid compressed point: expecting 32 bytes, got " ++ show (B.length bs) ++ " bytes")+ | otherwise = PointCompressed bs++pointCompressedP :: Bytes 32 -> PointCompressed+pointCompressedP = pointCompressed . B.pack . Bytes.unpack++unPointCompressedP :: PointCompressed -> Bytes 32+unPointCompressedP (PointCompressed bs) = Bytes.pack $ B.unpack bs++-- | Create a signature using a variant of ED25519 signature+--+-- we don't hash the secret key to derive a key + prefix, but+-- instead we take an explicit salt and compute a prefix+-- using the secret key + salt.+sign :: B.ByteArrayAccess msg => Scalar -> ByteString -> msg -> Signature+sign a salt msg =+ Signature (unPointCompressed pR `B.append` toBytes s)+ where+ prefix = hash ((unScalar a) `B.append` salt) :: Digest SHA512+ pA = scalarToPoint a+ r = sha512_modq (B.convert prefix `B.append` B.convert msg)+ pR = ePointCompress $ ePointMul r pG+ h = sha512_modq (unPointCompressed pR `B.append` unPointCompressed pA `B.append` B.convert msg)+ s = (unFq r + unFq h * (fromBytes (unScalar a))) `mod` q++-- | Verify a signature+verify :: B.ByteArrayAccess msg => PointCompressed -> msg -> Signature -> Bool+verify pA msg (Signature signature) =+ pS `pointEqual` ePointAdd (ePointDecompress pR) hA+ where+ (pR, s) =+ let (sig0, sig1) = B.splitAt 32 signature+ in (PointCompressed sig0, fq $ fromBytes sig1)++ pointEqual (ExtendedPoint pX pY pZ _) (ExtendedPoint qX qY qZ _) =+ ((pX * qZ - qX * pZ) `mod` p == 0) && ((pY * qZ - qY * pZ) `mod` p == 0)++ h = sha512_modq (unPointCompressed pR `B.append` unPointCompressed pA `B.append` B.convert msg)+ pS = ePointMul s pG+ hA = ePointMul h (ePointDecompress pA)++-- | Add 2 scalar in the base field together+scalarAdd :: Scalar -> Scalar -> Scalar+scalarAdd (Scalar s1) (Scalar s2) = Scalar $ toBytes r+ where+ r = (fromBytes s1 + fromBytes s2) `mod` q++-- | Create a scalar from integer. mainly for debugging purpose.+scalarFromInteger :: Integer -> Scalar+scalarFromInteger n = Scalar $ toBytes (n `mod` q)++-- | Add 2 points together+pointAdd :: PointCompressed -> PointCompressed -> PointCompressed+pointAdd p1 p2 = ePointCompress $ ePointAdd (ePointDecompress p1) (ePointDecompress p2)++-- | Lift a scalar to the curve, and returning a compressed point+scalarToPoint :: Scalar -> PointCompressed+scalarToPoint (Scalar sec) = ePointCompress $ ePointMul (fq (fromBytes sec `mod` q)) pG++-- | Point represented by (X, Y, Z, T) in extended twisted edward coordinates.+--+-- x = X/Z+-- y = Y/Z+-- x*y = T/Z+data ExtendedPoint = ExtendedPoint !Integer !Integer !Integer !Integer+ deriving (Show,Eq)++ePointAdd :: ExtendedPoint -> ExtendedPoint -> ExtendedPoint+ePointAdd (ExtendedPoint pX pY pZ pT) (ExtendedPoint qX qY qZ qT) =+ ExtendedPoint (e*f) (g*h) (f*g) (e*h)+ where+ a = ((pY-pX) * (qY-qX)) `mod` p+ b = ((pY+pX) * (qY+qX)) `mod` p+ c = (2 * pT * qT * curveD) `mod` p+ d = (2 * pZ * qZ) `mod` p+ e = b-a+ f = d-c+ g = d+c+ h = b+a++ePointMul :: Fq -> ExtendedPoint -> ExtendedPoint+ePointMul (Fq s) = loop 255 (ExtendedPoint 0 1 1 0)+ where+ loop !i !acc !pP+ | i < 0 = pP `seq` acc+ | testBit s i = loop (i-1) (ePointAdd acc pP) (ePointAdd pP pP)+ | otherwise = loop (i-1) (ePointAdd acc acc) (ePointAdd acc pP)++ePointCompress :: ExtendedPoint -> PointCompressed+ePointCompress (ExtendedPoint pX pY pZ _) =+ PointCompressed $ toBytes (y .|. ((x .&. 0x1) `shiftL` 255))+ where+ zinv = modp_inv pZ+ x = (pX * zinv) `mod` p+ y = (pY * zinv) `mod` p++ePointDecompress :: PointCompressed -> ExtendedPoint+ePointDecompress (PointCompressed bs) =+ let cy = fromBytes bs+ xSign = testBit cy 255+ y = clearBit cy 255+ x = recoverX y xSign+ in ExtendedPoint x y 1 ((x*y) `mod` p)++-- | Given y and the sign of x, recover x+recoverX :: Integer -> Bool -> Integer+recoverX y xSign = x''+ where+ x2 = (y*y-1) * modp_inv (curveD*y*y+1)+ x = expFast x2 ((p+3) `div` 8) p++ x'+ | (x*x - x2) `mod` p /= 0 = (x * modp_sqrt_m1) `mod` p+ | otherwise = x++ x''+ | odd x' /= xSign = p - x'+ | otherwise = x'++ modp_sqrt_m1 :: Integer+ !modp_sqrt_m1 = expFast 2 ((p-1) `div` 4) p++-- | Unserialize little endian+fromBytes :: ByteString -> Integer+fromBytes = os2ip . B.reverse++-- | Serialize little endian of a given size (32 bytes)+toBytes :: Integer -> ByteString+toBytes = B.reverse . i2ospOf_ 32++-- | Inverse modular p+modp_inv :: Integer -> Integer+modp_inv x = expFast x (p-2) p++-- | Base field 2^255-19 => 25519+p :: Integer+p = 2^(255 ::Int) - 19++-- | Curve constant d+curveD :: Integer+curveD = (-121665 * modp_inv 121666) `mod` p++-- | Group order+q :: Integer+q = 2^(252 ::Int) + 27742317777372353535851937790883648493++-- | Base Point in extended form+pG :: ExtendedPoint+pG = ExtendedPoint g_x g_y 1 ((g_x * g_y) `mod` p)+ where+ !g_y = (4 * modp_inv 5) `mod` p+ !g_x = recoverX g_y False++sha512_modq :: B.ByteArrayAccess ba => ba -> Fq+sha512_modq bs =+ Fq (fromBytes (B.convert (hash bs :: Digest SHA512)) `mod` q)
+ src/Crypto/Math/NatMath.hs view
@@ -0,0 +1,173 @@+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE CPP #-}+-- this is a copy of Crypto.Internal.Nat in cryptonite+module Crypto.Math.NatMath+ where++import GHC.TypeLits++type family Div8 (bitLen :: Nat) :: Nat where+ Div8 0 = 0+ Div8 1 = 0+ Div8 2 = 0+ Div8 3 = 0+ Div8 4 = 0+ Div8 5 = 0+ Div8 6 = 0+ Div8 7 = 0+ Div8 8 = 1+ Div8 9 = 1+ Div8 10 = 1+ Div8 11 = 1+ Div8 12 = 1+ Div8 13 = 1+ Div8 14 = 1+ Div8 15 = 1+ Div8 16 = 2+ Div8 17 = 2+ Div8 18 = 2+ Div8 19 = 2+ Div8 20 = 2+ Div8 21 = 2+ Div8 22 = 2+ Div8 23 = 2+ Div8 24 = 3+ Div8 25 = 3+ Div8 26 = 3+ Div8 27 = 3+ Div8 28 = 3+ Div8 29 = 3+ Div8 30 = 3+ Div8 31 = 3+ Div8 32 = 4+ Div8 33 = 4+ Div8 34 = 4+ Div8 35 = 4+ Div8 36 = 4+ Div8 37 = 4+ Div8 38 = 4+ Div8 39 = 4+ Div8 40 = 5+ Div8 41 = 5+ Div8 42 = 5+ Div8 43 = 5+ Div8 44 = 5+ Div8 45 = 5+ Div8 46 = 5+ Div8 47 = 5+ Div8 48 = 6+ Div8 49 = 6+ Div8 50 = 6+ Div8 51 = 6+ Div8 52 = 6+ Div8 53 = 6+ Div8 54 = 6+ Div8 55 = 6+ Div8 56 = 7+ Div8 57 = 7+ Div8 58 = 7+ Div8 59 = 7+ Div8 60 = 7+ Div8 61 = 7+ Div8 62 = 7+ Div8 63 = 7+ Div8 64 = 8+ Div8 n = 8 + Div8 (n - 64)++type family IsDiv8 (bitLen :: Nat) (n :: Nat) where+ IsDiv8 bitLen 0 = 'True+#if MIN_VERSION_base(4,9,0)+ IsDiv8 bitLen 1 = TypeError ('Text "bitLen " ':<>: 'ShowType bitLen ':<>: 'Text " is not divisible by 8")+ IsDiv8 bitLen 2 = TypeError ('Text "bitLen " ':<>: 'ShowType bitLen ':<>: 'Text " is not divisible by 8")+ IsDiv8 bitLen 3 = TypeError ('Text "bitLen " ':<>: 'ShowType bitLen ':<>: 'Text " is not divisible by 8")+ IsDiv8 bitLen 4 = TypeError ('Text "bitLen " ':<>: 'ShowType bitLen ':<>: 'Text " is not divisible by 8")+ IsDiv8 bitLen 5 = TypeError ('Text "bitLen " ':<>: 'ShowType bitLen ':<>: 'Text " is not divisible by 8")+ IsDiv8 bitLen 6 = TypeError ('Text "bitLen " ':<>: 'ShowType bitLen ':<>: 'Text " is not divisible by 8")+ IsDiv8 bitLen 7 = TypeError ('Text "bitLen " ':<>: 'ShowType bitLen ':<>: 'Text " is not divisible by 8")+#else+ IsDiv8 bitLen 1 = 'False+ IsDiv8 bitLen 2 = 'False+ IsDiv8 bitLen 3 = 'False+ IsDiv8 bitLen 4 = 'False+ IsDiv8 bitLen 5 = 'False+ IsDiv8 bitLen 6 = 'False+ IsDiv8 bitLen 7 = 'False+#endif+ IsDiv8 bitLen n = IsDiv8 n (Mod8 n)++type family Mod8 (n :: Nat) where+ Mod8 0 = 0+ Mod8 1 = 1+ Mod8 2 = 2+ Mod8 3 = 3+ Mod8 4 = 4+ Mod8 5 = 5+ Mod8 6 = 6+ Mod8 7 = 7+ Mod8 8 = 0+ Mod8 9 = 1+ Mod8 10 = 2+ Mod8 11 = 3+ Mod8 12 = 4+ Mod8 13 = 5+ Mod8 14 = 6+ Mod8 15 = 7+ Mod8 16 = 0+ Mod8 17 = 1+ Mod8 18 = 2+ Mod8 19 = 3+ Mod8 20 = 4+ Mod8 21 = 5+ Mod8 22 = 6+ Mod8 23 = 7+ Mod8 24 = 0+ Mod8 25 = 1+ Mod8 26 = 2+ Mod8 27 = 3+ Mod8 28 = 4+ Mod8 29 = 5+ Mod8 30 = 6+ Mod8 31 = 7+ Mod8 32 = 0+ Mod8 33 = 1+ Mod8 34 = 2+ Mod8 35 = 3+ Mod8 36 = 4+ Mod8 37 = 5+ Mod8 38 = 6+ Mod8 39 = 7+ Mod8 40 = 0+ Mod8 41 = 1+ Mod8 42 = 2+ Mod8 43 = 3+ Mod8 44 = 4+ Mod8 45 = 5+ Mod8 46 = 6+ Mod8 47 = 7+ Mod8 48 = 0+ Mod8 49 = 1+ Mod8 50 = 2+ Mod8 51 = 3+ Mod8 52 = 4+ Mod8 53 = 5+ Mod8 54 = 6+ Mod8 55 = 7+ Mod8 56 = 0+ Mod8 57 = 1+ Mod8 58 = 2+ Mod8 59 = 3+ Mod8 60 = 4+ Mod8 61 = 5+ Mod8 62 = 6+ Mod8 63 = 7+ Mod8 n = Mod8 (n - 64)++type IsDivisibleBy8 bitLen = IsDiv8 bitLen bitLen ~ 'True
+ test/GoldenTest.hs view
@@ -0,0 +1,250 @@+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE TypeFamilies #-}++module Main (main) where++import Basement.Nat+import qualified Basement.Sized.List as LN++import Foundation+import Foundation.Check+import qualified Foundation.Parser as Parser+import Foundation.Collection ((!), nonEmpty_)+import Foundation.String+import Foundation.String.Read (readIntegral)++import Data.List (elemIndex)+import Control.Arrow (left)++import Inspector+import qualified Inspector.TestVector.Types as Type+import qualified Inspector.TestVector.Value as Value++import Data.ByteArray (Bytes, convert)+import qualified Data.ByteArray as B++import Cardano.Crypto.Wallet+import Cardano.Crypto.Encoding.Seed+import Cardano.Crypto.Encoding.BIP39+import Crypto.Encoding.BIP39.English (english)+import Cardano.Internal.Compat (fromRight)++import Test.Orphans++main :: IO ()+main = defaultTest $ do+ goldenSignatureEd25519+ goldenBIP39+ goldenHDWallet+ goldenPaperwallet++-- -------------------------------------------------------------------------- --++type GoldenPaperWallet n+ = "cardano" :> "crypto" :> PathParameter "scramble" n+ :> Payload "iv" ScrambleIV+ :> Payload "input" (Mnemonic 'English (MnemonicWords n))+ :> Payload "passphrase" Passphrase+ :> Payload "shielded_input" (Mnemonic 'English (MnemonicWords (n + IVSizeBits)))++goldenPaperwallet :: GoldenT ()+goldenPaperwallet = group $ do+ golden (Proxy :: Proxy (GoldenPaperWallet 128)) $ \iv (Mnemonic input) pw ->+ Mnemonic (scrambleMnemonic (Proxy @128) iv input pw)+ golden (Proxy :: Proxy (GoldenPaperWallet 160)) $ \iv (Mnemonic input) pw ->+ Mnemonic (scrambleMnemonic (Proxy @160) iv input pw)+ golden (Proxy :: Proxy (GoldenPaperWallet 192)) $ \iv (Mnemonic input) pw ->+ Mnemonic (scrambleMnemonic (Proxy @192) iv input pw)++-- -------------------------------------------------------------------------- --++type HDWallet n+ = "cardano" :> "crypto" :> "wallet" :> PathParameter "BIP39-" n+ :> Payload "words" (Mnemonic 'English (MnemonicWords n))+ :> Payload "passphrase" Passphrase+ :> Payload "master_key_generation" MasterKeyGeneration+ :> Payload "derivation_scheme" DerivationScheme+ :> Payload "path" ChainCodePath+ :> Payload "data_to_sign" String+ :> ( Payload "xPub" XPub+ , Payload "xPriv" XPrv+ , Payload "signature" XSignature+ , Payload "seed" Seed+ )++goldenHDWallet :: GoldenT ()+goldenHDWallet = group $ do+ summary "This test vectors uses the `Cardano.Crypto.Wallet` primitives to produce extended\n\+ \private keys which are _encrypted_ with a passphrase. A passphrase can be empty as well.\n\+ \Under this schema, we support only hardened key derivation."++ golden (Proxy :: Proxy (HDWallet 128)) (runTest (Proxy @128))+ golden (Proxy :: Proxy (HDWallet 160)) (runTest (Proxy @160))+ golden (Proxy :: Proxy (HDWallet 192)) (runTest (Proxy @192))+ golden (Proxy :: Proxy (HDWallet 224)) (runTest (Proxy @224))+ golden (Proxy :: Proxy (HDWallet 256)) (runTest (Proxy @256))+ where+ runTest :: forall n csz mw . ConsistentEntropy n mw csz+ => Proxy n+ -> Mnemonic 'English mw+ -> Passphrase+ -> MasterKeyGeneration+ -> DerivationScheme+ -> ChainCodePath+ -> String+ -> (XPub, XPrv, XSignature, Seed)+ runTest p (Mnemonic mw) pw mkg ds (Root path) toSign =+ let -- 1. retrieve the seed+ -- 1. retrieve the seed and 2. generate from the seed+ (seed, master) = case mkg of+ MasterKeyRetryOld ->+ let seedX = fromMaybe (error "Invalid Mnemonic, cannot retrieve the `Seed'")+ (cardanoSlSeed p mw)+ in (seedX, generate seedX pw)+ MasterKeyPBKDF ->+ let seedX = seedFromMnemonics p mw+ in (seedX, generateNew seedX (B.empty :: Bytes) pw)+ -- 3. get the XPrv from the master and the path+ priv = deriveWith master path+ -- 4. get the public key+ pub = toXPub priv+ -- 5. sign some data+ s = sign pw priv toSign+ in (pub, priv, s, seed)+ where+ deriveWith :: XPrv -> [Word32] -> XPrv+ deriveWith = foldl' (deriveXPrv ds pw)++ seedFromMnemonics :: forall n csz mw . ConsistentEntropy n mw csz+ => Proxy n+ -> MnemonicSentence mw+ -> Seed+ seedFromMnemonics _ mw =+ case wordsToEntropy @n @csz @mw mw of+ Left _ -> error "Invalid Mnemonic"+ Right e -> B.convert $ entropyRaw e++-- -------------------------------------------------------------------------- --++type BIP39 n+ = "crypto" :> "encoding" :> PathParameter "BIP39-" n+ :> Payload "words" (Mnemonic 'English (MnemonicWords n))+ :> Payload "passphrase" Passphrase+ :> ( Payload "entropy" (Entropy n)+ , Payload "seed" Seed+ )++goldenBIP39 :: GoldenT ()+goldenBIP39 = group $ do+ summary "Test official BIP39"++ golden (Proxy :: Proxy (BIP39 128)) (runTest (Proxy @128))+ -- golden (Proxy :: Proxy (BIP39 160)) (runTest (Proxy @160))+ golden (Proxy :: Proxy (BIP39 192)) (runTest (Proxy @192))+ -- golden (Proxy :: Proxy (BIP39 224)) (runTest (Proxy @224))+ golden (Proxy :: Proxy (BIP39 256)) (runTest (Proxy @256))+ where+ runTest :: forall n csz mw . ConsistentEntropy n mw csz+ => Proxy n+ -> Mnemonic 'English mw+ -> Passphrase+ -> (Entropy n, Seed)+ runTest p (Mnemonic mw) pw =+ let -- 1. retrieve the entroy+ entropy = fromRight (error "invalid mnemonic phrase")+ (wordsToEntropy @n mw)+ -- 2. retrieve the seed+ seed = sentenceToSeed @mw mw english pw+ in (entropy, seed)++-- -------------------------------------------------------------------------- --++type SignatureEd25519+ = "cardano" :> "crypto" :> "signature-ed25519"+ :> Payload "xpub" XPub+ :> Payload "data" Bytes+ :> Payload "signature" XSignature+ :> Payload "valid" Bool++goldenSignatureEd25519 :: GoldenT ()+goldenSignatureEd25519 = golden (Proxy :: Proxy SignatureEd25519) verify++-- -------------------------------------------------------------------------- --+-- Helpers --+-- -------------------------------------------------------------------------- --++-- | `m/0'/1'/1000'`+newtype ChainCodePath = Root [Word32]+ deriving (Show, Eq, Typeable)+instance Arbitrary ChainCodePath where+ arbitrary = Root <$> arbitrary++instance Inspectable ChainCodePath where+ documentation _ = "Derivation Chain code path: list of derivation path."+ exportType _ = Type.Array $ Type.UnsizedArray Type.Unsigned32+ builder (Root l) = builder l+ parser v = Root <$> parser v++-- Enum for the support language to read/write from mnemonic+data Language = English++-- | a convenient type to help read/parse/document expected input of type+-- BIP39 mnemonics+newtype Mnemonic (k :: Language) n = Mnemonic (MnemonicSentence n)+ deriving (Eq, Typeable)++-- | The type of master key generation+data MasterKeyGeneration = MasterKeyRetryOld | MasterKeyPBKDF+ deriving (Show,Eq)++instance Inspectable MasterKeyGeneration where+ documentation _ = "Master Key Derivation: list of derivation path."+ exportType _ = Type.String+ builder MasterKeyRetryOld = Value.String "retry-old"+ builder MasterKeyPBKDF = Value.String "pbkdf"+ parser = withString "MasterKeyGeneration" $ \str -> case str of+ "retry-old" -> pure MasterKeyRetryOld+ "pbkdf" -> pure MasterKeyPBKDF+ _ -> Left $ "Expected either `retry-old' or `pbkdf' but found: `" <> str <> "'"++instance Arbitrary MasterKeyGeneration where+ arbitrary = elements $ nonEmpty_ [MasterKeyRetryOld, MasterKeyPBKDF]++instance Arbitrary (Mnemonic 'English 12) where+ arbitrary = Mnemonic . entropyToWords @128 @4 @12 <$> arbitrary+instance Arbitrary (Mnemonic 'English 15) where+ arbitrary = Mnemonic . entropyToWords @160 @5 @15 <$> arbitrary+instance Arbitrary (Mnemonic 'English 18) where+ arbitrary = Mnemonic . entropyToWords @192 @6 @18 <$> arbitrary+instance Arbitrary (Mnemonic 'English 21) where+ arbitrary = Mnemonic . entropyToWords @224 @7 @21 <$> arbitrary+instance Arbitrary (Mnemonic 'English 24) where+ arbitrary = Mnemonic . entropyToWords @256 @8 @24 <$> arbitrary++instance ValidMnemonicSentence n => Inspectable (Mnemonic 'English n) where+ documentation _ = "BIP39 mnemonic sentence (in English) of " <> show n <> " BIP39 Enlighs words"+ where+ n = natVal @n Proxy+ exportType _ = Type.String+ builder (Mnemonic l) = Value.String $ mnemonicSentenceToString english l+ parser v = do+ strs <- words <$> parser v+ phrase <- left show $ mnemonicPhrase @n strs+ left show $ Mnemonic <$> mnemonicPhraseToMnemonicSentence english phrase+ where+ n = natVal @n Proxy++instance Arbitrary XSignature where+ arbitrary = undefined+instance Arbitrary Bytes where+ arbitrary = undefined+instance Arbitrary XPub where+ arbitrary = undefined
+ test/Spec.hs view
@@ -0,0 +1,425 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ScopedTypeVariables #-}+module Main where++import Control.Monad+import GHC.TypeLits++import Basement.From+import Basement.Nat+import Basement.Bounded+import Foundation.Collection (nonEmpty_)+import Foundation (IsList(..))+import Foundation.Check+import Foundation.Check.Main++import qualified Crypto.Math.Edwards25519 as Edwards25519+import qualified Crypto.ECC.Ed25519Donna as EdVariant++import qualified Crypto.ECC.Ed25519BIP32 as EdBIP32++import Cardano.Crypto.Wallet+import Cardano.Crypto.Wallet.Encrypted+import qualified Cardano.Crypto.Wallet.Pure as PureWallet+import qualified Data.ByteString as B+import qualified Data.ByteArray as B (convert)+import Crypto.Error+import Crypto.Random (drgNewTest, withDRG)+import qualified Crypto.Random as Random+import Crypto.Math.Bits+import qualified Crypto.Math.Bytes as Bytes+import Data.Word+import Data.Bits+import Data.Monoid ((<>))+import Data.Proxy++import Data.Type.Equality+import Utils++import qualified Crypto.Encoding.BIP39 as BIP39+import qualified Cardano.Crypto.Encoding.Seed as PW++import qualified Test.Crypto as Crypto+import qualified Test.Cardano as Cardano++noPassphrase :: B.ByteString+noPassphrase = ""++dummyPassphrase :: B.ByteString+dummyPassphrase = "dummy passphrase"++newtype Passphrase = Passphrase B.ByteString+ deriving (Show,Eq)++data Ed = Ed Integer Edwards25519.Scalar++newtype Seed = Seed B.ByteString+ deriving (Show,Eq)++newtype ValidSeed = ValidSeed Seed+ deriving (Show,Eq)++newtype Message = Message B.ByteString+ deriving (Show,Eq)++newtype Salt = Salt B.ByteString+ deriving (Show,Eq)++p :: Integer+p = 2^(255 :: Int) - 19++q :: Integer+q = 2^(252 :: Int) + 27742317777372353535851937790883648493++chooseInt :: forall n . KnownNat n => Proxy n -> Gen Int+chooseInt _ = fromInteger . from . unZn <$> (arbitrary :: Gen (Zn n))++chooseInteger :: forall n . KnownNat n => Integer -> Proxy n -> Gen Integer+chooseInteger base _ = ((+) base) . fromInteger . from . unZn <$> (arbitrary :: Gen (Zn n))++instance Show Ed where+ show (Ed i _) = "Edwards25519.Scalar " <> show i+instance Eq Ed where+ (Ed x _) == (Ed y _) = x == y+instance Arbitrary Ed where+ arbitrary = do+ n <- frequency $ nonEmpty_+ [ (1, chooseInteger (q-10000) (Proxy :: Proxy 9999))+ , (1, chooseInteger 1 (Proxy :: Proxy 999))+ , (2, chooseInteger 1 (Proxy :: Proxy 7237005577332262213973186563042994240857116359379907606001950938285454250988))+ ]+ return (Ed n (Edwards25519.scalarFromInteger n))+instance Arbitrary Message where+ arbitrary = Message . B.pack <$> (chooseInt (Proxy :: Proxy 10) >>= \n -> replicateM n arbitrary)+instance Arbitrary Salt where+ arbitrary = Salt . B.pack <$> (chooseInt (Proxy :: Proxy 10) >>= \n -> replicateM n arbitrary)+instance Arbitrary Passphrase where+ arbitrary = Passphrase . B.pack <$> (chooseInt (Proxy :: Proxy 23) >>= \n -> replicateM n arbitrary)+instance Arbitrary Seed where+ arbitrary = Seed . B.pack <$> replicateM 32 arbitrary+instance Arbitrary ValidSeed where+ arbitrary = do+ s@(Seed seed) <- arbitrary+ case seedToSecret seed of+ CryptoPassed _ -> pure $ ValidSeed s+ _ -> arbitrary++testEdwards25519 =+ [ Property "add" $ \(Ed _ a) (Ed _ b) -> (ltc a .+ ltc b) == ltc (Edwards25519.scalarAdd a b)+ ]+ where+ (.+) = Edwards25519.pointAdd+ ltc = Edwards25519.scalarToPoint++testPointAdd =+ [ Property "add" $ \(Ed _ a) (Ed _ b) ->+ let pa = Edwards25519.scalarToPoint a+ pb = Edwards25519.scalarToPoint b+ pc = Edwards25519.pointAdd pa pb+ pa' = pointToPublic pa+ pb' = pointToPublic pb+ pc' = EdVariant.publicAdd pa' pb'+ in Edwards25519.unPointCompressed pc === B.convert pc'+ ]++{-+testHdDerivation =+ [ Property "pub . sec-derivation = pub-derivation . pub" normalDerive+ , Property "verify (pub . pub-derive) (sign . sec-derivation)" verifyDerive+ ]+ where+ dummyChainCode = B.replicate 32 38+ dummyMsg = B.pack [1,2,3,4,5,6,7]++ normalDerive (Ed _ s) n =+ let pubKey = Edwards25519.scalarToPoint s+ prv = either error id $ xprv (Edwards25519.unScalar s `B.append` Edwards25519.unPointCompressed pubKey `B.append` dummyChainCode)+ pub = toXPub prv+ cPrv = deriveXPrv noPassphrase prv n+ cPub = deriveXPub pub n+ in unXPub (toXPub cPrv) === unXPub cPub++ verifyDerive (Ed _ s) n =+ let pubKey = Edwards25519.scalarToPoint s+ prv = either error id $ xprv (Edwards25519.unScalar s `B.append` Edwards25519.unPointCompressed pubKey `B.append` dummyChainCode)+ pub = toXPub prv+ cPrv = deriveXPrv noPassphrase prv n+ cPub = deriveXPub pub n+ in verify cPub dummyMsg (sign noPassphrase cPrv dummyMsg)+-}++testEncrypted =+ [ Property "pub(sec) = pub(encrypted(no-pass, sec))" (pubEq noPassphrase)+ , Property "pub(sec) = pub(encrypted(dummy, sec))" (pubEq dummyPassphrase)+ , Property "pub(sec) = pub(encrypted(no-pass, sec))" (pubEqValid noPassphrase)+ , Property "pub(sec) = pub(encrypted(dummy, sec))" (pubEqValid dummyPassphrase)+ , Property "sign(sec, msg) = sign(encrypted(no-pass, sec), msg)" (signEq noPassphrase)+ , Property "sign(sec, msg) = sign(encrypted(dummy, sec), msg)" (signEq dummyPassphrase)+ , Property "n <= 0x80000000 => pub(derive(sec, n)) = derive-public(pub(sec), n) [chaincode]" (deriveNormalChainCode noPassphrase)+ , Property "n <= 0x80000000 => pub(derive(sec, n)) = derive-public(pub(sec), n) [publickey]" (deriveNormalPublicKey dummyPassphrase)+ {-+ , Property "derive-hard(sec, n) = derive-hard(encrypted(no-pass, sec), n)" (deriveEq True noPassphrase)+ , Property "derive-hard(sec, n) = derive-hard(encrypted(dummy, sec), n)" (deriveEq True dummyPassphrase)+ , Property "derive-norm(sec, n) = derive-norm(encrypted(no-pass, sec), n)" (deriveEq False noPassphrase)+ , Property "derive-norm(sec, n) = derive-norm(encrypted(dummy, sec), n)" (deriveEq False dummyPassphrase)+ -}+ ]+ where+ dummyChainCode = B.replicate 32 38+ pubEq pass (Seed s) =+ let a = seedToSecret s+ pub1 = EdVariant.toPublic <$> a+ ekey = encryptedCreate s pass dummyChainCode+ in (B.convert <$> pub1) === (encryptedPublic <$> ekey)+ pubEqValid pass (ValidSeed (Seed s)) =+ case (seedToSecret s, encryptedCreate s pass dummyChainCode) of+ (CryptoPassed a, CryptoPassed ekey) ->+ let pub1 = EdVariant.toPublic a+ in B.convert pub1 === encryptedPublic ekey+ _ -> error "valid seed got a invalid result"++ signEq pass (ValidSeed (Seed s)) (Message msg) =+ case (seedToSecret s, encryptedCreate s pass dummyChainCode) of+ (CryptoPassed a, CryptoPassed ekey) ->+ let pub1 = EdVariant.toPublic a+ sig1 = EdVariant.sign a dummyChainCode pub1 msg+ (Signature sig2) = encryptedSign ekey pass msg+ in B.convert sig1 === sig2+ _ -> error "valid seed got a invalid result"+ deriveNormalPublicKey pass dscheme (ValidSeed (Seed s)) nRaw =+ let ekey = throwCryptoError $ encryptedCreate s pass dummyChainCode+ ckey = encryptedDerivePrivate dscheme ekey pass n+ (expectedPubkey, expectedChainCode) = encryptedDerivePublic dscheme (encryptedPublic ekey, encryptedChainCode ekey) n+ in encryptedPublic ckey === expectedPubkey+ where n = nRaw `mod` 0x80000000+ deriveNormalChainCode pass dscheme (ValidSeed (Seed s)) nRaw =+ let ekey = throwCryptoError $ encryptedCreate s pass dummyChainCode+ ckey = encryptedDerivePrivate dscheme ekey pass n+ (expectedPubkey, expectedChainCode) = encryptedDerivePublic dscheme (encryptedPublic ekey, encryptedChainCode ekey) n+ in encryptedChainCode ckey === expectedChainCode+ where n = nRaw `mod` 0x80000000+ {-+ deriveEq True pass (Seed s) n =+ let a = scalarToSecret s+ xprv1 = flip PureWallet.XPrv (ChainCode dummyChainCode) <$> s+ cprv1 = PureWallet.deriveXPrvHardened xprv1 n+ xprv2 = encryptedCreate s pass dummyChainCode+ cprv2 = encryptedDeriveHardened xprv2 pass n+ in PureWallet.xprvPub cprv1 === (encryptedPublic <$> cprv2)+ deriveEq False pass (Seed s) n =+ let a = scalarToSecret s+ xprv1 = PureWallet.XPrv s (ChainCode dummyChainCode)+ cprv1 = PureWallet.deriveXPrv xprv1 n+ xprv2 = encryptedCreate s pass dummyChainCode+ cprv2 = encryptedDeriveNormal xprv2 pass n+ in PureWallet.xprvPub cprv1 === encryptedPublic cprv2+ -}++testVariant =+ [ Property "public-key" testPublicKey+ , Property "signature" testSignature+ , Property "scalar-add" testScalarAdd+ -- , Property "point-add" testPointAdd+ ]+ where+ testPublicKey (Ed _ a) =+ let pub1 = Edwards25519.scalarToPoint a+ pub2 = EdVariant.toPublic (scalarToSecret a)+ in pub1 `pointEqPublic` pub2+ testSignature (Ed _ a) (Salt salt) (Message msg) =+ let -- pub = Edwards25519.unPointCompressed $ Edwards25519.scalarToPoint a+ sec = scalarToSecret a+ sig1 = Edwards25519.sign a salt msg+ sig2 = EdVariant.sign sec salt (EdVariant.toPublic sec) msg+ in sig1 `signatureEqSig` sig2+ testScalarAdd (Ed _ a) (Ed _ b) =+ let r1 = Edwards25519.scalarAdd a b+ r2 = EdVariant.secretAdd (scalarToSecret a) (scalarToSecret b)+ in r1 `scalarEqSecret` r2+ testPointAdd (Ed _ a) (Ed _ b) =+ let p = Edwards25519.scalarToPoint a+ q = Edwards25519.scalarToPoint b+ p' = EdVariant.toPublic $ scalarToSecret a+ q' = EdVariant.toPublic $ scalarToSecret b+ in Edwards25519.pointAdd p q `pointEqPublic` EdVariant.publicAdd p' q'++ signatureEqSig :: Edwards25519.Signature -> EdVariant.Signature -> PropertyCheck+ signatureEqSig sig sig2 = Edwards25519.unSignature sig === B.convert sig2++ pointEqPublic :: Edwards25519.PointCompressed -> EdVariant.PublicKey -> PropertyCheck+ pointEqPublic pub (EdVariant.PublicKey pub2) = Edwards25519.unPointCompressed pub === B.convert pub2++ scalarEqSecret :: Edwards25519.Scalar -> EdVariant.SecretKey -> PropertyCheck+ scalarEqSecret s sec = Edwards25519.unScalar s === B.convert sec++pointToPublic :: Edwards25519.PointCompressed -> EdVariant.PublicKey+pointToPublic = throwCryptoError . EdVariant.publicKey . Edwards25519.unPointCompressed++scalarToSecret :: Edwards25519.Scalar -> EdVariant.SecretKey+scalarToSecret = throwCryptoError . EdVariant.secretKey . Edwards25519.unScalar++testChangePassphrase :: [Test]+testChangePassphrase =+ [ Property "change-passphrase-publickey-stable" pubEq+ , Property "normal-derive-key-different-passphrase-stable" deriveNormalEq+ , Property "hardened-derive-key-different-passphrase-stable" deriveHardenedEq+ ]+ where+ pubEq (ValidSeed (Seed s)) (Passphrase p1) (Passphrase p2) =+ let xprv1 = throwCryptoError $ encryptedCreate s p1 dummyChainCode+ xprv2 = encryptedChangePass p1 p2 xprv1+ in encryptedPublic xprv1 === encryptedPublic xprv2++ deriveNormalEq dscheme (ValidSeed (Seed s)) (Passphrase p1) (Passphrase p2) n =+ let xprv1 = throwCryptoError $ encryptedCreate s p1 dummyChainCode+ xprv2 = encryptedChangePass p1 p2 xprv1+ cPrv1 = encryptedDerivePrivate dscheme xprv1 p1 (toNormal n)+ cPrv2 = encryptedDerivePrivate dscheme xprv2 p2 (toNormal n)+ in encryptedPublic cPrv1 === encryptedPublic cPrv2++ deriveHardenedEq dscheme (ValidSeed (Seed s)) (Passphrase p1) (Passphrase p2) n =+ let xprv1 = throwCryptoError $ encryptedCreate s p1 dummyChainCode+ xprv2 = encryptedChangePass p1 p2 xprv1+ cPrv1 = encryptedDerivePrivate dscheme xprv1 p1 (toHardened n)+ cPrv2 = encryptedDerivePrivate dscheme xprv2 p2 (toHardened n)+ in encryptedPublic cPrv1 === encryptedPublic cPrv2++ dummyChainCode = B.replicate 32 38++ toHardened, toNormal :: Word32 -> Word32+ toHardened n = setBit n 31+ toNormal n = clearBit n 31++seedToSecret :: B.ByteString -> CryptoFailable EdVariant.SecretKey+seedToSecret = EdVariant.secretKey++series :: String -> [a] -> (a -> Test) -> Test+series cmd l runProp = Group (fromList cmd) $ map runProp l++withHardIndex :: Integer+ -> (forall n . (KnownNat n, EdBIP32.ValidDerivationIndex n ~ 'True, EdBIP32.ValidDerivationHardIndex n ~ 'True)+ => EdBIP32.DerivationIndex 'EdBIP32.Hard n+ -> Test)+ -> Test+withHardIndex idxVal f =+ case someNatVal idxVal of+ Just (SomeNat (pidx :: Proxy n)) ->+ case EdBIP32.getValidIndex pidx of+ Nothing -> error ("invalid index: " ++ show idxVal)+ Just Refl ->+ case EdBIP32.getValidHardIndex pidx of+ Nothing -> error ("invalid hard index: " ++ show idxVal)+ Just Refl -> f (EdBIP32.DerivationIndex :: EdBIP32.DerivationIndex 'EdBIP32.Hard n)+ Nothing ->+ error "not a known number"++withSoftIndex :: Integer+ -> (forall n . (KnownNat n, EdBIP32.ValidDerivationIndex n ~ 'True, EdBIP32.ValidDerivationSoftIndex n ~ 'True)+ => EdBIP32.DerivationIndex 'EdBIP32.Soft n+ -> Test)+ -> Test+withSoftIndex idxVal f =+ case someNatVal idxVal of+ Just (SomeNat (pidx :: Proxy n)) ->+ case EdBIP32.getValidIndex pidx of+ Nothing -> error ("invalid index: " ++ show idxVal)+ Just Refl ->+ case EdBIP32.getValidSoftIndex pidx of+ Nothing -> error ("invalid soft index: " ++ show idxVal)+ Just Refl -> f (EdBIP32.DerivationIndex :: EdBIP32.DerivationIndex 'EdBIP32.Soft n)+ Nothing ->+ error "not a known number"++testEdBIP32 :: [Test]+testEdBIP32 =+ [ Property "Xprv creation" $ \rsk rcc ->+ let extPriv = makeXprv rsk rcc+ k = makeEdBip32 rsk rcc+ in xprvEqKey extPriv k+ , Property "pub same" $ \rsk rcc ->+ let extPriv = makeXprv rsk rcc+ k = makeEdBip32 rsk rcc+ in xprvEqPublicKey (toXPub extPriv) (EdBIP32.toPublic k)+ , series "verify-hard-secret-derivation" hardIdx $ \idx ->+ withHardIndex idx $ \hIdx ->+ Property (fromList $ show idx) $ \rsk rcc ->+ let extPriv = makeXprv rsk rcc+ cPrv1 = deriveXPrv DerivationScheme2 noPassphrase extPriv (fromIntegral idx)+ k = makeEdBip32 rsk rcc+ cK = EdBIP32.derive hIdx k+ in xprvEqKey cPrv1 cK+ , series "verify-soft-secret-derivation" softIdx $ \idx ->+ withSoftIndex idx $ \hIdx ->+ Property (fromList $ show idx) $ \rsk rcc ->+ let extPriv = makeXprv rsk rcc+ cPrv1 = deriveXPrv DerivationScheme2 noPassphrase extPriv (fromIntegral idx)+ k = makeEdBip32 rsk rcc+ cK = EdBIP32.derive hIdx k+ in xprvEqKey cPrv1 cK+ ]+ where++ makeEdBip32 (RandomSecretKey k) (RandomChainCode cc) =+ let (s1,s2) = B.splitAt 32 k+ in (packN s1, packN s2, EdBIP32.ChainCode $ packBytesN cc)++ softIdx = [1..9]+ hardIdx = [0x80000000..0x80000003] ++ [0xf00f0001..0xf00f0004] ++ [0x90000003..0x90000005]++ xprvEqKey :: XPrv -> EdBIP32.Key -> Bool+ xprvEqKey xPrv (k1,k2,EdBIP32.ChainCode cc) =+ -- xprv is 64 bits of secret key, 32 bits of public key and 32 bits of chain code+ let (s1, r1) = B.splitAt 32 $ B.convert xPrv+ (s2, r2) = B.splitAt 32 r1+ (_p , c) = B.splitAt 32 r2+ in assertEq "chain code" (B.unpack c) (Bytes.unpack cc) &&+ assertEq "key2" (B.unpack s2) (Bytes.unpack $ Bytes.fromBits Bytes.LittleEndian k2) &&+ assertEq "key1" (B.unpack s1) (Bytes.unpack $ Bytes.fromBits Bytes.LittleEndian k1)++ xprvEqPublicKey :: XPub -> EdBIP32.Public -> Bool+ xprvEqPublicKey xPub (point, EdBIP32.ChainCode cc) =+ assertEq "point" (B.unpack $ xpubPublicKey xPub) (Bytes.unpack $ Bytes.fromBits Bytes.LittleEndian point) &&+ assertEq "public chain code" (B.unpack $ B.convert $ xpubChaincode xPub) (Bytes.unpack cc)++ assertEq s l1 l2+ | l1 /= l2 = error ("expected Eq for " ++ s ++ "\n" ++ " wallet: " ++ dumpRaw l1 ++ "\n alt : " ++ dumpRaw l2)+ | otherwise = True+++ packN :: B.ByteString -> FBits 256+ packN = Bytes.toBits Bytes.LittleEndian . Bytes.pack . B.unpack++ packBytesN :: B.ByteString -> Bytes.Bytes 32+ packBytesN = Bytes.pack . B.unpack++ --unpackN :: KnownNat n => FBits n -> B.ByteString+ --unpackN = B.pack . binFromFBits++-- -------------------------------------------------------------------------- --+-- Main --+-- -------------------------------------------------------------------------- --++main :: IO ()+main = defaultMain $ Group "cardano-crypto"+ [ Group "edwards25519-arithmetic" testEdwards25519+ , Group "edwards25519-BIP32" testEdBIP32+ , Group "point-addition" testPointAdd+ , Group "encrypted" testEncrypted+ , Group "change-pass" testChangePassphrase+ , Crypto.tests+ , Cardano.tests+ ]+ {-+ , Group "edwards25519-ed25519variant" testVariant+ , Group "hd-derivation" testHdDerivation+ ]+ -}
+ test/Test/Cardano.hs view
@@ -0,0 +1,14 @@+{-# LANGUAGE OverloadedStrings #-}++module Test.Cardano+ ( tests+ ) where++import Foundation.Check++import qualified Test.Cardano.Crypto as Crypto++tests :: Test+tests = Group "Cardano"+ [ Crypto.tests+ ]
+ test/Test/Cardano/Crypto.hs view
@@ -0,0 +1,14 @@+{-# LANGUAGE OverloadedStrings #-}++module Test.Cardano.Crypto+ ( tests+ ) where++import Foundation.Check++import qualified Test.Cardano.Crypto.Encoding as Encoding++tests :: Test+tests = Group "Crypto"+ [ Encoding.tests+ ]
+ test/Test/Cardano/Crypto/Encoding.hs view
@@ -0,0 +1,14 @@+{-# LANGUAGE OverloadedStrings #-}++module Test.Cardano.Crypto.Encoding+ ( tests+ ) where++import Foundation.Check++import qualified Test.Cardano.Crypto.Encoding.Seed as Seed++tests :: Test+tests = Group "Encoding"+ [ Seed.tests+ ]
+ test/Test/Cardano/Crypto/Encoding/Seed.hs view
@@ -0,0 +1,50 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeOperators #-}++module Test.Cardano.Crypto.Encoding.Seed+ ( tests+ ) where++import Foundation+import Foundation.Check+import Foundation.String (words)+import Basement.Nat++import Crypto.Encoding.BIP39+import Crypto.Encoding.BIP39.English (english)++import Crypto.Error (throwCryptoError)++import Cardano.Crypto.Encoding.Seed as PW++-- -------------------------------------------------------------------------- --+-- Encoding/Seed --+-- -------------------------------------------------------------------------- --++tests :: Test+tests = Group "Seed (paper-wallet)"+ [ go (Proxy @128)+ , go (Proxy @160)+ , go (Proxy @192)+ ]+ where+ go :: forall n m s+ . ( PW.ConsistentEntropy n m s+ , PW.ConsistentEntropy (n + PW.IVSizeBits) (m + PW.IVSizeWords) (CheckSumBits (n + PW.IVSizeBits))+ , Arbitrary (PW.Entropy n)+ )+ => Proxy n+ -> Test+ go pr = Property ("unscramble . scramble @" <> sz <> " == id") $ \iv (e :: PW.Entropy n) p ->+ let s = PW.scramble @n iv e p+ u = PW.unscramble s p+ in e === u+ where+ sz = show $ natVal pr
+ test/Test/Crypto.hs view
@@ -0,0 +1,14 @@+{-# LANGUAGE OverloadedStrings #-}++module Test.Crypto+ ( tests+ ) where++import Foundation.Check++import qualified Test.Crypto.Encoding as Encoding++tests :: Test+tests = Group "Crypto"+ [ Encoding.tests+ ]
+ test/Test/Crypto/Encoding.hs view
@@ -0,0 +1,14 @@+{-# LANGUAGE OverloadedStrings #-}++module Test.Crypto.Encoding+ ( tests+ ) where++import Foundation.Check++import qualified Test.Crypto.Encoding.BIP39 as BIP39++tests :: Test+tests = Group "Encoding"+ [ BIP39.tests+ ]
+ test/Test/Crypto/Encoding/BIP39.hs view
@@ -0,0 +1,111 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE FlexibleContexts #-}++module Test.Crypto.Encoding.BIP39+ ( tests+ ) where++import Foundation+import Foundation.Check+import Basement.Nat+import Basement.Types.OffsetSize (Offset(..))++import Data.ByteString (ByteString)+import qualified Data.ByteString as BS++import Crypto.Encoding.BIP39+import Crypto.Encoding.BIP39.English (english)++import Cardano.Internal.Compat (fromRight)++tests :: Test+tests = Group "BIP39"+ [ testsP @96 @9 @3 Proxy+ , testsP @128 @12 @4 Proxy+ , testsP @160 @15 @5 Proxy+ , testsP @192 @18 @6 Proxy+ , testsP @224 @21 @7 Proxy+ , testsP @256 @24 @8 Proxy+ , testsVector+ ]++testsP :: forall ent mw csz . (Arbitrary (Entropy ent), ConsistentEntropy ent mw csz)+ => Proxy ent+ -> Test+testsP _ = Group (show (natVal (Proxy @ent)))+ [ Property "wordsToEntropy . entropyToWords == id" $ \(e :: Entropy ent) ->+ (fromRight undefined . wordsToEntropy @ent) (entropyToWords e) === e+ ]++testsVector :: Test+testsVector = Group "Test Vector" $ runTest <$> testVectors++data TestVector = TestVector+ { testVectorInput :: ByteString+ , testVectorWords :: String+ , testVectorWIndex :: [Offset String]+ , testVectorSeed :: Seed+ }++runTest :: TestVector -> Test+runTest tv =+ case BS.length (testVectorInput tv) * 8 of+ 96 -> go (Proxy @96)+ 128 -> go (Proxy @128)+ 160 -> go (Proxy @160)+ 192 -> go (Proxy @192)+ 224 -> go (Proxy @224)+ 256 -> go (Proxy @256)+ _ -> error "invalid size"+ where+ testVectorWIndex' = fmap wordIndex . testVectorWIndex++ go :: forall n csz mw . ConsistentEntropy n mw csz+ => Proxy n -> Test+ go proxyN = CheckPlan ("test " <> show (natVal proxyN)) $+ case toEntropy @n (testVectorInput tv) of+ Left err -> error $ show err+ Right e -> do+ let w = entropyToWords e+ e' = fromRight undefined $ wordsToEntropy @n w+ seed = sentenceToSeed w english "TREZOR"+ words = mnemonicSentenceToString @mw english w+ validate "phrases are equal" (words === testVectorWords tv)+ validate "words equal" (toList w === testVectorWIndex' tv)+ validate "seed equal" (seed === testVectorSeed tv)+ validate "entropy equal" (e === e')++testVectors :: [TestVector]+testVectors =+ [ TestVector+ "\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f"+ "legal winner thank year wave sausage worth useful legal winner thank yellow"+ [1019,2015,1790,2039,1983,1533,2031,1919,1019,2015,1790,2040]+ "\x2e\x89\x05\x81\x9b\x87\x23\xfe\x2c\x1d\x16\x18\x60\xe5\xee\x18\x30\x31\x8d\xbf\x49\xa8\x3b\xd4\x51\xcf\xb8\x44\x0c\x28\xbd\x6f\xa4\x57\xfe\x12\x96\x10\x65\x59\xa3\xc8\x09\x37\xa1\xc1\x06\x9b\xe3\xa3\xa5\xbd\x38\x1e\xe6\x26\x0e\x8d\x97\x39\xfc\xe1\xf6\x07"+ , TestVector+ "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80"+ "letter advice cage absurd amount doctor acoustic avoid letter advice cage above"+ [1028,32,257,8,64,514,16,128,1028,32,257,4]+ "\xd7\x1d\xe8\x56\xf8\x1a\x8a\xcc\x65\xe6\xfc\x85\x1a\x38\xd4\xd7\xec\x21\x6f\xd0\x79\x6d\x0a\x68\x27\xa3\xad\x6e\xd5\x51\x1a\x30\xfa\x28\x0f\x12\xeb\x2e\x47\xed\x2a\xc0\x3b\x5c\x46\x2a\x03\x58\xd1\x8d\x69\xfe\x4f\x98\x5e\xc8\x17\x78\xc1\xb3\x70\xb6\x52\xa8"+ , TestVector+ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"+ "zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong"+ [2047,2047,2047,2047,2047,2047,2047,2047,2047,2047,2047,2037]+ "\xac\x27\x49\x54\x80\x22\x52\x22\x07\x9d\x7b\xe1\x81\x58\x37\x51\xe8\x6f\x57\x10\x27\xb0\x49\x7b\x5b\x5d\x11\x21\x8e\x0a\x8a\x13\x33\x25\x72\x91\x7f\x0f\x8e\x5a\x58\x96\x20\xc6\xf1\x5b\x11\xc6\x1d\xee\x32\x76\x51\xa1\x4c\x34\xe1\x82\x31\x05\x2e\x48\xc0\x69"+ , TestVector+ "\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f"+ "legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal will"+ [1019,2015,1790,2039,1983,1533,2031,1919,1019,2015,1790,2039,1983,1533,2031,1919,1019,2009]+ "\xf2\xb9\x45\x08\x73\x2b\xcb\xac\xbc\xc0\x20\xfa\xef\xec\xfc\x89\xfe\xaf\xa6\x64\x9a\x54\x91\xb8\xc9\x52\xce\xde\x49\x6c\x21\x4a\x0c\x7b\x3c\x39\x2d\x16\x87\x48\xf2\xd4\xa6\x12\xba\xda\x07\x53\xb5\x2a\x1c\x7a\xc5\x3c\x1e\x93\xab\xd5\xc6\x32\x0b\x9e\x95\xdd"+ , TestVector+ "\xf5\x85\xc1\x1a\xec\x52\x0d\xb5\x7d\xd3\x53\xc6\x95\x54\xb2\x1a\x89\xb2\x0f\xb0\x65\x09\x66\xfa\x0a\x9d\x6f\x74\xfd\x98\x9d\x8f"+ "void come effort suffer camp survey warrior heavy shoot primary clutch crush open amazing screen patrol group space point ten exist slush involve unfold"+ [1964,368,565,1733,262,1749,1978,851,1588,1365,356,424,1241,62,1548,1289,823,1666,1338,1783,638,1634,945,1897]+ "\x01\xf5\xbc\xed\x59\xde\xc4\x8e\x36\x2f\x2c\x45\xb5\xde\x68\xb9\xfd\x6c\x92\xc6\x63\x4f\x44\xd6\xd4\x0a\xab\x69\x05\x65\x06\xf0\xe3\x55\x24\xa5\x18\x03\x4d\xdc\x11\x92\xe1\xda\xcd\x32\xc1\xed\x3e\xaa\x3c\x3b\x13\x1c\x88\xed\x8e\x7e\x54\xc4\x9a\x5d\x09\x98"+ ]
+ test/Test/Orphans.hs view
@@ -0,0 +1,101 @@+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE UndecidableInstances #-}++module Test.Orphans+ (+ ) where++import Foundation+import Foundation.Parser (elements)+import Basement.Nat++import Inspector+import qualified Inspector.TestVector.Types as Type+import qualified Inspector.TestVector.Value as Value++import Crypto.Error++import Data.ByteArray (Bytes, convert, ByteArrayAccess)+import Data.ByteString (ByteString)++import qualified Cardano.Crypto.Encoding.Seed as Seed+import qualified Cardano.Crypto.Wallet.Types as Wallet+import qualified Cardano.Crypto.Wallet as Wallet+import qualified Crypto.Encoding.BIP39 as BIP39++toBytes :: ByteArrayAccess ba => ba -> Bytes+toBytes = convert++instance Inspectable Seed.ScrambleIV where+ documentation _ = "Seed scramble IV of 8 bytes"+ exportType _ = Type.Array $ Type.SizedArray Type.Unsigned8 8+ builder = builder . toBytes+ parser v = do+ bs <- parser v :: Either String ByteString+ case Seed.mkScrambleIV bs of+ CryptoFailed err -> Left $ "Expected a `ScrambleIV'" <> show err+ CryptoPassed r -> pure r++instance Inspectable Wallet.DerivationScheme where+ documentation _ = "Wallet's derivation schemes: String either \"derivation-scheme1\" or \"derivation-scheme2\""+ exportType _ = Type.String+ builder Wallet.DerivationScheme1 = Value.String "derivation-scheme1"+ builder Wallet.DerivationScheme2 = Value.String "derivation-scheme2"+ parser = withString "DerivationScheme" $ \str -> case str of+ "derivation-scheme1" -> pure Wallet.DerivationScheme1+ "derivation-scheme2" -> pure Wallet.DerivationScheme2+ _ -> Left $ "Expected either `derivation-scheme1' or `derivation-scheme2' but found: `" <> str <> "'"++instance Inspectable Wallet.XPub where+ documentation _ = "Wallet's extended public key"+ exportType _ = Type.Array $ Type.SizedArray Type.Unsigned8 64+ builder = builder . Wallet.unXPub+ parser v = do+ bs <- parser v :: Either String ByteString+ case Wallet.xpub bs of+ Left err -> Left $ "Expected `xPub' " <> fromList err+ Right e -> pure e++instance Inspectable Wallet.XPrv where+ documentation _ = "Wallet's extended private key"+ exportType _ = Type.Array $ Type.SizedArray Type.Unsigned8 96+ builder = builder . Wallet.unXPrv+ parser v = do+ bs <- parser v :: Either String ByteString+ case Wallet.xprv bs of+ Left err -> Left $ "Expected `xPrv' " <> fromList err+ Right e -> pure e++instance Inspectable Wallet.XSignature where+ documentation _ = "Wallet's extended signature"+ exportType _ = Type.Array $ Type.SizedArray Type.Unsigned8 64+ builder = builder . toBytes+ parser v = do+ bs <- parser v :: Either String ByteString+ case Wallet.xsignature bs of+ Left err -> Left $ "Expected `xPrv' " <> fromList err+ Right e -> pure e++instance (BIP39.ValidEntropySize n, BIP39.ValidChecksumSize n csz) => Inspectable (BIP39.Entropy n) where+ documentation _ = "BIP39 Entropy"+ exportType _ = Type.Array $ Type.UnsizedArray Type.Unsigned8+ builder = builder . BIP39.entropyRaw+ parser v = do+ bs <- parser v+ case BIP39.toEntropy (bs :: Bytes) of+ Left _ -> Left "Expected `Entropy' not the correct size"+ Right r -> pure r++instance Inspectable BIP39.Seed where+ documentation _ = "BIP39 Seed"+ exportType _ = Type.Array $ Type.UnsizedArray Type.Unsigned8+ builder = builder . toBytes+ parser v = convert <$> (parser v :: Either String ByteString)++instance Inspectable ByteString where+ documentation _ = "Some random bytes"+ exportType _ = Type.Array $ Type.UnsizedArray Type.Unsigned8+ builder = builder . toBytes+ parser v = convert <$> (parser v :: Either String Bytes)
+ test/Utils.hs view
@@ -0,0 +1,110 @@+module Utils+ ( RandomSecretKey(..)+ , RandomChainCode(..)+ , HardIdx(..)+ , SoftIdx(..)+ -- * Functions helper+ , makeXprv+ , rskToScalar+ , dumpRaw+ ) where++import Data.Word+import Data.Bits+import qualified Data.ByteString as B+import Control.Monad+import qualified Crypto.Math.Edwards25519 as Edwards25519+import Cardano.Crypto.Wallet (XPrv, xprv)++import Foundation.Check++-- | Randomly generated ED25519 Extended secret key (64 bytes with a special structure)+newtype RandomSecretKey = RandomSecretKey B.ByteString+ deriving (Eq)++instance Show RandomSecretKey where+ show (RandomSecretKey bs) = "RandomSecretKey " ++ (dumpRaw $ B.unpack bs)++instance Arbitrary RandomSecretKey where+ arbitrary = do+ {-+ high <- toHigh <$> pure 0+ middle <- replicateM 30 (pure 0)+ low <- toLow <$> pure 0+ extended <- replicateM 32 (pure 0)+ -}++ high <- toHigh <$> arbitrary+ middle <- replicateM 30 arbitrary+ low <- toLow <$> arbitrary+ extended <- replicateM 32 arbitrary+ pure $ RandomSecretKey $ B.pack $ [low] ++ middle ++ [high] ++ extended+ where+ toHigh w = w `clearBit` 7 `clearBit` 5 `setBit` 6+ toLow w = w `clearBit` 0 `clearBit` 1 `clearBit` 2+++-- | Randomly generate chain code (32 bytes)+newtype RandomChainCode = RandomChainCode B.ByteString+ deriving (Eq)++instance Show RandomChainCode where+ show (RandomChainCode bs) = "RandomChainCode " ++ (dumpRaw $ B.unpack bs)++instance Arbitrary RandomChainCode where+ arbitrary = RandomChainCode . B.pack <$> {-pure (replicate 32 0) <$>-} replicateM 32 arbitrary++newtype HardIdx = HardIdx Word32+ deriving (Show,Eq)++instance Arbitrary HardIdx where+ arbitrary = HardIdx . setBit 31 <$> arbitrary++newtype SoftIdx = SoftIdx Word32+ deriving (Show,Eq)++instance Arbitrary SoftIdx where+ arbitrary = SoftIdx . clearBit 31 <$> arbitrary++makeXprv :: RandomSecretKey -> RandomChainCode -> XPrv+makeXprv (RandomSecretKey k) (RandomChainCode cc) =+ let (s1,s2) = B.splitAt 32 k+ scalar = Edwards25519.scalar s1+ pub = Edwards25519.scalarToPoint scalar+ xprvData = k `B.append` Edwards25519.unPointCompressed pub `B.append` cc+ in either (error "makeXprv: invalid") id $ xprv xprvData++rskToScalar :: RandomSecretKey -> Edwards25519.Scalar+rskToScalar (RandomSecretKey rsk) = Edwards25519.scalar (B.take 32 rsk)++hex :: Int -> Char+hex 0 = '0'+hex 1 = '1'+hex 2 = '2'+hex 3 = '3'+hex 4 = '4'+hex 5 = '5'+hex 6 = '6'+hex 7 = '7'+hex 8 = '8'+hex 9 = '9'+hex 10 = 'a'+hex 11 = 'b'+hex 12 = 'c'+hex 13 = 'd'+hex 14 = 'e'+hex 15 = 'f'+hex _ = ' '++{-# INLINE hexBytes #-}+hexBytes :: Word8 -> (Char, Char)+hexBytes w = (hex h, hex l) where (h,l) = (fromIntegral w) `divMod` 16++-- | Dump one byte into a 2 hexadecimal characters.+hexString :: Word8 -> String+hexString i = [h,l] where (h,l) = hexBytes i++-- | Dump a list of word8 into a raw string of hex value+dumpRaw :: [Word8] -> String+dumpRaw = concatMap hexString+