├── .devcontainer ├── Dockerfile └── devcontainer.json ├── .eggignore ├── .github └── workflows │ ├── codeql-analysis.yml │ ├── deno.yml │ └── test.yml ├── .gitignore ├── .releaserc.json ├── .vscode └── settings.json ├── Cargo.toml ├── LICENSE ├── README.md ├── _config.yml ├── cli.ts ├── deno.jsonc ├── deno.lock ├── deps.ts ├── dprint.json ├── egg.json ├── example.ts ├── lib ├── _wasm │ ├── Cargo.toml │ ├── LICENSE │ ├── README.md │ ├── scrypt_wasm.generated.d.ts │ ├── scrypt_wasm.generated.js │ └── src │ │ └── lib.rs ├── format.ts ├── format_test.ts ├── helpers.ts ├── helpers_test.ts ├── hmac.ts ├── hmac_bench.ts ├── hmac_test.ts ├── scrypt.ts ├── scrypt_bench.ts └── scrypt_test.ts ├── mod.ts └── mod_test.ts /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | # [Choice] Debian OS version: bullseye, buster 2 | ARG VARIANT=bullseye 3 | FROM --platform=linux/amd64 mcr.microsoft.com/vscode/devcontainers/rust:1-${VARIANT} 4 | 5 | ENV DENO_INSTALL=/deno 6 | RUN mkdir -p /deno \ 7 | && curl -fsSL https://deno.land/x/install/install.sh | sh \ 8 | && chown -R vscode /deno 9 | 10 | ENV PATH=${DENO_INSTALL}/bin:${PATH} \ 11 | DENO_DIR=${DENO_INSTALL}/.cache/deno 12 | 13 | # [Optional] Uncomment this section to install additional OS packages. 14 | # RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ 15 | # && apt-get -y install --no-install-recommends 16 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: 2 | // https://github.com/microsoft/vscode-dev-containers/tree/v0.245.2/containers/deno 3 | { 4 | "name": "Deno", 5 | "build": { 6 | "dockerfile": "Dockerfile", 7 | // Update 'VARIANT' to pick an Debian OS version: bullseye, buster 8 | "args": { 9 | "VARIANT": "bullseye" 10 | } 11 | }, 12 | 13 | // Configure tool-specific properties. 14 | "customizations": { 15 | // Configure properties specific to VS Code. 16 | "vscode": { 17 | // Set *default* container specific settings.json values on container create. 18 | "settings": { 19 | // Enables the project as a Deno project 20 | "deno.enable": true, 21 | // Enables Deno linting for the project 22 | "deno.lint": true, 23 | "deno.suggest.imports.hosts": { 24 | "https://deno.land": false 25 | }, 26 | "deno.unstable": true, 27 | // Sets Deno as the default formatter for the project 28 | "editor.defaultFormatter": "denoland.vscode-deno" 29 | }, 30 | 31 | // Add the IDs of extensions you want installed when the container is created. 32 | "extensions": [ 33 | "denoland.vscode-deno" 34 | ] 35 | } 36 | }, 37 | "remoteUser": "vscode" 38 | } 39 | -------------------------------------------------------------------------------- /.eggignore: -------------------------------------------------------------------------------- 1 | + extends .gitignore 2 | .vscode/** 3 | .github/** -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ "master" ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ "master" ] 20 | schedule: 21 | - cron: '36 13 * * 0' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'javascript' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support 38 | 39 | steps: 40 | - name: Checkout repository 41 | uses: actions/checkout@v4 42 | 43 | # Initializes the CodeQL tools for scanning. 44 | - name: Initialize CodeQL 45 | uses: github/codeql-action/init@v3 46 | with: 47 | languages: ${{ matrix.language }} 48 | # If you wish to specify custom queries, you can do so here or in a config file. 49 | # By default, queries listed here will override any specified in a config file. 50 | # Prefix the list here with "+" to use these queries and those in the config file. 51 | 52 | # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 53 | # queries: security-extended,security-and-quality 54 | 55 | 56 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 57 | # If this step fails, then you should remove it and run the build manually (see below) 58 | - name: Autobuild 59 | uses: github/codeql-action/autobuild@v3 60 | 61 | # ℹ️ Command-line programs to run using the OS shell. 62 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 63 | 64 | # If the Autobuild fails above, remove it and uncomment the following three lines. 65 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. 66 | 67 | # - run: | 68 | # echo "Run, Build Application using script" 69 | # ./location_of_script_within_repo/buildscript.sh 70 | 71 | - name: Perform CodeQL Analysis 72 | uses: github/codeql-action/analyze@v3 73 | with: 74 | category: "/language:${{matrix.language}}" 75 | -------------------------------------------------------------------------------- /.github/workflows/deno.yml: -------------------------------------------------------------------------------- 1 | name: Deno CI 2 | on: 3 | push: 4 | branches: 5 | - master 6 | workflow_dispatch: 7 | jobs: 8 | test: 9 | name: test ${{ matrix.os }} 10 | runs-on: ${{ matrix.os }} 11 | if: ${{ !contains(github.event.head_commit.message, '[skip ci]') }} 12 | strategy: 13 | matrix: 14 | os: [macOS-latest, ubuntu-latest, windows-latest] 15 | env: 16 | GH_ACTIONS: true 17 | DENO_BUILD_MODE: release 18 | V8_BINARY: true 19 | steps: 20 | - uses: actions/checkout@v4 21 | - name: Setup Deno 22 | uses: denoland/setup-deno@v1 23 | with: 24 | deno-version: 1.x 25 | - name: Tests 26 | run: deno test --allow-read 27 | bench: 28 | name: benchmark ${{ matrix.os }} 29 | runs-on: ${{ matrix.os }} 30 | needs: test 31 | if: ${{ !contains(github.event.head_commit.message, '[skip ci]') }} 32 | continue-on-error: true 33 | timeout-minutes: 25 34 | strategy: 35 | matrix: 36 | os: [ubuntu-latest, macOS-latest, windows-latest] 37 | env: 38 | GH_ACTIONS: true 39 | DENO_BUILD_MODE: release 40 | V8_BINARY: true 41 | steps: 42 | - uses: actions/checkout@v4 43 | - name: Setup Deno 44 | uses: denoland/setup-deno@v1 45 | with: 46 | deno-version: 1.x 47 | - name: Run benchmarks 48 | continue-on-error: true 49 | run: deno bench 50 | release: 51 | name: Release 52 | permissions: 53 | contents: write 54 | id-token: write 55 | runs-on: ubuntu-latest 56 | needs: test 57 | if: ${{ !contains(github.event.head_commit.message, '[skip ci]') }} 58 | steps: 59 | - name: Checkout 60 | uses: actions/checkout@v4 61 | with: 62 | fetch-depth: 0 # get all commits, not just the last one 63 | - name: Cache Rust artifacts 64 | uses: actions/cache@v4 65 | with: 66 | path: | 67 | ~/.cargo/bin/ 68 | ~/.cargo/registry/index/ 69 | ~/.cargo/registry/cache/ 70 | ~/.cargo/git/db/ 71 | target/ 72 | key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} 73 | - name: Setup Node.js 74 | uses: actions/setup-node@v4 75 | with: 76 | node-version: 16 77 | - name: Setup Deno 78 | uses: denoland/setup-deno@v1 79 | with: 80 | deno-version: 1.x 81 | - name: build wasm 82 | run: deno task wasmbuild 83 | - name: Setup package.json 84 | run: echo '{"name":"@denorg/scrypt","version":"0.0.0","publishConfig":{"access":"public"},"scripts":{"semantic-release":"semantic-release"},"repository":{"type":"git","url":"https://github.com/denorg/scrypt.git"},"author":"Denorg","license":"MIT","bugs":{"url":"https://github.com/denorg/scrypt/issues"},"homepage":"https://denorg.github.io/scrypt/","devDependencies":{"semantic-release":"^19.0.3","@semantic-release/exec":"^6.0.3","@semantic-release/commit-analyzer":"^9.0.2","@semantic-release/github":"^8.0.5","@semantic-release/npm":"^9.0.1","@semantic-release/git":"^10.0.1","@semantic-release/release-notes-generator":"^10.0.3"}}' > package.json 85 | - name: Install dependencies 86 | run: npm install 87 | - name: Release 88 | run: npx semantic-release 89 | env: 90 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 91 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 92 | - name: Publish on nest.land 93 | continue-on-error: true # eggs fails if the version doesn't change 94 | run: | 95 | deno install --allow-write --allow-env --allow-read --allow-net --unstable https://x.nest.land/eggs@0.3.10/eggs.ts 96 | eggs link ${{ secrets.NEST_TOKEN }} 97 | eggs publish --yes --no-check 98 | - name: Publish to JSR 99 | run: | 100 | sed -i "s/from \".*\"; \/\/jsr: /from /" deps.ts # remove https imports 101 | deno publish --allow-dirty 102 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test CI 2 | on: 3 | push: 4 | branches-ignore: 5 | - "master" 6 | pull_request: 7 | branches-ignore: 8 | - "master" 9 | jobs: 10 | test: 11 | name: test ${{ matrix.os }} 12 | runs-on: ${{ matrix.os }} 13 | if: ${{ !contains(github.event.head_commit.message, '[skip ci]') }} 14 | strategy: 15 | matrix: 16 | os: [macOS-latest, ubuntu-latest, windows-latest] 17 | env: 18 | GH_ACTIONS: true 19 | DENO_BUILD_MODE: release 20 | V8_BINARY: true 21 | steps: 22 | - uses: actions/checkout@v4 23 | - name: Setup Deno 24 | uses: denoland/setup-deno@v1 25 | with: 26 | deno-version: 1.x 27 | - name: Run tests 28 | run: deno test --allow-read 29 | bench: 30 | name: benchmark ${{ matrix.os }} 31 | runs-on: ${{ matrix.os }} 32 | needs: test 33 | if: ${{ !contains(github.event.head_commit.message, '[skip ci]') }} 34 | strategy: 35 | matrix: 36 | os: [ubuntu-latest, macOS-latest, windows-latest] 37 | env: 38 | GH_ACTIONS: true 39 | DENO_BUILD_MODE: release 40 | V8_BINARY: true 41 | steps: 42 | - uses: actions/checkout@v4 43 | - name: Setup Deno 44 | uses: denoland/setup-deno@v1 45 | with: 46 | deno-version: 1.x 47 | - name: Run benchmarks 48 | continue-on-error: true # Node.js Scrypt runs out of memory and throws in larger benchmarks... 49 | run: deno bench 50 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | Cargo.lock 3 | out/ 4 | node_modules/ 5 | package.json 6 | package-lock.json -------------------------------------------------------------------------------- /.releaserc.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "@semantic-release/commit-analyzer", 4 | [ 5 | "@semantic-release/exec", 6 | { 7 | "prepareCmd": "sed -i \"s/scrypt@[[:digit:]]\\+\\.[[:digit:]]\\+\\.[[:digit:]]\\+/scrypt@${nextRelease.version}/g\" README.md; sed -i \"s/\\\"version\\\": \\\"[[:digit:]]\\+\\.[[:digit:]]\\+\\.[[:digit:]]\\\"/\\\"version\\\": \\\"${nextRelease.version}\\\"/\" deno.jsonc; sed -i \"s/[[:digit:]]\\+\\.[[:digit:]]\\+\\.[[:digit:]]/${nextRelease.version}/\" egg.json; sed -i \"s/scrypt@v[[:digit:]]\\+\\.[[:digit:]]\\+\\.[[:digit:]]/scrypt@v${nextRelease.version}/\" lib/scrypt_bench.ts; sed -i \"s/@version [[:digit:]]\\+\\.[[:digit:]]\\+\\.[[:digit:]]/@version ${nextRelease.version}/\" mod.ts" 8 | } 9 | ], 10 | [ 11 | "@semantic-release/git", 12 | { 13 | "assets": [ 14 | "README.md", 15 | "egg.json", 16 | "deno.jsonc", 17 | "lib/_wasm/scrypt_wasm.generated.js", 18 | "lib/scrypt_bench.ts", 19 | "mod.ts" 20 | ], 21 | "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}" 22 | } 23 | ], 24 | "@semantic-release/github", 25 | "@semantic-release/npm", 26 | "@semantic-release/release-notes-generator" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "deno.enable": true, 3 | "deno.suggest.imports.hosts": { 4 | "https://deno.land": false 5 | }, 6 | "deno.lint": true, 7 | "deno.unstable": true 8 | } 9 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["lib/_wasm"] 3 | default-members = ["lib/_wasm"] 4 | resolver = "2" 5 | [profile.release] 6 | opt-level = 3 7 | strip = true 8 | lto = true 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Denorg 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🔑 scrypt 2 | 3 | This is a wasm-based (using rust-crypto) implementation of scrypt key derivation 4 | function that doesn't require any privileges. 5 | 6 | [![Deno CI](https://github.com/denorg/scrypt/workflows/Deno%20CI/badge.svg)](https://github.com/denorg/scrypt/actions) 7 | [![GitHub](https://img.shields.io/github/license/denorg/scrypt)](https://github.com/denorg/scrypt/blob/master/LICENSE) 8 | [![Contributors](https://img.shields.io/github/contributors/denorg/scrypt)](https://github.com/denorg/scrypt/graphs/contributors) 9 | [![Scrypt](https://img.shields.io/badge/deno-scrypt-brightgreen)](https://denorg.github.io/scrypt/) 10 | [![Made by Denorg](https://img.shields.io/badge/made%20by-denorg-0082fb)](https://github.com/denorg) 11 | [![TypeScript](https://img.shields.io/badge/types-TypeScript-blue)](https://github.com/denorg/scrypt) 12 | [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release) 13 | 14 | ## ⭐ Getting started 15 | 16 | Import the `hash` and/or `verify` functions and use them: 17 | 18 | ```ts 19 | import { hash, verify } from "jsr:@denorg/scrypt@4.4.4"; 20 | 21 | const hashResult = hash("password"); 22 | const verifyResult = verify("password", hashResult); 23 | ``` 24 | 25 | ### CLI with [DPX](https://github.com/denorg/dpx) 26 | 27 | After [installing DPX](https://github.com/denorg/dpx), you can directly use the 28 | CLI using the `dpx` command: 29 | 30 | ```bash 31 | dpx scrypt hash 32 | dpx scrypt verify 33 | ``` 34 | 35 | ### CLI 36 | 37 | Alternatively, you can use it directly from the CLI by using `deno run`: 38 | 39 | ```bash 40 | deno run jsr:@denorg/scrypt@4.4.4/cli hash 41 | deno run jsr:@denorg/scrypt@4.4.4/cli verify 42 | ``` 43 | 44 | You can also install it globally using the following: 45 | 46 | ```bash 47 | deno install -n scrypt jsr:@denorg/scrypt@4.4.4/cli 48 | ``` 49 | 50 | Then, the package is available to run: 51 | 52 | ```bash 53 | scrypt hash 54 | scrypt verify 55 | ``` 56 | 57 | ## 👩‍💻 Development 58 | 59 | Run tests: 60 | 61 | ```bash 62 | deno test 63 | ``` 64 | 65 | ## 📄 License 66 | 67 | MIT © [Denorg](https://den.org.in) 68 | 69 |

70 | 71 | 72 | 73 |

74 |

75 | A project by Denorg, the world's first Deno-focused community
organization and consulting company. Work with us →
76 |

77 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-minimal 2 | -------------------------------------------------------------------------------- /cli.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @module scrypt/cli 3 | * @author oplik0 4 | * This is a simple CLI for the scrypt module. It doesn't export anything, but can be used as a standalone script. 5 | */ 6 | import { genSalt, hash, verify } from "./mod.ts"; 7 | /** 8 | * @todo add a proper argument parser ([args](https://deno.land/x/args) perhaps?) 9 | */ 10 | if (import.meta.main) { 11 | const args = Deno.args.slice(); 12 | const command = args.shift(); 13 | switch (command) { 14 | case "hash": 15 | for (const arg of args) { 16 | console.log(hash(arg)); 17 | } 18 | break; 19 | case "verify": 20 | console.log(verify(args[0], args[1])); 21 | break; 22 | case "salt": 23 | if (args.length) { 24 | for (const arg of args) { 25 | console.log(genSalt(parseInt(arg, 10))); 26 | } 27 | } else { 28 | console.log(genSalt()); 29 | } 30 | break; 31 | default: 32 | console.log(`usage: hash , verify , `); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /deno.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@denorg/scrypt", 3 | "version": "4.4.4", 4 | "exports": { 5 | ".": "./mod.ts", 6 | "./cli": "./cli.ts", 7 | "./format": "./lib/format.ts", 8 | "./hmac": "./lib/hmac.ts" 9 | }, 10 | "$schema": "https://deno.land/x/deno/cli/schemas/config-file.v1.json", 11 | "lint": { 12 | "exclude": [ 13 | "lib/_wasm/wasm.js", 14 | "lib/_wasm/out/" 15 | ] 16 | }, 17 | "tasks": { 18 | "wasmbuild": "RUSTFLAGS='-C target-feature=+simd128' deno run --allow-env --allow-run --allow-read --allow-write --allow-net jsr:@deno/wasmbuild@0.17.1 --out ./lib/_wasm --project scrypt-wasm --sync" 19 | }, 20 | "fmt": { 21 | "exclude": [ 22 | "target/" 23 | ] 24 | }, 25 | "publish": { 26 | "exclude": [ 27 | "**/*_bench.ts", 28 | ".releaserc.json", 29 | "egg.json", 30 | ".eggignore", 31 | "_config.yml", 32 | ".vscode/" 33 | ] 34 | }, 35 | "imports": { 36 | "@std/assert": "jsr:@std/assert@0.222.1", 37 | "@std/crypto": "jsr:@std/crypto@0.222.1", 38 | "@std/encoding": "jsr:@std/encoding@0.222.1" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /deno.lock: -------------------------------------------------------------------------------- 1 | { 2 | "version": "3", 3 | "packages": { 4 | "specifiers": { 5 | "jsr:@std/assert@0.218.2": "jsr:@std/assert@0.218.2", 6 | "jsr:@std/assert@^0.218.2": "jsr:@std/assert@0.218.2", 7 | "jsr:@std/crypto@0.218.2": "jsr:@std/crypto@0.218.2", 8 | "jsr:@std/encoding@0.218.2": "jsr:@std/encoding@0.218.2", 9 | "jsr:@std/encoding@^0.218.2": "jsr:@std/encoding@0.218.2", 10 | "jsr:@std/fmt@^0.218.2": "jsr:@std/fmt@0.218.2", 11 | "npm:@noble/hashes": "npm:@noble/hashes@1.4.0", 12 | "npm:@types/node": "npm:@types/node@18.16.19", 13 | "npm:hash-wasm": "npm:hash-wasm@4.11.0", 14 | "npm:scrypt": "npm:scrypt@6.0.3" 15 | }, 16 | "jsr": { 17 | "@std/assert@0.218.2": { 18 | "integrity": "7f0a5a1a8cf86607cd6c2c030584096e1ffad27fc9271429a8cb48cfbdee5eaf", 19 | "dependencies": [ 20 | "jsr:@std/fmt@^0.218.2" 21 | ] 22 | }, 23 | "@std/crypto@0.218.2": { 24 | "integrity": "8c5031a3a1c3ac3bed3c0d4bed2fe7e7faedcb673bbfa0edd10570c8452f5cd2", 25 | "dependencies": [ 26 | "jsr:@std/assert@^0.218.2", 27 | "jsr:@std/encoding@^0.218.2" 28 | ] 29 | }, 30 | "@std/encoding@0.218.2": { 31 | "integrity": "da55a763c29bf0dbf06fd286430b358266eb99c28789d89fe9a3e28edecb8d8e" 32 | }, 33 | "@std/fmt@0.218.2": { 34 | "integrity": "99526449d2505aa758b6cbef81e7dd471d8b28ec0dcb1491d122b284c548788a" 35 | } 36 | }, 37 | "npm": { 38 | "@noble/hashes@1.4.0": { 39 | "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", 40 | "dependencies": {} 41 | }, 42 | "@types/node@18.16.19": { 43 | "integrity": "sha512-IXl7o+R9iti9eBW4Wg2hx1xQDig183jj7YLn8F7udNceyfkbn1ZxmzZXuak20gR40D7pIkIY1kYGx5VIGbaHKA==", 44 | "dependencies": {} 45 | }, 46 | "hash-wasm@4.11.0": { 47 | "integrity": "sha512-HVusNXlVqHe0fzIzdQOGolnFN6mX/fqcrSAOcTBXdvzrXVHwTz11vXeKRmkR5gTuwVpvHZEIyKoePDvuAR+XwQ==", 48 | "dependencies": {} 49 | }, 50 | "nan@2.19.0": { 51 | "integrity": "sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==", 52 | "dependencies": {} 53 | }, 54 | "scrypt@6.0.3": { 55 | "integrity": "sha512-NDrWb9hCm6Ev170XYVl7TSgu4R44Rjc8EVw1ce0TMN8EkfLvkhlwcfp61OVNc8EJDiHaQwVErn1fIU0RO3kSZw==", 56 | "dependencies": { 57 | "nan": "nan@2.19.0" 58 | } 59 | } 60 | } 61 | }, 62 | "remote": { 63 | "https://deno.land/std@0.160.0/hash/sha256.ts": "aa9479c260f41b72c639f36c3e4bc9319940b5d2e52fe793ebe3dc646d12832f", 64 | "https://deno.land/std@0.162.0/_util/assert.ts": "e94f2eb37cebd7f199952e242c77654e43333c1ac4c5c700e929ea3aa5489f74", 65 | "https://deno.land/std@0.162.0/flags/mod.ts": "e35fbfc7e90db230f7a4a99bc2888c60d9ccbff415cb930350366a38b0de79c7", 66 | "https://deno.land/std@0.218.2/assert/_constants.ts": "a271e8ef5a573f1df8e822a6eb9d09df064ad66a4390f21b3e31f820a38e0975", 67 | "https://deno.land/std@0.218.2/assert/_diff.ts": "dcc63d94ca289aec80644030cf88ccbf7acaa6fbd7b0f22add93616b36593840", 68 | "https://deno.land/std@0.218.2/assert/_format.ts": "0ba808961bf678437fb486b56405b6fefad2cf87b5809667c781ddee8c32aff4", 69 | "https://deno.land/std@0.218.2/assert/assert.ts": "bec068b2fccdd434c138a555b19a2c2393b71dfaada02b7d568a01541e67cdc5", 70 | "https://deno.land/std@0.218.2/assert/assert_almost_equals.ts": "8b96b7385cc117668b0720115eb6ee73d04c9bcb2f5d2344d674918c9113688f", 71 | "https://deno.land/std@0.218.2/assert/assert_array_includes.ts": "1688d76317fd45b7e93ef9e2765f112fdf2b7c9821016cdfb380b9445374aed1", 72 | "https://deno.land/std@0.218.2/assert/assert_equals.ts": "4497c56fe7d2993b0d447926702802fc0becb44e319079e8eca39b482ee01b4e", 73 | "https://deno.land/std@0.218.2/assert/assert_exists.ts": "24a7bf965e634f909242cd09fbaf38bde6b791128ece08e33ab08586a7cc55c9", 74 | "https://deno.land/std@0.218.2/assert/assert_false.ts": "6f382568e5128c0f855e5f7dbda8624c1ed9af4fcc33ef4a9afeeedcdce99769", 75 | "https://deno.land/std@0.218.2/assert/assert_greater.ts": "4945cf5729f1a38874d7e589e0fe5cc5cd5abe5573ca2ddca9d3791aa891856c", 76 | "https://deno.land/std@0.218.2/assert/assert_greater_or_equal.ts": "573ed8823283b8d94b7443eb69a849a3c369a8eb9666b2d1db50c33763a5d219", 77 | "https://deno.land/std@0.218.2/assert/assert_instance_of.ts": "72dc1faff1e248692d873c89382fa1579dd7b53b56d52f37f9874a75b11ba444", 78 | "https://deno.land/std@0.218.2/assert/assert_is_error.ts": "6596f2b5ba89ba2fe9b074f75e9318cda97a2381e59d476812e30077fbdb6ed2", 79 | "https://deno.land/std@0.218.2/assert/assert_less.ts": "2b4b3fe7910f65f7be52212f19c3977ecb8ba5b2d6d0a296c83cde42920bb005", 80 | "https://deno.land/std@0.218.2/assert/assert_less_or_equal.ts": "b93d212fe669fbde959e35b3437ac9a4468f2e6b77377e7b6ea2cfdd825d38a0", 81 | "https://deno.land/std@0.218.2/assert/assert_match.ts": "ec2d9680ed3e7b9746ec57ec923a17eef6d476202f339ad91d22277d7f1d16e1", 82 | "https://deno.land/std@0.218.2/assert/assert_not_equals.ts": "ac86413ab70ffb14fdfc41740ba579a983fe355ba0ce4a9ab685e6b8e7f6a250", 83 | "https://deno.land/std@0.218.2/assert/assert_not_instance_of.ts": "8f720d92d83775c40b2542a8d76c60c2d4aeddaf8713c8d11df8984af2604931", 84 | "https://deno.land/std@0.218.2/assert/assert_not_match.ts": "b4b7c77f146963e2b673c1ce4846473703409eb93f5ab0eb60f6e6f8aeffe39f", 85 | "https://deno.land/std@0.218.2/assert/assert_not_strict_equals.ts": "da0b8ab60a45d5a9371088378e5313f624799470c3b54c76e8b8abeec40a77be", 86 | "https://deno.land/std@0.218.2/assert/assert_object_match.ts": "e85e5eef62a56ce364c3afdd27978ccab979288a3e772e6855c270a7b118fa49", 87 | "https://deno.land/std@0.218.2/assert/assert_rejects.ts": "5206ac37d883797d9504e3915a0c7b692df6efcdefff3889cc14bb5a325641dd", 88 | "https://deno.land/std@0.218.2/assert/assert_strict_equals.ts": "0425a98f70badccb151644c902384c12771a93e65f8ff610244b8147b03a2366", 89 | "https://deno.land/std@0.218.2/assert/assert_string_includes.ts": "dfb072a890167146f8e5bdd6fde887ce4657098e9f71f12716ef37f35fb6f4a7", 90 | "https://deno.land/std@0.218.2/assert/assert_throws.ts": "31f3c061338aec2c2c33731973d58ccd4f14e42f355501541409ee958d2eb8e5", 91 | "https://deno.land/std@0.218.2/assert/assertion_error.ts": "9f689a101ee586c4ce92f52fa7ddd362e86434ffdf1f848e45987dc7689976b8", 92 | "https://deno.land/std@0.218.2/assert/equal.ts": "fae5e8a52a11d3ac694bbe1a53e13a7969e3f60791262312e91a3e741ae519e2", 93 | "https://deno.land/std@0.218.2/assert/fail.ts": "f310e51992bac8e54f5fd8e44d098638434b2edb802383690e0d7a9be1979f1c", 94 | "https://deno.land/std@0.218.2/assert/mod.ts": "325df8c0683ad83a873b9691aa66b812d6275fc9fec0b2d180ac68a2c5efed3b", 95 | "https://deno.land/std@0.218.2/assert/unimplemented.ts": "47ca67d1c6dc53abd0bd729b71a31e0825fc452dbcd4fde4ca06789d5644e7fd", 96 | "https://deno.land/std@0.218.2/assert/unreachable.ts": "3670816a4ab3214349acb6730e3e6f5299021234657eefe05b48092f3848c270", 97 | "https://deno.land/std@0.218.2/crypto/_fnv/fnv32.ts": "ba2c5ef976b9f047d7ce2d33dfe18671afc75154bcf20ef89d932b2fe8820535", 98 | "https://deno.land/std@0.218.2/crypto/_fnv/fnv64.ts": "580cadfe2ff333fe253d15df450f927c8ac7e408b704547be26aab41b5772558", 99 | "https://deno.land/std@0.218.2/crypto/_fnv/mod.ts": "8dbb60f062a6e77b82f7a62ac11fabfba52c3cd408c21916b130d8f57a880f96", 100 | "https://deno.land/std@0.218.2/crypto/_fnv/util.ts": "27b36ce3440d0a180af6bf1cfc2c326f68823288540a354dc1d636b781b9b75f", 101 | "https://deno.land/std@0.218.2/crypto/_wasm/lib/deno_std_wasm_crypto.generated.mjs": "76c727912539737def4549bb62a96897f37eb334b979f49c57b8af7a1617635e", 102 | "https://deno.land/std@0.218.2/crypto/_wasm/mod.ts": "c55f91473846827f077dfd7e5fc6e2726dee5003b6a5747610707cdc638a22ba", 103 | "https://deno.land/std@0.218.2/crypto/crypto.ts": "b7bacddd990ad4193556697b88c7291ed61edc145fafbc060559984f3e8e4977", 104 | "https://deno.land/std@0.218.2/crypto/mod.ts": "7e7971e8abd90addbb02640e43c124e28d10b07e88b61851049c40fc2b5eb04b", 105 | "https://deno.land/std@0.218.2/crypto/timing_safe_equal.ts": "bc3622b5aec05e2d8b735bf60633425c34333c06cfb6c4a9f102e4a0f3931ced", 106 | "https://deno.land/std@0.218.2/crypto/unstable_keystack.ts": "c2a6f6ed67a4e78745e3c9b490ebb7c12f6066f5c2fe0c69d353961909dc82dd", 107 | "https://deno.land/std@0.218.2/encoding/_util.ts": "beacef316c1255da9bc8e95afb1fa56ed69baef919c88dc06ae6cb7a6103d376", 108 | "https://deno.land/std@0.218.2/encoding/base64.ts": "b0fe5f1c55571dc9f091abc7d4830482f2f67ab4308c9c1b57071e770b7dcc74", 109 | "https://deno.land/std@0.218.2/encoding/base64url.ts": "9cc46cf510436be63ac00ebf97a7de1993e603ca58e1853b344bf90d80ea9945", 110 | "https://deno.land/std@0.218.2/encoding/hex.ts": "e939f50d55be48a1fe42fecaaecdb54353df38e831c47f374be7e6fdbe61510e", 111 | "https://deno.land/std@0.218.2/fmt/colors.ts": "d239d84620b921ea520125d778947881f62c50e78deef2657073840b8af9559a", 112 | "https://deno.land/std@0.222.1/assert/_constants.ts": "a271e8ef5a573f1df8e822a6eb9d09df064ad66a4390f21b3e31f820a38e0975", 113 | "https://deno.land/std@0.222.1/assert/_diff.ts": "4bf42969aa8b1a33aaf23eb8e478b011bfaa31b82d85d2ff4b5c4662d8780d2b", 114 | "https://deno.land/std@0.222.1/assert/_format.ts": "0ba808961bf678437fb486b56405b6fefad2cf87b5809667c781ddee8c32aff4", 115 | "https://deno.land/std@0.222.1/assert/assert.ts": "09d30564c09de846855b7b071e62b5974b001bb72a4b797958fe0660e7849834", 116 | "https://deno.land/std@0.222.1/assert/assert_almost_equals.ts": "9e416114322012c9a21fa68e187637ce2d7df25bcbdbfd957cd639e65d3cf293", 117 | "https://deno.land/std@0.222.1/assert/assert_array_includes.ts": "167b2c29997defd49a1835de52b54ae3cbb2bcba52df7c7ee45fe64b473264f1", 118 | "https://deno.land/std@0.222.1/assert/assert_equals.ts": "cc1f4b0ff4ad511e69f965535b56a6cdbbbc0f086bf376e0243214df6039c883", 119 | "https://deno.land/std@0.222.1/assert/assert_exists.ts": "43420cf7f956748ae6ed1230646567b3593cb7a36c5a5327269279c870c5ddfd", 120 | "https://deno.land/std@0.222.1/assert/assert_false.ts": "3e9be8e33275db00d952e9acb0cd29481a44fa0a4af6d37239ff58d79e8edeff", 121 | "https://deno.land/std@0.222.1/assert/assert_greater.ts": "26903fc7170a9eb37ee6c6606c772b5a0465a85e719cfe46f57de35555931419", 122 | "https://deno.land/std@0.222.1/assert/assert_greater_or_equal.ts": "10527cf379a71a55a88b96d9b3373d0346ea2bdd8d73d2faaab1224e2cedb727", 123 | "https://deno.land/std@0.222.1/assert/assert_instance_of.ts": "e22343c1fdcacfaea8f37784ad782683ec1cf599ae9b1b618954e9c22f376f2c", 124 | "https://deno.land/std@0.222.1/assert/assert_is_error.ts": "f856b3bc978a7aa6a601f3fec6603491ab6255118afa6baa84b04426dd3cc491", 125 | "https://deno.land/std@0.222.1/assert/assert_less.ts": "091f0cc80f53425be22b14c9b6ae410fea08e16eca391a476303c5f4852fcd9e", 126 | "https://deno.land/std@0.222.1/assert/assert_less_or_equal.ts": "9418b2f809023f778d58fd6834410814900eacb8a91708647970ae1085553813", 127 | "https://deno.land/std@0.222.1/assert/assert_match.ts": "ace1710dd3b2811c391946954234b5da910c5665aed817943d086d4d4871a8b7", 128 | "https://deno.land/std@0.222.1/assert/assert_not_equals.ts": "78d45dd46133d76ce624b2c6c09392f6110f0df9b73f911d20208a68dee2ef29", 129 | "https://deno.land/std@0.222.1/assert/assert_not_instance_of.ts": "3434a669b4d20cdcc5359779301a0588f941ffdc2ad68803c31eabdb4890cf7a", 130 | "https://deno.land/std@0.222.1/assert/assert_not_match.ts": "df30417240aa2d35b1ea44df7e541991348a063d9ee823430e0b58079a72242a", 131 | "https://deno.land/std@0.222.1/assert/assert_not_strict_equals.ts": "61e4adfd80eddaab5da5e5444431dfb19457f26b1f1e7a8be27c5d981b7f50b9", 132 | "https://deno.land/std@0.222.1/assert/assert_object_match.ts": "411450fd194fdaabc0089ae68f916b545a49d7b7e6d0026e84a54c9e7eed2693", 133 | "https://deno.land/std@0.222.1/assert/assert_rejects.ts": "4bee1d6d565a5b623146a14668da8f9eb1f026a4f338bbf92b37e43e0aa53c31", 134 | "https://deno.land/std@0.222.1/assert/assert_strict_equals.ts": "dbcdcb5b8b74e6c06bce6a9fa43ff4d1089793e7832baff251e514954b9b266b", 135 | "https://deno.land/std@0.222.1/assert/assert_string_includes.ts": "496b9ecad84deab72c8718735373feb6cdaa071eb91a98206f6f3cb4285e71b8", 136 | "https://deno.land/std@0.222.1/assert/assert_throws.ts": "c6508b2879d465898dab2798009299867e67c570d7d34c90a2d235e4553906eb", 137 | "https://deno.land/std@0.222.1/assert/assertion_error.ts": "ba8752bd27ebc51f723702fac2f54d3e94447598f54264a6653d6413738a8917", 138 | "https://deno.land/std@0.222.1/assert/equal.ts": "bddf07bb5fc718e10bb72d5dc2c36c1ce5a8bdd3b647069b6319e07af181ac47", 139 | "https://deno.land/std@0.222.1/assert/fail.ts": "0eba674ffb47dff083f02ced76d5130460bff1a9a68c6514ebe0cdea4abadb68", 140 | "https://deno.land/std@0.222.1/assert/mod.ts": "48b8cb8a619ea0b7958ad7ee9376500fe902284bb36f0e32c598c3dc34cbd6f3", 141 | "https://deno.land/std@0.222.1/assert/unimplemented.ts": "8c55a5793e9147b4f1ef68cd66496b7d5ba7a9e7ca30c6da070c1a58da723d73", 142 | "https://deno.land/std@0.222.1/assert/unreachable.ts": "5ae3dbf63ef988615b93eb08d395dda771c96546565f9e521ed86f6510c29e19", 143 | "https://deno.land/std@0.222.1/crypto/_wasm/lib/deno_std_wasm_crypto.generated.mjs": "376be64de048805874ebbc21c5ea7ce75a7f7d01da6f901cc697b1d4ffd6a721", 144 | "https://deno.land/std@0.222.1/crypto/_wasm/mod.ts": "e89fbbc3c4722602ff975dd85f18273c7741ec766a9b68f6de4fd1d9876409f8", 145 | "https://deno.land/std@0.222.1/crypto/crypto.ts": "451837d00409e40401e01e2ddad3c376e69a11a36e3fa67ec8dfe8b967fe0bf0", 146 | "https://deno.land/std@0.222.1/crypto/mod.ts": "9148fb70ca3d64977e9487b2002d3b1026e8ad8a2078774b807586ba3c77e3bb", 147 | "https://deno.land/std@0.222.1/crypto/timing_safe_equal.ts": "bc3622b5aec05e2d8b735bf60633425c34333c06cfb6c4a9f102e4a0f3931ced", 148 | "https://deno.land/std@0.222.1/crypto/unstable_keystack.ts": "c2a6f6ed67a4e78745e3c9b490ebb7c12f6066f5c2fe0c69d353961909dc82dd", 149 | "https://deno.land/std@0.222.1/encoding/_util.ts": "beacef316c1255da9bc8e95afb1fa56ed69baef919c88dc06ae6cb7a6103d376", 150 | "https://deno.land/std@0.222.1/encoding/base64.ts": "dd59695391584c8ffc5a296ba82bcdba6dd8a84d41a6a539fbee8e5075286eaf", 151 | "https://deno.land/std@0.222.1/encoding/base64url.ts": "ef40e0f18315ab539f17cebcc32839779e018d86dea9df39d94d302f342a1713", 152 | "https://deno.land/std@0.222.1/encoding/hex.ts": "6270f25e5d85f99fcf315278670ba012b04b7c94b67715b53f30d03249687c07", 153 | "https://deno.land/std@0.222.1/fmt/colors.ts": "d239d84620b921ea520125d778947881f62c50e78deef2657073840b8af9559a", 154 | "https://deno.land/x/scrypt@v4.3.4/deps.ts": "6b131a276ec247e87fe2d911844e2838f1c3926ce22471c24c63d3aed8c0be54", 155 | "https://deno.land/x/scrypt@v4.3.4/lib/_wasm/scrypt_wasm.generated.js": "24ce114e1be6ac85462bb581526011bc883f402c50f77834f23a6ff660027862", 156 | "https://deno.land/x/scrypt@v4.3.4/lib/format.ts": "fc7282e5697d34298f5f2b374d0df5344c50af5856bd51cdd1968048c40081cd", 157 | "https://deno.land/x/scrypt@v4.3.4/lib/helpers.ts": "ab937ba5bc709a06ee91ea9dc47e5003cc333c8ff6e50fb1fe802c0e9694bac8", 158 | "https://deno.land/x/scrypt@v4.3.4/lib/hmac.ts": "54b688de699b29a139c4aa68655f54c73eaca5ac54006da25bb0049785c2a3f3", 159 | "https://deno.land/x/scrypt@v4.3.4/lib/scrypt.ts": "af42fa97e6fc7b64a1abae2899c084a6c798f37c8095c85c937cef1543134ce2", 160 | "https://deno.land/x/scrypt@v4.3.4/mod.ts": "03f0dd67c896c503afafb3bfa7ddac1dd64bf7253a933e1cc87651f6b03ca7bd", 161 | "https://deno.land/x/scrypt@v4.4.2/deps.ts": "322cb38bd59721b93b7c75f6bab822230234f908ff1059bedfb5423470147be8", 162 | "https://deno.land/x/scrypt@v4.4.2/lib/_wasm/scrypt_wasm.generated.js": "dd6bd9094bfb46f7745ae9166359883a7d5acb8d903b3fa71d16ac71e0745ae7", 163 | "https://deno.land/x/scrypt@v4.4.2/lib/format.ts": "fc7282e5697d34298f5f2b374d0df5344c50af5856bd51cdd1968048c40081cd", 164 | "https://deno.land/x/scrypt@v4.4.2/lib/helpers.ts": "ab937ba5bc709a06ee91ea9dc47e5003cc333c8ff6e50fb1fe802c0e9694bac8", 165 | "https://deno.land/x/scrypt@v4.4.2/lib/hmac.ts": "54b688de699b29a139c4aa68655f54c73eaca5ac54006da25bb0049785c2a3f3", 166 | "https://deno.land/x/scrypt@v4.4.2/lib/scrypt.ts": "af42fa97e6fc7b64a1abae2899c084a6c798f37c8095c85c937cef1543134ce2", 167 | "https://deno.land/x/scrypt@v4.4.2/mod.ts": "07207d49a11814a7a8fc53e356756fe78cbdf7e5dc08fd7e34697b4e8f44db71", 168 | "https://deno.land/x/scrypt@v4.4.3/deps.ts": "322cb38bd59721b93b7c75f6bab822230234f908ff1059bedfb5423470147be8", 169 | "https://deno.land/x/scrypt@v4.4.3/lib/_wasm/scrypt_wasm.generated.js": "9da6221a40f5378096cdaa43dbc1f7af3889d224395317fa18a917a8368ee216", 170 | "https://deno.land/x/scrypt@v4.4.3/lib/scrypt.ts": "af42fa97e6fc7b64a1abae2899c084a6c798f37c8095c85c937cef1543134ce2", 171 | "https://deno.land/x/scrypto@v1.0.0/main.ts": "2f5733cbbef436d87e128204df4baf8de0177bd2ce38601e1a83e866bc828d0c", 172 | "https://deno.land/x/scrypto@v1.0.0/scrypt.ts": "8db05b7f839f9442fbd2df1e7e93b7245a409abbf2a6a7ba28e71f8ff0ffbf33" 173 | }, 174 | "workspace": { 175 | "dependencies": [ 176 | "jsr:@std/assert@0.222.1", 177 | "jsr:@std/crypto@0.222.1", 178 | "jsr:@std/encoding@0.222.1" 179 | ] 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /deps.ts: -------------------------------------------------------------------------------- 1 | export { 2 | assert, 3 | assertEquals, 4 | } from "https://deno.land/std@0.222.1/assert/mod.ts"; //jsr: "@std/assert"; 5 | export { crypto } from "https://deno.land/std@0.222.1/crypto/mod.ts"; //jsr: "@std/crypto"; 6 | export { timingSafeEqual } from "https://deno.land/std@0.222.1/crypto/timing_safe_equal.ts"; //jsr: "@std/crypto"; 7 | export { 8 | decodeBase64, 9 | encodeBase64, 10 | } from "https://deno.land/std@0.222.1/encoding/base64.ts"; //jsr: "@std/encoding/base64"; 11 | export { 12 | decodeHex, 13 | encodeHex, 14 | } from "https://deno.land/std@0.222.1/encoding/hex.ts"; //jsr: "@std/encoding/hex"; 15 | -------------------------------------------------------------------------------- /dprint.json: -------------------------------------------------------------------------------- 1 | { 2 | "markdown": {}, 3 | "toml": {}, 4 | "includes": ["**/*.{md,toml,rs}"], 5 | "excludes": ["**/node_modules", "**/*-lock.json", "**/*.generated.js"], 6 | "exec": { 7 | "commands": [ 8 | { 9 | "command": "rustfmt --edition 2021", 10 | "exts": ["rs"] 11 | } 12 | ] 13 | }, 14 | "plugins": [ 15 | "https://plugins.dprint.dev/markdown-0.16.3.wasm", 16 | "https://plugins.dprint.dev/toml-0.5.4.wasm", 17 | "https://plugins.dprint.dev/exec-0.4.4.json@c207bf9b9a4ee1f0ecb75c594f774924baf62e8e53a2ce9d873816a408cecbf7" 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /egg.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://x.nest.land/eggs@4.4.4/src/schema.json", 3 | "name": "scrypt", 4 | "entry": "./mod.ts", 5 | "description": "This is a wasm-based (using rust-crypto) implementation of scrypt key derivation function that doesn't require any privileges.", 6 | "homepage": "https://github.com/denorg/scrypt", 7 | "version": "4.4.4", 8 | "releaseType": null, 9 | "unstable": false, 10 | "unlisted": false, 11 | "files": [ 12 | "mod.ts", 13 | "cli.ts", 14 | "Cargo.toml", 15 | "deno.jsonc", 16 | "mod_test.ts", 17 | "README.md", 18 | "LICENSE", 19 | "lib/*", 20 | "lib/_wasm/src/*", 21 | "lib/_wasm/Cargo.toml", 22 | "lib/_wasm/LICENSE", 23 | "lib/_wasm/README.md", 24 | "lib/_wasm/scrypt_wasm.generated.js" 25 | ], 26 | "ignore": [ 27 | ".gitignore", 28 | ".vscode/**", 29 | ".releaserc.json", 30 | "_config.yml", 31 | "lib/_wasm/out/**/*", 32 | "lib/_wasm/target/**/*", 33 | "lib/_wasm/cargo.lock" 34 | ], 35 | "checkFormat": false, 36 | "checkTests": false, 37 | "checkInstallation": false, 38 | "check": true 39 | } 40 | -------------------------------------------------------------------------------- /example.ts: -------------------------------------------------------------------------------- 1 | import { hash, verify } from "https://deno.land/x/scrypt@v4.4.2/mod.ts"; 2 | 3 | console.time("hash"); 4 | const hashResult = hash("password", { logN: 17 }); 5 | console.timeEnd("hash"); 6 | 7 | console.time("verify"); 8 | const verifyResult = verify("password", hashResult); 9 | console.timeEnd("verify"); -------------------------------------------------------------------------------- /lib/_wasm/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "scrypt-wasm" 3 | version = "0.2.1" 4 | authors = ["oplik0"] 5 | edition = "2021" 6 | 7 | [lib] 8 | crate-type = ["cdylib", "rlib"] 9 | 10 | [dependencies] 11 | getrandom = { version = "0.2", features = ["js"] } 12 | scrypt = { version = "0.11", default-features = false } 13 | wasm-bindgen = { version = "=0.2.92", default-features = false } 14 | 15 | [dev-dependencies] 16 | wasm-bindgen-test = "=0.3.42" 17 | 18 | [profile.release] 19 | opt-level = 3 20 | strip = true 21 | lto = true 22 | 23 | [features] 24 | default = [] 25 | 26 | [package.metadata.wasm-pack.profile.release] 27 | wasm-opt = ['--enable-simd'] -------------------------------------------------------------------------------- /lib/_wasm/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 oplik0 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /lib/_wasm/README.md: -------------------------------------------------------------------------------- 1 | # scrypt-wasm 2 | 3 | Scrypt crypto library in Web Assembly 4 | 5 | # Prerequisities 6 | 7 | - Rust toolchain needs to be installed (see https://rustup.rs/) 8 | 9 | ### Build 10 | 11 | from the main package folder run 12 | 13 | ```sh 14 | deno task wasmbuild 15 | ``` 16 | -------------------------------------------------------------------------------- /lib/_wasm/scrypt_wasm.generated.d.ts: -------------------------------------------------------------------------------- 1 | // deno-lint-ignore-file 2 | // deno-fmt-ignore-file 3 | 4 | export interface InstantiateResult { 5 | instance: WebAssembly.Instance; 6 | exports: { 7 | scrypt_hash: typeof scrypt_hash 8 | }; 9 | } 10 | 11 | /** Gets if the Wasm module has been instantiated. */ 12 | export function isInstantiated(): boolean; 13 | 14 | 15 | /** Instantiates an instance of the Wasm module returning its functions. 16 | * @remarks It is safe to call this multiple times and once successfully 17 | * loaded it will always return a reference to the same object. */ 18 | export function instantiate(): InstantiateResult["exports"]; 19 | 20 | /** Instantiates an instance of the Wasm module along with its exports. 21 | * @remarks It is safe to call this multiple times and once successfully 22 | * loaded it will always return a reference to the same object. */ 23 | export function instantiateWithInstance(): InstantiateResult; 24 | 25 | /** 26 | * @param {Uint8Array} password 27 | * @param {Uint8Array} salt 28 | * @param {number} n 29 | * @param {number} r 30 | * @param {number} p 31 | * @param {number} dklen 32 | * @returns {Uint8Array} 33 | */ 34 | export function scrypt_hash(password: Uint8Array, salt: Uint8Array, n: number, r: number, p: number, dklen: number): Uint8Array; 35 | -------------------------------------------------------------------------------- /lib/_wasm/scrypt_wasm.generated.js: -------------------------------------------------------------------------------- 1 | // @generated file from wasmbuild -- do not edit 2 | // @ts-nocheck: generated 3 | // deno-lint-ignore-file 4 | // deno-fmt-ignore-file 5 | /// 6 | 7 | // source-hash: fde43a7487aa88ac1a66269d4891b4fc18b25207 8 | let wasm; 9 | 10 | let cachedUint8Memory0 = null; 11 | 12 | function getUint8Memory0() { 13 | if (cachedUint8Memory0 === null || cachedUint8Memory0.byteLength === 0) { 14 | cachedUint8Memory0 = new Uint8Array(wasm.memory.buffer); 15 | } 16 | return cachedUint8Memory0; 17 | } 18 | 19 | let WASM_VECTOR_LEN = 0; 20 | 21 | function passArray8ToWasm0(arg, malloc) { 22 | const ptr = malloc(arg.length * 1, 1) >>> 0; 23 | getUint8Memory0().set(arg, ptr / 1); 24 | WASM_VECTOR_LEN = arg.length; 25 | return ptr; 26 | } 27 | 28 | let cachedInt32Memory0 = null; 29 | 30 | function getInt32Memory0() { 31 | if (cachedInt32Memory0 === null || cachedInt32Memory0.byteLength === 0) { 32 | cachedInt32Memory0 = new Int32Array(wasm.memory.buffer); 33 | } 34 | return cachedInt32Memory0; 35 | } 36 | 37 | function getArrayU8FromWasm0(ptr, len) { 38 | ptr = ptr >>> 0; 39 | return getUint8Memory0().subarray(ptr / 1, ptr / 1 + len); 40 | } 41 | /** 42 | * @param {Uint8Array} password 43 | * @param {Uint8Array} salt 44 | * @param {number} n 45 | * @param {number} r 46 | * @param {number} p 47 | * @param {number} dklen 48 | * @returns {Uint8Array} 49 | */ 50 | export function scrypt_hash(password, salt, n, r, p, dklen) { 51 | try { 52 | const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); 53 | const ptr0 = passArray8ToWasm0(password, wasm.__wbindgen_export_0); 54 | const len0 = WASM_VECTOR_LEN; 55 | const ptr1 = passArray8ToWasm0(salt, wasm.__wbindgen_export_0); 56 | const len1 = WASM_VECTOR_LEN; 57 | wasm.scrypt_hash(retptr, ptr0, len0, ptr1, len1, n, r, p, dklen); 58 | var r0 = getInt32Memory0()[retptr / 4 + 0]; 59 | var r1 = getInt32Memory0()[retptr / 4 + 1]; 60 | var v3 = getArrayU8FromWasm0(r0, r1).slice(); 61 | wasm.__wbindgen_export_1(r0, r1 * 1, 1); 62 | return v3; 63 | } finally { 64 | wasm.__wbindgen_add_to_stack_pointer(16); 65 | } 66 | } 67 | 68 | const imports = { 69 | __wbindgen_placeholder__: {}, 70 | }; 71 | 72 | export function instantiate() { 73 | return instantiateWithInstance().exports; 74 | } 75 | 76 | let instanceWithExports; 77 | 78 | export function instantiateWithInstance() { 79 | if (instanceWithExports == null) { 80 | const instance = instantiateInstance(); 81 | wasm = instance.exports; 82 | cachedInt32Memory0 = new Int32Array(wasm.memory.buffer); 83 | cachedUint8Memory0 = new Uint8Array(wasm.memory.buffer); 84 | instanceWithExports = { 85 | instance, 86 | exports: { scrypt_hash }, 87 | }; 88 | } 89 | return instanceWithExports; 90 | } 91 | 92 | export function isInstantiated() { 93 | return instanceWithExports != null; 94 | } 95 | 96 | function instantiateInstance() { 97 | const wasmBytes = base64decode( 98 | "\ 99 | AGFzbQEAAAABgAERYAAAYAF/AGABfwF/YAJ/fwBgAn9/AX9gA39/fwBgA39/fwF/YAR/f39/AGAEf3\ 100 | 9/fwF/YAV/f39/fwBgBX9/f39/AX9gBn9/f39/fwBgBn9/f39/fwF/YAd/f39/f39/AGAHf39/f39/\ 101 | fwF/YAl/f39/f39/f38AYAN+f38BfwNWVQUCDQcGBAUMCAEGDQMEDgMGBBADAwsFAw8HBgkPAQMJBQ\ 102 | UFBQMEBgMFBAEFCgADAQEEAwYIBQQEBAMDAwMDBAUDBAQBAgQEAwQDBgYBAAUABAEBAQEEBQFwARkZ\ 103 | BQMBABEGCQF/AUGAgMAACwdmBQZtZW1vcnkCAAtzY3J5cHRfaGFzaAAcH19fd2JpbmRnZW5fYWRkX3\ 104 | RvX3N0YWNrX3BvaW50ZXIARBNfX3diaW5kZ2VuX2V4cG9ydF8wACkTX193YmluZGdlbl9leHBvcnRf\ 105 | MQA1CR4BAEEBCxhRRkVCJDAmEUg5UjsnPC8UHlM6QTY+VD0KzfMBVdU+ASN/IAAoAhwhAyAAKAIYIQ\ 106 | QgACgCFCEFIAAoAhAhBiAAKAIMIQcgACgCCCEIIAAoAgQhCSAAKAIAIQoCQCACRQ0AIAEgAkEGdGoh\ 107 | CwNAIAggCXMgCnEgCCAJcXMgCkEedyAKQRN3cyAKQQp3c2ogAyAGQRp3IAZBFXdzIAZBB3dzaiAEIA\ 108 | VzIAZxIARzaiABKAAAIgJBGHQgAkGA/gNxQQh0ciACQQh2QYD+A3EgAkEYdnJyIgxqQZjfqJQEaiIN\ 109 | aiICQR53IAJBE3dzIAJBCndzIAIgCSAKc3EgCSAKcXNqIAQgASgABCIOQRh0IA5BgP4DcUEIdHIgDk\ 110 | EIdkGA/gNxIA5BGHZyciIPaiANIAdqIhAgBSAGc3EgBXNqIBBBGncgEEEVd3MgEEEHd3NqQZGJ3YkH\ 111 | aiIRaiIOQR53IA5BE3dzIA5BCndzIA4gAiAKc3EgAiAKcXNqIAUgASgACCINQRh0IA1BgP4DcUEIdH\ 112 | IgDUEIdkGA/gNxIA1BGHZyciISaiARIAhqIhMgECAGc3EgBnNqIBNBGncgE0EVd3MgE0EHd3NqQc/3\ 113 | g657aiIUaiINQR53IA1BE3dzIA1BCndzIA0gDiACc3EgDiACcXNqIAYgASgADCIRQRh0IBFBgP4DcU\ 114 | EIdHIgEUEIdkGA/gNxIBFBGHZyciIVaiAUIAlqIhQgEyAQc3EgEHNqIBRBGncgFEEVd3MgFEEHd3Nq\ 115 | QaW3181+aiIWaiIRQR53IBFBE3dzIBFBCndzIBEgDSAOc3EgDSAOcXNqIBAgASgAECIXQRh0IBdBgP\ 116 | 4DcUEIdHIgF0EIdkGA/gNxIBdBGHZyciIYaiAWIApqIhcgFCATc3EgE3NqIBdBGncgF0EVd3MgF0EH\ 117 | d3NqQduE28oDaiIZaiIQQR53IBBBE3dzIBBBCndzIBAgESANc3EgESANcXNqIAEoABQiFkEYdCAWQY\ 118 | D+A3FBCHRyIBZBCHZBgP4DcSAWQRh2cnIiGiATaiAZIAJqIhMgFyAUc3EgFHNqIBNBGncgE0EVd3Mg\ 119 | E0EHd3NqQfGjxM8FaiIZaiICQR53IAJBE3dzIAJBCndzIAIgECARc3EgECARcXNqIAEoABgiFkEYdC\ 120 | AWQYD+A3FBCHRyIBZBCHZBgP4DcSAWQRh2cnIiGyAUaiAZIA5qIhQgEyAXc3EgF3NqIBRBGncgFEEV\ 121 | d3MgFEEHd3NqQaSF/pF5aiIZaiIOQR53IA5BE3dzIA5BCndzIA4gAiAQc3EgAiAQcXNqIAEoABwiFk\ 122 | EYdCAWQYD+A3FBCHRyIBZBCHZBgP4DcSAWQRh2cnIiHCAXaiAZIA1qIhcgFCATc3EgE3NqIBdBGncg\ 123 | F0EVd3MgF0EHd3NqQdW98dh6aiIZaiINQR53IA1BE3dzIA1BCndzIA0gDiACc3EgDiACcXNqIAEoAC\ 124 | AiFkEYdCAWQYD+A3FBCHRyIBZBCHZBgP4DcSAWQRh2cnIiHSATaiAZIBFqIhMgFyAUc3EgFHNqIBNB\ 125 | GncgE0EVd3MgE0EHd3NqQZjVnsB9aiIZaiIRQR53IBFBE3dzIBFBCndzIBEgDSAOc3EgDSAOcXNqIA\ 126 | EoACQiFkEYdCAWQYD+A3FBCHRyIBZBCHZBgP4DcSAWQRh2cnIiHiAUaiAZIBBqIhQgEyAXc3EgF3Nq\ 127 | IBRBGncgFEEVd3MgFEEHd3NqQYG2jZQBaiIZaiIQQR53IBBBE3dzIBBBCndzIBAgESANc3EgESANcX\ 128 | NqIAEoACgiFkEYdCAWQYD+A3FBCHRyIBZBCHZBgP4DcSAWQRh2cnIiHyAXaiAZIAJqIhcgFCATc3Eg\ 129 | E3NqIBdBGncgF0EVd3MgF0EHd3NqQb6LxqECaiIZaiICQR53IAJBE3dzIAJBCndzIAIgECARc3EgEC\ 130 | ARcXNqIAEoACwiFkEYdCAWQYD+A3FBCHRyIBZBCHZBgP4DcSAWQRh2cnIiICATaiAZIA5qIhYgFyAU\ 131 | c3EgFHNqIBZBGncgFkEVd3MgFkEHd3NqQcP7sagFaiIZaiIOQR53IA5BE3dzIA5BCndzIA4gAiAQc3\ 132 | EgAiAQcXNqIAEoADAiE0EYdCATQYD+A3FBCHRyIBNBCHZBgP4DcSATQRh2cnIiISAUaiAZIA1qIhkg\ 133 | FiAXc3EgF3NqIBlBGncgGUEVd3MgGUEHd3NqQfS6+ZUHaiIUaiINQR53IA1BE3dzIA1BCndzIA0gDi\ 134 | ACc3EgDiACcXNqIAEoADQiE0EYdCATQYD+A3FBCHRyIBNBCHZBgP4DcSATQRh2cnIiIiAXaiAUIBFq\ 135 | IiMgGSAWc3EgFnNqICNBGncgI0EVd3MgI0EHd3NqQf7j+oZ4aiIUaiIRQR53IBFBE3dzIBFBCndzIB\ 136 | EgDSAOc3EgDSAOcXNqIAEoADgiE0EYdCATQYD+A3FBCHRyIBNBCHZBgP4DcSATQRh2cnIiEyAWaiAU\ 137 | IBBqIiQgIyAZc3EgGXNqICRBGncgJEEVd3MgJEEHd3NqQaeN8N55aiIXaiIQQR53IBBBE3dzIBBBCn\ 138 | dzIBAgESANc3EgESANcXNqIAEoADwiFEEYdCAUQYD+A3FBCHRyIBRBCHZBgP4DcSAUQRh2cnIiFCAZ\ 139 | aiAXIAJqIiUgJCAjc3EgI3NqICVBGncgJUEVd3MgJUEHd3NqQfTi74x8aiIWaiICQR53IAJBE3dzIA\ 140 | JBCndzIAIgECARc3EgECARcXNqIA9BGXcgD0EOd3MgD0EDdnMgDGogHmogE0EPdyATQQ13cyATQQp2\ 141 | c2oiFyAjaiAWIA5qIgwgJSAkc3EgJHNqIAxBGncgDEEVd3MgDEEHd3NqQcHT7aR+aiIZaiIOQR53IA\ 142 | 5BE3dzIA5BCndzIA4gAiAQc3EgAiAQcXNqIBJBGXcgEkEOd3MgEkEDdnMgD2ogH2ogFEEPdyAUQQ13\ 143 | cyAUQQp2c2oiFiAkaiAZIA1qIg8gDCAlc3EgJXNqIA9BGncgD0EVd3MgD0EHd3NqQYaP+f1+aiIjai\ 144 | INQR53IA1BE3dzIA1BCndzIA0gDiACc3EgDiACcXNqIBVBGXcgFUEOd3MgFUEDdnMgEmogIGogF0EP\ 145 | dyAXQQ13cyAXQQp2c2oiGSAlaiAjIBFqIhIgDyAMc3EgDHNqIBJBGncgEkEVd3MgEkEHd3NqQca7hv\ 146 | 4AaiIkaiIRQR53IBFBE3dzIBFBCndzIBEgDSAOc3EgDSAOcXNqIBhBGXcgGEEOd3MgGEEDdnMgFWog\ 147 | IWogFkEPdyAWQQ13cyAWQQp2c2oiIyAMaiAkIBBqIhUgEiAPc3EgD3NqIBVBGncgFUEVd3MgFUEHd3\ 148 | NqQczDsqACaiIlaiIQQR53IBBBE3dzIBBBCndzIBAgESANc3EgESANcXNqIBpBGXcgGkEOd3MgGkED\ 149 | dnMgGGogImogGUEPdyAZQQ13cyAZQQp2c2oiJCAPaiAlIAJqIhggFSASc3EgEnNqIBhBGncgGEEVd3\ 150 | MgGEEHd3NqQe/YpO8CaiIMaiICQR53IAJBE3dzIAJBCndzIAIgECARc3EgECARcXNqIBtBGXcgG0EO\ 151 | d3MgG0EDdnMgGmogE2ogI0EPdyAjQQ13cyAjQQp2c2oiJSASaiAMIA5qIhogGCAVc3EgFXNqIBpBGn\ 152 | cgGkEVd3MgGkEHd3NqQaqJ0tMEaiIPaiIOQR53IA5BE3dzIA5BCndzIA4gAiAQc3EgAiAQcXNqIBxB\ 153 | GXcgHEEOd3MgHEEDdnMgG2ogFGogJEEPdyAkQQ13cyAkQQp2c2oiDCAVaiAPIA1qIhsgGiAYc3EgGH\ 154 | NqIBtBGncgG0EVd3MgG0EHd3NqQdzTwuUFaiISaiINQR53IA1BE3dzIA1BCndzIA0gDiACc3EgDiAC\ 155 | cXNqIB1BGXcgHUEOd3MgHUEDdnMgHGogF2ogJUEPdyAlQQ13cyAlQQp2c2oiDyAYaiASIBFqIhwgGy\ 156 | Aac3EgGnNqIBxBGncgHEEVd3MgHEEHd3NqQdqR5rcHaiIVaiIRQR53IBFBE3dzIBFBCndzIBEgDSAO\ 157 | c3EgDSAOcXNqIB5BGXcgHkEOd3MgHkEDdnMgHWogFmogDEEPdyAMQQ13cyAMQQp2c2oiEiAaaiAVIB\ 158 | BqIh0gHCAbc3EgG3NqIB1BGncgHUEVd3MgHUEHd3NqQdKi+cF5aiIYaiIQQR53IBBBE3dzIBBBCndz\ 159 | IBAgESANc3EgESANcXNqIB9BGXcgH0EOd3MgH0EDdnMgHmogGWogD0EPdyAPQQ13cyAPQQp2c2oiFS\ 160 | AbaiAYIAJqIh4gHSAcc3EgHHNqIB5BGncgHkEVd3MgHkEHd3NqQe2Mx8F6aiIaaiICQR53IAJBE3dz\ 161 | IAJBCndzIAIgECARc3EgECARcXNqICBBGXcgIEEOd3MgIEEDdnMgH2ogI2ogEkEPdyASQQ13cyASQQ\ 162 | p2c2oiGCAcaiAaIA5qIh8gHiAdc3EgHXNqIB9BGncgH0EVd3MgH0EHd3NqQcjPjIB7aiIbaiIOQR53\ 163 | IA5BE3dzIA5BCndzIA4gAiAQc3EgAiAQcXNqICFBGXcgIUEOd3MgIUEDdnMgIGogJGogFUEPdyAVQQ\ 164 | 13cyAVQQp2c2oiGiAdaiAbIA1qIh0gHyAec3EgHnNqIB1BGncgHUEVd3MgHUEHd3NqQcf/5fp7aiIc\ 165 | aiINQR53IA1BE3dzIA1BCndzIA0gDiACc3EgDiACcXNqICJBGXcgIkEOd3MgIkEDdnMgIWogJWogGE\ 166 | EPdyAYQQ13cyAYQQp2c2oiGyAeaiAcIBFqIh4gHSAfc3EgH3NqIB5BGncgHkEVd3MgHkEHd3NqQfOX\ 167 | gLd8aiIgaiIRQR53IBFBE3dzIBFBCndzIBEgDSAOc3EgDSAOcXNqIBNBGXcgE0EOd3MgE0EDdnMgIm\ 168 | ogDGogGkEPdyAaQQ13cyAaQQp2c2oiHCAfaiAgIBBqIh8gHiAdc3EgHXNqIB9BGncgH0EVd3MgH0EH\ 169 | d3NqQceinq19aiIgaiIQQR53IBBBE3dzIBBBCndzIBAgESANc3EgESANcXNqIBRBGXcgFEEOd3MgFE\ 170 | EDdnMgE2ogD2ogG0EPdyAbQQ13cyAbQQp2c2oiEyAdaiAgIAJqIh0gHyAec3EgHnNqIB1BGncgHUEV\ 171 | d3MgHUEHd3NqQdHGqTZqIiBqIgJBHncgAkETd3MgAkEKd3MgAiAQIBFzcSAQIBFxc2ogF0EZdyAXQQ\ 172 | 53cyAXQQN2cyAUaiASaiAcQQ93IBxBDXdzIBxBCnZzaiIUIB5qICAgDmoiHiAdIB9zcSAfc2ogHkEa\ 173 | dyAeQRV3cyAeQQd3c2pB59KkoQFqIiBqIg5BHncgDkETd3MgDkEKd3MgDiACIBBzcSACIBBxc2ogFk\ 174 | EZdyAWQQ53cyAWQQN2cyAXaiAVaiATQQ93IBNBDXdzIBNBCnZzaiIXIB9qICAgDWoiHyAeIB1zcSAd\ 175 | c2ogH0EadyAfQRV3cyAfQQd3c2pBhZXcvQJqIiBqIg1BHncgDUETd3MgDUEKd3MgDSAOIAJzcSAOIA\ 176 | Jxc2ogGUEZdyAZQQ53cyAZQQN2cyAWaiAYaiAUQQ93IBRBDXdzIBRBCnZzaiIWIB1qICAgEWoiHSAf\ 177 | IB5zcSAec2ogHUEadyAdQRV3cyAdQQd3c2pBuMLs8AJqIiBqIhFBHncgEUETd3MgEUEKd3MgESANIA\ 178 | 5zcSANIA5xc2ogI0EZdyAjQQ53cyAjQQN2cyAZaiAaaiAXQQ93IBdBDXdzIBdBCnZzaiIZIB5qICAg\ 179 | EGoiHiAdIB9zcSAfc2ogHkEadyAeQRV3cyAeQQd3c2pB/Nux6QRqIiBqIhBBHncgEEETd3MgEEEKd3\ 180 | MgECARIA1zcSARIA1xc2ogJEEZdyAkQQ53cyAkQQN2cyAjaiAbaiAWQQ93IBZBDXdzIBZBCnZzaiIj\ 181 | IB9qICAgAmoiHyAeIB1zcSAdc2ogH0EadyAfQRV3cyAfQQd3c2pBk5rgmQVqIiBqIgJBHncgAkETd3\ 182 | MgAkEKd3MgAiAQIBFzcSAQIBFxc2ogJUEZdyAlQQ53cyAlQQN2cyAkaiAcaiAZQQ93IBlBDXdzIBlB\ 183 | CnZzaiIkIB1qICAgDmoiHSAfIB5zcSAec2ogHUEadyAdQRV3cyAdQQd3c2pB1OapqAZqIiBqIg5BHn\ 184 | cgDkETd3MgDkEKd3MgDiACIBBzcSACIBBxc2ogDEEZdyAMQQ53cyAMQQN2cyAlaiATaiAjQQ93ICNB\ 185 | DXdzICNBCnZzaiIlIB5qICAgDWoiHiAdIB9zcSAfc2ogHkEadyAeQRV3cyAeQQd3c2pBu5WoswdqIi\ 186 | BqIg1BHncgDUETd3MgDUEKd3MgDSAOIAJzcSAOIAJxc2ogD0EZdyAPQQ53cyAPQQN2cyAMaiAUaiAk\ 187 | QQ93ICRBDXdzICRBCnZzaiIMIB9qICAgEWoiHyAeIB1zcSAdc2ogH0EadyAfQRV3cyAfQQd3c2pBrp\ 188 | KLjnhqIiBqIhFBHncgEUETd3MgEUEKd3MgESANIA5zcSANIA5xc2ogEkEZdyASQQ53cyASQQN2cyAP\ 189 | aiAXaiAlQQ93ICVBDXdzICVBCnZzaiIPIB1qICAgEGoiHSAfIB5zcSAec2ogHUEadyAdQRV3cyAdQQ\ 190 | d3c2pBhdnIk3lqIiBqIhBBHncgEEETd3MgEEEKd3MgECARIA1zcSARIA1xc2ogFUEZdyAVQQ53cyAV\ 191 | QQN2cyASaiAWaiAMQQ93IAxBDXdzIAxBCnZzaiISIB5qICAgAmoiHiAdIB9zcSAfc2ogHkEadyAeQR\ 192 | V3cyAeQQd3c2pBodH/lXpqIiBqIgJBHncgAkETd3MgAkEKd3MgAiAQIBFzcSAQIBFxc2ogGEEZdyAY\ 193 | QQ53cyAYQQN2cyAVaiAZaiAPQQ93IA9BDXdzIA9BCnZzaiIVIB9qICAgDmoiHyAeIB1zcSAdc2ogH0\ 194 | EadyAfQRV3cyAfQQd3c2pBy8zpwHpqIiBqIg5BHncgDkETd3MgDkEKd3MgDiACIBBzcSACIBBxc2og\ 195 | GkEZdyAaQQ53cyAaQQN2cyAYaiAjaiASQQ93IBJBDXdzIBJBCnZzaiIYIB1qICAgDWoiHSAfIB5zcS\ 196 | Aec2ogHUEadyAdQRV3cyAdQQd3c2pB8JauknxqIiBqIg1BHncgDUETd3MgDUEKd3MgDSAOIAJzcSAO\ 197 | IAJxc2ogG0EZdyAbQQ53cyAbQQN2cyAaaiAkaiAVQQ93IBVBDXdzIBVBCnZzaiIaIB5qICAgEWoiHi\ 198 | AdIB9zcSAfc2ogHkEadyAeQRV3cyAeQQd3c2pBo6Oxu3xqIiBqIhFBHncgEUETd3MgEUEKd3MgESAN\ 199 | IA5zcSANIA5xc2ogHEEZdyAcQQ53cyAcQQN2cyAbaiAlaiAYQQ93IBhBDXdzIBhBCnZzaiIbIB9qIC\ 200 | AgEGoiHyAeIB1zcSAdc2ogH0EadyAfQRV3cyAfQQd3c2pBmdDLjH1qIiBqIhBBHncgEEETd3MgEEEK\ 201 | d3MgECARIA1zcSARIA1xc2ogE0EZdyATQQ53cyATQQN2cyAcaiAMaiAaQQ93IBpBDXdzIBpBCnZzai\ 202 | IcIB1qICAgAmoiHSAfIB5zcSAec2ogHUEadyAdQRV3cyAdQQd3c2pBpIzktH1qIiBqIgJBHncgAkET\ 203 | d3MgAkEKd3MgAiAQIBFzcSAQIBFxc2ogFEEZdyAUQQ53cyAUQQN2cyATaiAPaiAbQQ93IBtBDXdzIB\ 204 | tBCnZzaiITIB5qICAgDmoiHiAdIB9zcSAfc2ogHkEadyAeQRV3cyAeQQd3c2pBheu4oH9qIiBqIg5B\ 205 | HncgDkETd3MgDkEKd3MgDiACIBBzcSACIBBxc2ogF0EZdyAXQQ53cyAXQQN2cyAUaiASaiAcQQ93IB\ 206 | xBDXdzIBxBCnZzaiIUIB9qICAgDWoiHyAeIB1zcSAdc2ogH0EadyAfQRV3cyAfQQd3c2pB8MCqgwFq\ 207 | IiBqIg1BHncgDUETd3MgDUEKd3MgDSAOIAJzcSAOIAJxc2ogFkEZdyAWQQ53cyAWQQN2cyAXaiAVai\ 208 | ATQQ93IBNBDXdzIBNBCnZzaiIXIB1qICAgEWoiHSAfIB5zcSAec2ogHUEadyAdQRV3cyAdQQd3c2pB\ 209 | loKTzQFqIiFqIhFBHncgEUETd3MgEUEKd3MgESANIA5zcSANIA5xc2ogGUEZdyAZQQ53cyAZQQN2cy\ 210 | AWaiAYaiAUQQ93IBRBDXdzIBRBCnZzaiIgIB5qICEgEGoiFiAdIB9zcSAfc2ogFkEadyAWQRV3cyAW\ 211 | QQd3c2pBiNjd8QFqIiFqIhBBHncgEEETd3MgEEEKd3MgECARIA1zcSARIA1xc2ogI0EZdyAjQQ53cy\ 212 | AjQQN2cyAZaiAaaiAXQQ93IBdBDXdzIBdBCnZzaiIeIB9qICEgAmoiGSAWIB1zcSAdc2ogGUEadyAZ\ 213 | QRV3cyAZQQd3c2pBzO6hugJqIiFqIgJBHncgAkETd3MgAkEKd3MgAiAQIBFzcSAQIBFxc2ogJEEZdy\ 214 | AkQQ53cyAkQQN2cyAjaiAbaiAgQQ93ICBBDXdzICBBCnZzaiIfIB1qICEgDmoiIyAZIBZzcSAWc2og\ 215 | I0EadyAjQRV3cyAjQQd3c2pBtfnCpQNqIh1qIg5BHncgDkETd3MgDkEKd3MgDiACIBBzcSACIBBxc2\ 216 | ogJUEZdyAlQQ53cyAlQQN2cyAkaiAcaiAeQQ93IB5BDXdzIB5BCnZzaiIkIBZqIB0gDWoiFiAjIBlz\ 217 | cSAZc2ogFkEadyAWQRV3cyAWQQd3c2pBs5nwyANqIh1qIg1BHncgDUETd3MgDUEKd3MgDSAOIAJzcS\ 218 | AOIAJxc2ogDEEZdyAMQQ53cyAMQQN2cyAlaiATaiAfQQ93IB9BDXdzIB9BCnZzaiIlIBlqIB0gEWoi\ 219 | GSAWICNzcSAjc2ogGUEadyAZQRV3cyAZQQd3c2pBytTi9gRqIh1qIhFBHncgEUETd3MgEUEKd3MgES\ 220 | ANIA5zcSANIA5xc2ogD0EZdyAPQQ53cyAPQQN2cyAMaiAUaiAkQQ93ICRBDXdzICRBCnZzaiIMICNq\ 221 | IB0gEGoiIyAZIBZzcSAWc2ogI0EadyAjQRV3cyAjQQd3c2pBz5Tz3AVqIh1qIhBBHncgEEETd3MgEE\ 222 | EKd3MgECARIA1zcSARIA1xc2ogEkEZdyASQQ53cyASQQN2cyAPaiAXaiAlQQ93ICVBDXdzICVBCnZz\ 223 | aiIPIBZqIB0gAmoiFiAjIBlzcSAZc2ogFkEadyAWQRV3cyAWQQd3c2pB89+5wQZqIh1qIgJBHncgAk\ 224 | ETd3MgAkEKd3MgAiAQIBFzcSAQIBFxc2ogFUEZdyAVQQ53cyAVQQN2cyASaiAgaiAMQQ93IAxBDXdz\ 225 | IAxBCnZzaiISIBlqIB0gDmoiGSAWICNzcSAjc2ogGUEadyAZQRV3cyAZQQd3c2pB7oW+pAdqIh1qIg\ 226 | 5BHncgDkETd3MgDkEKd3MgDiACIBBzcSACIBBxc2ogGEEZdyAYQQ53cyAYQQN2cyAVaiAeaiAPQQ93\ 227 | IA9BDXdzIA9BCnZzaiIVICNqIB0gDWoiIyAZIBZzcSAWc2ogI0EadyAjQRV3cyAjQQd3c2pB78aVxQ\ 228 | dqIh1qIg1BHncgDUETd3MgDUEKd3MgDSAOIAJzcSAOIAJxc2ogGkEZdyAaQQ53cyAaQQN2cyAYaiAf\ 229 | aiASQQ93IBJBDXdzIBJBCnZzaiIYIBZqIB0gEWoiFiAjIBlzcSAZc2ogFkEadyAWQRV3cyAWQQd3c2\ 230 | pBlPChpnhqIh1qIhFBHncgEUETd3MgEUEKd3MgESANIA5zcSANIA5xc2ogG0EZdyAbQQ53cyAbQQN2\ 231 | cyAaaiAkaiAVQQ93IBVBDXdzIBVBCnZzaiIkIBlqIB0gEGoiGSAWICNzcSAjc2ogGUEadyAZQRV3cy\ 232 | AZQQd3c2pBiISc5nhqIhVqIhBBHncgEEETd3MgEEEKd3MgECARIA1zcSARIA1xc2ogHEEZdyAcQQ53\ 233 | cyAcQQN2cyAbaiAlaiAYQQ93IBhBDXdzIBhBCnZzaiIlICNqIBUgAmoiIyAZIBZzcSAWc2ogI0Eady\ 234 | AjQRV3cyAjQQd3c2pB+v/7hXlqIhVqIgJBHncgAkETd3MgAkEKd3MgAiAQIBFzcSAQIBFxc2ogE0EZ\ 235 | dyATQQ53cyATQQN2cyAcaiAMaiAkQQ93ICRBDXdzICRBCnZzaiIkIBZqIBUgDmoiDiAjIBlzcSAZc2\ 236 | ogDkEadyAOQRV3cyAOQQd3c2pB69nBonpqIgxqIhZBHncgFkETd3MgFkEKd3MgFiACIBBzcSACIBBx\ 237 | c2ogEyAUQRl3IBRBDndzIBRBA3ZzaiAPaiAlQQ93ICVBDXdzICVBCnZzaiAZaiAMIA1qIg0gDiAjc3\ 238 | EgI3NqIA1BGncgDUEVd3MgDUEHd3NqQffH5vd7aiIZaiITIBYgAnNxIBYgAnFzIApqIBNBHncgE0ET\ 239 | d3MgE0EKd3NqIBQgF0EZdyAXQQ53cyAXQQN2c2ogEmogJEEPdyAkQQ13cyAkQQp2c2ogI2ogGSARai\ 240 | IRIA0gDnNxIA5zaiARQRp3IBFBFXdzIBFBB3dzakHy8cWzfGoiFGohCiATIAlqIQkgECAGaiAUaiEG\ 241 | IBYgCGohCCARIAVqIQUgAiAHaiEHIA0gBGohBCAOIANqIQMgAUHAAGoiASALRw0ACwsgACADNgIcIA\ 242 | AgBDYCGCAAIAU2AhQgACAGNgIQIAAgBzYCDCAAIAg2AgggACAJNgIEIAAgCjYCAAvyIwIJfwF+IwBB\ 243 | EGsiASQAAkACQAJAAkACQAJAAkACQCAAQfUBSQ0AQQAhAiAAQc3/e08NByAAQQtqIgBBeHEhA0EAKA\ 244 | LwjkAiBEUNBEEAIQUCQCADQYACSQ0AQR8hBSADQf///wdLDQAgA0EGIABBCHZnIgBrdkEBcSAAQQF0\ 245 | a0E+aiEFC0EAIANrIQICQCAFQQJ0QdSLwABqKAIAIgYNAEEAIQBBACEHDAILQQAhACADQQBBGSAFQQ\ 246 | F2ayAFQR9GG3QhCEEAIQcDQAJAIAYoAgRBeHEiCSADSQ0AIAkgA2siCSACTw0AIAkhAiAGIQcgCQ0A\ 247 | QQAhAiAGIQcgBiEADAQLIAZBFGooAgAiCSAAIAkgBiAIQR12QQRxakEQaigCACIGRxsgACAJGyEAIA\ 248 | hBAXQhCCAGRQ0CDAALCwJAQQAoAuyOQCIHQRAgAEELakF4cSAAQQtJGyIDQQN2IgJ2IgBBA3FFDQAC\ 249 | QAJAIABBf3NBAXEgAmoiA0EDdCIAQeSMwABqIgIgAEHsjMAAaigCACIAKAIIIgZGDQAgBiACNgIMIA\ 250 | IgBjYCCAwBC0EAIAdBfiADd3E2AuyOQAsgAEEIaiECIAAgA0EDdCIDQQNyNgIEIAAgA2oiACAAKAIE\ 251 | QQFyNgIEDAcLIANBACgC9I5ATQ0DAkACQAJAIAANAEEAKALwjkAiAEUNBiAAaEECdEHUi8AAaigCAC\ 252 | IGKAIEQXhxIANrIQIgBiEHA0ACQCAGKAIQIgANACAGQRRqKAIAIgANACAHKAIYIQUCQAJAAkAgBygC\ 253 | DCIAIAdHDQAgB0EUQRAgB0EUaiIAKAIAIggbaigCACIGDQFBACEADAILIAcoAggiBiAANgIMIAAgBj\ 254 | YCCAwBCyAAIAdBEGogCBshCANAIAghCSAGIgBBFGoiBiAAQRBqIAYoAgAiBhshCCAAQRRBECAGG2oo\ 255 | AgAiBg0ACyAJQQA2AgALIAVFDQQCQCAHKAIcQQJ0QdSLwABqIgYoAgAgB0YNACAFQRBBFCAFKAIQIA\ 256 | dGG2ogADYCACAARQ0FDAQLIAYgADYCACAADQNBAEEAKALwjkBBfiAHKAIcd3E2AvCOQAwECyAAKAIE\ 257 | QXhxIANrIgYgAiAGIAJJIgYbIQIgACAHIAYbIQcgACEGDAALCwJAAkAgACACdEECIAJ0IgBBACAAa3\ 258 | JxaCICQQN0IgBB5IzAAGoiBiAAQeyMwABqKAIAIgAoAggiCEYNACAIIAY2AgwgBiAINgIIDAELQQAg\ 259 | B0F+IAJ3cTYC7I5ACyAAIANBA3I2AgQgACADaiIIIAJBA3QiAiADayIGQQFyNgIEIAAgAmogBjYCAA\ 260 | JAQQAoAvSOQCIHRQ0AIAdBeHFB5IzAAGohAkEAKAL8jkAhAwJAAkBBACgC7I5AIglBASAHQQN2dCIH\ 261 | cQ0AQQAgCSAHcjYC7I5AIAIhBwwBCyACKAIIIQcLIAIgAzYCCCAHIAM2AgwgAyACNgIMIAMgBzYCCA\ 262 | sgAEEIaiECQQAgCDYC/I5AQQAgBjYC9I5ADAgLIAAgBTYCGAJAIAcoAhAiBkUNACAAIAY2AhAgBiAA\ 263 | NgIYCyAHQRRqKAIAIgZFDQAgAEEUaiAGNgIAIAYgADYCGAsCQAJAAkAgAkEQSQ0AIAcgA0EDcjYCBC\ 264 | AHIANqIgMgAkEBcjYCBCADIAJqIAI2AgBBACgC9I5AIghFDQEgCEF4cUHkjMAAaiEGQQAoAvyOQCEA\ 265 | AkACQEEAKALsjkAiCUEBIAhBA3Z0IghxDQBBACAJIAhyNgLsjkAgBiEIDAELIAYoAgghCAsgBiAANg\ 266 | IIIAggADYCDCAAIAY2AgwgACAINgIIDAELIAcgAiADaiIAQQNyNgIEIAcgAGoiACAAKAIEQQFyNgIE\ 267 | DAELQQAgAzYC/I5AQQAgAjYC9I5ACyAHQQhqIQIMBgsCQCAAIAdyDQBBACEHQQIgBXQiAEEAIABrci\ 268 | AEcSIARQ0DIABoQQJ0QdSLwABqKAIAIQALIABFDQELA0AgACAHIAAoAgRBeHEiBiADayIJIAJJIgUb\ 269 | IQQgBiADSSEIIAkgAiAFGyEJAkAgACgCECIGDQAgAEEUaigCACEGCyAHIAQgCBshByACIAkgCBshAi\ 270 | AGIQAgBg0ACwsgB0UNAAJAQQAoAvSOQCIAIANJDQAgAiAAIANrTw0BCyAHKAIYIQUCQAJAAkAgBygC\ 271 | DCIAIAdHDQAgB0EUQRAgB0EUaiIAKAIAIggbaigCACIGDQFBACEADAILIAcoAggiBiAANgIMIAAgBj\ 272 | YCCAwBCyAAIAdBEGogCBshCANAIAghCSAGIgBBFGoiBiAAQRBqIAYoAgAiBhshCCAAQRRBECAGG2oo\ 273 | AgAiBg0ACyAJQQA2AgALIAVFDQICQCAHKAIcQQJ0QdSLwABqIgYoAgAgB0YNACAFQRBBFCAFKAIQIA\ 274 | dGG2ogADYCACAARQ0DDAILIAYgADYCACAADQFBAEEAKALwjkBBfiAHKAIcd3E2AvCOQAwCCwJAAkAC\ 275 | QAJAAkACQEEAKAL0jkAiACADTw0AAkBBACgC+I5AIgAgA0sNACABQQRqQZiPwAAgA0GvgARqQYCAfH\ 276 | EQKwJAIAEoAgQiBw0AQQAhAgwKCyABKAIMIQVBAEEAKAKEj0AgASgCCCIJaiIANgKEj0BBAEEAKAKI\ 277 | j0AiAiAAIAIgAEsbNgKIj0ACQAJAAkBBACgCgI9AIgJFDQBB1IzAACEAA0AgByAAKAIAIgYgACgCBC\ 278 | IIakYNAiAAKAIIIgANAAwDCwsCQAJAQQAoApCPQCIARQ0AIAcgAE8NAQtBACAHNgKQj0ALQQBB/x82\ 279 | ApSPQEEAIAU2AuCMQEEAIAk2AtiMQEEAIAc2AtSMQEEAQeSMwAA2AvCMQEEAQeyMwAA2AviMQEEAQe\ 280 | SMwAA2AuyMQEEAQfSMwAA2AoCNQEEAQeyMwAA2AvSMQEEAQfyMwAA2AoiNQEEAQfSMwAA2AvyMQEEA\ 281 | QYSNwAA2ApCNQEEAQfyMwAA2AoSNQEEAQYyNwAA2ApiNQEEAQYSNwAA2AoyNQEEAQZSNwAA2AqCNQE\ 282 | EAQYyNwAA2ApSNQEEAQZyNwAA2AqiNQEEAQZSNwAA2ApyNQEEAQaSNwAA2ArCNQEEAQZyNwAA2AqSN\ 283 | QEEAQaSNwAA2AqyNQEEAQayNwAA2AriNQEEAQayNwAA2ArSNQEEAQbSNwAA2AsCNQEEAQbSNwAA2Ar\ 284 | yNQEEAQbyNwAA2AsiNQEEAQbyNwAA2AsSNQEEAQcSNwAA2AtCNQEEAQcSNwAA2AsyNQEEAQcyNwAA2\ 285 | AtiNQEEAQcyNwAA2AtSNQEEAQdSNwAA2AuCNQEEAQdSNwAA2AtyNQEEAQdyNwAA2AuiNQEEAQdyNwA\ 286 | A2AuSNQEEAQeSNwAA2AvCNQEEAQeyNwAA2AviNQEEAQeSNwAA2AuyNQEEAQfSNwAA2AoCOQEEAQeyN\ 287 | wAA2AvSNQEEAQfyNwAA2AoiOQEEAQfSNwAA2AvyNQEEAQYSOwAA2ApCOQEEAQfyNwAA2AoSOQEEAQY\ 288 | yOwAA2ApiOQEEAQYSOwAA2AoyOQEEAQZSOwAA2AqCOQEEAQYyOwAA2ApSOQEEAQZyOwAA2AqiOQEEA\ 289 | QZSOwAA2ApyOQEEAQaSOwAA2ArCOQEEAQZyOwAA2AqSOQEEAQayOwAA2AriOQEEAQaSOwAA2AqyOQE\ 290 | EAQbSOwAA2AsCOQEEAQayOwAA2ArSOQEEAQbyOwAA2AsiOQEEAQbSOwAA2AryOQEEAQcSOwAA2AtCO\ 291 | QEEAQbyOwAA2AsSOQEEAQcyOwAA2AtiOQEEAQcSOwAA2AsyOQEEAQdSOwAA2AuCOQEEAQcyOwAA2At\ 292 | SOQEEAQdyOwAA2AuiOQEEAQdSOwAA2AtyOQEEAIAdBD2pBeHEiAEF4aiICNgKAj0BBAEHcjsAANgLk\ 293 | jkBBACAHIABrIAlBWGoiAGpBCGoiBjYC+I5AIAIgBkEBcjYCBCAHIABqQSg2AgRBAEGAgIABNgKMj0\ 294 | AMCAsgAiAHTw0AIAYgAksNACAAKAIMIgZBAXENACAGQQF2IAVGDQMLQQBBACgCkI9AIgAgByAHIABL\ 295 | GzYCkI9AIAcgCWohBkHUjMAAIQACQAJAAkADQCAAKAIAIAZGDQEgACgCCCIADQAMAgsLIAAoAgwiCE\ 296 | EBcQ0AIAhBAXYgBUYNAQtB1IzAACEAAkADQAJAIAAoAgAiBiACSw0AIAYgACgCBGoiBiACSw0CCyAA\ 297 | KAIIIQAMAAsLQQAgB0EPakF4cSIAQXhqIgg2AoCPQEEAIAcgAGsgCUFYaiIAakEIaiIENgL4jkAgCC\ 298 | AEQQFyNgIEIAcgAGpBKDYCBEEAQYCAgAE2AoyPQCACIAZBYGpBeHFBeGoiACAAIAJBEGpJGyIIQRs2\ 299 | AgRBACkC1IxAIQogCEEQakEAKQLcjEA3AgAgCCAKNwIIQQAgBTYC4IxAQQAgCTYC2IxAQQAgBzYC1I\ 300 | xAQQAgCEEIajYC3IxAIAhBHGohAANAIABBBzYCACAAQQRqIgAgBkkNAAsgCCACRg0HIAggCCgCBEF+\ 301 | cTYCBCACIAggAmsiAEEBcjYCBCAIIAA2AgACQCAAQYACSQ0AIAIgABATDAgLIABBeHFB5IzAAGohBg\ 302 | JAAkBBACgC7I5AIgdBASAAQQN2dCIAcQ0AQQAgByAAcjYC7I5AIAYhAAwBCyAGKAIIIQALIAYgAjYC\ 303 | CCAAIAI2AgwgAiAGNgIMIAIgADYCCAwHCyAAIAc2AgAgACAAKAIEIAlqNgIEIAdBD2pBeHFBeGoiBy\ 304 | ADQQNyNgIEIAZBD2pBeHFBeGoiAiAHIANqIgBrIQMgAkEAKAKAj0BGDQMgAkEAKAL8jkBGDQQCQCAC\ 305 | KAIEIgZBA3FBAUcNACACIAZBeHEiBhAPIAYgA2ohAyACIAZqIgIoAgQhBgsgAiAGQX5xNgIEIAAgA0\ 306 | EBcjYCBCAAIANqIAM2AgACQCADQYACSQ0AIAAgAxATDAYLIANBeHFB5IzAAGohAgJAAkBBACgC7I5A\ 307 | IgZBASADQQN2dCIDcQ0AQQAgBiADcjYC7I5AIAIhAwwBCyACKAIIIQMLIAIgADYCCCADIAA2AgwgAC\ 308 | ACNgIMIAAgAzYCCAwFC0EAIAAgA2siAjYC+I5AQQBBACgCgI9AIgAgA2oiBjYCgI9AIAYgAkEBcjYC\ 309 | BCAAIANBA3I2AgQgAEEIaiECDAgLQQAoAvyOQCECAkACQCAAIANrIgZBD0sNAEEAQQA2AvyOQEEAQQ\ 310 | A2AvSOQCACIABBA3I2AgQgAiAAaiIAIAAoAgRBAXI2AgQMAQtBACAGNgL0jkBBACACIANqIgc2AvyO\ 311 | QCAHIAZBAXI2AgQgAiAAaiAGNgIAIAIgA0EDcjYCBAsgAkEIaiECDAcLIAAgCCAJajYCBEEAQQAoAo\ 312 | CPQCIAQQ9qQXhxIgJBeGoiBjYCgI9AQQAgACACa0EAKAL4jkAgCWoiAmpBCGoiBzYC+I5AIAYgB0EB\ 313 | cjYCBCAAIAJqQSg2AgRBAEGAgIABNgKMj0AMAwtBACAANgKAj0BBAEEAKAL4jkAgA2oiAzYC+I5AIA\ 314 | AgA0EBcjYCBAwBC0EAIAA2AvyOQEEAQQAoAvSOQCADaiIDNgL0jkAgACADQQFyNgIEIAAgA2ogAzYC\ 315 | AAsgB0EIaiECDAMLQQAhAkEAKAL4jkAiACADTQ0CQQAgACADayICNgL4jkBBAEEAKAKAj0AiACADai\ 316 | IGNgKAj0AgBiACQQFyNgIEIAAgA0EDcjYCBCAAQQhqIQIMAgsgACAFNgIYAkAgBygCECIGRQ0AIAAg\ 317 | BjYCECAGIAA2AhgLIAdBFGooAgAiBkUNACAAQRRqIAY2AgAgBiAANgIYCwJAAkAgAkEQSQ0AIAcgA0\ 318 | EDcjYCBCAHIANqIgAgAkEBcjYCBCAAIAJqIAI2AgACQCACQYACSQ0AIAAgAhATDAILIAJBeHFB5IzA\ 319 | AGohAwJAAkBBACgC7I5AIgZBASACQQN2dCICcQ0AQQAgBiACcjYC7I5AIAMhAgwBCyADKAIIIQILIA\ 320 | MgADYCCCACIAA2AgwgACADNgIMIAAgAjYCCAwBCyAHIAIgA2oiAEEDcjYCBCAHIABqIgAgACgCBEEB\ 321 | cjYCBAsgB0EIaiECCyABQRBqJAAgAgvCHQMafwd+AXsjAEGgBGsiByQAIAdBwAJqIAAgARAGIAcgB/\ 322 | 0ABMAC/Qw2NjY2NjY2NjY2NjY2NjY2Iij9Uf0LBMACIAcgB/0ABNACICj9Uf0LBNACIAcgB/0ABOAC\ 323 | ICj9Uf0LBOACIAcgB/0ABPACICj9Uf0LBPACIAdB4ANqQRBqIghBAP0AA6iDQP0LAwAgB0EA/QADmI\ 324 | NA/QsD4AMgB0IBNwOABCAHQeADaiAHQcACakEBEAAgByAH/QAEwAL9DGpqampqampqampqampqamoi\ 325 | KP1R/QsEwAIgByAH/QAE0AIgKP1R/QsE0AIgByAH/QAE4AIgKP1R/QsE4AIgByAH/QAE8AIgKP1R/Q\ 326 | sE8AIgB0GoAWpBEGoiCUEA/QADqINA/QsDACAHQQD9AAOYg0D9CwOoASAHQgE3A8gBIAdBqAFqIAdB\ 327 | wAJqQQEQACAHQcAAakEQaiIKIAn9AAMA/QsDACAHQeAAakEQaiILIAj9AAMA/QsDACAHQRBqIgz9DA\ 328 | AAAAAAAAAAAAAAAAAAAAAiKP0LAwAgB0EgaiINICj9CwMAIAdBMGoiDiAo/QsDACAHIAf9AAOoAf0L\ 329 | A0AgByAH/QAD4AP9CwNgIAcgKP0LAwACQCAGRQ0AIAcpA8gBISEgBykDgAQiIkIJhiIjQoAChCIkQo\ 330 | D+A4NCKIYgJEKAgPwHg0IYhiAkQoCAgPgPg0IIhoSEICJCAYZCgICA+A+DICJCD4hCgID8B4OEICJC\ 331 | H4hCgP4DgyAjQjiIhISEISUgA0E/cSEPIAIgA0FAcWohECAiIANBBnYiEa18ISYgB0GoAWpBKGohEi\ 332 | AHQcACakEoaiETIAdBwAJqQdAAaiEUIAdBqAFqQdAAaiEVIANBwABJIRYgB0GxA2oiF0EPaiEYIARB\ 333 | AkkhGUEAIRoDQCAFQQAgBkEgIAZBIEkbIhsQSyEcIBJBEGogCv0AAwD9CwMAIBIgB/0AA0D9CwMAIA\ 334 | kgC/0AAwD9CwMAIBVBMGogDv0AAwD9CwMAIBVBIGogDf0AAwD9CwMAIBVBEGogDP0AAwD9CwMAIBUg\ 335 | B/0AAwD9CwMAIAcgB/0AA2D9CwOoASAHICE3A/ABIAcgIjcDyAEgB0EAOgC4AgJAAkAgFg0AIAcgJj\ 336 | cDyAEgB0GoAWogAiAREAAgFSAQIA8QShogDyEFDAELIBUgAiADEEoaIAMhBQsgByAFOgC4AiAHIBpB\ 337 | AWoiGkEYdCAaQYD+A3FBCHRyIBpBCHZBgP4DcSAaQRh2cnIiATYCwAICQAJAIAVB/wFxIgVBPEkNAA\ 338 | JAAkAgBQ0AIAdBwAJqIQFBBCEFDAELIBUgBWogB0HAAmpBwAAgBWsiARBKGiAHIAcpA8gBQgF8NwPI\ 339 | ASAHQagBaiAVQQEQACAFQURqIQUgB0HAAmogAWohAQsgFSABIAVBQHFqIAUQShoMAQsgFSAFaiABNg\ 340 | AAIAVBBGohBQsgByAFOgC4AiAHQcACaiAHQagBakGYARBKGiAUIActANADIgVqIgFBgAE6AAAgBykD\ 341 | 4AIiJEIBhkKAgID4D4MgJEIPiEKAgPwHg4QgJEIfiEKA/gODICRCCYYiJEI4iISEISMgBa0iJ0I7hi\ 342 | AkICdCA4aEIiRCgP4Dg0IohoQgJEKAgPwHg0IYhiAkQoCAgPgPg0IIhoSEISQCQCAFQT9zIgBFDQAg\ 343 | AUEBakEAIAAQSxoLICQgI4QhJAJAAkAgBUE4c0EHSw0AIAdBwAJqIBRBARAAIAdB4ANqQTBqQgA3Aw\ 344 | AgB0HgA2pBIGogKP0LAwAgCCAo/QsDACAHICj9CwPgAyAHICQ3A5gEIAdBwAJqIAdB4ANqQQEQAAwB\ 345 | CyAHICQ3A8gDIAdBwAJqIBRBARAACyAHQSA6ANADIAcgBygC3AIiBUEYdCAFQYD+A3FBCHRyIAVBCH\ 346 | ZBgP4DcSAFQRh2cnI2AqwDIAcgBygC2AIiBUEYdCAFQYD+A3FBCHRyIAVBCHZBgP4DcSAFQRh2cnI2\ 347 | AqgDIAcgBygC1AIiBUEYdCAFQYD+A3FBCHRyIAVBCHZBgP4DcSAFQRh2cnI2AqQDIAcgBygC0AIiBU\ 348 | EYdCAFQYD+A3FBCHRyIAVBCHZBgP4DcSAFQRh2cnI2AqADIAcgBygCzAIiBUEYdCAFQYD+A3FBCHRy\ 349 | IAVBCHZBgP4DcSAFQRh2cnI2ApwDIAcgBygCyAIiBUEYdCAFQYD+A3FBCHRyIAVBCHZBgP4DcSAFQR\ 350 | h2cnI2ApgDIAcgBygCxAIiBUEYdCAFQYD+A3FBCHRyIAVBCHZBgP4DcSAFQRh2cnI2ApQDIAcgBygC\ 351 | wAIiBUEYdCAFQYD+A3FBCHRyIAVBCHZBgP4DcSAFQRh2cnI2ApADIAcpA4gDISQgGEIANwAAIBcgKP\ 352 | 0LAAAgB0GAAToAsAMgByAkQgmGIidCgAKEIiNCgP4Dg0IohiAjQoCA/AeDQhiGICNCgICA+A+DQgiG\ 353 | hIQgJEIBhkKAgID4D4MgJEIPiEKAgPwHg4QgJEIfiEKA/gODICdCOIiEhIQ3A8gDIBMgFEEBEAAgBy\ 354 | AHKAKEAyIFQRh0IAVBgP4DcUEIdHIgBUEIdkGA/gNxIAVBGHZycjYC/AMgByAHKAKAAyIFQRh0IAVB\ 355 | gP4DcUEIdHIgBUEIdkGA/gNxIAVBGHZycjYC+AMgByAHKAL8AiIFQRh0IAVBgP4DcUEIdHIgBUEIdk\ 356 | GA/gNxIAVBGHZycjYC9AMgByAHKAL4AiIFQRh0IAVBgP4DcUEIdHIgBUEIdkGA/gNxIAVBGHZycjYC\ 357 | 8AMgByAHKAL0AiIFQRh0IAVBgP4DcUEIdHIgBUEIdkGA/gNxIAVBGHZycjYC7AMgByAHKALwAiIFQR\ 358 | h0IAVBgP4DcUEIdHIgBUEIdkGA/gNxIAVBGHZycjYC6AMgByAHKALsAiIFQRh0IAVBgP4DcUEIdHIg\ 359 | BUEIdkGA/gNxIAVBGHZycjYC5AMgByAHKALoAiIFQRh0IAVBgP4DcUEIdHIgBUEIdkGA/gNxIAVBGH\ 360 | ZycjYC4ANBACEBAkACQCAbQRBJIh0NACAcIBz9AAAAIAf9AATgA/1R/QsAAAJAIBtBMHEiAUEQRg0A\ 361 | IBwgHP0AABAgB/0ABPAD/VH9CwAQCyAbIAFGDQELIBsgAWshACAcIAFqIQUgB0HgA2ogAWohAQNAIA\ 362 | UgBS0AACABLQAAczoAACABQQFqIQEgBUEBaiEFIABBf2oiAA0ACwsgBiAbayEGIAdBgAFqQRBqIh4g\ 363 | CP0ABAD9CwQAIAcgB/0ABOAD/QsEgAECQCAZDQAgG0EwcSEfQQEhIANAIBMgB/0AA0D9CwMAIBNBEG\ 364 | ogCv0AAwD9CwMAIAdBwAJqQRBqIgEgC/0AAwD9CwMAIAkgDP0AAwD9CwMAIAdBqAFqQSBqIA39AAMA\ 365 | /QsDACAHQagBakEwaiAO/QADAP0LAwAgByAH/QADAP0LA6gBIAcgB/0AA2D9CwPAAiAJIB79AAQA/Q\ 366 | sDACAHIAf9AASAAf0LA6gBIAcgITcDiAMgByAiNwPgAiAUQRBqIAn9AAMA/QsDACAUIAf9AAOoAf0L\ 367 | AwAgB0EgOgDQAyAHQYABOgCwAyAYQgA3AAAgFyAo/QsAACAHICU3A8gDIAdBwAJqIBRBARAAIAdBID\ 368 | oA0AMgB0GAAToAsAMgByAHKALcAiIFQRh0IAVBgP4DcUEIdHIgBUEIdkGA/gNxIAVBGHZycjYCrAMg\ 369 | ByAHQcACakEYaigCACIFQRh0IAVBgP4DcUEIdHIgBUEIdkGA/gNxIAVBGHZycjYCqAMgByAHKALUAi\ 370 | IFQRh0IAVBgP4DcUEIdHIgBUEIdkGA/gNxIAVBGHZycjYCpAMgByABKAIAIgVBGHQgBUGA/gNxQQh0\ 371 | ciAFQQh2QYD+A3EgBUEYdnJyNgKgAyAHIAcoAswCIgVBGHQgBUGA/gNxQQh0ciAFQQh2QYD+A3EgBU\ 372 | EYdnJyNgKcAyAHIAdBwAJqQQhqKAIAIgVBGHQgBUGA/gNxQQh0ciAFQQh2QYD+A3EgBUEYdnJyNgKY\ 373 | AyAHIAcoAsQCIgVBGHQgBUGA/gNxQQh0ciAFQQh2QYD+A3EgBUEYdnJyNgKUAyAHIAcoAsACIgVBGH\ 374 | QgBUGA/gNxQQh0ciAFQQh2QYD+A3EgBUEYdnJyNgKQAyAHKQOIAyEkIBhCADcAACAXICj9CwAAIAcg\ 375 | JEIJhiInQoAChCIjQoD+A4NCKIYgI0KAgPwHg0IYhiAjQoCAgPgPg0IIhoSEICRCAYZCgICA+A+DIC\ 376 | RCD4hCgID8B4OEICRCH4hCgP4DgyAnQjiIhISENwPIAyATIBRBARAAIAdBgAFqQRhqIAcoAoADIgVB\ 377 | GHQgBUGA/gNxQQh0ciAFQQh2QYD+A3EgBUEYdnJyNgIAIB4gBygC+AIiBUEYdCAFQYD+A3FBCHRyIA\ 378 | VBCHZBgP4DcSAFQRh2cnI2AgAgByAHKAKEAyIFQRh0IAVBgP4DcUEIdHIgBUEIdkGA/gNxIAVBGHZy\ 379 | cjYCnAEgByAHKAL8AiIFQRh0IAVBgP4DcUEIdHIgBUEIdkGA/gNxIAVBGHZycjYClAEgByAHKAL0Ai\ 380 | IFQRh0IAVBgP4DcUEIdHIgBUEIdkGA/gNxIAVBGHZycjYCjAEgByAHKALwAiIFQRh0IAVBgP4DcUEI\ 381 | dHIgBUEIdkGA/gNxIAVBGHZycjYCiAEgByAHKALsAiIFQRh0IAVBgP4DcUEIdHIgBUEIdkGA/gNxIA\ 382 | VBGHZycjYChAEgByAHKALoAiIFQRh0IAVBgP4DcUEIdHIgBUEIdkGA/gNxIAVBGHZycjYCgAFBACEB\ 383 | AkACQCAdDQAgHCAc/QAAACAH/QAEgAH9Uf0LAAACQCAfQRBGDQAgHCAc/QAAECAH/QAEkAH9Uf0LAB\ 384 | ALIB8hASAbIB9GDQELIBsgAWshACAcIAFqIQUgB0GAAWogAWohAQNAIAUgBS0AACABLQAAczoAACAB\ 385 | QQFqIQEgBUEBaiEFIABBf2oiAA0ACwsgIEEBaiIgIARHDQALCyAcIBtqIQUgBg0ACwsgB0GgBGokAA\ 386 | vrCQMhfwF+A3sjAEGAAWsiBCQAIAFBQGohBQJAIAFBwABJDQAgBEEwaiIGIAAgBWoiBUEwav0AAAD9\ 387 | CwQAIARBIGoiByAFQSBq/QAAAP0LBAAgBEEQaiIIIAVBEGr9AAAA/QsEACAEIAX9AAAA/QsEACAEQc\ 388 | AAakEwav0MAAAAAAAAAAAAAAAAAAAAACIm/QsEACAEQcAAakEgaiAm/QsEACAEQcAAakEQaiAm/QsE\ 389 | ACAEICb9CwRAIAFBAXYhCUEAIQoCQAJAA0BBACELAkACQCABQcAAIAFBwABJGyIMQRBJDQAgBCAA/Q\ 390 | AAACAE/QAEAP1R/QsEQAJAIAxB8ABxIgtBEEYNACAEIAD9AAAQIAT9AAQQ/VH9CwRQIAtBIEYNACAE\ 391 | IAD9AAAgIAT9AAQg/VH9CwRgIAtBMEYNACAEIAD9AAAwIAT9AAQw/VH9CwRwCyAMIAtGDQELIAAgC2\ 392 | ohBSAMIAtrIQ0gBCALaiEOIARBwABqIAtqIQsDQCALIAUtAAAgDi0AAHM6AAAgBUEBaiEFIA5BAWoh\ 393 | DiALQQFqIQsgDUF/aiINDQALCyAKQQFqIQ8gASAMayEBIAAgDGohACAE/QADaCIm/RsDIRAgJv0bAi\ 394 | EFICb9GwEhDiAm/RsAIQsgBP0ABFAiJ/0bAyERICf9GwIhDSAn/RsBIQwgJ/0bACESIAT9AARAIij9\ 395 | GwMhEyAo/RsCIRQgKP0bASEVICj9GwAhFkEEIRcgBCkDYCIlpyIYIRkgJUIgiKciGiEbIAQoAngiHC\ 396 | EdIAQoAnwiHiEfA0AgDiAfakEHdyATcyITIB9qQQl3IBFzIiAgE2pBDXcgDnMiISAgakESdyAfcyIf\ 397 | IA0gC2pBB3cgHXMiDmpBB3cgBSAWakEHdyAScyISIBZqQQl3IBlzIiIgEmpBDXcgBXMiI3MiBSAfak\ 398 | EJdyAVIAxqQQd3IBtzIhEgDGpBCXcgEHMiJHMiECAFakENdyAOcyIdIBBqQRJ3IB9zIR8gDiAOIAtq\ 399 | QQl3IBRzIhRqQQ13IA1zIg0gFGpBEncgC3MiCyARakEHdyAhcyIOIAtqQQl3ICJzIhkgDmpBDXcgEX\ 400 | MiGyAZakESdyALcyELICQgJCARakENdyAVcyIVakESdyAMcyIMIBJqQQd3IA1zIg0gDGpBCXcgIHMi\ 401 | ESANakENdyAScyISIBFqQRJ3IAxzIQwgEyAjICJqQRJ3IBZzIhZqQQd3IBVzIhUgFmpBCXcgFHMiFC\ 402 | AVakENdyATcyITIBRqQRJ3IBZzIRYgF0F/aiIXDQALIAQgHiAfajYCPCAEIBwgHWo2AjggBCAbIBpq\ 403 | rUIghiAZIBhqrYQ3AyAgBCAmIAv9ESAO/RwBIAX9HAIgEP0cA/2uAf0LAyggBCAnIBL9ESAM/RwBIA\ 404 | 39HAIgEf0cA/2uAf0LBBAgBCAoIBb9ESAV/RwBIBT9HAIgE/0cA/2uAf0LBABBACAKQQFxayAJcSAK\ 405 | QQV0QUBxaiIFQcAAaiEOIAVBv39LDQEgDiADSw0CIAIgBWoiBSAE/QAEAP0LAAAgBUEwaiAG/QAEAP\ 406 | 0LAAAgBUEgaiAH/QAEAP0LAAAgBUEQaiAI/QAEAP0LAAAgDyEKIAENAAsgBEGAAWokAA8LIAUgDkGo\ 407 | hsAAECIACyAOIANBqIbAABAhAAsgBSABQbiGwAAQIAALtgcBCH8CQCAAKAIAIgMgACgCCCIEckUNAA\ 408 | JAIARFDQAgASACaiEFIABBDGooAgBBAWohBkEAIQcgASEIAkADQCAIIQQgBkF/aiIGRQ0BIAQgBUYN\ 409 | AgJAAkAgBCwAACIJQX9MDQAgBEEBaiEIIAlB/wFxIQkMAQsgBC0AAUE/cSEKIAlBH3EhCAJAIAlBX0\ 410 | sNACAIQQZ0IApyIQkgBEECaiEIDAELIApBBnQgBC0AAkE/cXIhCgJAIAlBcE8NACAKIAhBDHRyIQkg\ 411 | BEEDaiEIDAELIApBBnQgBC0AA0E/cXIgCEESdEGAgPAAcXIiCUGAgMQARg0DIARBBGohCAsgByAEay\ 412 | AIaiEHIAlBgIDEAEcNAAwCCwsgBCAFRg0AAkAgBCwAACIIQX9KDQAgCEFgSQ0AIAhBcEkNACAELQAC\ 413 | QT9xQQZ0IAQtAAFBP3FBDHRyIAQtAANBP3FyIAhB/wFxQRJ0QYCA8ABxckGAgMQARg0BCwJAAkAgB0\ 414 | UNAAJAIAcgAkkNAEEAIQQgByACRg0BDAILQQAhBCABIAdqLAAAQUBIDQELIAEhBAsgByACIAQbIQIg\ 415 | BCABIAQbIQELAkAgAw0AIAAoAhQgASACIABBGGooAgAoAgwRBgAPCyAAKAIEIQUCQAJAIAJBEEkNAC\ 416 | ABIAIQBSEEDAELAkAgAg0AQQAhBAwBCyACQQNxIQYCQAJAIAJBBE8NAEEAIQRBACEJDAELIAJBfHEh\ 417 | B0EAIQRBACEJA0AgBCABIAlqIggsAABBv39KaiAIQQFqLAAAQb9/SmogCEECaiwAAEG/f0pqIAhBA2\ 418 | osAABBv39KaiEEIAcgCUEEaiIJRw0ACwsgBkUNACABIAlqIQgDQCAEIAgsAABBv39KaiEEIAhBAWoh\ 419 | CCAGQX9qIgYNAAsLAkACQCAFIARNDQAgBSAEayEHQQAhBAJAAkACQCAALQAgDgQCAAECAgsgByEEQQ\ 420 | AhBwwBCyAHQQF2IQQgB0EBakEBdiEHCyAEQQFqIQQgAEEYaigCACEIIAAoAhAhBiAAKAIUIQkDQCAE\ 421 | QX9qIgRFDQIgCSAGIAgoAhARBABFDQALQQEPCyAAKAIUIAEgAiAAQRhqKAIAKAIMEQYADwtBASEEAk\ 422 | AgCSABIAIgCCgCDBEGAA0AQQAhBAJAA0ACQCAHIARHDQAgByEEDAILIARBAWohBCAJIAYgCCgCEBEE\ 423 | AEUNAAsgBEF/aiEECyAEIAdJIQQLIAQPCyAAKAIUIAEgAiAAQRhqKAIAKAIMEQYAC4AHAQl/AkACQC\ 424 | ABIABBA2pBfHEiAiAAayIDSQ0AIAEgA2siBEEESQ0AIARBA3EhBUEAIQZBACEBAkAgAiAARiIHDQBB\ 425 | ACEBAkACQCACIABBf3NqQQNPDQBBACEIDAELQQAhCANAIAEgACAIaiIJLAAAQb9/SmogCUEBaiwAAE\ 426 | G/f0pqIAlBAmosAABBv39KaiAJQQNqLAAAQb9/SmohASAIQQRqIggNAAsLIAcNACAAIAJrIQIgACAI\ 427 | aiEJA0AgASAJLAAAQb9/SmohASAJQQFqIQkgAkEBaiICDQALCyAAIANqIQgCQCAFRQ0AIAggBEF8cW\ 428 | oiCSwAAEG/f0ohBiAFQQFGDQAgBiAJLAABQb9/SmohBiAFQQJGDQAgBiAJLAACQb9/SmohBgsgBEEC\ 429 | diEDIAYgAWohAgNAIAghBiADRQ0CIANBwAEgA0HAAUkbIgRBA3EhBSAEQQJ0IQcCQAJAIARB/AFxIg\ 430 | oNAEEAIQkMAQsgBiAKQQJ0aiEAQQAhCSAGIQEDQCABQQxqKAIAIghBf3NBB3YgCEEGdnJBgYKECHEg\ 431 | AUEIaigCACIIQX9zQQd2IAhBBnZyQYGChAhxIAFBBGooAgAiCEF/c0EHdiAIQQZ2ckGBgoQIcSABKA\ 432 | IAIghBf3NBB3YgCEEGdnJBgYKECHEgCWpqamohCSABQRBqIgEgAEcNAAsLIAMgBGshAyAGIAdqIQgg\ 433 | CUEIdkH/gfwHcSAJQf+B/AdxakGBgARsQRB2IAJqIQIgBUUNAAsgBiAKQQJ0aiIJKAIAIgFBf3NBB3\ 434 | YgAUEGdnJBgYKECHEhAQJAIAVBAUYNACAJKAIEIghBf3NBB3YgCEEGdnJBgYKECHEgAWohASAFQQJG\ 435 | DQAgCSgCCCIJQX9zQQd2IAlBBnZyQYGChAhxIAFqIQELIAFBCHZB/4EccSABQf+B/AdxakGBgARsQR\ 436 | B2IAJqIQIMAQsCQCABDQBBAA8LIAFBA3EhCAJAAkAgAUEETw0AQQAhAkEAIQkMAQsgAUF8cSEDQQAh\ 437 | AkEAIQkDQCACIAAgCWoiASwAAEG/f0pqIAFBAWosAABBv39KaiABQQJqLAAAQb9/SmogAUEDaiwAAE\ 438 | G/f0pqIQIgAyAJQQRqIglHDQALCyAIRQ0AIAAgCWohAQNAIAIgASwAAEG/f0pqIQIgAUEBaiEBIAhB\ 439 | f2oiCA0ACwsgAgu7BwMDfwN+AXsjAEHgAmsiAyQAIANBMGr9DAAAAAAAAAAAAAAAAAAAAAAiCf0LAw\ 440 | AgA0EgaiAJ/QsDACADQRBqIAn9CwMAIAMgCf0LAwACQAJAIAJBwQBJDQAgA0HAAGpBKGpBAEHBABBL\ 441 | IQQgA0HAAGpBEGpBAP0AA9iEQP0LAwAgAyACQQZ2IgWtNwNgIANBAP0AA8iEQP0LA0AgA0HAAGogAS\ 442 | AFEAAgBCABIAJBQHFqIAJBP3EiAhBKGiADQcAAakHoAGogAjoAACADQbABaiADQcAAakHwABBKGiAD\ 443 | QbABakEoaiIBIANBsAFqQegAai0AACICaiIEQYABOgAAIAMpA9ABIgZCAYZCgICA+A+DIAZCD4hCgI\ 444 | D8B4OEIAZCH4hCgP4DgyAGQgmGIgZCOIiEhCEHIAKtIghCO4YgBiAIQgOGhCIGQoD+A4NCKIaEIAZC\ 445 | gID8B4NCGIYgBkKAgID4D4NCCIaEhCEGAkAgAkE/cyIFRQ0AIARBAWpBACAFEEsaCyAGIAeEIQYCQA\ 446 | JAIAJBOHNBB0sNACADQbABaiABQQEQACADQdACakIANwMAIANBwAJqIAn9CwMAIANBsAJqIAn9CwMA\ 447 | IAMgCf0LA6ACIAMgBjcD2AIgA0GwAWogA0GgAmpBARAADAELIANBkAJqIAY3AwAgA0GwAWogAUEBEA\ 448 | ALIAMgAygCzAEiAkEYdCACQYD+A3FBCHRyIAJBCHZBgP4DcSACQRh2cnI2AhwgAyADKALIASICQRh0\ 449 | IAJBgP4DcUEIdHIgAkEIdkGA/gNxIAJBGHZycjYCGCADIAMoAsQBIgJBGHQgAkGA/gNxQQh0ciACQQ\ 450 | h2QYD+A3EgAkEYdnJyNgIUIAMgAygCwAEiAkEYdCACQYD+A3FBCHRyIAJBCHZBgP4DcSACQRh2cnI2\ 451 | AhAgAyADKAK8ASICQRh0IAJBgP4DcUEIdHIgAkEIdkGA/gNxIAJBGHZycjYCDCADIAMoArgBIgJBGH\ 452 | QgAkGA/gNxQQh0ciACQQh2QYD+A3EgAkEYdnJyNgIIIAMgAygCtAEiAkEYdCACQYD+A3FBCHRyIAJB\ 453 | CHZBgP4DcSACQRh2cnI2AgQgAyADKAKwASICQRh0IAJBgP4DcUEIdHIgAkEIdkGA/gNxIAJBGHZycj\ 454 | YCAAwBCyADIAEgAhBKGgsgACAD/QADAP0LAAAgAEEwaiADQTBq/QADAP0LAAAgAEEgaiADQSBq/QAD\ 455 | AP0LAAAgAEEQaiADQRBq/QADAP0LAAAgA0HgAmokAAv9BQEHfwJAAkAgAQ0AIAVBAWohBiAAKAIcIQ\ 456 | dBLSEIDAELQStBgIDEACAAKAIcIgdBAXEiARshCCABIAVqIQYLAkACQCAHQQRxDQBBACECDAELAkAC\ 457 | QCADQRBJDQAgAiADEAUhAQwBCwJAIAMNAEEAIQEMAQsgA0EDcSEJAkACQCADQQRPDQBBACEBQQAhCg\ 458 | wBCyADQXxxIQtBACEBQQAhCgNAIAEgAiAKaiIMLAAAQb9/SmogDEEBaiwAAEG/f0pqIAxBAmosAABB\ 459 | v39KaiAMQQNqLAAAQb9/SmohASALIApBBGoiCkcNAAsLIAlFDQAgAiAKaiEMA0AgASAMLAAAQb9/Sm\ 460 | ohASAMQQFqIQwgCUF/aiIJDQALCyABIAZqIQYLAkACQCAAKAIADQBBASEBIAAoAhQiDCAAKAIYIgog\ 461 | CCACIAMQLA0BIAwgBCAFIAooAgwRBgAPCwJAIAAoAgQiCSAGSw0AQQEhASAAKAIUIgwgACgCGCIKIA\ 462 | ggAiADECwNASAMIAQgBSAKKAIMEQYADwsCQCAHQQhxRQ0AIAAoAhAhCyAAQTA2AhAgAC0AICEHQQEh\ 463 | ASAAQQE6ACAgACgCFCIMIAAoAhgiCiAIIAIgAxAsDQEgCSAGa0EBaiEBAkADQCABQX9qIgFFDQEgDE\ 464 | EwIAooAhARBABFDQALQQEPC0EBIQEgDCAEIAUgCigCDBEGAA0BIAAgBzoAICAAIAs2AhBBACEBDAEL\ 465 | IAkgBmshBgJAAkACQCAALQAgIgEOBAIAAQACCyAGIQFBACEGDAELIAZBAXYhASAGQQFqQQF2IQYLIA\ 466 | FBAWohASAAQRhqKAIAIQwgACgCECEJIAAoAhQhCgJAA0AgAUF/aiIBRQ0BIAogCSAMKAIQEQQARQ0A\ 467 | C0EBDwtBASEBIAogDCAIIAIgAxAsDQAgCiAEIAUgDCgCDBEGAA0AQQAhAQNAAkAgBiABRw0AIAYgBk\ 468 | kPCyABQQFqIQEgCiAJIAwoAhARBABFDQALIAFBf2ogBkkPCyABC8gFAQV/AkACQAJAAkAgAkEJSQ0A\ 469 | IAIgAxANIgINAUEADwtBACECIANBzP97Sw0BQRAgA0ELakF4cSADQQtJGyEBIABBfGoiBCgCACIFQX\ 470 | hxIQYCQAJAIAVBA3ENACABQYACSQ0BIAYgAUEEckkNASAGIAFrQYGACE8NASAADwsgAEF4aiIHIAZq\ 471 | IQgCQAJAAkACQAJAIAYgAU8NACAIQQAoAoCPQEYNBCAIQQAoAvyOQEYNAiAIKAIEIgVBAnENBSAFQX\ 472 | hxIgUgBmoiBiABSQ0FIAggBRAPIAYgAWsiA0EQSQ0BIAQgASAEKAIAQQFxckECcjYCACAHIAFqIgIg\ 473 | A0EDcjYCBCAHIAZqIgEgASgCBEEBcjYCBCACIAMQDCAADwsgBiABayIDQQ9LDQIgAA8LIAQgBiAEKA\ 474 | IAQQFxckECcjYCACAHIAZqIgMgAygCBEEBcjYCBCAADwtBACgC9I5AIAZqIgYgAUkNAgJAAkAgBiAB\ 475 | ayIDQQ9LDQAgBCAFQQFxIAZyQQJyNgIAIAcgBmoiAyADKAIEQQFyNgIEQQAhA0EAIQIMAQsgBCABIA\ 476 | VBAXFyQQJyNgIAIAcgAWoiAiADQQFyNgIEIAcgBmoiASADNgIAIAEgASgCBEF+cTYCBAtBACACNgL8\ 477 | jkBBACADNgL0jkAgAA8LIAQgASAFQQFxckECcjYCACAHIAFqIgIgA0EDcjYCBCAIIAgoAgRBAXI2Ag\ 478 | QgAiADEAwgAA8LQQAoAviOQCAGaiIGIAFLDQMLIAMQASIBRQ0BIAEgAEF8QXggBCgCACICQQNxGyAC\ 479 | QXhxaiICIAMgAiADSRsQSiEDIAAQCSADDwsgAiAAIAEgAyABIANJGxBKGiAAEAkLIAIPCyAEIAEgBU\ 480 | EBcXJBAnI2AgAgByABaiIDIAYgAWsiAkEBcjYCBEEAIAI2AviOQEEAIAM2AoCPQCAAC/kFAQV/IABB\ 481 | eGoiASAAQXxqKAIAIgJBeHEiAGohAwJAAkACQAJAIAJBAXENACACQQNxRQ0BIAEoAgAiAiAAaiEAAk\ 482 | AgASACayIBQQAoAvyOQEcNACADKAIEQQNxQQNHDQFBACAANgL0jkAgAyADKAIEQX5xNgIEIAEgAEEB\ 483 | cjYCBCADIAA2AgAPCyABIAIQDwsCQAJAAkAgAygCBCICQQJxDQAgA0EAKAKAj0BGDQIgA0EAKAL8jk\ 484 | BGDQUgAyACQXhxIgIQDyABIAIgAGoiAEEBcjYCBCABIABqIAA2AgAgAUEAKAL8jkBHDQFBACAANgL0\ 485 | jkAPCyADIAJBfnE2AgQgASAAQQFyNgIEIAEgAGogADYCAAsgAEGAAkkNAiABIAAQE0EAIQFBAEEAKA\ 486 | KUj0BBf2oiADYClI9AIAANAQJAQQAoAtyMQCIARQ0AQQAhAQNAIAFBAWohASAAKAIIIgANAAsLQQAg\ 487 | AUH/HyABQf8fSxs2ApSPQA8LQQAgATYCgI9AQQBBACgC+I5AIABqIgA2AviOQCABIABBAXI2AgQCQC\ 488 | ABQQAoAvyOQEcNAEEAQQA2AvSOQEEAQQA2AvyOQAsgAEEAKAKMj0AiBE0NAEEAKAKAj0AiA0UNAEEA\ 489 | IQECQEEAKAL4jkAiBUEpSQ0AQdSMwAAhAANAAkAgACgCACICIANLDQAgAiAAKAIEaiADSw0CCyAAKA\ 490 | IIIgANAAsLAkBBACgC3IxAIgBFDQBBACEBA0AgAUEBaiEBIAAoAggiAA0ACwtBACABQf8fIAFB/x9L\ 491 | GzYClI9AIAUgBE0NAEEAQX82AoyPQAsPCyAAQXhxQeSMwABqIQMCQAJAQQAoAuyOQCICQQEgAEEDdn\ 492 | QiAHENAEEAIAIgAHI2AuyOQCADIQAMAQsgAygCCCEACyADIAE2AgggACABNgIMIAEgAzYCDCABIAA2\ 493 | AggPC0EAIAE2AvyOQEEAQQAoAvSOQCAAaiIANgL0jkAgASAAQQFyNgIEIAEgAGogADYCAAu5BQELfy\ 494 | MAQTBrIgMkACADQSRqIAE2AgAgA0EDOgAsIANBIDYCHEEAIQQgA0EANgIoIAMgADYCICADQQA2AhQg\ 495 | A0EANgIMAkACQAJAAkACQCACKAIQIgUNACACQQxqKAIAIgBFDQEgAigCCCIBIABBA3RqIQYgAEF/ak\ 496 | H/////AXFBAWohBCACKAIAIQBBACEHA0ACQCAAQQRqKAIAIghFDQAgAygCICAAKAIAIAggAygCJCgC\ 497 | DBEGAA0ECyABKAIAIANBDGogAUEEaigCABEEAA0DIAdBAWohByAAQQhqIQAgAUEIaiIBIAZHDQAMAg\ 498 | sLIAJBFGooAgAiAUUNACABQQV0IQkgAUF/akH///8/cUEBaiEEIAIoAgghCiACKAIAIQBBACEHQQAh\ 499 | CwNAAkAgAEEEaigCACIBRQ0AIAMoAiAgACgCACABIAMoAiQoAgwRBgANAwsgAyAFIAdqIgFBEGooAg\ 500 | A2AhwgAyABQRxqLQAAOgAsIAMgAUEYaigCADYCKCABQQxqKAIAIQZBACEMQQAhCAJAAkACQCABQQhq\ 501 | KAIADgMBAAIBCyAGQQN0IQ1BACEIIAogDWoiDSgCBEEURw0BIA0oAgAoAgAhBgtBASEICyADIAY2Ah\ 502 | AgAyAINgIMIAFBBGooAgAhCAJAAkACQCABKAIADgMBAAIBCyAIQQN0IQYgCiAGaiIGKAIEQRRHDQEg\ 503 | BigCACgCACEIC0EBIQwLIAMgCDYCGCADIAw2AhQgCiABQRRqKAIAQQN0aiIBKAIAIANBDGogAUEEai\ 504 | gCABEEAA0CIAtBAWohCyAAQQhqIQAgCSAHQSBqIgdHDQALCyAEIAIoAgRPDQEgAygCICACKAIAIARB\ 505 | A3RqIgEoAgAgASgCBCADKAIkKAIMEQYARQ0BC0EBIQEMAQtBACEBCyADQTBqJAAgAQvbBAEMfyMAQS\ 506 | BrIgckAAJAIAFFDQACQAJAAkACQCADRQ0AIAMhCCACIQkDQCAIIAEgCCABSRshCiAIIAFJDQIgCSAA\ 507 | IAoQSiIJIAogACABEAMgCSAKaiEJIAggCmsiCA0ACwsCQAJAIAZFDQAgAUFAaiIIIAFBRGoiCksNAQ\ 508 | JAAkAgAUE8SQ0AIAZBf2ohCyAAIAhqIQwgBSABIAUgAUkbIg0NAQNAIAwoAAAgC3EiCCABbCIOIAhB\ 509 | AWogAWwiCEsNBiAIIANLDQcgBCAFIAAgARADIAZBf2oiBg0ADAMLCyAKIAFBmIbAABAhAAsgDUFwcS\ 510 | EPQQAhECANQRBJIREDQCAMKAAAIAtxIgggAWwiDiAIQQFqIAFsIghLDQQgCCADSw0FQQAhCQJAAkAg\ 511 | EQ0AIAIgDmohCCAPIRIgACEKIAQhCQNAIAkgCP0AAAAgCv0AAAD9Uf0LAAAgCkEQaiEKIAhBEGohCC\ 512 | AJQRBqIQkgEkFwaiISDQALIA8hCSANIA9GDQELIA0gCWshEiAAIAlqIQggBCAJaiEKIAIgCSAOamoh\ 513 | CQNAIAogCS0AACAILQAAczoAACAJQQFqIQkgCEEBaiEIIApBAWohCiASQX9qIhINAAsLIAQgBSAAIA\ 514 | EQAyAQQQFqIhAgBkcNAAsLIAdBIGokAA8LIAggCkGYhsAAECIACyAKIAFBiIbAABAjAAsgDiAIQfiF\ 515 | wAAQIgALIAggA0H4hcAAECEACyAHQRRqQgA3AgAgB0EBNgIMIAdBhIXAADYCCCAHQeiEwAA2AhAgB0\ 516 | EIakHohcAAEC4AC/ADAQJ/IAAgAWohAgJAAkAgACgCBCIDQQFxDQAgA0EDcUUNASAAKAIAIgMgAWoh\ 517 | AQJAIAAgA2siAEEAKAL8jkBHDQAgAigCBEEDcUEDRw0BQQAgATYC9I5AIAIgAigCBEF+cTYCBCAAIA\ 518 | FBAXI2AgQgAiABNgIADAILIAAgAxAPCwJAAkACQAJAIAIoAgQiA0ECcQ0AIAJBACgCgI9ARg0CIAJB\ 519 | ACgC/I5ARg0DIAIgA0F4cSIDEA8gACADIAFqIgFBAXI2AgQgACABaiABNgIAIABBACgC/I5ARw0BQQ\ 520 | AgATYC9I5ADwsgAiADQX5xNgIEIAAgAUEBcjYCBCAAIAFqIAE2AgALAkAgAUGAAkkNACAAIAEQEw8L\ 521 | IAFBeHFB5IzAAGohAgJAAkBBACgC7I5AIgNBASABQQN2dCIBcQ0AQQAgAyABcjYC7I5AIAIhAQwBCy\ 522 | ACKAIIIQELIAIgADYCCCABIAA2AgwgACACNgIMIAAgATYCCA8LQQAgADYCgI9AQQBBACgC+I5AIAFq\ 523 | IgE2AviOQCAAIAFBAXI2AgQgAEEAKAL8jkBHDQFBAEEANgL0jkBBAEEANgL8jkAPC0EAIAA2AvyOQE\ 524 | EAQQAoAvSOQCABaiIBNgL0jkAgACABQQFyNgIEIAAgAWogATYCAA8LC+8CAQV/QQAhAgJAQc3/eyAA\ 525 | QRAgAEEQSxsiAGsgAU0NACAAQRAgAUELakF4cSABQQtJGyIDakEMahABIgFFDQAgAUF4aiECAkACQC\ 526 | AAQX9qIgQgAXENACACIQAMAQsgAUF8aiIFKAIAIgZBeHEgBCABakEAIABrcUF4aiIBQQAgACABIAJr\ 527 | QRBLG2oiACACayIBayEEAkAgBkEDcUUNACAAIAQgACgCBEEBcXJBAnI2AgQgACAEaiIEIAQoAgRBAX\ 528 | I2AgQgBSABIAUoAgBBAXFyQQJyNgIAIAIgAWoiBCAEKAIEQQFyNgIEIAIgARAMDAELIAIoAgAhAiAA\ 529 | IAQ2AgQgACACIAFqNgIACwJAIAAoAgQiAUEDcUUNACABQXhxIgIgA0EQak0NACAAIAMgAUEBcXJBAn\ 530 | I2AgQgACADaiIBIAIgA2siA0EDcjYCBCAAIAJqIgIgAigCBEEBcjYCBCABIAMQDAsgAEEIaiECCyAC\ 531 | C/oCAQh/IwBBIGsiByQAAkACQAJAAkACQAJAIAZFDQAgBC0ADCEIQQEhCQJAIAQoAgQgBCgCAEEHdC\ 532 | IKbCILRQ0AIAtBf0oiBEUNBCALIAQQOCIJRQ0FCyAAIAEgAiADQQEgCSALEAJBASEMAkAgCiAIdCIC\ 533 | RQ0AIAJBf0oiBEUNBCACIAQQOCIMRQ0GCyAKRQ0CIApBf0oiBEUNAyAKIAQQOCINRQ0BAkAgC0UNAE\ 534 | EBIAh0IQ4gCyEEIAkhCANAIAggBCAKIAQgCkkbIgMgDCACIA0gCiAOEAsgCCADaiEIIAQgA2siBA0A\ 535 | CwsgACABIAkgC0EBIAUgBhACIA0gCkEBED8CQCACRQ0AIAwgAkEBED8LIAtFDQAgCSALQQEQPwsgB0\ 536 | EgaiQAIAZFDwsgBCAKEEkACyAHQRRqQgA3AgAgB0EBNgIMIAdB1IPAADYCCCAHQbiDwAA2AhAgB0EI\ 537 | akG4hMAAEC4ACxAtAAsgBCALEEkACyAEIAIQSQALgwMBBH8gACgCDCECAkACQAJAIAFBgAJJDQAgAC\ 538 | gCGCEDAkACQAJAIAIgAEcNACAAQRRBECAAQRRqIgIoAgAiBBtqKAIAIgENAUEAIQIMAgsgACgCCCIB\ 539 | IAI2AgwgAiABNgIIDAELIAIgAEEQaiAEGyEEA0AgBCEFIAEiAkEUaiIBIAJBEGogASgCACIBGyEEIA\ 540 | JBFEEQIAEbaigCACIBDQALIAVBADYCAAsgA0UNAgJAIAAoAhxBAnRB1IvAAGoiASgCACAARg0AIANB\ 541 | EEEUIAMoAhAgAEYbaiACNgIAIAJFDQMMAgsgASACNgIAIAINAUEAQQAoAvCOQEF+IAAoAhx3cTYC8I\ 542 | 5ADAILAkAgAiAAKAIIIgRGDQAgBCACNgIMIAIgBDYCCA8LQQBBACgC7I5AQX4gAUEDdndxNgLsjkAP\ 543 | CyACIAM2AhgCQCAAKAIQIgFFDQAgAiABNgIQIAEgAjYCGAsgAEEUaigCACIBRQ0AIAJBFGogATYCAC\ 544 | ABIAI2AhgPCwvBAgEIfwJAAkAgAkEQTw0AIAAhAwwBCyAAQQAgAGtBA3EiBGohBQJAIARFDQAgACED\ 545 | IAEhBgNAIAMgBi0AADoAACAGQQFqIQYgA0EBaiIDIAVJDQALCyAFIAIgBGsiB0F8cSIIaiEDAkACQC\ 546 | ABIARqIglBA3FFDQAgCEEBSA0BIAlBA3QiBkEYcSECIAlBfHEiCkEEaiEBQQAgBmtBGHEhBCAKKAIA\ 547 | IQYDQCAFIAYgAnYgASgCACIGIAR0cjYCACABQQRqIQEgBUEEaiIFIANJDQAMAgsLIAhBAUgNACAJIQ\ 548 | EDQCAFIAEoAgA2AgAgAUEEaiEBIAVBBGoiBSADSQ0ACwsgB0EDcSECIAkgCGohAQsCQCACRQ0AIAMg\ 549 | AmohBQNAIAMgAS0AADoAACABQQFqIQEgA0EBaiIDIAVJDQALCyAAC9cCAQJ/IwBBEGsiAiQAAkACQA\ 550 | JAAkAgAUGAAUkNACACQQA2AgwgAUGAEEkNAQJAIAFBgIAETw0AIAIgAUE/cUGAAXI6AA4gAiABQQx2\ 551 | QeABcjoADCACIAFBBnZBP3FBgAFyOgANQQMhAQwDCyACIAFBP3FBgAFyOgAPIAIgAUEGdkE/cUGAAX\ 552 | I6AA4gAiABQQx2QT9xQYABcjoADSACIAFBEnZBB3FB8AFyOgAMQQQhAQwCCwJAIAAoAggiAyAAKAIA\ 553 | Rw0AIAAgAxAXIAAoAgghAwsgACADQQFqNgIIIAAoAgQgA2ogAToAAAwCCyACIAFBP3FBgAFyOgANIA\ 554 | IgAUEGdkHAAXI6AAxBAiEBCwJAIAAoAgAgACgCCCIDayABTw0AIAAgAyABEBYgACgCCCEDCyAAKAIE\ 555 | IANqIAJBDGogARBKGiAAIAMgAWo2AggLIAJBEGokAEEAC9ICAgV/AX4jAEEwayIDJABBJyEEAkACQC\ 556 | AAQpDOAFoNACAAIQgMAQtBJyEEA0AgA0EJaiAEaiIFQXxqIAAgAEKQzgCAIghCkM4Afn2nIgZB//8D\ 557 | cUHkAG4iB0EBdEHgh8AAai8AADsAACAFQX5qIAYgB0HkAGxrQf//A3FBAXRB4IfAAGovAAA7AAAgBE\ 558 | F8aiEEIABC/8HXL1YhBSAIIQAgBQ0ACwsCQCAIpyIFQeMATQ0AIANBCWogBEF+aiIEaiAIpyIFIAVB\ 559 | //8DcUHkAG4iBUHkAGxrQf//A3FBAXRB4IfAAGovAAA7AAALAkACQCAFQQpJDQAgA0EJaiAEQX5qIg\ 560 | RqIAVBAXRB4IfAAGovAAA7AAAMAQsgA0EJaiAEQX9qIgRqIAVBMGo6AAALIAIgAUGQh8AAQQAgA0EJ\ 561 | aiAEakEnIARrEAchBCADQTBqJAAgBAu7AgEEf0EAIQICQCABQYACSQ0AQR8hAiABQf///wdLDQAgAU\ 562 | EGIAFBCHZnIgJrdkEBcSACQQF0a0E+aiECCyAAQgA3AhAgACACNgIcIAJBAnRB1IvAAGohAwJAAkBB\ 563 | ACgC8I5AIgRBASACdCIFcQ0AQQAgBCAFcjYC8I5AIAMgADYCACAAIAM2AhgMAQsCQAJAAkAgAygCAC\ 564 | IEKAIEQXhxIAFHDQAgBCECDAELIAFBAEEZIAJBAXZrIAJBH0YbdCEDA0AgBCADQR12QQRxakEQaiIF\ 565 | KAIAIgJFDQIgA0EBdCEDIAIhBCACKAIEQXhxIAFHDQALCyACKAIIIgMgADYCDCACIAA2AgggAEEANg\ 566 | IYIAAgAjYCDCAAIAM2AggPCyAFIAA2AgAgACAENgIYCyAAIAA2AgwgACAANgIIC4ECAgN/AX4jAEEw\ 567 | ayICJAACQCABKAIAQYCAgIB4Rw0AIAEoAgwhAyACQSRqQQhqIgRBADYCACACQoCAgIAQNwIkIAJBJG\ 568 | pBnIHAACADEAoaIAJBGGpBCGogBCgCACIDNgIAIAIgAikCJCIFNwMYIAFBCGogAzYCACABIAU3AgAL\ 569 | IAEpAgAhBSABQoCAgIAQNwIAIAJBCGpBCGoiAyABQQhqIgEoAgA2AgAgAUEANgIAQQAtAJmLQBogAi\ 570 | AFNwMIAkBBDEEEEDciAQ0AQQRBDBBJAAsgASACKQMINwIAIAFBCGogAygCADYCACAAQbyCwAA2AgQg\ 571 | ACABNgIAIAJBMGokAAuEAgECfyMAQSBrIgYkAEEAQQAoAtCLQCIHQQFqNgLQi0ACQAJAIAdBAEgNAE\ 572 | EALQCcj0BB/wFxDQBBAEEBOgCcj0BBAEEAKAKYj0BBAWo2ApiPQCAGIAU6AB0gBiAEOgAcIAYgAzYC\ 573 | GCAGIAI2AhQgBkGEg8AANgIQIAZBnIHAADYCDEEAKALAi0AiB0F/TA0AQQAgB0EBajYCwItAAkBBAC\ 574 | gCyItARQ0AIAYgACABKAIQEQMAIAYgBikDADcCDEEAKALIi0AgBkEMakEAKALMi0AoAhQRAwBBACgC\ 575 | wItAQX9qIQcLQQAgBzYCwItAQQBBADoAnI9AIAQNAQsACyAAIAEQQAALygEBAn8jAEEgayIDJAACQA\ 576 | JAIAEgAmoiAiABSQ0AIAAoAgAiAUEBdCIEIAIgBCACSxsiAkEIIAJBCEsbIgJBf3NBH3YhBAJAAkAg\ 577 | AQ0AIANBADYCGAwBCyADIAE2AhwgA0EBNgIYIAMgACgCBDYCFAsgA0EIaiAEIAIgA0EUahAZIAMoAg\ 578 | whAQJAIAMoAggNACAAIAI2AgAgACABNgIEDAILIAFBgYCAgHhGDQEgAUUNACABIANBEGooAgAQSQAL\ 579 | EC0ACyADQSBqJAALyAEBA38jAEEgayICJAACQAJAIAFBAWoiAUUNACAAKAIAIgNBAXQiBCABIAQgAU\ 580 | sbIgFBCCABQQhLGyIBQX9zQR92IQQCQAJAIAMNACACQQA2AhgMAQsgAiADNgIcIAJBATYCGCACIAAo\ 581 | AgQ2AhQLIAJBCGogBCABIAJBFGoQGSACKAIMIQMCQCACKAIIDQAgACABNgIAIAAgAzYCBAwCCyADQY\ 582 | GAgIB4Rg0BIANFDQAgAyACQRBqKAIAEEkACxAtAAsgAkEgaiQAC9IBAQN/IwBBMGsiCSQAAkACQAJA\ 583 | AkACQAJAIAgNAEEBIQoMAQsgCEF/SiILRQ0BIAggCxA4IgpFDQILIAlBGGpBHyAFZ2sgBiAHIAgQGy\ 584 | AJKAIYDQIgCSAJ/QACHP0LAwggASACIAMgBCAJQQhqIAogCBAORQ0DQZ2AwABBKyAJQS9qQciAwABB\ 585 | 7IDAABAfAAsQLQALIAsgCBBJAAtBnYDAAEErIAlBL2pB/IDAAEGMgcAAEB8ACyAAIAg2AgggACAKNg\ 586 | IEIAAgCDYCACAJQTBqJAAL0wEBAX8CQAJAAkAgAUUNACACQX9MDQECQAJAAkAgAygCBEUNAAJAIANB\ 587 | CGooAgAiBA0AAkAgAg0AIAEhAwwEC0EALQCZi0AaDAILIAMoAgAgBCABIAIQNCEDDAILAkAgAg0AIA\ 588 | EhAwwCC0EALQCZi0AaCyACIAEQNyEDCwJAIANFDQAgACADNgIEIABBCGogAjYCACAAQQA2AgAPCyAA\ 589 | IAE2AgQgAEEIaiACNgIADAILIABBADYCBCAAQQhqIAI2AgAMAQsgAEEANgIECyAAQQE2AgALtQEBA3\ 590 | 8CQAJAIAJBEE8NACAAIQMMAQsgAEEAIABrQQNxIgRqIQUCQCAERQ0AIAAhAwNAIAMgAToAACADQQFq\ 591 | IgMgBUkNAAsLIAUgAiAEayIEQXxxIgJqIQMCQCACQQFIDQAgAUH/AXFBgYKECGwhAgNAIAUgAjYCAC\ 592 | AFQQRqIgUgA0kNAAsLIARBA3EhAgsCQCACRQ0AIAMgAmohBQNAIAMgAToAACADQQFqIgMgBUkNAAsL\ 593 | IAALpgECAn8BfkEBIQUCQCABQf8BcSIGQR9LDQAgAkUNACADRQ0AIARBv39qQUlJDQAgAkH///8PSw\ 594 | 0AQQEhBSACQQd0rSIHQQEgBnStfkIgiKcNACAHIAOtfkIgiKcNACACQQR0IAZNDQAgAyACbEH/////\ 595 | A0sNACAAIAI2AgQgAEEQaiABOgAAIABBDGogBDYCACAAQQhqIAM2AgBBACEFCyAAIAU2AgALqgEBAX\ 596 | 8jAEEQayIJJAAgCUEEaiABIAIgAyAEIAUgBiAHIAgQGAJAIARFDQAgAyAEQQEQPwsCQCACRQ0AIAEg\ 597 | AkEBED8LAkACQCAJKAIEIgMgCSgCDCIESw0AIAkoAgghAgwBCyAJKAIIIQECQCAEDQBBASECIAEgA0\ 598 | EBED8MAQsgASADQQEgBBA0IgINAEEBIAQQSQALIAAgBDYCBCAAIAI2AgAgCUEQaiQAC8ABAQN/IwBB\ 599 | EGsiASQAIAAoAgAiAkEMaigCACEDAkACQAJAAkAgAigCBA4CAAEDCyADDQJBnIHAACECQQAhAwwBCy\ 600 | ADDQEgAigCACICKAIEIQMgAigCACECCyABIAM2AgQgASACNgIAIAFB3ILAACAAKAIEIgIoAgggACgC\ 601 | CCACLQAQIAItABEQFQALIAEgAjYCDCABQYCAgIB4NgIAIAFB8ILAACAAKAIEIgIoAgggACgCCCACLQ\ 602 | AQIAItABEQFQALlwECA38BfiMAQSBrIgIkAAJAIAEoAgBBgICAgHhHDQAgASgCDCEDIAJBFGpBCGoi\ 603 | BEEANgIAIAJCgICAgBA3AhQgAkEUakGcgcAAIAMQChogAkEIakEIaiAEKAIAIgM2AgAgAiACKQIUIg\ 604 | U3AwggAUEIaiADNgIAIAEgBTcCAAsgAEG8gsAANgIEIAAgATYCACACQSBqJAALhAEBAX8jAEHAAGsi\ 605 | BSQAIAUgATYCDCAFIAA2AgggBSADNgIUIAUgAjYCECAFQRhqQQxqQgI3AgAgBUEwakEMakEVNgIAIA\ 606 | VBAjYCHCAFQdCHwAA2AhggBUEWNgI0IAUgBUEwajYCICAFIAVBEGo2AjggBSAFQQhqNgIwIAVBGGog\ 607 | BBAuAAtyAQF/IwBBMGsiAyQAIAMgADYCACADIAE2AgQgA0EIakEMakICNwIAIANBIGpBDGpBBDYCAC\ 608 | ADQQI2AgwgA0HcicAANgIIIANBBDYCJCADIANBIGo2AhAgAyADQQRqNgIoIAMgAzYCICADQQhqIAIQ\ 609 | LgALcgEBfyMAQTBrIgMkACADIAA2AgAgAyABNgIEIANBCGpBDGpCAjcCACADQSBqQQxqQQQ2AgAgA0\ 610 | ECNgIMIANB/InAADYCCCADQQQ2AiQgAyADQSBqNgIQIAMgA0EEajYCKCADIAM2AiAgA0EIaiACEC4A\ 611 | C3IBAX8jAEEwayIDJAAgAyAANgIAIAMgATYCBCADQQhqQQxqQgI3AgAgA0EgakEMakEENgIAIANBAj\ 612 | YCDCADQbCKwAA2AgggA0EENgIkIAMgA0EgajYCECADIANBBGo2AiggAyADNgIgIANBCGogAhAuAAty\ 613 | AQF/IwBBMGsiAyQAIAMgATYCBCADIAA2AgAgA0EIakEMakICNwIAIANBIGpBDGpBBDYCACADQQM2Ag\ 614 | wgA0GAi8AANgIIIANBBDYCJCADIANBIGo2AhAgAyADNgIoIAMgA0EEajYCICADQQhqIAIQLgALawEB\ 615 | fyMAQTBrIgIkAAJAQQAtAJiLQEUNACACQRhqQgE3AgAgAkECNgIQIAJB2IHAADYCDCACQQQ2AiggAi\ 616 | ABNgIsIAIgAkEkajYCFCACIAJBLGo2AiQgAkEMakGAgsAAEC4ACyACQTBqJAALQAACQAJAIAFBCUkN\ 617 | ACABIAAQDSEBDAELIAAQASEBCwJAIAFFDQAgAUF8ai0AAEEDcUUNACABQQAgABBLGgsgAQtDAQF/Ak\ 618 | AgACgCACAAKAIIIgNrIAJPDQAgACADIAIQFiAAKAIIIQMLIAAoAgQgA2ogASACEEoaIAAgAyACajYC\ 619 | CEEAC00BAn9BAC0AmYtAGiABKAIEIQIgASgCACEDAkBBCEEEEDciAQ0AQQRBCBBJAAsgASACNgIEIA\ 620 | EgAzYCACAAQcyCwAA2AgQgACABNgIAC0cBAX8jAEEgayIDJAAgA0EMakIANwIAIANBATYCBCADQZCH\ 621 | wAA2AgggAyABNgIcIAMgADYCGCADIANBGGo2AgAgAyACEC4ACzwAAkAgAWlBAUcNAEGAgICAeCABay\ 622 | AASQ0AAkAgAEUNAEEALQCZi0AaIAAgARA3IgFFDQELIAEPCxBNAAtBAQJ/IwBBEGsiASQAAkAgACgC\ 623 | CCICDQBBrILAABBDAAsgASAAKAIMNgIMIAEgADYCCCABIAI2AgQgAUEEahBMAAs5AQF/IAJBEHZAAC\ 624 | EDIABBADYCCCAAQQAgAkGAgHxxIANBf0YiAhs2AgQgAEEAIANBEHQgAhs2AgALQgEBfwJAAkACQCAC\ 625 | QYCAxABGDQBBASEFIAAgAiABKAIQEQQADQELIAMNAUEAIQULIAUPCyAAIAMgBCABKAIMEQYACz8BAX\ 626 | 8jAEEgayIAJAAgAEEUakIANwIAIABBATYCDCAAQfiGwAA2AgggAEHIhsAANgIQIABBCGpBgIfAABAu\ 627 | AAs+AQF/IwBBIGsiAiQAIAJBATsBHCACIAE2AhggAiAANgIUIAJBvIfAADYCECACQZCHwAA2AgwgAk\ 628 | EMahAqAAspAQF/AkAgACgCACIBQYCAgIB4ckGAgICAeEYNACAAKAIEIAFBARA/CwscAQF/AkAgACgC\ 629 | ACIBRQ0AIAAoAgQgAUEBED8LCxcAAkAgAUEJSQ0AIAEgABANDwsgABABCxoBAX8gASAAQQAoAryLQC\ 630 | ICQQUgAhsRAwAACxkAIAAoAhQgASACIABBGGooAgAoAgwRBgALEwEBfyAAIAEgAiADEAghBCAEDwsS\ 631 | AAJAIAFFDQAgACABIAIQPwsLFAAgACgCACABIAAoAgQoAgwRBAALDwEBfyAAIAEQMSECIAIPCw8BAX\ 632 | 8gACABECUhAiACDwsiACAAQsnz8dCf4uju7QA3AwggAELd79jGgKGn0PIANwMACyIAIABCkI3shuqQ\ 633 | isL2ADcDCCAAQsv1w5Cd4rK9tH83AwALIAAgAELk3seFkNCF3n03AwggAELB9/nozJOy0UE3AwALEw\ 634 | AgAEHMgsAANgIEIAAgATYCAAsiACAAQpCN7IbqkIrC9gA3AwggAELL9cOQneKyvbR/NwMACxAAIAEg\ 635 | ACgCACAAKAIEEAQLCwAgACABIAIQTg8LCgAgACABEFAaAAsNACAAKAIAGgN/DAALCw0AIAA1AgBBAS\ 636 | ABEBILDgBBkYfAAEErIAAQKAALCwAgACMAaiQAIwALDQAgAUGAgMAAQQ0QMwsNACABQY2AwABBEBAz\ 637 | CwkAIAAgARAyDwsNACAAQZyBwAAgARAKCwkAIAEgABBHAAsKACAAIAEgAhAQCwoAIAAgASACEBoLBw\ 638 | AgABAdAAsFABBPAAsGACAAEAkLAwAACwMAAAsCAAsCAAsCAAsCAAsLogsBAEGAgMAAC5gLSW52YWxp\ 639 | ZFBhcmFtc0ludmFsaWRPdXRwdXRMZW5jYWxsZWQgYFJlc3VsdDo6dW53cmFwKClgIG9uIGFuIGBFcn\ 640 | JgIHZhbHVlAQAAAAAAAAABAAAAAgAAAGxpYi9fd2FzbS9zcmMvbGliLnJzWAAQABQAAAAPAAAANAAA\ 641 | AAEAAAAAAAAAAQAAAAMAAABYABAAFAAAAA4AAAAyAAAABgAAAAwAAAAEAAAABwAAAAgAAAAJAAAAbW\ 642 | Vtb3J5IGFsbG9jYXRpb24gb2YgIGJ5dGVzIGZhaWxlZAAAtAAQABUAAADJABAADQAAAGxpYnJhcnkv\ 643 | c3RkL3NyYy9hbGxvYy5yc+gAEAAYAAAAYgEAAAkAAABsaWJyYXJ5L3N0ZC9zcmMvcGFuaWNraW5nLn\ 644 | JzEAEQABwAAACGAgAAHgAAAAYAAAAMAAAABAAAAAoAAAALAAAACAAAAAQAAAAMAAAACwAAAAgAAAAE\ 645 | AAAADQAAAA4AAAAPAAAAEAAAAAQAAAAQAAAAEQAAABIAAAAAAAAAAQAAABMAAAAAAAAAZ+YJaoWuZ7\ 646 | ty8248OvVPpX9SDlGMaAWbq9mDHxnN4FtjaHVuayBzaXplIG11c3QgYmUgbm9uLXplcm8AuAEQABsA\ 647 | AAAvaG9tZS9ydW5uZXIvLmNhcmdvL3JlZ2lzdHJ5L3NyYy9pbmRleC5jcmF0ZXMuaW8tNmYxN2QyMm\ 648 | JiYTE1MDAxZi9zY3J5cHQtMC4xMS4wL3NyYy9saWIucnMAANwBEABaAAAAcgAAABkAAABn5glqha5n\ 649 | u3Lzbjw69U+lf1IOUYxoBZur2YMfGc3gW2NodW5rIHNpemUgbXVzdCBiZSBub24temVybwBoAhAAGw\ 650 | AAAC9ob21lL3J1bm5lci8uY2FyZ28vcmVnaXN0cnkvc3JjL2luZGV4LmNyYXRlcy5pby02ZjE3ZDIy\ 651 | YmJhMTUwMDFmL3NjcnlwdC0wLjExLjAvc3JjL3JvbWl4LnJzjAIQAFwAAAAVAAAAFAAAAIwCEABcAA\ 652 | AAHAAAABIAAACMAhAAXAAAABYAAAAPAAAAjAIQAFwAAAAPAAAAJQAAAIwCEABcAAAAQgAAAA8AAACM\ 653 | AhAAXAAAAC0AAAAdAAAAbGlicmFyeS9hbGxvYy9zcmMvcmF3X3ZlYy5yc2NhcGFjaXR5IG92ZXJmbG\ 654 | 93AAAAZAMQABEAAABIAxAAHAAAADoCAAAFAAAAKWNhbGxlZCBgT3B0aW9uOjp1bndyYXAoKWAgb24g\ 655 | YSBgTm9uZWAgdmFsdWUXAAAAAAAAAAEAAAAYAAAAOiAAAJADEAAAAAAAzAMQAAIAAAAwMDAxMDIwMz\ 656 | A0MDUwNjA3MDgwOTEwMTExMjEzMTQxNTE2MTcxODE5MjAyMTIyMjMyNDI1MjYyNzI4MjkzMDMxMzIz\ 657 | MzM0MzUzNjM3MzgzOTQwNDE0MjQzNDQ0NTQ2NDc0ODQ5NTA1MTUyNTM1NDU1NTY1NzU4NTk2MDYxNj\ 658 | I2MzY0NjU2NjY3Njg2OTcwNzE3MjczNzQ3NTc2Nzc3ODc5ODA4MTgyODM4NDg1ODY4Nzg4ODk5MDkx\ 659 | OTI5Mzk0OTU5Njk3OTg5OXJhbmdlIHN0YXJ0IGluZGV4ICBvdXQgb2YgcmFuZ2UgZm9yIHNsaWNlIG\ 660 | 9mIGxlbmd0aCCoBBAAEgAAALoEEAAiAAAAcmFuZ2UgZW5kIGluZGV4IOwEEAAQAAAAugQQACIAAABz\ 661 | bGljZSBpbmRleCBzdGFydHMgYXQgIGJ1dCBlbmRzIGF0IAAMBRAAFgAAACIFEAANAAAAc291cmNlIH\ 662 | NsaWNlIGxlbmd0aCAoKSBkb2VzIG5vdCBtYXRjaCBkZXN0aW5hdGlvbiBzbGljZSBsZW5ndGggKEAF\ 663 | EAAVAAAAVQUQACsAAACQAxAAAQAAAAApBG5hbWUBIgFEH19fd2JpbmRnZW5fYWRkX3RvX3N0YWNrX3\ 664 | BvaW50ZXIAOwlwcm9kdWNlcnMBDHByb2Nlc3NlZC1ieQIGd2FscnVzBjAuMjAuMwx3YXNtLWJpbmRn\ 665 | ZW4GMC4yLjky\ 666 | ", 667 | ); 668 | const wasmModule = new WebAssembly.Module(wasmBytes); 669 | return new WebAssembly.Instance(wasmModule, imports); 670 | } 671 | 672 | function base64decode(b64) { 673 | const binString = atob(b64); 674 | const size = binString.length; 675 | const bytes = new Uint8Array(size); 676 | for (let i = 0; i < size; i++) { 677 | bytes[i] = binString.charCodeAt(i); 678 | } 679 | return bytes; 680 | } 681 | -------------------------------------------------------------------------------- /lib/_wasm/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | extern crate alloc; 3 | extern crate scrypt; 4 | extern crate wasm_bindgen; 5 | use alloc::vec; 6 | use alloc::vec::Vec; 7 | use scrypt::{scrypt, Params}; 8 | use wasm_bindgen::prelude::*; 9 | 10 | #[wasm_bindgen] 11 | pub fn scrypt_hash(password: &[u8], salt: &[u8], n: u32, r: u32, p: u32, dklen: usize) -> Vec { 12 | let log_n = (32 - n.leading_zeros() - 1) as u8; 13 | let mut result: Vec = vec![0; dklen]; 14 | let params = Params::new(log_n, r, p, dklen).unwrap(); 15 | scrypt(&password, &salt, ¶ms, &mut result).unwrap(); 16 | result 17 | } 18 | 19 | #[cfg(test)] 20 | mod tests { 21 | use super::*; 22 | #[test] 23 | fn basic_scrypt() { 24 | let result = scrypt_hash("password".as_bytes(), "NaCl".as_bytes(), 1024, 8, 16, 64); 25 | assert_eq!(result.len(), 64); 26 | 27 | let expected = vec![ 28 | 0xfd, 0xba, 0xbe, 0x1c, 0x9d, 0x34, 0x72, 0x00, 0x78, 0x56, 0xe7, 0x19, 0x0d, 0x01, 29 | 0xe9, 0xfe, 0x7c, 0x6a, 0xd7, 0xcb, 0xc8, 0x23, 0x78, 0x30, 0xe7, 0x73, 0x76, 0x63, 30 | 0x4b, 0x37, 0x31, 0x62, 0x2e, 0xaf, 0x30, 0xd9, 0x2e, 0x22, 0xa3, 0x88, 0x6f, 0xf1, 31 | 0x09, 0x27, 0x9d, 0x98, 0x30, 0xda, 0xc7, 0x27, 0xaf, 0xb9, 0x4a, 0x83, 0xee, 0x6d, 32 | 0x83, 0x60, 0xcb, 0xdf, 0xa2, 0xcc, 0x06, 0x40, 33 | ]; 34 | assert_eq!(result, expected); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lib/format.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @module scrypt/format 3 | * @author oplik0 4 | * @description scrypt output formatting related functions 5 | */ 6 | import { crypto } from "../deps.ts"; 7 | import { decodeBase64, encodeBase64 } from "../deps.ts"; 8 | import { hmacSHA256 } from "./hmac.ts"; 9 | // dprint-ignore-next-line 10 | // deno-fmt-ignore 11 | export type logN = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63; 12 | /** 13 | * Available parameters primarily influencing security (and runtime) of scrypt 14 | */ 15 | export interface ScryptParameters { 16 | /** 17 | * log2 of the work factor N. Must be an integer between 1 and 63. Defaults to 17 (N=131072) 18 | */ 19 | logN?: logN; 20 | /** 21 | * Block size. Defaults to 8 22 | */ 23 | r?: number; 24 | /** 25 | * Parralelism factor. Defaults to 1 26 | */ 27 | p?: number; 28 | /** 29 | * custom salt (by default it will be randomly generated) 30 | */ 31 | salt?: string | Uint8Array; 32 | /** 33 | * desired key length (in bytes). 34 | */ 35 | dklen?: number; 36 | /** 37 | * full number of iterations, if you prefer it over logN (this overrides that setting). Must be a power of 2. 38 | */ 39 | N?: number; 40 | } 41 | /** 42 | * Available formats for scrypt hashes 43 | * scrypt - original scrypt format, see (https://github.com/Tarsnap/scrypt/blob/master/FORMAT). This is the default format. 44 | * phc - PHC format, a stricter subset of Modular Crypt Format created for argon2. 45 | * raw - raw hash, without any additional data. Can't be used to verify the hash without also passing the parameters used to generate it. 46 | */ 47 | export type scryptFormat = "scrypt" | "phc" | "raw"; 48 | /** 49 | * Format hash using HMAC-based format from node-scrypt 50 | * based on the original tarsnap scrypt encrypted data format 51 | * @see https://github.com/barrysteyn/node-scrypt#kdf 52 | * @see https://github.com/Tarsnap/scrypt/blob/master/FORMAT 53 | * @param {string} rawHash - Raw scrypt hash in base64 format 54 | * @param {number} logN - The log2 of the cost factor 55 | * @param {number} r - Block size 56 | * @param {number} p - Parallelism factor 57 | * @param {string|Uint8Array} salt - Salt used 58 | * @returns {string} - hash in original scrypt format as a base64 string 59 | */ 60 | export function formatScrypt( 61 | rawHash: string, 62 | logN: logN, 63 | r: number, 64 | p: number, 65 | salt: string | Uint8Array, 66 | ): string { 67 | const encoder = new TextEncoder(); 68 | const result = new Uint8Array(96); 69 | const dataview = new DataView(result.buffer); 70 | // first 6 bytes are the word "scrypt", 7th byte is 0 71 | result.set([115, 99, 114, 121, 112, 116, 0], 0); 72 | dataview.setUint8(7, logN); 73 | dataview.setUint32(8, r, false); 74 | dataview.setUint32(12, p, false); 75 | result.set(typeof salt === "string" ? encoder.encode(salt) : salt, 16); 76 | const hashedResult = crypto.subtle.digestSync( 77 | "SHA-256", 78 | result.subarray(0, 48), 79 | ); 80 | result.set(new Uint8Array(hashedResult), 48); 81 | result.set( 82 | hmacSHA256( 83 | new Uint8Array(decodeBase64(rawHash)).subarray(32), 84 | result.subarray(0, 64), 85 | ), 86 | 64, 87 | ); 88 | // encode the result as a base64 string 89 | return encodeBase64(result); 90 | } 91 | /** 92 | * Retrieve scrypt parameters from an scrypt formatted hash 93 | * @param {string} formattedHash - scrypt formatted hash 94 | * @returns {ScryptParameters} - scrypt parameters used to generate the hash 95 | */ 96 | function decomposeScrypt( 97 | formattedHash: string, 98 | ): ScryptParameters { 99 | const bytes: Uint8Array = new Uint8Array(decodeBase64(formattedHash)); 100 | const dataview: DataView = new DataView(bytes.buffer); 101 | const parameters: ScryptParameters = {}; 102 | parameters.logN = bytes[7] as logN; 103 | parameters.r = dataview.getUint32(8, false); 104 | parameters.p = dataview.getUint32(12, false); 105 | parameters.salt = bytes.subarray(16, 48); 106 | return parameters; 107 | } 108 | 109 | /** 110 | * Format hash as a PHC format string (a stricter subset of Modular Crypt Format created for argon2) 111 | * This format is fully compatible with MCF and this implementation is based on passlib 112 | * Salt and hash are saved as base64 encoded strings without padding 113 | * @param {string} rawHash - base64 formatted hash 114 | * @param {logN} logN - log2 of cost factor 115 | * @param {number} r - block size 116 | * @param {number} p - parallelism factor 117 | * @param {string|Uint8Array} salt - salt used when hashing 118 | */ 119 | export function formatPHC( 120 | rawHash: string, 121 | logN: logN, 122 | r: number, 123 | p: number, 124 | salt: string | Uint8Array, 125 | ): string { 126 | // convert salt to base64 without padding 127 | salt = encodeBase64(salt).replace(/=/g, ""); 128 | rawHash = rawHash.replace(/=/g, ""); 129 | return `\$scrypt\$ln=${logN},r=${r},p=${p}\$${salt}\$${rawHash}`; 130 | } 131 | function decomposePHC(formattedHash: string): ScryptParameters { 132 | const regex = 133 | /\$scrypt\$ln=(?\d+),r=(?\d+),p=(?

\d+)\$(?[a-zA-Z0-9\-\_\+\/\=]*)\$/; 134 | const parameters: ScryptParameters = formattedHash.match(regex) 135 | ?.groups as ScryptParameters; 136 | parameters.salt = new Uint8Array(decodeBase64(parameters.salt as string)); 137 | // the PHC format from passlib always uses 32 bytes hashes 138 | parameters.dklen = 32; 139 | return parameters; 140 | } 141 | 142 | /** 143 | * Retrieve scrypt parameters from a supported formatted hash 144 | * @param {string} formattedHash - formatted hash 145 | * @param {scryptFormat} format - format of the hash. Will be detected automatically if not provided 146 | * @returns 147 | */ 148 | export function decomposeFormat( 149 | formattedHash: string, 150 | format?: scryptFormat, 151 | ): ScryptParameters { 152 | format = format ?? detectFormat(formattedHash); 153 | switch (format) { 154 | case "scrypt": 155 | return decomposeScrypt(formattedHash); 156 | case "phc": 157 | return decomposePHC(formattedHash); 158 | case "raw": 159 | throw new Error("Unable to extract parameters from raw hash"); 160 | default: 161 | throw new Error("Unknown hash format"); 162 | } 163 | } 164 | 165 | /** 166 | * Guess the format of a hash based on its prefix 167 | * It's technically possible for the raw hash to start with a colliding prefix, but it's very unlikely 168 | * @param {string} formattedHash - formatted hash to check the format of 169 | * @returns {scryptFormat} - detected format of the hash 170 | */ 171 | export function detectFormat( 172 | formattedHash: string, 173 | ): scryptFormat { 174 | switch (formattedHash.substring(0, 6)) { 175 | case "c2NyeX": 176 | case "scrypt": 177 | return "scrypt"; 178 | case "$scryp": 179 | return "phc"; 180 | default: 181 | return "raw"; 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /lib/format_test.ts: -------------------------------------------------------------------------------- 1 | import { assertEquals } from "../deps.ts"; 2 | 3 | import { decomposeFormat, ScryptParameters } from "./format.ts"; 4 | 5 | Deno.test("decompose scrypt with format detection", (): void => { 6 | const params = decomposeFormat( 7 | "c2NyeXB0AAwAAAAIAAAAAcQ0zwp7QNLklxCn14vB75AYWDIrrT9I/7F9+lVGBfKN/1TH2hs/HboSy1ptzN0YzMmobAXD3CqJJLRLaTK7nOHbjNTWA20LuUmGwEoJtonW", 8 | ); 9 | 10 | const expectedParams = { 11 | logN: 12, 12 | r: 8, 13 | p: 1, 14 | // dprint-ignore-next-line 15 | // deno-fmt-ignore 16 | salt: new Uint8Array([196, 52, 207, 10, 123, 64, 210, 228, 151, 16, 167, 215, 139, 193, 239, 144, 24, 88, 50, 43, 173, 63, 72, 255, 177, 125, 250, 85, 70, 5, 242, 141]), 17 | } as ScryptParameters; 18 | assertEquals(params, expectedParams); 19 | }); 20 | -------------------------------------------------------------------------------- /lib/helpers.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author oplik0 3 | * @description Small helper functions that don't fit anywhere else 4 | */ 5 | 6 | /** 7 | * Truncate input to 32 bytes 8 | * Text will be encoded using UTF-8 9 | * @param {string|Uint8Array} input - data to truncate 10 | * @returns {Uint8Array} - truncated data 11 | */ 12 | export function to32bytes(input: string | Uint8Array): Uint8Array { 13 | if (typeof input === "string") { 14 | const encoder = new TextEncoder(); 15 | input = encoder.encode(input); 16 | } 17 | if (input.byteLength === 32) { 18 | return input; 19 | } 20 | return input.subarray(0, 32); 21 | } 22 | -------------------------------------------------------------------------------- /lib/helpers_test.ts: -------------------------------------------------------------------------------- 1 | import { assertEquals } from "../deps.ts"; 2 | import { to32bytes } from "./helpers.ts"; 3 | 4 | Deno.test("to32bytes long string", (): void => { 5 | const input = "just a somewhat longer string that's more than 32 bytes long"; 6 | const expected = new Uint8Array([ 7 | 106, 8 | 117, 9 | 115, 10 | 116, 11 | 32, 12 | 97, 13 | 32, 14 | 115, 15 | 111, 16 | 109, 17 | 101, 18 | 119, 19 | 104, 20 | 97, 21 | 116, 22 | 32, 23 | 108, 24 | 111, 25 | 110, 26 | 103, 27 | 101, 28 | 114, 29 | 32, 30 | 115, 31 | 116, 32 | 114, 33 | 105, 34 | 110, 35 | 103, 36 | 32, 37 | 116, 38 | 104, 39 | ]); 40 | const actual = to32bytes(input); 41 | assertEquals(actual, expected); 42 | }); 43 | 44 | Deno.test("to32bytes short string", (): void => { 45 | const input = "hello world"; 46 | const expected = new Uint8Array([ 47 | 104, 48 | 101, 49 | 108, 50 | 108, 51 | 111, 52 | 32, 53 | 119, 54 | 111, 55 | 114, 56 | 108, 57 | 100, 58 | ]); 59 | const actual = to32bytes(input); 60 | assertEquals(actual, expected); 61 | }); 62 | -------------------------------------------------------------------------------- /lib/hmac.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @module scrypt/hmac 3 | * @author oplik0 4 | * @description A very primitive crypto.subtle.digestSync-based HMAC-SHA256 synchronous implementation. 5 | */ 6 | import { crypto } from "../deps.ts"; 7 | 8 | /** 9 | * Join two arrays at the end of the first one 10 | * @param {Uint8Array} a - first array 11 | * @param {Uint8Array} b - second array 12 | * @returns {Uint8Array} - joined array of length a.length + b.length 13 | */ 14 | function mergeArrays(a: Uint8Array, b: Uint8Array): Uint8Array { 15 | const result = new Uint8Array(a.length + b.length); 16 | result.set(a); 17 | result.set(b, a.length); 18 | return result; 19 | } 20 | /** 21 | * Ensure that key is of the correct length 22 | * @param {Uint8Array} key 23 | * @param {Uint8Array} blockSize length to get the key to 24 | * @returns 25 | */ 26 | function blockSizedKey(key: Uint8Array, blockSize: number): Uint8Array { 27 | if (key.length > blockSize) { 28 | return new Uint8Array(crypto.subtle.digestSync("SHA-256", key)); 29 | } else if (key.length < blockSize) { 30 | const result = new Uint8Array(blockSize); 31 | result.set(key); 32 | return result; 33 | } 34 | return key; 35 | } 36 | 37 | /** 38 | * Synchronous Hash-based Message Authentication Code implementation using SHA256 39 | * @see https://en.wikipedia.org/wiki/HMAC 40 | * @param {Uint8Array} key 41 | * @param {Uint8Array} data 42 | * @returns {Uint8Array} - HMAC-SHA256 of data using key 43 | */ 44 | export function hmacSHA256(key: Uint8Array, data: Uint8Array): Uint8Array { 45 | const b_key = blockSizedKey(key, 64); 46 | const o_pad = new Uint8Array(64); 47 | const i_pad = new Uint8Array(64); 48 | for (let i = 0; i < 64; i++) { 49 | o_pad[i] = b_key[i] ^ 0x5c; 50 | i_pad[i] = b_key[i] ^ 0x36; 51 | } 52 | return new Uint8Array(crypto.subtle.digestSync( 53 | "SHA-256", 54 | mergeArrays( 55 | o_pad, 56 | new Uint8Array( 57 | crypto.subtle.digestSync("SHA-256", mergeArrays(i_pad, data)), 58 | ), 59 | ), 60 | )); 61 | } 62 | -------------------------------------------------------------------------------- /lib/hmac_bench.ts: -------------------------------------------------------------------------------- 1 | import { HmacSha256 } from "https://deno.land/std@0.160.0/hash/sha256.ts"; 2 | import { decodeHex } from "../deps.ts"; 3 | import { hmacSHA256 } from "./hmac.ts"; 4 | 5 | Deno.bench("hmac - subtle", { group: "small hmac", baseline: true }, () => { 6 | hmacSHA256( 7 | decodeHex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"), 8 | decodeHex("4869205468657265"), 9 | ); 10 | }); 11 | Deno.bench("hmac - old", { group: "small hmac" }, () => { 12 | const hmac = new HmacSha256( 13 | decodeHex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"), 14 | ); 15 | hmac.update(decodeHex("4869205468657265")); 16 | hmac.digest(); 17 | }); 18 | 19 | Deno.bench("hmac - subtle", { group: "larger hmac", baseline: true }, () => { 20 | hmacSHA256( 21 | decodeHex( 22 | "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 23 | ), 24 | decodeHex( 25 | "5468697320697320612074657374207573696e672061206c6172676572207468616e20626c6f636b2d73697a65206b657920616e642061206c6172676572207468616e20626c6f636b2d73697a6520646174612e20546865206b6579206e6565647320746f20626520686173686564206265666f7265206265696e6720757365642062792074686520484d414320616c676f726974686d2e", 26 | ), 27 | ); 28 | }); 29 | Deno.bench("hmac - old", { group: "larger hmac" }, () => { 30 | const hmac = new HmacSha256( 31 | decodeHex( 32 | "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 33 | ), 34 | ); 35 | hmac.update( 36 | decodeHex( 37 | "5468697320697320612074657374207573696e672061206c6172676572207468616e20626c6f636b2d73697a65206b657920616e642061206c6172676572207468616e20626c6f636b2d73697a6520646174612e20546865206b6579206e6565647320746f20626520686173686564206265666f7265206265696e6720757365642062792074686520484d414320616c676f726974686d2e", 38 | ), 39 | ); 40 | hmac.digest(); 41 | }); 42 | 43 | // appears to be comparable to the old implementation in practice 44 | Deno.bench("hmac - subtle", { group: "hmac as used", baseline: true }, () => { 45 | hmacSHA256( 46 | decodeHex( 47 | "834680896aab19cf86a4c0edf4cef4db8af5bd05a40d42e768e658057ee521e63acadefa59fb2f3133def01d2c3dd5d1", 48 | ).subarray(0, 48), 49 | decodeHex( 50 | "024b5b12a8b3d622c289ad69536a30cda848074c82d06ff05775d653bf0fc48033ddafba8071b7f119810dd57619553e87aff3bc8c237669523dc6530b8ee267", 51 | ).subarray(0, 64), 52 | ); 53 | }); 54 | Deno.bench("hmac - old", { group: "hmac as used" }, () => { 55 | const hmac = new HmacSha256( 56 | decodeHex( 57 | "834680896aab19cf86a4c0edf4cef4db8af5bd05a40d42e768e658057ee521e63acadefa59fb2f3133def01d2c3dd5d1", 58 | ).subarray(0, 48), 59 | ); 60 | hmac.update( 61 | decodeHex( 62 | "024b5b12a8b3d622c289ad69536a30cda848074c82d06ff05775d653bf0fc48033ddafba8071b7f119810dd57619553e87aff3bc8c237669523dc6530b8ee267", 63 | ).subarray(0, 64), 64 | ); 65 | hmac.digest(); 66 | }); 67 | -------------------------------------------------------------------------------- /lib/hmac_test.ts: -------------------------------------------------------------------------------- 1 | import { decodeHex } from "../deps.ts"; 2 | import { assertEquals } from "../deps.ts"; 3 | import { hmacSHA256 } from "./hmac.ts"; 4 | 5 | // test data from RFC 4231 6 | 7 | Deno.test("basic hmacSHA256", (): void => { 8 | const result = hmacSHA256( 9 | decodeHex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"), 10 | decodeHex("4869205468657265"), 11 | ); 12 | assertEquals( 13 | result, 14 | decodeHex( 15 | "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7", 16 | ), 17 | ); 18 | }); 19 | 20 | Deno.test("hmacSHA256 with short key", (): void => { 21 | const result = hmacSHA256( 22 | decodeHex("4a656665"), 23 | decodeHex( 24 | "7768617420646f2079612077616e7420666f72206e6f7468696e673f", 25 | ), 26 | ); 27 | assertEquals( 28 | result, 29 | decodeHex( 30 | "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843", 31 | ), 32 | ); 33 | }); 34 | 35 | Deno.test("hmacSHA256 with combined key and data longer than block size", (): void => { 36 | const result = hmacSHA256( 37 | decodeHex( 38 | "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 39 | ), 40 | decodeHex( 41 | "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", 42 | ), 43 | ); 44 | assertEquals( 45 | result, 46 | decodeHex( 47 | "773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe", 48 | ), 49 | ); 50 | }); 51 | 52 | Deno.test("hmacSHA256 with both key and data longer than block size", (): void => { 53 | const result = hmacSHA256( 54 | decodeHex( 55 | "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 56 | ), 57 | decodeHex( 58 | "5468697320697320612074657374207573696e672061206c6172676572207468616e20626c6f636b2d73697a65206b657920616e642061206c6172676572207468616e20626c6f636b2d73697a6520646174612e20546865206b6579206e6565647320746f20626520686173686564206265666f7265206265696e6720757365642062792074686520484d414320616c676f726974686d2e", 59 | ), 60 | ); 61 | assertEquals( 62 | result, 63 | decodeHex( 64 | "9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2", 65 | ), 66 | ); 67 | }); 68 | -------------------------------------------------------------------------------- /lib/scrypt.ts: -------------------------------------------------------------------------------- 1 | import { encodeBase64 } from "../deps.ts"; 2 | import { encodeHex } from "../deps.ts"; 3 | import { instantiate } from "./_wasm/scrypt_wasm.generated.js"; 4 | const encoder: TextEncoder = new TextEncoder(); 5 | const decoder: TextDecoder = new TextDecoder("utf-8"); 6 | const { scrypt_hash } = instantiate(); 7 | export type encoding = "utf-8" | "base64" | "hex"; 8 | /** 9 | * Scrypt implementation using web assembly 10 | * @param {string|Uint8Array} password - string to hash 11 | * @param {string|Uint8Array} salt - 12 | * @param {number} N - CPU/Memory cost parameter. Must be a power of 2 smaller than 2^(128*r/8) 13 | * @param {number} r - block size 14 | * @param {number} p - parallelism factor 15 | * @param {number} [dklen] - length (in bytes) of the output. Defaults to 32. 16 | * @param {encoding} [outputEncoding] - encoding used, defaults to null (Uint8Array) 17 | * @returns {string|Uint8Array} - the resulting hash encoded according to outputEncoding 18 | */ 19 | export function scrypt( 20 | password: string | Uint8Array, 21 | salt: string | Uint8Array, 22 | N: number, 23 | r: number, 24 | p: number, 25 | dklen?: number, 26 | outputEncoding?: encoding, 27 | ): Uint8Array | string { 28 | dklen = dklen ?? 64; 29 | password = typeof password === "string" ? encoder.encode(password) : password; 30 | salt = typeof salt === "string" ? encoder.encode(salt) : salt; 31 | const result: Uint8Array = scrypt_hash(password, salt, N, r, p, dklen); 32 | switch (outputEncoding) { 33 | case "base64": 34 | return encodeBase64(result); 35 | case "hex": 36 | return encodeHex(result); 37 | case "utf-8": 38 | return decoder.decode(result); 39 | default: 40 | return result; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /lib/scrypt_bench.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Just a few simple benchmarks 3 | * @todo document the benchmarks better 4 | */ 5 | import { scrypt as scryptOld } from "https://deno.land/x/scrypt@v4.4.4/lib/scrypt.ts"; 6 | import { scrypt } from "./scrypt.ts"; 7 | import { scrypt as scryptNodeRaw } from "node:crypto"; 8 | import { scrypt as scryptoRaw } from "https://deno.land/x/scrypto@v1.0.0/main.ts"; 9 | import { scrypt as scryptWasmRaw } from "npm:hash-wasm" 10 | import { scrypt as scryptNobleRaw } from "npm:@noble/hashes/scrypt" 11 | 12 | function scryptNode( 13 | password: string, 14 | salt: string, 15 | N: number, 16 | r: number, 17 | p: number, 18 | dklen: number = 64, 19 | ) { 20 | return new Promise((resolve) => 21 | scryptNodeRaw(password, salt, dklen, { N, r, p }, resolve) 22 | ); 23 | } 24 | 25 | function scrypto( 26 | password: string, 27 | salt: string, 28 | N: number, 29 | r: number, 30 | p: number, 31 | dkLen: number = 64, 32 | ) { 33 | return scryptoRaw(password, salt, { N, r, p, dkLen}) 34 | } 35 | 36 | function scryptWasm ( 37 | password: string, 38 | salt: string, 39 | N: number, 40 | r: number, 41 | p: number, 42 | dkLen: number = 64, 43 | ) { 44 | return scryptWasmRaw({password, salt, costFactor: N, blockSize: r, parallelism: p, hashLength: dkLen}); 45 | } 46 | 47 | function scryptNoble ( 48 | password: string, 49 | salt: string, 50 | N: number, 51 | r: number, 52 | p: number, 53 | dkLen: number = 64, 54 | ) { 55 | return scryptNobleRaw(password, salt, {N, r, p, dkLen}); 56 | } 57 | 58 | const scryptImplementations = { 59 | "current": scrypt, 60 | "last version": scryptOld, 61 | "hash-wasm": scryptWasm, 62 | "noble-hashes": scryptNoble, 63 | "node": scryptNode, 64 | // "scrypto": scrypto, // disabled because it's 5x slower, so the data isn't very useful and the benchmark takes unnecessarily long 65 | }; 66 | 67 | const extremeSalt = 68 | `IkjpewCbNm4A7cuY1VL9KC3y92blEthtLf9Cet6uEoTxz5cyF660da2zeci42fYwVCVwsKogETMCXupSZZAUh6a80ZnnBTk17B3UTCSVQPpYfL8GktJ2BDokE7ox2hV8OwwUT1hFvCuJqwHZpRvZw1RNCO6HfukPdgMHhq9rWLTXXUNwrIjlmkeydKGFJz2mS1xFcvLQtle4olJVK0SXXXYHAigBfpYxxSC2acvoxuacWcXhzSSRZAMysU2J7zDfXdxnYoqz50rvmvi36g7t2WDSAdzZ44JpxVcc3bYD7xYI3UgfVMPOfeblzwJi455QIurHzDuXEUNS0tZX1kWwZ0XcNSCwGzPs7WSVHxHc0KVUNhwSz16wDYFK4pYeA29ThXgFiFICSLVshiRrCfuzRthW7IZtRa9efcf4nFJsVBk51jpHY0b8CLhARrQU92mlBULwmJKe8DgST3Vn9rva98E9jk4y7NfSb4i9g74OjuFQ8yRO3BHksBZoVtBl4wUppM2hsLt72LZKA0ZsaWW7dG9a1bgWUkBBRG5OwzARenDqQIA2Gp5V4JsXuUUYNDylCelkLUVfS7hB1AZHtnIgwVqTaGDxl7nNZGKpAx6MrOd40laTUhrtZo4prwFZROHPNVJGQk2PQDgwqxX5SWoBTK8cCCzrbGBfHq9r8BwBvSVdeQ7bgjUW2j7NCapHHZ6filzxZaVsLsEITGZNcK0t5DdSnaDLRxyOn21ncKVIyZfOdlvpytvqpQaH5RWu4G50IPkEevue8KenXpGLP0pmEseBf6eX02rlN9arqZ4HJWmD7RbAChs7OJwfKlNIawb0V3G3N0eJeXiRsYOk10GIb91pyZRLSr2AJDtiWCcMuOWZfgLVHIrUVftfh9iXmRk2RAT1sigivbNtdqcF2cVvbTVMUCe7MIPRt4dGqwOQqdReGjPy9p1CNfKfJBIgW0xhYsOGMkcUqSurHxPl4wTOnMBx8vEZQsqJCZomENA1`; 69 | const extremePassword = 70 | `TFImeWrtF2kOIvDjG4P0ybmMrNOq0bQ0aERcC69iHflECWrwuSMO4JPD3Ng5HwNXZrCpHyEwviW8zly3WLsQ6zJ60lnfwhVRdkEQCsFiH4NvGl0tCAuty9Rruf47WHeE3GK7qAJwhcXHx3FCJgWN8KHdoy3vn2zUKJlhhjSFGANJdVYQGSaQTmtoJdhcemmYT5hprkALp7Q9vMwCk9hDvV5vB0evXfxqG0dFV3MPJmywwWAUJEi5MyM2Pio7fL50M5ohPWFmUllpa6G5pVBhi26GtOy6sM3GDGHmnohavtsMvTeRcMX1ds4HWA9U3vH7urQ3XGkCUzulB6WxuxHn8Z3fRz3BL6MZI0EReep2qUVaqJn8onzsI6da6pU6iDtRbufWxi0q8XN1S3BCtFGjzaTU12nvfg5js53PiSw1KUnZj2thKxWtnKcpwzbXdTuuZ9GVhZHIMcOXXrDR0rj539ZLAVyJmqwDOMjTsqPN7BY522PcJHoTElSRNRAsAsFx2m7h9brhcZXOgV1PZohJsdQS7RWhAl9EYBkgF8WCgGw9DXidVduIIHDlEd7mAVJfo9HYX85kFcwrLEpuPiFxfNhubeDpeBu2FAbAo6DNHFlqXUUnyKvMbzptcgisSr2V1pwykB6uLVrwx3AceRnyqg5flldmfsSKw0AFZ4PagGMJuFDMGrV29Vmqhv61SRL9in0ngZx0gJ2vKv26qS3jGN72UUsbkysuGNz6ul0D5jIapvIcCTncIiXSY24pPctxFsawcXvSNw4jEKccsHCTZF0gri6iFS7JqqQd87FNowbrug6sIWSwiWHYGN1VfSwuE5plQHVvNCHNZnMBBIoaMWh45lhtlfCWdUwVpjjK5dAUcOtKftJ2hcl4mIlxs7Fy8ASWhYvWAbpp3fRgmAeTRYAFEwMohN9b03iXyDSNFIeZtQoaL7HYFVWoXV4BfBVlR3CvNIwp6OPBAFFSDlSn9CZU06UziY1tSwqBzkCD`; 71 | 72 | for (const [name, implementation] of Object.entries(scryptImplementations)) { 73 | Deno.bench(`small scrypt - ${name}`, { 74 | group: "small scrypt", 75 | baseline: name === "current", 76 | }, async () => { 77 | await implementation("password", "salt", 1024, 8, 1, 64); 78 | }); 79 | 80 | Deno.bench(`small scrypt - ${name} (longer password and salt)`, { 81 | group: "small scrypt (longer password and salt)", 82 | baseline: name === "current", 83 | }, async () => { 84 | await implementation( 85 | "long password to test that", 86 | "long salt to test that", 87 | 1024, 88 | 8, 89 | 1, 90 | 64, 91 | ); 92 | }); 93 | 94 | Deno.bench(`small scrypt - ${name} (extremely long password and salt)`, { 95 | group: "small scrypt (extremely long password and salt)", 96 | baseline: name === "current", 97 | }, async () => { 98 | await implementation(extremePassword, extremeSalt, 1024, 8, 1, 64); 99 | }); 100 | 101 | Deno.bench(`old standard scrypt (logN=14) - ${name}`, { 102 | group: "scrypt (logN=14)", 103 | baseline: name === "current", 104 | }, async () => { 105 | await implementation("password", "salt", 16384, 8, 1, 64); 106 | }); 107 | 108 | Deno.bench(`standard scrypt (logN=17) - ${name}`, { 109 | group: "scrypt", 110 | baseline: name === "current", 111 | }, async () => { 112 | await implementation("password", "salt", 131072, 8, 1, 64); 113 | }); 114 | 115 | Deno.bench( 116 | `old standard scrypt (logN=14) - ${name} (longer password and salt)`, 117 | { 118 | group: "scrypt (logN=14; longer password and salt)", 119 | baseline: name === "current", 120 | }, 121 | async () => { 122 | await implementation( 123 | "long password to test that", 124 | "long salt to test that", 125 | 16384, 126 | 8, 127 | 1, 128 | 64, 129 | ); 130 | }, 131 | ); 132 | 133 | Deno.bench( 134 | `standard scrypt (logN=17) - ${name} (longer password and salt)`, 135 | { 136 | group: "scrypt (longer password and salt)", 137 | baseline: name === "current", 138 | }, 139 | async () => { 140 | await implementation( 141 | "long password to test that", 142 | "long salt to test that", 143 | 131072, 144 | 8, 145 | 1, 146 | 64, 147 | ); 148 | }, 149 | ); 150 | 151 | Deno.bench( 152 | `old standard scrypt (logN=14) - ${name} (extremely long password and salt)`, 153 | { 154 | group: "scrypt (logN=14; extremely long password and salt)", 155 | baseline: name === "current", 156 | }, 157 | async () => { 158 | await implementation(extremePassword, extremeSalt, 16384, 8, 1, 64); 159 | }, 160 | ); 161 | 162 | Deno.bench( 163 | `standard scrypt (logN=17) - ${name} (extremely long password and salt)`, 164 | { 165 | group: "scrypt (extremely long password and salt)", 166 | baseline: name === "current", 167 | }, 168 | async () => { 169 | await implementation(extremePassword, extremeSalt, 131072, 8, 1, 64); 170 | }, 171 | ); 172 | 173 | Deno.bench(`large n scrypt - ${name} (4x standard)`, { 174 | group: "large n scrypt", 175 | baseline: name === "current", 176 | }, async () => { 177 | await implementation("password", "salt", 524288, 8, 1, 64); 178 | }); 179 | 180 | Deno.bench(`large r scrypt - ${name} (4x standard)`, { 181 | group: "large r scrypt", 182 | baseline: name === "current", 183 | }, async () => { 184 | await implementation("password", "salt", 131072, 32, 1, 64); 185 | }); 186 | 187 | Deno.bench(`large p scrypt - ${name} (4x standard)`, { 188 | group: "large p scrypt", 189 | baseline: name === "current", 190 | }, async () => { 191 | await implementation("password", "salt", 131072, 8, 4, 64); 192 | }); 193 | } 194 | -------------------------------------------------------------------------------- /lib/scrypt_test.ts: -------------------------------------------------------------------------------- 1 | import { assertEquals } from "../deps.ts"; 2 | import { scrypt } from "./scrypt.ts"; 3 | 4 | Deno.test("scrypt #1", (): void => { 5 | // dprint-ignore-next-line 6 | // deno-fmt-ignore 7 | const expectedOutput: Uint8Array = new Uint8Array([0x77, 0xd6, 0x57, 0x62, 0x38, 0x65, 0x7b, 0x20, 0x3b, 0x19, 0xca, 0x42, 0xc1, 0x8a, 0x04, 0x97, 0xf1, 0x6b, 0x48, 0x44, 0xe3, 0x07, 0x4a, 0xe8, 0xdf, 0xdf, 0xfa, 0x3f, 0xed, 0xe2, 0x14, 0x42, 0xfc, 0xd0, 0x06, 0x9d, 0xed, 0x09, 0x48, 0xf8, 0x32, 0x6a, 0x75, 0x3a, 0x0f, 0xc8, 0x1f, 0x17, 0xe8, 0xd3, 0xe0, 0xfb, 0x2e, 0x0d, 0x36, 0x28, 0xcf, 0x35, 0xe2, 0x0c, 0x38, 0xd1, 0x89, 0x06]); 8 | assertEquals( 9 | (scrypt("", "", 16, 1, 1, 64)) as Uint8Array, 10 | expectedOutput, 11 | ); 12 | }); 13 | 14 | Deno.test("scrypt #2", (): void => { 15 | // dprint-ignore-next-line 16 | // deno-fmt-ignore 17 | const expectedOutput: Uint8Array = new Uint8Array([0xfd, 0xba, 0xbe, 0x1c, 0x9d, 0x34, 0x72, 0x00, 0x78, 0x56, 0xe7, 0x19, 0x0d, 0x01, 0xe9, 0xfe, 0x7c, 0x6a, 0xd7, 0xcb, 0xc8, 0x23, 0x78, 0x30, 0xe7, 0x73, 0x76, 0x63, 0x4b, 0x37, 0x31, 0x62, 0x2e, 0xaf, 0x30, 0xd9, 0x2e, 0x22, 0xa3, 0x88, 0x6f, 0xf1, 0x09, 0x27, 0x9d, 0x98, 0x30, 0xda, 0xc7, 0x27, 0xaf, 0xb9, 0x4a, 0x83, 0xee, 0x6d, 0x83, 0x60, 0xcb, 0xdf, 0xa2, 0xcc, 0x06, 0x40]); 18 | assertEquals( 19 | (scrypt("password", "NaCl", 1024, 8, 16, 64)) as Uint8Array, 20 | expectedOutput, 21 | ); 22 | }); 23 | 24 | Deno.test("scrypt #3", (): void => { 25 | // dprint-ignore-next-line 26 | // deno-fmt-ignore 27 | const expectedOutput: Uint8Array = new Uint8Array([0x70, 0x23, 0xbd, 0xcb, 0x3a, 0xfd, 0x73, 0x48, 0x46, 0x1c, 0x06, 0xcd, 0x81, 0xfd, 0x38, 0xeb, 0xfd, 0xa8, 0xfb, 0xba, 0x90, 0x4f, 0x8e, 0x3e, 0xa9, 0xb5, 0x43, 0xf6, 0x54, 0x5d, 0xa1, 0xf2, 0xd5, 0x43, 0x29, 0x55, 0x61, 0x3f, 0x0f, 0xcf, 0x62, 0xd4, 0x97, 0x05, 0x24, 0x2a, 0x9a, 0xf9, 0xe6, 0x1e, 0x85, 0xdc, 0x0d, 0x65, 0x1e, 0x40, 0xdf, 0xcf, 0x01, 0x7b, 0x45, 0x57, 0x58, 0x87]); 28 | assertEquals( 29 | (scrypt( 30 | "pleaseletmein", 31 | "SodiumChloride", 32 | 16384, 33 | 8, 34 | 1, 35 | 64, 36 | )) as Uint8Array, 37 | expectedOutput, 38 | ); 39 | }); 40 | -------------------------------------------------------------------------------- /mod.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @module scrypt 3 | * @author oplik0 4 | * @version 4.4.4 5 | */ 6 | 7 | import { timingSafeEqual } from "./deps.ts"; 8 | import { 9 | decomposeFormat, 10 | detectFormat, 11 | formatPHC, 12 | formatScrypt, 13 | logN, 14 | scryptFormat, 15 | ScryptParameters, 16 | } from "./lib/format.ts"; 17 | import { to32bytes } from "./lib/helpers.ts"; 18 | import { scrypt } from "./lib/scrypt.ts"; 19 | 20 | const encoder = new TextEncoder(); 21 | 22 | /** 23 | * Hash a password with scrypt. Outputs a string in scrypt format by default. 24 | * @author oplik0 25 | * @param {string} password - Password that will be hashed 26 | * @param {ScryptParameters} [parameters] - Scrypt parameters (n, r and p) used for hashing. 27 | * @param {scryptFormat} [format="scrypt"] - format of the result. Defaults to scrypt encrypted data format (https://github.com/Tarsnap/scrypt/blob/master/FORMAT) 28 | * @param {number} [parameters.logN=17] - log2 of the work factor N. Must be an integer between 1 and 63. Defaults to 14 (N=16384) 29 | * @param {number} [parameters.r=8] - Block size. Defaults to 16 30 | * @param {number} [parameters.p=1] - Parralelism factor. Defaults to 1 31 | * @param {string} [parameters.salt] - custom salt (by default it will be randomly generated) 32 | * @param {number} [parameters.dklen=64] - desired key length (in bytes) 33 | * @param {number} [parameters.N=16384] - full number of iterations if you don't like using logN (this overrides that setting). Must be a power of 2. 34 | * @returns {string} - Hash in the chosen format (scrypt by default) 35 | */ 36 | export function hash( 37 | password: string, 38 | parameters?: ScryptParameters, 39 | format?: scryptFormat, 40 | ): string { 41 | format = format ? format : "scrypt"; 42 | parameters = parameters ?? {}; 43 | const N = parameters.N ?? 2 ** (parameters.logN ?? 17); 44 | const r = parameters.r ?? 8; 45 | const p = parameters.p ?? 1; 46 | const salt = parameters.salt 47 | ? (format === "scrypt" ? to32bytes(parameters.salt) : parameters.salt) 48 | : genSalt(32, "Uint8Array"); 49 | const dklen = parameters.dklen 50 | ? parameters.dklen 51 | : format === "phc" 52 | ? 32 53 | : 64; 54 | const scryptResult = scrypt( 55 | password, 56 | salt, 57 | N, 58 | r, 59 | p, 60 | dklen, 61 | "base64", 62 | ) as string; 63 | switch (format) { 64 | case "raw": 65 | return scryptResult; 66 | case "scrypt": 67 | return formatScrypt(scryptResult, Math.log2(N) as logN, r, p, salt); 68 | case "phc": 69 | return formatPHC(scryptResult, Math.log2(N) as logN, r, p, salt); 70 | default: 71 | throw new Error("invalid output format"); 72 | } 73 | } 74 | /** 75 | * Checks provided string against provided hash 76 | * @author oplik0 77 | * @param {string} password - string that will be checked against the hash 78 | * @param {string} testedHash - hash in a compatible format (scrypt and phc formats supported for now) 79 | * @param {scryptFormat} [format] - format of the tested hash. Will attempt to detect it automatically if it's not provided. 80 | * @returns {boolean} result of the check, true if the password matches the hash 81 | */ 82 | export function verify( 83 | password: string, 84 | testedHash: string, 85 | format?: scryptFormat, 86 | ): boolean { 87 | format = format ?? detectFormat(testedHash); 88 | const params: ScryptParameters = decomposeFormat(testedHash, format); 89 | const newHash = hash(password, params, format); 90 | return timingSafeEqual(encoder.encode(newHash), encoder.encode(testedHash)); 91 | } 92 | 93 | /** 94 | * generate random salt using Deno csprng (crypto.getRandomValues) 95 | * @author oplik0 96 | * @param {number} [length=16] - numebr of bytes to generate 97 | * @param {string} [outputType] - decide if the output should be a string or Uint8Array 98 | * @returns {string|Uint8Array} random salt 99 | */ 100 | export function genSalt( 101 | length?: number, 102 | outputType?: "string" | "Uint8Array", 103 | ): string | Uint8Array { 104 | const array = new Uint8Array(length || 32); 105 | const decoder = new TextDecoder(); 106 | const randomArray = crypto.getRandomValues(array); 107 | const salt = outputType === "Uint8Array" 108 | ? randomArray 109 | : decoder.decode(randomArray); 110 | return salt; 111 | } 112 | -------------------------------------------------------------------------------- /mod_test.ts: -------------------------------------------------------------------------------- 1 | import { assert, assertEquals } from "./deps.ts"; 2 | import { hash, verify } from "./mod.ts"; 3 | 4 | Deno.test("basic hashing - scrypt format", (): void => { 5 | const hashedPassword = hash("test-password"); 6 | assert(verify("test-password", hashedPassword)); 7 | }); 8 | Deno.test("basic hashing - PHC format", (): void => { 9 | const hashedPassword = hash("test-password", undefined, "phc"); 10 | assert(verify("test-password", hashedPassword)); 11 | }); 12 | 13 | Deno.test("basic hashing raw", (): void => { 14 | const hashedPassword = hash( 15 | "test-password", 16 | { salt: "test", logN: 14 }, // the expected hash was generated using the older default parameters, hence logN=14 instead of logN=17 17 | "raw", 18 | ); 19 | assertEquals( 20 | hashedPassword, 21 | "zu8gd0RTeX6r0dbNzBv5ZzXOAQo0UnFUw49uRXrPwAlDocpJSA43WEgAcKNlsBhLyA+zVDluz/0GFa1ShAcr6g==", 22 | ); 23 | }); 24 | // source of this test string: https://github.com/barrysteyn/node-scrypt#what-are-the-essential-properties-for-storing-passwords 25 | Deno.test("verify scrypt string", (): void => { 26 | assert( 27 | verify( 28 | "password1", 29 | "c2NyeXB0AAwAAAAIAAAAATpP+fdQAryDiRmCmcoOrZa2mZ049KdbA/ofTTrATQQ+m0L/gR811d0WQyip6p2skXVEMz2+8U+xGryFu2p0yzfCxYLUrAaIzaZELkN2M6k0", 30 | ), 31 | ); 32 | }); 33 | // source of this test string: https://passlib.readthedocs.io/en/stable/lib/passlib.hash.scrypt.html 34 | Deno.test("verify PHC string", (): void => { 35 | assert( 36 | verify( 37 | "password", 38 | "$scrypt$ln=16,r=8,p=1$aM15713r3Xsvxbi31lqr1Q$nFNh2CVHVjNldFVKDHDlm4CbdRSCdEBsjjJxD+iCs5E", 39 | ), 40 | ); 41 | }); 42 | 43 | Deno.test("reject invalid password (PHC)", (): void => { 44 | assertEquals( 45 | verify( 46 | "invalid-password", 47 | "$scrypt$ln=16,r=8,p=1$aM15713r3Xsvxbi31lqr1Q$nFNh2CVHVjNldFVKDHDlm4CbdRSCdEBsjjJxD+iCs5E", 48 | ), 49 | false, 50 | ); 51 | }); 52 | 53 | Deno.test("reject invalid password (scrypt)", (): void => { 54 | assertEquals( 55 | verify( 56 | "invalid-password", 57 | "c2NyeXB0AAwAAAAIAAAAATpP+fdQAryDiRmCmcoOrZa2mZ049KdbA/ofTTrATQQ+m0L/gR811d0WQyip6p2skXVEMz2+8U+xGryFu2p0yzfCxYLUrAaIzaZELkN2M6k0", 58 | ), 59 | false, 60 | ); 61 | }); 62 | --------------------------------------------------------------------------------