Full Code of pbhogan/scrypt for AI

master 2491ad3c9865 cached
60 files
152.2 KB
52.2k tokens
128 symbols
1 requests
Download .txt
Repository: pbhogan/scrypt
Branch: master
Commit: 2491ad3c9865
Files: 60
Total size: 152.2 KB

Directory structure:
gitextract_x0o4l56k/

├── .document
├── .github/
│   └── workflows/
│       └── ruby.yml
├── .gitignore
├── .rdoc_options
├── .rspec
├── .rubocop.yml
├── .ruby-gemset
├── .ruby-version
├── CHANGELOG.md
├── COPYING
├── Gemfile
├── README.md
├── Rakefile
├── certs/
│   ├── pbhogan.pem
│   └── stakach.pem
├── checksum/
│   └── scrypt-3.0.6.gem.sha512
├── ext/
│   ├── alt-impl/
│   │   ├── crypto_scrypt-nosse.c
│   │   └── crypto_scrypt-ref.c
│   └── scrypt/
│       ├── Rakefile
│       ├── cpusupport.h
│       ├── crypto_scrypt.c
│       ├── crypto_scrypt.h
│       ├── crypto_scrypt_internal.h
│       ├── crypto_scrypt_smix.c
│       ├── crypto_scrypt_smix.h
│       ├── crypto_scrypt_smix_sse2.c
│       ├── crypto_scrypt_smix_sse2.h
│       ├── insecure_memzero.c
│       ├── insecure_memzero.h
│       ├── memlimit.c
│       ├── memlimit.h
│       ├── scrypt_calibrate.c
│       ├── scrypt_calibrate.h
│       ├── scrypt_ext.c
│       ├── scrypt_ext.h
│       ├── scrypt_platform.h
│       ├── scryptenc_cpuperf.c
│       ├── scryptenc_cpuperf.h
│       ├── sha256.c
│       ├── sha256.h
│       ├── sysendian.h
│       ├── warnp.c
│       └── warnp.h
├── lib/
│   ├── scrypt/
│   │   ├── engine.rb
│   │   ├── errors.rb
│   │   ├── password.rb
│   │   ├── scrypt_ext.rb
│   │   ├── security_utils.rb
│   │   └── version.rb
│   └── scrypt.rb
├── scrypt.gemspec
└── spec/
    ├── fixtures/
    │   └── test_vectors.yml
    ├── scrypt/
    │   ├── engine_spec.rb
    │   ├── ffi_spec.rb
    │   ├── integration_spec.rb
    │   ├── password_spec.rb
    │   └── utils_spec.rb
    ├── spec_helper.rb
    └── support/
        ├── shared_examples.rb
        └── test_helpers.rb

================================================
FILE CONTENTS
================================================

================================================
FILE: .document
================================================
README.md
COPYING
/lib/**/*.rb


================================================
FILE: .github/workflows/ruby.yml
================================================
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby

name: Ruby

on:
  push:
    branches: [ "master" ]
  pull_request:
    branches: [ "master" ]

permissions:
  contents: read

jobs:
  test:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        # Testing on Ubuntu for the time being to avoid potential cost issues with macOS runners
        os: [ubuntu-latest]
        ruby-version: ['2.3', '2.4', '2.5', '2.6', ' 2.7', '3.0', '3.1', '3.2', '3.3', '3.4', head, jruby, jruby-head, truffleruby, truffleruby-head]

    steps:
    - uses: actions/checkout@v4
    - name: Set up Ruby
      uses: ruby/setup-ruby@v1
      with:
        ruby-version: ${{ matrix.ruby-version }}
        bundler-cache: true
    - name: Run tests
      run: bundle exec rake


================================================
FILE: .gitignore
================================================

# Created by https://www.gitignore.io/api/c,ruby,macos,rubymine,visualstudiocode
# Edit at https://www.gitignore.io/?templates=c,ruby,macos,rubymine,visualstudiocode

### C ###
# Prerequisites
*.d

# Object files
*.o
*.ko
*.obj
*.elf

# Linker output
*.ilk
*.map
*.exp

# Precompiled Headers
*.gch
*.pch

# Libraries
*.lib
*.a
*.la
*.lo

# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib

# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex

# Debug files
*.dSYM/
*.su
*.idb
*.pdb

# Kernel Module Compile Results
*.mod*
*.cmd
.tmp_versions/
modules.order
Module.symvers
Mkfile.old
dkms.conf

### macOS ###
# General
.DS_Store
.AppleDouble
.LSOverride

# Icon must end with two \r
Icon

# Thumbnails
._*

# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent

# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk

### Ruby ###
*.gem
*.rbc
/.config
/coverage/
/InstalledFiles
/pkg/
/spec/reports/
/spec/examples.txt
/test/tmp/
/test/version_tmp/
/tmp/

# Used by dotenv library to load environment variables.
# .env

# Ignore Byebug command history file.
.byebug_history

## Specific to RubyMotion:
.dat*
.repl_history
build/
*.bridgesupport
build-iPhoneOS/
build-iPhoneSimulator/

## Specific to RubyMotion (use of CocoaPods):
#
# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
# vendor/Pods/

## Documentation cache and generated files:
/.yardoc/
/_yardoc/
/doc/
/rdoc/

## Environment normalization:
/.bundle/
/vendor/bundle
/lib/bundler/man/

# for a library or gem, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
Gemfile.lock
# .ruby-version
# .ruby-gemset

# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
.rvmrc

### RubyMine ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839

# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf

# Generated files
.idea/**/contentModel.xml

# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml

# Gradle
.idea/**/gradle.xml
.idea/**/libraries

# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn.  Uncomment if using
# auto-import.
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr

# CMake
cmake-build-*/

# Mongo Explorer plugin
.idea/**/mongoSettings.xml

# File-based project format
*.iws

# IntelliJ
out/

# mpeltonen/sbt-idea plugin
.idea_modules/

# JIRA plugin
atlassian-ide-plugin.xml

# Cursive Clojure plugin
.idea/replstate.xml

# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties

# Editor-based Rest Client
.idea/httpRequests

# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser

### RubyMine Patch ###
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721

# *.iml
# modules.xml
# .idea/misc.xml
# *.ipr

# Sonarlint plugin
.idea/**/sonarlint/

# SonarQube Plugin
.idea/**/sonarIssues.xml

# Markdown Navigator plugin
.idea/**/markdown-navigator.xml
.idea/**/markdown-navigator/

### VisualStudioCode ###
.vscode/*
# !.vscode/settings.json
# !.vscode/tasks.json
# !.vscode/launch.json
# !.vscode/extensions.json

### VisualStudioCode Patch ###
# Ignore all local history of files
.history

# End of https://www.gitignore.io/api/c,ruby,macos,rubymine,visualstudiocode

*.bundle
/.idea


================================================
FILE: .rdoc_options
================================================
---
main_page: README.md
title: SCrypt Ruby Documentation

charset: UTF-8
encoding: UTF-8
force_update: true
line_numbers: true
markup: rdoc
op_dir: html
visibility: :private


================================================
FILE: .rspec
================================================
--require spec_helper
--color
--format documentation


================================================
FILE: .rubocop.yml
================================================

# require: rubocop-rspec

plugins:
  - rubocop-performance
  - rubocop-rake
  - rubocop-rspec

AllCops:
  Include:
    - Rakefile
    - ext/**/Rakefile
    - lib/**/*.{rb,rake}
    - spec/**/*.rb

  NewCops: enable
  TargetRubyVersion: 2.3

Layout/LineLength:
  Max: 120

Naming/VariableNumber:
  EnforcedStyle: snake_case


================================================
FILE: .ruby-gemset
================================================
scrypt

================================================
FILE: .ruby-version
================================================
ruby-3.4.5


================================================
FILE: CHANGELOG.md
================================================
3.0.7
-----

Changes:

* Replaced `scanf` usage to avoid the need for a runtime dependency with the upcoming Ruby 2.7.
* **Development:** Added Rubocop and rules to the project.
* Refactored:
    * Extracted (organized) `Engine`, `Errors` and `Password` class/modules into dedicated files in `scrypt` sub-directory.
    * Logic and syntax cleanup and formatting.

3.0.6
-----
Fixed:

* Expanded complication flags in support of macOS Mojave.

3.0.5
-----

Changes:

* Make `rake` development dependency not runtime

3.0.4
-----

Fixed:

* Compilation on Archlinux

3.0.3
-----

Fixed:

* ~Compilation on Archlinux~


3.0.2
-----

Fixed:

* ~~Compilation on Archlinux~~


3.0.1
-----

Fixed:

* Windows support was broken in 3.0.0


3.0.0
-----

Breaking Changes:

* None

Added:

* Updated of core scrypt ext code: https://github.com/pbhogan/scrypt/pull/53
* Support for platforms other than x86 such as ARM

2.1.1
-----

Changes:

* Uses more secure defaults: Increased max_mem from 1MB to 16MB, and salt_len from 8 to 32 bytes.
* See discussion at https://github.com/pbhogan/scrypt/issues/25

2.0.1
-----

Changes:
* Adds a `:cost` option for specifying a cost string (e.g. `'400$8$19$'`) from the `calibrate` method
  (https://github.com/pbhogan/scrypt/commit/95ce6e3e37f4b2e8681a544713bfe783d2d69466)

2.0.0
-----

Breaking Changes:

* `SCrypt::Password#hash` has been renamed to `#checksum`
  (https://github.com/pbhogan/scrypt/commit/a1a60e06ec9d863c3156ac06fda32ce82cddd759)



================================================
FILE: COPYING
================================================
Copyright 2010 Patrick Hogan <pbhogan@gmail.com>

Original implementation of scrypt by Colin Percival.
This product includes software developed by Coda Hale.

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in the
   documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
   derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


================================================
FILE: Gemfile
================================================
# frozen_string_literal: true

source 'https://rubygems.org'

gemspec

group :development, :test do
  gem 'irb'
  gem 'rdoc', '~> 6'

  gem 'rake', '~> 13'
  gem 'rspec', '~> 3'

  if RUBY_VERSION >= '3.0.0'
    gem 'rubocop', '~> 1'
    gem 'rubocop-performance', '~> 1'
    gem 'rubocop-rake', '~> 0.7'
    gem 'rubocop-rspec', '~> 3'
  end
end


================================================
FILE: README.md
================================================
# scrypt

A Ruby library providing a secure password hashing solution using the scrypt key derivation function.

[![Gem Version](https://badge.fury.io/rb/scrypt.svg)](https://badge.fury.io/rb/scrypt) [![Ruby](https://github.com/pbhogan/scrypt/actions/workflows/ruby.yml/badge.svg)](https://github.com/pbhogan/scrypt/actions/workflows/ruby.yml)

## About scrypt

The scrypt key derivation function is designed to be far more secure against hardware brute-force attacks than alternative functions such as PBKDF2 or bcrypt. It accomplishes this by being deliberately memory-intensive, making it expensive to implement in hardware.

**Key Features:**
- Memory-hard function that resists ASIC and FPGA attacks
- Configurable computational cost, memory usage, and parallelization
- Drop-in replacement for bcrypt in most applications
- Production-ready and battle-tested

**Resources:**
- [Original scrypt paper](http://www.tarsnap.com/scrypt.html)
- [GitHub repository](http://github.com/pbhogan/scrypt)

## Why you should use scrypt

![KDF comparison](https://github.com/tarcieri/scrypt/raw/modern-readme/kdf-comparison.png)

The designers of scrypt estimate that on modern (2009) hardware, if 5 seconds are spent computing a derived key, the cost of a hardware brute-force attack against scrypt is roughly 4,000 times greater than the cost of a similar attack against bcrypt (to find the same password), and 20,000 times greater than a similar attack against PBKDF2.

## Installation

Add this line to your application's Gemfile:

```ruby
gem 'scrypt'
```

And then execute:

```bash
bundle install
```

Or install it yourself as:

```bash
gem install scrypt
```

## Basic Usage

The scrypt gem works similarly to ruby-bcrypt with a few minor differences, especially regarding the cost factor configuration.

```ruby
require "scrypt"

# Hash a user's password
password = SCrypt::Password.create("my grand secret")
# => "400$8$36$78f4ae6983f76119$37ec6ce55a2b928dc56ff9a7d0cdafbd7dbde49d9282c38a40b1434e88f24cf5"

# Compare passwords
password == "my grand secret" # => true
password == "a paltry guess"  # => false
```

### Configuration Options

`Password.create` accepts several options to customize the key length, salt size, and computational cost limits:

* **`:key_len`** - Length in bytes of the generated key. Default: 32 bytes (256 bits). Range: 16-512 bytes.
* **`:salt_size`** - Size in bytes of the random salt. Default: 32 bytes (256 bits). Range: 8-32 bytes.
* **`:max_time`** - Maximum computation time in seconds. Default: 0.2 seconds.
* **`:max_mem`** - Maximum memory usage in bytes. Default: 16 MB. Set to 0 for no limit (minimum 1 MB).
* **`:max_memfrac`** - Maximum memory as a fraction of available resources. Default: 0.5. Range: 0-0.5.
* **`:cost`** - Explicit cost string from `calibrate` method (e.g., `'400$8$19$'`). When provided, `max_*` options are ignored.

**Note:** Default options result in approximately 200ms computation time with 16 MB memory usage.

## Advanced Usage

### Engine Methods

The scrypt gem provides low-level access to the scrypt algorithm through the `SCrypt::Engine` class:

```ruby
require "scrypt"

# Calibrate scrypt parameters for your system
SCrypt::Engine.calibrate
# => "400$8$25$"

# Generate a salt with default parameters
salt = SCrypt::Engine.generate_salt
# => "400$8$26$b62e0f787a5fc373"

# Hash a secret with a specific salt
SCrypt::Engine.hash_secret("my grand secret", salt)
# => "400$8$26$b62e0f787a5fc373$0399ccd4fa26642d92741b17c366b7f6bd12ccea5214987af445d2bed97bc6a2"

# Calibrate with custom memory limits and save for future use
SCrypt::Engine.calibrate!(max_mem: 16 * 1024 * 1024)
# => "4000$8$4$"

# Subsequent salt generation will use the calibrated parameters
SCrypt::Engine.generate_salt
# => "4000$8$4$c6d101522d3cb045"
```

### Password Creation with Custom Options

```ruby
# Create password with custom parameters
password = SCrypt::Password.create("my secret", {
  key_len: 64,
  salt_size: 16,
  max_time: 0.5,
  max_mem: 32 * 1024 * 1024
})

# Create password with pre-calibrated cost
cost = SCrypt::Engine.calibrate(max_time: 0.1)
password = SCrypt::Password.create("my secret", cost: cost)
```

## Usage in Rails (and the like)

```ruby
## Usage in Rails (and similar frameworks)

# Store password safely in the user model
user.update_attribute(:password, SCrypt::Password.create("my grand secret"))

# Read it back later
user.reload!
password = SCrypt::Password.new(user.password)
password == "my grand secret" # => true
```

## Security Considerations

* **Memory Safety**: The scrypt algorithm requires significant memory, making it resistant to hardware-based attacks
* **Time-Memory Trade-off**: Higher memory requirements make it expensive to parallelize attacks
* **Parameter Selection**: Use `calibrate` to find optimal parameters for your system's performance requirements
* **Salt Generation**: Always use cryptographically secure random salts (handled automatically)

## Performance Tuning

The scrypt parameters can be tuned based on your security and performance requirements:

```ruby
# For high-security applications (slower)
password = SCrypt::Password.create("secret", max_time: 1.0, max_mem: 64 * 1024 * 1024)

# For faster authentication (less secure)
password = SCrypt::Password.create("secret", max_time: 0.1, max_mem: 8 * 1024 * 1024)

# Calibrate once and reuse parameters
SCrypt::Engine.calibrate!(max_time: 0.5)
# All subsequent Password.create calls will use these parameters
```

## Error Handling

The library raises specific exceptions for different error conditions:

```ruby
begin
  SCrypt::Password.new("invalid_hash_format")
rescue SCrypt::Errors::InvalidHash => e
  puts "Invalid hash format: #{e.message}"
end

begin
  SCrypt::Engine.hash_secret(nil, "salt")
rescue SCrypt::Errors::InvalidSecret => e
  puts "Invalid secret: #{e.message}"
end
```

## Contributing

1. Fork the repository
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create a new Pull Request

## Acknowledgments

### Original scrypt Algorithm
- **Colin Percival** and **Tarsnap** for creating the scrypt key derivation function and providing the reference implementation
- The original scrypt paper: [Stronger Key Derivation via Sequential Memory-Hard Functions](http://www.tarsnap.com/scrypt.html)

### Core Collaborators

- **Patrick Hogan** ([@pbhogan](https://github.com/pbhogan))
- **Stephen von Takach** ([@stakach](https://github.com/stakach))
- **Rene van Paassen** ([@repagh](https://github.com/repagh))
- **Johanns Gregorian** ([@johanns](https://github.com/johanns))

### Special Thanks
- The Ruby community for testing and feedback
- Contributors who have submitted bug reports, feature requests, and patches
- The cryptography community for security reviews and recommendations

## License

This project is licensed under the BSD-3-Clause License - see the [COPYING](COPYING) file for details.


================================================
FILE: Rakefile
================================================
# frozen_string_literal: true

require 'bundler/setup'
require 'bundler/gem_tasks'
require 'digest/sha2'

require 'ffi'
require 'ffi-compiler/compile_task'

require 'fileutils'
require 'rake'
require 'rake/clean'
require 'rdoc/task'

require 'rspec/core/rake_task'

require 'rubygems'
require 'rubygems/package_task'

require './lib/scrypt/version'

task default: %i[clean compile_ffi spec]

desc 'Run all specs'
RSpec::Core::RakeTask.new(:spec) do |t|
  t.rspec_opts = ['--color', '--backtrace', '--format', 'documentation']
end

desc 'Generate checksum for built gem'
task :checksum do
  built_gem_path = "pkg/scrypt-#{SCrypt::VERSION}.gem"

  unless File.exist?(built_gem_path)
    puts "Gem file not found: #{built_gem_path}"
    puts "Run 'rake build' first to create the gem."
    exit 1
  end

  checksum = Digest::SHA512.new.hexdigest(File.read(built_gem_path))
  checksum_path = "checksum/scrypt-#{SCrypt::VERSION}.gem.sha512"

  # Ensure checksum directory exists
  FileUtils.mkdir_p(File.dirname(checksum_path))

  File.write(checksum_path, checksum)
  puts "Checksum written to: #{checksum_path}"
end

desc 'Compile FFI extension'
namespace :ffi_compiler do
  FFI::Compiler::CompileTask.new('ext/scrypt/scrypt_ext') do |t|
    target_cpu = RbConfig::CONFIG['target_cpu']

    t.cflags << '-Wall -std=c99'
    t.cflags << '-msse -msse2' if t.platform.arch.include?('86')
    t.cflags << '-D_GNU_SOURCE=1' if RbConfig::CONFIG['host_os'].downcase =~ /mingw/
    t.cflags << '-D_POSIX_C_SOURCE=200809L' if RbConfig::CONFIG['host_os'].downcase =~ /linux/

    if 1.size == 4 && target_cpu =~ /i386|x86_32/ && t.platform.mac?
      t.cflags << '-arch i386'
      t.ldflags << '-arch i386'
    elsif 1.size == 8 && target_cpu =~ /i686|x86_64/ && t.platform.mac?
      t.cflags << '-arch x86_64'
      t.ldflags << '-arch x86_64'
    end

    t.add_define 'WINDOWS_OS' if FFI::Platform.windows?
  end
end
task compile_ffi: ['ffi_compiler:default']

CLEAN.include('ext/scrypt/*{.o,.log,.so,.bundle}')
CLEAN.include('lib/**/*{.o,.log,.so,.bundle}')

desc 'Generate RDoc documentation'
RDoc::Task.new(:rdoc) do |rdoc|
  rdoc.rdoc_dir = 'doc/rdoc'
  rdoc.options << '--force-update'
  rdoc.options << '-V'

  rdoc.template = ENV['TEMPLATE'] if ENV['TEMPLATE']
end

desc 'Run all specs'
RSpec::Core::RakeTask.new do |_t|
  # Task automatically runs specs based on RSpec defaults
end

def gem_spec
  @gem_spec ||= Gem::Specification.load('scrypt.gemspec')
end

Gem::PackageTask.new(gem_spec) do |pkg|
  pkg.need_zip = true
  pkg.need_tar = true
  pkg.package_dir = 'pkg'
end


================================================
FILE: certs/pbhogan.pem
================================================
-----BEGIN CERTIFICATE-----
MIIEbDCCAtSgAwIBAgIBATANBgkqhkiG9w0BAQsFADA+MRAwDgYDVQQDDAdwYmhv
Z2FuMRUwEwYKCZImiZPyLGQBGRYFZ21haWwxEzARBgoJkiaJk/IsZAEZFgNjb20w
HhcNMjUwNzIyMTM1NDMxWhcNMjYwNzIyMTM1NDMxWjA+MRAwDgYDVQQDDAdwYmhv
Z2FuMRUwEwYKCZImiZPyLGQBGRYFZ21haWwxEzARBgoJkiaJk/IsZAEZFgNjb20w
ggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCSWjGKTBcJNoRa0QeIh0Au
6uAZ2daA43tu9Kst/DTB3OdsDfZnnJu9NftgmNTw7di9ZTQFH4+BrQg2/HodvZdP
+HvZecC3ZxXu/US8f+ryz70BrFz1ve+xW11bKNDlw+KkCVmlZobqYQMUuCXjU6wD
s5lGHGXiiK5tDK9US1rFqK5aV35gibpPaNRBRlEdmGKABmhhdNQw6fVDzfIWxIvE
IgeTVTvnSAmVfO8F1pH73fRL3zGWXirK8gg09i118POoT7FLtvgU6QzZu46DPhph
YMgLRK+RM+aAvVa0IH/cD94SrgHXrK82SXKgrccnYTUajiO+BemUWY82dRWWQnW6
5SSs1KYlNqo2OE5Fx6cSmcCdXermtidRj9SVVK6cp3Z+V4dNCMwe5d0PkmhbcLqH
xxIb9GFU0Tl7qVnyzuTAHkEbhGM6vTlOnggQzmDQJGT/urpUnYXkPqYiOFB58UWR
zoUJzGbzGkoyt+8IK2Wi4T0FM+iIjM+nWKfHyx1BKA8CAwEAAaN1MHMwCQYDVR0T
BAIwADALBgNVHQ8EBAMCBLAwHQYDVR0OBBYEFEF+cJzNMLtyKh6xGnlyx97tiHCl
MBwGA1UdEQQVMBOBEXBiaG9nYW5AZ21haWwuY29tMBwGA1UdEgQVMBOBEXBiaG9n
YW5AZ21haWwuY29tMA0GCSqGSIb3DQEBCwUAA4IBgQAsiXgPScyfZqqrUkaykumD
XtahlA0BcS9fchzkf21qd8w34L5I8gyz3fvAJXPAvSqZPSWEn6ud/TOxhXmG6+K/
rZ7J1iKbGpk3/yMmmkyTLsItloc4xABTRjyJ4Cy1wuJ4kdwgIW/kHTwWG0PFA1YF
ZoqZijAXbTQ4Z+wTcRiUjVpbizB4MtmaQb+Mrr+zxeEmRv/B8iZdkRCZ02C1u+T+
bwvmftjB0xuKvPmHP1KpSnFh3I4uvlykDMVSNwE0pKlGsVrzkJFf68R2YZJgDwiH
GmXe0sAsp14rX0I+JyC6a35TPrC7o1PH1zWLSJn2hBIbA/fObf8CAwNRIVHUTTUt
kr/2/0UpZZ6O3j7S8lovBRVi6Cv+P6avNYOiQpOH0kJyaSw2LMLl87D7t3JYQ0+8
rTgQJuEZY0TADK4NMJujsMEok9mO6Qfj4d+dVYdpFfuFgYf/LVnpT4sZ8bKVn0PQ
KtQ2gCSB20nUFBsuf/VRbsMWL+MxzesANGDEIrEXNS0=
-----END CERTIFICATE-----


================================================
FILE: certs/stakach.pem
================================================
-----BEGIN CERTIFICATE-----
MIIEfDCCAuSgAwIBAgIBATANBgkqhkiG9w0BAQsFADBCMQ4wDAYDVQQDDAVzdGV2
ZTEbMBkGCgmSJomT8ixkARkWC2FjYXByb2plY3RzMRMwEQYKCZImiZPyLGQBGRYD
Y29tMB4XDTE5MTExMzIzMDMwMFoXDTIwMTExMjIzMDMwMFowQjEOMAwGA1UEAwwF
c3RldmUxGzAZBgoJkiaJk/IsZAEZFgthY2Fwcm9qZWN0czETMBEGCgmSJomT8ixk
ARkWA2NvbTCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBALtarCg2Ux+m
XjcGQ6XVxRbVwwVUxGWIBfpKXzq23WOXk0NkRooyYLuxSfkA/PFVd5OLZTMP+ULr
KgM9w7+xR/Xhs/qxib/84u54H8rqHTCozYmldR5QpYTwsB4BeG0HpSbD0PGL+4N+
oa50wRyvwVBAZMG4F4QYUGnQlwBpLSm4Fhm6xhKqD9DDhbS5jgIg/S3Cr4dqghUG
kqsIGjKd6X9wIOIqF1IWLZkXiwN1IcKCJ9FO2iTBEo7UidJXROO5xs5D0Vr3iyiw
F3tmhpq1C7KkXkv0AxAxRK3SmdpIiagRukvdNFEAcpkgX6qUg62G8KMRGc3dP9lx
tBP8IonLEcpLktQakuqsV4YETQaKQb5F4WADxh1tvIPcYJUxHsw3sdHZeDywT3De
LPCNTbuBseIF33hj2qiZ77XMusgVxiqG1eaCD0X58zeVTd7ZDZUFuVKlgAudhyOi
O30rMiCHNIchQqwVNLah0Tu4KAF7PGAwJhu01qMXOEl9WCEtApOS6wIDAQABo30w
ezAJBgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQUjrc6E0haseLehiw2
JME0lZzbYKMwIAYDVR0RBBkwF4EVc3RldmVAYWNhcHJvamVjdHMuY29tMCAGA1Ud
EgQZMBeBFXN0ZXZlQGFjYXByb2plY3RzLmNvbTANBgkqhkiG9w0BAQsFAAOCAYEA
fpmwkaIoCUA8A5IDHTcGWDX5gFYwhrRLMPwvdbU3r9RUeo7slWjek1OCAH4gyLUM
K+OeWIYyQjOzeRHllNapY3AnOWbwXX7rVrYa0OxFd8JgXgVS/XJR4elzNJ0lb8En
szSDkj4xl2Yn7FDZBsT+Oq19zMKFZNSF3SYumTuLMq3AdJa3vO2Gg4I1r8oSfZBB
5V81o2GU9YTGCNrl57dmq+Iop1qVU9jF60wEXyiOz/Fkhvk+kdz2PveH8nhlpBiw
t3kOzg645P903giemoqlYZJ1XTmBqHLhflfTSxNie6my4izqFQgB9UxtUeesRtaJ
5y48Vz2twr2OQfw+1lM//SY/H9rPJkaOPDM7AlPodnZvYrr1hAlwXUebgmOq+Mvm
13PWwCGItI0lMBPfAfadtZKJQNvzl4K4Iq76ksQy3tobcrYw1r4cKTyqvrrrKhWn
93B950TkkA8h64SLwNEzV3ayjvGKTI95l0cz0B1STPIwvQecQI2j1y8/DzyztNXO
-----END CERTIFICATE-----


================================================
FILE: checksum/scrypt-3.0.6.gem.sha512
================================================
fb1b89bddfd5fa440994aad7f3edc6cce588c41018bf60ba82eab927863e243025c2e25094be2dfefdbe21a022dec62bdd072284ff83e472071791ff69bcb949

================================================
FILE: ext/alt-impl/crypto_scrypt-nosse.c
================================================
/*-
 * Copyright 2009 Colin Percival
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * This file was originally written by Colin Percival as part of the Tarsnap
 * online backup system.
 */
#include "scrypt_platform.h"

#include <sys/types.h>
#ifndef __MINGW32__
#include <sys/mman.h>
#endif

#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#include "sha256.h"
#include "sysendian.h"

#include "crypto_scrypt.h"

static void blkcpy(void *, void *, size_t);
static void blkxor(void *, void *, size_t);
static void salsa20_8(uint32_t[16]);
static void blockmix_salsa8(uint32_t *, uint32_t *, uint32_t *, size_t);
static uint64_t integerify(void *, size_t);
static void smix(uint8_t *, size_t, uint64_t, uint32_t *, uint32_t *);

static void
blkcpy(void * dest, void * src, size_t len)
{
	size_t * D = dest;
	size_t * S = src;
	size_t L = len / sizeof(size_t);
	size_t i;

	for (i = 0; i < L; i++)
		D[i] = S[i];
}

static void
blkxor(void * dest, void * src, size_t len)
{
	size_t * D = dest;
	size_t * S = src;
	size_t L = len / sizeof(size_t);
	size_t i;

	for (i = 0; i < L; i++)
		D[i] ^= S[i];
}

/**
 * salsa20_8(B):
 * Apply the salsa20/8 core to the provided block.
 */
static void
salsa20_8(uint32_t B[16])
{
	uint32_t x[16];
	size_t i;

	blkcpy(x, B, 64);
	for (i = 0; i < 8; i += 2) {
#define R(a,b) (((a) << (b)) | ((a) >> (32 - (b))))
		/* Operate on columns. */
		x[ 4] ^= R(x[ 0]+x[12], 7);  x[ 8] ^= R(x[ 4]+x[ 0], 9);
		x[12] ^= R(x[ 8]+x[ 4],13);  x[ 0] ^= R(x[12]+x[ 8],18);

		x[ 9] ^= R(x[ 5]+x[ 1], 7);  x[13] ^= R(x[ 9]+x[ 5], 9);
		x[ 1] ^= R(x[13]+x[ 9],13);  x[ 5] ^= R(x[ 1]+x[13],18);

		x[14] ^= R(x[10]+x[ 6], 7);  x[ 2] ^= R(x[14]+x[10], 9);
		x[ 6] ^= R(x[ 2]+x[14],13);  x[10] ^= R(x[ 6]+x[ 2],18);

		x[ 3] ^= R(x[15]+x[11], 7);  x[ 7] ^= R(x[ 3]+x[15], 9);
		x[11] ^= R(x[ 7]+x[ 3],13);  x[15] ^= R(x[11]+x[ 7],18);

		/* Operate on rows. */
		x[ 1] ^= R(x[ 0]+x[ 3], 7);  x[ 2] ^= R(x[ 1]+x[ 0], 9);
		x[ 3] ^= R(x[ 2]+x[ 1],13);  x[ 0] ^= R(x[ 3]+x[ 2],18);

		x[ 6] ^= R(x[ 5]+x[ 4], 7);  x[ 7] ^= R(x[ 6]+x[ 5], 9);
		x[ 4] ^= R(x[ 7]+x[ 6],13);  x[ 5] ^= R(x[ 4]+x[ 7],18);

		x[11] ^= R(x[10]+x[ 9], 7);  x[ 8] ^= R(x[11]+x[10], 9);
		x[ 9] ^= R(x[ 8]+x[11],13);  x[10] ^= R(x[ 9]+x[ 8],18);

		x[12] ^= R(x[15]+x[14], 7);  x[13] ^= R(x[12]+x[15], 9);
		x[14] ^= R(x[13]+x[12],13);  x[15] ^= R(x[14]+x[13],18);
#undef R
	}
	for (i = 0; i < 16; i++)
		B[i] += x[i];
}

/**
 * blockmix_salsa8(Bin, Bout, X, r):
 * Compute Bout = BlockMix_{salsa20/8, r}(Bin).  The input Bin must be 128r
 * bytes in length; the output Bout must also be the same size.  The
 * temporary space X must be 64 bytes.
 */
static void
blockmix_salsa8(uint32_t * Bin, uint32_t * Bout, uint32_t * X, size_t r)
{
	size_t i;

	/* 1: X <-- B_{2r - 1} */
	blkcpy(X, &Bin[(2 * r - 1) * 16], 64);

	/* 2: for i = 0 to 2r - 1 do */
	for (i = 0; i < 2 * r; i += 2) {
		/* 3: X <-- H(X \xor B_i) */
		blkxor(X, &Bin[i * 16], 64);
		salsa20_8(X);

		/* 4: Y_i <-- X */
		/* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */
		blkcpy(&Bout[i * 8], X, 64);

		/* 3: X <-- H(X \xor B_i) */
		blkxor(X, &Bin[i * 16 + 16], 64);
		salsa20_8(X);

		/* 4: Y_i <-- X */
		/* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */
		blkcpy(&Bout[i * 8 + r * 16], X, 64);
	}
}

/**
 * integerify(B, r):
 * Return the result of parsing B_{2r-1} as a little-endian integer.
 */
static uint64_t
integerify(void * B, size_t r)
{
	uint32_t * X = (void *)((uintptr_t)(B) + (2 * r - 1) * 64);

	return (((uint64_t)(X[1]) << 32) + X[0]);
}

/**
 * smix(B, r, N, V, XY):
 * Compute B = SMix_r(B, N).  The input B must be 128r bytes in length;
 * the temporary storage V must be 128rN bytes in length; the temporary
 * storage XY must be 256r + 64 bytes in length.  The value N must be a
 * power of 2 greater than 1.  The arrays B, V, and XY must be aligned to a
 * multiple of 64 bytes.
 */
static void
smix(uint8_t * B, size_t r, uint64_t N, uint32_t * V, uint32_t * XY)
{
	uint32_t * X = XY;
	uint32_t * Y = &XY[32 * r];
	uint32_t * Z = &XY[64 * r];
	uint64_t i;
	uint64_t j;
	size_t k;

	/* 1: X <-- B */
	for (k = 0; k < 32 * r; k++)
		X[k] = le32dec(&B[4 * k]);

	/* 2: for i = 0 to N - 1 do */
	for (i = 0; i < N; i += 2) {
		/* 3: V_i <-- X */
		blkcpy(&V[i * (32 * r)], X, 128 * r);

		/* 4: X <-- H(X) */
		blockmix_salsa8(X, Y, Z, r);

		/* 3: V_i <-- X */
		blkcpy(&V[(i + 1) * (32 * r)], Y, 128 * r);

		/* 4: X <-- H(X) */
		blockmix_salsa8(Y, X, Z, r);
	}

	/* 6: for i = 0 to N - 1 do */
	for (i = 0; i < N; i += 2) {
		/* 7: j <-- Integerify(X) mod N */
		j = integerify(X, r) & (N - 1);

		/* 8: X <-- H(X \xor V_j) */
		blkxor(X, &V[j * (32 * r)], 128 * r);
		blockmix_salsa8(X, Y, Z, r);

		/* 7: j <-- Integerify(X) mod N */
		j = integerify(Y, r) & (N - 1);

		/* 8: X <-- H(X \xor V_j) */
		blkxor(Y, &V[j * (32 * r)], 128 * r);
		blockmix_salsa8(Y, X, Z, r);
	}

	/* 10: B' <-- X */
	for (k = 0; k < 32 * r; k++)
		le32enc(&B[4 * k], X[k]);
}

/**
 * crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen):
 * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r,
 * p, buflen) and write the result into buf.  The parameters r, p, and buflen
 * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32.  The parameter N
 * must be a power of 2 greater than 1.
 *
 * Return 0 on success; or -1 on error.
 */
int
crypto_scrypt(const uint8_t * passwd, size_t passwdlen,
    const uint8_t * salt, size_t saltlen, uint64_t N, uint32_t _r, uint32_t _p,
    uint8_t * buf, size_t buflen)
{
	void * B0, * V0, * XY0;
	uint8_t * B;
	uint32_t * V;
	uint32_t * XY;
	size_t r = _r, p = _p;
	uint32_t i;

	/* Sanity-check parameters. */
#if SIZE_MAX > UINT32_MAX
	if (buflen > (((uint64_t)(1) << 32) - 1) * 32) {
		errno = EFBIG;
		goto err0;
	}
#endif
	if ((uint64_t)(r) * (uint64_t)(p) >= (1 << 30)) {
		errno = EFBIG;
		goto err0;
	}
	if (((N & (N - 1)) != 0) || (N < 2)) {
		errno = EINVAL;
		goto err0;
	}
	if ((r > SIZE_MAX / 128 / p) ||
#if SIZE_MAX / 256 <= UINT32_MAX
	    (r > SIZE_MAX / 256) ||
#endif
	    (N > SIZE_MAX / 128 / r)) {
		errno = ENOMEM;
		goto err0;
	}

	/* Allocate memory. */
#ifdef HAVE_POSIX_MEMALIGN
	if ((errno = posix_memalign(&B0, 64, 128 * r * p)) != 0)
		goto err0;
	B = (uint8_t *)(B0);
	if ((errno = posix_memalign(&XY0, 64, 256 * r + 64)) != 0)
		goto err1;
	XY = (uint32_t *)(XY0);
#ifndef MAP_ANON
	if ((errno = posix_memalign(&V0, 64, 128 * r * N)) != 0)
		goto err2;
	V = (uint32_t *)(V0);
#endif
#else
	if ((B0 = malloc(128 * r * p + 63)) == NULL)
		goto err0;
	B = (uint8_t *)(((uintptr_t)(B0) + 63) & ~ (uintptr_t)(63));
	if ((XY0 = malloc(256 * r + 64 + 63)) == NULL)
		goto err1;
	XY = (uint32_t *)(((uintptr_t)(XY0) + 63) & ~ (uintptr_t)(63));
#ifndef MAP_ANON
	if ((V0 = malloc(128 * r * N + 63)) == NULL)
		goto err2;
	V = (uint32_t *)(((uintptr_t)(V0) + 63) & ~ (uintptr_t)(63));
#endif
#endif
#ifdef MAP_ANON
	if ((V0 = mmap(NULL, 128 * r * N, PROT_READ | PROT_WRITE,
#ifdef MAP_NOCORE
	    MAP_ANON | MAP_PRIVATE | MAP_NOCORE,
#else
	    MAP_ANON | MAP_PRIVATE,
#endif
	    -1, 0)) == MAP_FAILED)
		goto err2;
	V = (uint32_t *)(V0);
#endif

	/* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */
	PBKDF2_scrypt_SHA256(passwd, passwdlen, salt, saltlen, 1, B, p * 128 * r);

	/* 2: for i = 0 to p - 1 do */
	for (i = 0; i < p; i++) {
		/* 3: B_i <-- MF(B_i, N) */
		smix(&B[i * 128 * r], r, N, V, XY);
	}

	/* 5: DK <-- PBKDF2(P, B, 1, dkLen) */
	PBKDF2_scrypt_SHA256(passwd, passwdlen, B, p * 128 * r, 1, buf, buflen);

	/* Free memory. */
#ifdef MAP_ANON
	if (munmap(V0, 128 * r * N))
		goto err2;
#else
	free(V0);
#endif
	free(XY0);
	free(B0);

	/* Success! */
	return (0);

err2:
	free(XY0);
err1:
	free(B0);
err0:
	/* Failure! */
	return (-1);
}


================================================
FILE: ext/alt-impl/crypto_scrypt-ref.c
================================================
/*-
 * Copyright 2009 Colin Percival
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * This file was originally written by Colin Percival as part of the Tarsnap
 * online backup system.
 */
#include "scrypt_platform.h"

#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#include "sha256.h"
#include "sysendian.h"

#include "crypto_scrypt.h"

static void blkcpy(uint8_t *, uint8_t *, size_t);
static void blkxor(uint8_t *, uint8_t *, size_t);
static void salsa20_8(uint8_t[64]);
static void blockmix_salsa8(uint8_t *, uint8_t *, size_t);
static uint64_t integerify(uint8_t *, size_t);
static void smix(uint8_t *, size_t, uint64_t, uint8_t *, uint8_t *);

static void
blkcpy(uint8_t * dest, uint8_t * src, size_t len)
{
	size_t i;

	for (i = 0; i < len; i++)
		dest[i] = src[i];
}

static void
blkxor(uint8_t * dest, uint8_t * src, size_t len)
{
	size_t i;

	for (i = 0; i < len; i++)
		dest[i] ^= src[i];
}

/**
 * salsa20_8(B):
 * Apply the salsa20/8 core to the provided block.
 */
static void
salsa20_8(uint8_t B[64])
{
	uint32_t B32[16];
	uint32_t x[16];
	size_t i;

	/* Convert little-endian values in. */
	for (i = 0; i < 16; i++)
		B32[i] = le32dec(&B[i * 4]);

	/* Compute x = doubleround^4(B32). */
	for (i = 0; i < 16; i++)
		x[i] = B32[i];
	for (i = 0; i < 8; i += 2) {
#define R(a,b) (((a) << (b)) | ((a) >> (32 - (b))))
		/* Operate on columns. */
		x[ 4] ^= R(x[ 0]+x[12], 7);  x[ 8] ^= R(x[ 4]+x[ 0], 9);
		x[12] ^= R(x[ 8]+x[ 4],13);  x[ 0] ^= R(x[12]+x[ 8],18);

		x[ 9] ^= R(x[ 5]+x[ 1], 7);  x[13] ^= R(x[ 9]+x[ 5], 9);
		x[ 1] ^= R(x[13]+x[ 9],13);  x[ 5] ^= R(x[ 1]+x[13],18);

		x[14] ^= R(x[10]+x[ 6], 7);  x[ 2] ^= R(x[14]+x[10], 9);
		x[ 6] ^= R(x[ 2]+x[14],13);  x[10] ^= R(x[ 6]+x[ 2],18);

		x[ 3] ^= R(x[15]+x[11], 7);  x[ 7] ^= R(x[ 3]+x[15], 9);
		x[11] ^= R(x[ 7]+x[ 3],13);  x[15] ^= R(x[11]+x[ 7],18);

		/* Operate on rows. */
		x[ 1] ^= R(x[ 0]+x[ 3], 7);  x[ 2] ^= R(x[ 1]+x[ 0], 9);
		x[ 3] ^= R(x[ 2]+x[ 1],13);  x[ 0] ^= R(x[ 3]+x[ 2],18);

		x[ 6] ^= R(x[ 5]+x[ 4], 7);  x[ 7] ^= R(x[ 6]+x[ 5], 9);
		x[ 4] ^= R(x[ 7]+x[ 6],13);  x[ 5] ^= R(x[ 4]+x[ 7],18);

		x[11] ^= R(x[10]+x[ 9], 7);  x[ 8] ^= R(x[11]+x[10], 9);
		x[ 9] ^= R(x[ 8]+x[11],13);  x[10] ^= R(x[ 9]+x[ 8],18);

		x[12] ^= R(x[15]+x[14], 7);  x[13] ^= R(x[12]+x[15], 9);
		x[14] ^= R(x[13]+x[12],13);  x[15] ^= R(x[14]+x[13],18);
#undef R
	}

	/* Compute B32 = B32 + x. */
	for (i = 0; i < 16; i++)
		B32[i] += x[i];

	/* Convert little-endian values out. */
	for (i = 0; i < 16; i++)
		le32enc(&B[4 * i], B32[i]);
}

/**
 * blockmix_salsa8(B, Y, r):
 * Compute B = BlockMix_{salsa20/8, r}(B).  The input B must be 128r bytes in
 * length; the temporary space Y must also be the same size.
 */
static void
blockmix_salsa8(uint8_t * B, uint8_t * Y, size_t r)
{
	uint8_t X[64];
	size_t i;

	/* 1: X <-- B_{2r - 1} */
	blkcpy(X, &B[(2 * r - 1) * 64], 64);

	/* 2: for i = 0 to 2r - 1 do */
	for (i = 0; i < 2 * r; i++) {
		/* 3: X <-- H(X \xor B_i) */
		blkxor(X, &B[i * 64], 64);
		salsa20_8(X);

		/* 4: Y_i <-- X */
		blkcpy(&Y[i * 64], X, 64);
	}

	/* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */
	for (i = 0; i < r; i++)
		blkcpy(&B[i * 64], &Y[(i * 2) * 64], 64);
	for (i = 0; i < r; i++)
		blkcpy(&B[(i + r) * 64], &Y[(i * 2 + 1) * 64], 64);
}

/**
 * integerify(B, r):
 * Return the result of parsing B_{2r-1} as a little-endian integer.
 */
static uint64_t
integerify(uint8_t * B, size_t r)
{
	uint8_t * X = &B[(2 * r - 1) * 64];

	return (le64dec(X));
}

/**
 * smix(B, r, N, V, XY):
 * Compute B = SMix_r(B, N).  The input B must be 128r bytes in length; the
 * temporary storage V must be 128rN bytes in length; the temporary storage
 * XY must be 256r bytes in length.  The value N must be a power of 2.
 */
static void
smix(uint8_t * B, size_t r, uint64_t N, uint8_t * V, uint8_t * XY)
{
	uint8_t * X = XY;
	uint8_t * Y = &XY[128 * r];
	uint64_t i;
	uint64_t j;

	/* 1: X <-- B */
	blkcpy(X, B, 128 * r);

	/* 2: for i = 0 to N - 1 do */
	for (i = 0; i < N; i++) {
		/* 3: V_i <-- X */
		blkcpy(&V[i * (128 * r)], X, 128 * r);

		/* 4: X <-- H(X) */
		blockmix_salsa8(X, Y, r);
	}

	/* 6: for i = 0 to N - 1 do */
	for (i = 0; i < N; i++) {
		/* 7: j <-- Integerify(X) mod N */
		j = integerify(X, r) & (N - 1);

		/* 8: X <-- H(X \xor V_j) */
		blkxor(X, &V[j * (128 * r)], 128 * r);
		blockmix_salsa8(X, Y, r);
	}

	/* 10: B' <-- X */
	blkcpy(B, X, 128 * r);
}

/**
 * crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen):
 * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r,
 * p, buflen) and write the result into buf.  The parameters r, p, and buflen
 * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32.  The parameter N
 * must be a power of 2.
 *
 * Return 0 on success; or -1 on error.
 */
int
crypto_scrypt(const uint8_t * passwd, size_t passwdlen,
    const uint8_t * salt, size_t saltlen, uint64_t N, uint32_t _r, uint32_t _p,
    uint8_t * buf, size_t buflen)
{
	uint8_t * B;
	uint8_t * V;
	uint8_t * XY;
	size_t r = _r, p = _p;
	uint32_t i;

	/* Sanity-check parameters. */
#if SIZE_MAX > UINT32_MAX
	if (buflen > (((uint64_t)(1) << 32) - 1) * 32) {
		errno = EFBIG;
		goto err0;
	}
#endif
	if ((uint64_t)(r) * (uint64_t)(p) >= (1 << 30)) {
		errno = EFBIG;
		goto err0;
	}
	if (((N & (N - 1)) != 0) || (N == 0)) {
		errno = EINVAL;
		goto err0;
	}
	if ((r > SIZE_MAX / 128 / p) ||
#if SIZE_MAX / 256 <= UINT32_MAX
	    (r > SIZE_MAX / 256) ||
#endif
	    (N > SIZE_MAX / 128 / r)) {
		errno = ENOMEM;
		goto err0;
	}

	/* Allocate memory. */
	if ((B = malloc(128 * r * p)) == NULL)
		goto err0;
	if ((XY = malloc(256 * r)) == NULL)
		goto err1;
	if ((V = malloc(128 * r * N)) == NULL)
		goto err2;

	/* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */
	PBKDF2_scrypt_SHA256(passwd, passwdlen, salt, saltlen, 1, B, p * 128 * r);

	/* 2: for i = 0 to p - 1 do */
	for (i = 0; i < p; i++) {
		/* 3: B_i <-- MF(B_i, N) */
		smix(&B[i * 128 * r], r, N, V, XY);
	}

	/* 5: DK <-- PBKDF2(P, B, 1, dkLen) */
	PBKDF2_scrypt_SHA256(passwd, passwdlen, B, p * 128 * r, 1, buf, buflen);

	/* Free memory. */
	free(V);
	free(XY);
	free(B);

	/* Success! */
	return (0);

err2:
	free(XY);
err1:
	free(B);
err0:
	/* Failure! */
	return (-1);
}


================================================
FILE: ext/scrypt/Rakefile
================================================
require 'ffi-compiler/compile_task'

target_cpu = RbConfig::CONFIG['target_cpu']

FFI::Compiler::CompileTask.new('scrypt_ext') do |t|
  t.cflags << '-Wall -std=c99'
  t.cflags << '-msse -msse2' if t.platform.arch.include? '86'
  t.cflags << '-D_GNU_SOURCE=1' if RbConfig::CONFIG['host_os'].downcase =~ /mingw/
  t.cflags << '-D_POSIX_C_SOURCE=200809L' if RbConfig::CONFIG['host_os'].downcase =~ /linux/

  if 1.size == 4 && target_cpu =~ /i386|x86_32/ && t.platform.mac?
    t.cflags << '-arch i386'
    t.ldflags << '-arch i386'
  elsif 1.size == 8 && target_cpu =~ /i686|x86_64/ && t.platform.mac?
    t.cflags << '-arch x86_64'
    t.ldflags << '-arch x86_64'
  end

  t.export '../../lib/scrypt/scrypt_ext.rb'

  t.add_define 'WINDOWS_OS' if FFI::Platform.windows?
end


================================================
FILE: ext/scrypt/cpusupport.h
================================================
#ifndef _CPUSUPPORT_H_
#define _CPUSUPPORT_H_

/*
 * To enable support for non-portable CPU features at compile time, one or
 * more CPUSUPPORT_ARCH_FEATURE macros should be defined.  This can be done
 * directly on the compiler command line via -D CPUSUPPORT_ARCH_FEATURE or
 * -D CPUSUPPORT_ARCH_FEATURE=1; or a file can be created with the
 * necessary #define lines and then -D CPUSUPPORT_CONFIG_FILE=cpuconfig.h
 * (or similar) can be provided to include that file here.
 */
#ifdef CPUSUPPORT_CONFIG_FILE
#include CPUSUPPORT_CONFIG_FILE
#endif

/**
 * The CPUSUPPORT_FEATURE macro declares the necessary variables and
 * functions for detecting CPU feature support at run time.  The function
 * defined in the macro acts to cache the result of the ..._detect function
 * using the ..._present and ..._init variables.  The _detect function and the
 * _present and _init variables are turn defined by CPUSUPPORT_FEATURE_DECL in
 * appropriate cpusupport_foo_bar.c file.
 *
 * In order to allow CPUSUPPORT_FEATURE to be used for features which do not
 * have corresponding CPUSUPPORT_FEATURE_DECL blocks in another source file,
 * we abuse the C preprocessor: If CPUSUPPORT_${enabler} is defined to 1, then
 * we access _present_1, _init_1, and _detect_1; but if it is not defined, we
 * access _present_CPUSUPPORT_${enabler} etc., which we define as static, thus
 * preventing the compiler from emitting a reference to an external symbol.
 *
 * In this way, it becomes possible to issue CPUSUPPORT_FEATURE invocations
 * for nonexistent features without running afoul of the requirement that
 * "If an identifier declared with external linkage is used... in the entire
 * program there shall be exactly one external definition" (C99 standard, 6.9
 * paragraph 5).  In practice, this means that users of the cpusupport code
 * can omit build and runtime detection files without changing the framework
 * code.
 */
#define CPUSUPPORT_FEATURE__(arch_feature, enabler, enabled)					\
	static int cpusupport_ ## arch_feature ## _present ## _CPUSUPPORT_ ## enabler;		\
	static int cpusupport_ ## arch_feature ## _init ## _CPUSUPPORT_ ## enabler;		\
	static inline int cpusupport_ ## arch_feature ## _detect ## _CPUSUPPORT_ ## enabler(void) { return (0); }	\
	extern int cpusupport_ ## arch_feature ## _present_ ## enabled;				\
	extern int cpusupport_ ## arch_feature ## _init_ ## enabled;				\
	int cpusupport_ ## arch_feature ## _detect_ ## enabled(void);				\
												\
	static inline int									\
	cpusupport_ ## arch_feature(void)							\
	{											\
												\
		if (cpusupport_ ## arch_feature ## _present_ ## enabled)			\
			return (1);								\
		else if (cpusupport_ ## arch_feature ## _init_ ## enabled)			\
			return (0);								\
		cpusupport_ ## arch_feature ## _present_ ## enabled = 				\
		    cpusupport_ ## arch_feature ## _detect_ ## enabled();			\
		cpusupport_ ## arch_feature ## _init_ ## enabled = 1;				\
		return (cpusupport_ ## arch_feature ## _present_ ## enabled); 			\
	}											\
	static void (* cpusupport_ ## arch_feature ## _dummyptr)(void);				\
	static inline void									\
	cpusupport_ ## arch_feature ## _dummyfunc(void)						\
	{											\
												\
		(void)cpusupport_ ## arch_feature ## _present ## _CPUSUPPORT_ ## enabler;	\
		(void)cpusupport_ ## arch_feature ## _init ## _CPUSUPPORT_ ## enabler;		\
		(void)cpusupport_ ## arch_feature ## _detect ## _CPUSUPPORT_ ## enabler;	\
		(void)cpusupport_ ## arch_feature ## _present_ ## enabled;			\
		(void)cpusupport_ ## arch_feature ## _init_ ## enabled;				\
		(void)cpusupport_ ## arch_feature ## _detect_ ## enabled;			\
		(void)cpusupport_ ## arch_feature ## _dummyptr;					\
	}											\
	static void (* cpusupport_ ## arch_feature ## _dummyptr)(void) = cpusupport_ ## arch_feature ## _dummyfunc;	\
	struct cpusupport_ ## arch_feature ## _dummy
#define CPUSUPPORT_FEATURE_(arch_feature, enabler, enabled)	\
	CPUSUPPORT_FEATURE__(arch_feature, enabler, enabled)
#define CPUSUPPORT_FEATURE(arch, feature, enabler)				\
	CPUSUPPORT_FEATURE_(arch ## _ ## feature, enabler, CPUSUPPORT_ ## enabler)

/*
 * CPUSUPPORT_FEATURE_DECL(arch, feature):
 * Macro which defines variables and provides a function declaration for
 * detecting the presence of "feature" on the "arch" architecture.  The
 * function body following this macro expansion must return nonzero if the
 * feature is present, or zero if the feature is not present or the detection
 * fails for any reason.
 */
#define CPUSUPPORT_FEATURE_DECL(arch, feature)				\
	int cpusupport_ ## arch ## _ ## feature ## _present_1 = 0;	\
	int cpusupport_ ## arch ## _ ## feature ## _init_1 = 0;		\
	int								\
	cpusupport_ ## arch ## _ ## feature ## _detect_1(void)

/*
 * List of features.  If a feature here is not enabled by the appropriate
 * CPUSUPPORT_ARCH_FEATURE macro being defined, it has no effect; but if the
 * relevant macro may be defined (e.g., by Build/cpusupport.sh successfully
 * compiling Build/cpusupport-ARCH-FEATURE.c) then the C file containing the
 * corresponding run-time detection code (cpusupport_arch_feature.c) must be
 * compiled and linked in.
 */
CPUSUPPORT_FEATURE(x86, aesni, X86_AESNI);
CPUSUPPORT_FEATURE(x86, sse2, X86_SSE2);

#endif /* !_CPUSUPPORT_H_ */


================================================
FILE: ext/scrypt/crypto_scrypt.c
================================================
/*-
 * Copyright 2009 Colin Percival
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * This file was originally written by Colin Percival as part of the Tarsnap
 * online backup system.
 */
/* #include "bsdtar_platform.h" */

#include <sys/types.h>
#if !defined(WINDOWS_OS)
 	#include <sys/mman.h>
 	#ifndef HAVE_MMAP
		#define HAVE_MMAP 1
 	#endif
#endif
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#include "cpusupport.h"
#include "sha256.h"
//#include "warnp.h"

#include "crypto_scrypt_smix.h"
#include "crypto_scrypt_smix_sse2.h"

#include "crypto_scrypt.h"
#include "warnp.h"

static void (*smix_func)(uint8_t *, size_t, uint64_t, void *, void *) = NULL;

/**
 * _crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen, smix):
 * Perform the requested scrypt computation, using ${smix} as the smix routine.
 */
static int
_crypto_scrypt(const uint8_t * passwd, size_t passwdlen,
    const uint8_t * salt, size_t saltlen, uint64_t N, uint32_t _r, uint32_t _p,
    uint8_t * buf, size_t buflen,
    void (*smix)(uint8_t *, size_t, uint64_t, void *, void *))
{
	void * B0, * V0, * XY0;
	uint8_t * B;
	uint32_t * V;
	uint32_t * XY;
	size_t r = _r, p = _p;
	uint32_t i;

	/* Sanity-check parameters. */
#if SIZE_MAX > UINT32_MAX
	if (buflen > (((uint64_t)(1) << 32) - 1) * 32) {
		errno = EFBIG;
		goto err0;
	}
#endif
	if ((uint64_t)(r) * (uint64_t)(p) >= (1 << 30)) {
		errno = EFBIG;
		goto err0;
	}
	if (((N & (N - 1)) != 0) || (N < 2)) {
		errno = EINVAL;
		goto err0;
	}
	if ((r > SIZE_MAX / 128 / p) ||
#if SIZE_MAX / 256 <= UINT32_MAX
	    (r > (SIZE_MAX - 64) / 256) ||
#endif
	    (N > SIZE_MAX / 128 / r)) {
		errno = ENOMEM;
		goto err0;
	}

	/* Allocate memory. */
#ifdef HAVE_POSIX_MEMALIGN
	if ((errno = posix_memalign(&B0, 64, 128 * r * p)) != 0)
		goto err0;
	B = (uint8_t *)(B0);
	if ((errno = posix_memalign(&XY0, 64, 256 * r + 64)) != 0)
		goto err1;
	XY = (uint32_t *)(XY0);
#if !defined(MAP_ANON) || !defined(HAVE_MMAP)
	if ((errno = posix_memalign(&V0, 64, 128 * r * N)) != 0)
		goto err2;
	V = (uint32_t *)(V0);
#endif
#else
	if ((B0 = malloc(128 * r * p + 63)) == NULL)
		goto err0;
	B = (uint8_t *)(((uintptr_t)(B0) + 63) & ~ (uintptr_t)(63));
	if ((XY0 = malloc(256 * r + 64 + 63)) == NULL)
		goto err1;
	XY = (uint32_t *)(((uintptr_t)(XY0) + 63) & ~ (uintptr_t)(63));
#if !defined(MAP_ANON) || !defined(HAVE_MMAP)
	if ((V0 = malloc(128 * r * N + 63)) == NULL)
		goto err2;
	V = (uint32_t *)(((uintptr_t)(V0) + 63) & ~ (uintptr_t)(63));
#endif
#endif
#if defined(MAP_ANON) && defined(HAVE_MMAP)
	if ((V0 = mmap(NULL, 128 * r * N, PROT_READ | PROT_WRITE,
#ifdef MAP_NOCORE
	    MAP_ANON | MAP_PRIVATE | MAP_NOCORE,
#else
	    MAP_ANON | MAP_PRIVATE,
#endif
	    -1, 0)) == MAP_FAILED)
		goto err2;
	V = (uint32_t *)(V0);
#endif

	/* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */
	PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, 1, B, p * 128 * r);

	/* 2: for i = 0 to p - 1 do */
	for (i = 0; i < p; i++) {
		/* 3: B_i <-- MF(B_i, N) */
		(smix)(&B[i * 128 * r], r, N, V, XY);
	}

	/* 5: DK <-- PBKDF2(P, B, 1, dkLen) */
	PBKDF2_SHA256(passwd, passwdlen, B, p * 128 * r, 1, buf, buflen);

	/* Free memory. */
#if defined(MAP_ANON) && defined(HAVE_MMAP)
	if (munmap(V0, 128 * r * N))
		goto err2;
#else
	free(V0);
#endif
	free(XY0);
	free(B0);

	/* Success! */
	return (0);

err2:
	free(XY0);
err1:
	free(B0);
err0:
	/* Failure! */
	return (-1);
}

#define TESTLEN 64
static struct scrypt_test {
	const char * passwd;
	const char * salt;
	uint64_t N;
	uint32_t r;
	uint32_t p;
	uint8_t result[TESTLEN];
} testcase = {
	.passwd = "pleaseletmein",
	.salt = "SodiumChloride",
	.N = 16,
	.r = 8,
	.p = 1,
	.result = {
		0x25, 0xa9, 0xfa, 0x20, 0x7f, 0x87, 0xca, 0x09,
		0xa4, 0xef, 0x8b, 0x9f, 0x77, 0x7a, 0xca, 0x16,
		0xbe, 0xb7, 0x84, 0xae, 0x18, 0x30, 0xbf, 0xbf,
		0xd3, 0x83, 0x25, 0xaa, 0xbb, 0x93, 0x77, 0xdf,
		0x1b, 0xa7, 0x84, 0xd7, 0x46, 0xea, 0x27, 0x3b,
		0xf5, 0x16, 0xa4, 0x6f, 0xbf, 0xac, 0xf5, 0x11,
		0xc5, 0xbe, 0xba, 0x4c, 0x4a, 0xb3, 0xac, 0xc7,
		0xfa, 0x6f, 0x46, 0x0b, 0x6c, 0x0f, 0x47, 0x7b,
	}
};

static int
testsmix(void (*smix)(uint8_t *, size_t, uint64_t, void *, void *))
{
	uint8_t hbuf[TESTLEN];

	/* Perform the computation. */
	if (_crypto_scrypt(
	    (const uint8_t *)testcase.passwd, strlen(testcase.passwd),
	    (const uint8_t *)testcase.salt, strlen(testcase.salt),
	    testcase.N, testcase.r, testcase.p, hbuf, TESTLEN, smix))
		return (-1);

	/* Does it match? */
	return (memcmp(testcase.result, hbuf, TESTLEN));
}

static void
selectsmix(void)
{

#ifdef CPUSUPPORT_X86_SSE2
	/* If we're running on an SSE2-capable CPU, try that code. */
	if (cpusupport_x86_sse2()) {
		/* If SSE2ized smix works, use it. */
		if (!testsmix(crypto_scrypt_smix_sse2)) {
			smix_func = crypto_scrypt_smix_sse2;
			return;
		}
		warn0("Disabling broken SSE2 scrypt support - please report bug!");
	}
#endif

	/* If generic smix works, use it. */
	if (!testsmix(crypto_scrypt_smix)) {
		smix_func = crypto_scrypt_smix;
		return;
	}
	warn0("Generic scrypt code is broken - please report bug!");

	/* If we get here, something really bad happened. */
	abort();
}

/**
 * crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen):
 * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r,
 * p, buflen) and write the result into buf.  The parameters r, p, and buflen
 * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32.  The parameter N
 * must be a power of 2 greater than 1.
 *
 * Return 0 on success; or -1 on error.
 */
int
crypto_scrypt(const uint8_t * passwd, size_t passwdlen,
    const uint8_t * salt, size_t saltlen, uint64_t N, uint32_t _r, uint32_t _p,
    uint8_t * buf, size_t buflen)
{

	if (smix_func == NULL)
		selectsmix();

	return (_crypto_scrypt(passwd, passwdlen, salt, saltlen, N, _r, _p,
	    buf, buflen, smix_func));
}


================================================
FILE: ext/scrypt/crypto_scrypt.h
================================================
/*-
 * Copyright 2009 Colin Percival
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * This file was originally written by Colin Percival as part of the Tarsnap
 * online backup system.
 */
#ifndef _CRYPTO_SCRYPT_H_
#define _CRYPTO_SCRYPT_H_

#include <stdint.h>
#include <unistd.h>

/**
 * crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen):
 * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r,
 * p, buflen) and write the result into buf.  The parameters r, p, and buflen
 * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32.  The parameter N
 * must be a power of 2 greater than 1.
 *
 * Return 0 on success; or -1 on error.
 */
int crypto_scrypt(const uint8_t *, size_t, const uint8_t *, size_t, uint64_t,
    uint32_t, uint32_t, uint8_t *, size_t);

#endif /* !_CRYPTO_SCRYPT_H_ */


================================================
FILE: ext/scrypt/crypto_scrypt_internal.h
================================================


================================================
FILE: ext/scrypt/crypto_scrypt_smix.c
================================================
/*-
 * Copyright 2009 Colin Percival
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * This file was originally written by Colin Percival as part of the Tarsnap
 * online backup system.
 */
#include <stdint.h>
#include <string.h>

#include "sysendian.h"

#include "crypto_scrypt_smix.h"

static void blkcpy(void *, const void *, size_t);
static void blkxor(void *, const void *, size_t);
static void salsa20_8(uint32_t[16]);
static void blockmix_salsa8(const uint32_t *, uint32_t *, uint32_t *, size_t);
static uint64_t integerify(const void *, size_t);

static void
blkcpy(void * dest, const void * src, size_t len)
{
	size_t * D = dest;
	const size_t * S = src;
	size_t L = len / sizeof(size_t);
	size_t i;

	for (i = 0; i < L; i++)
		D[i] = S[i];
}

static void
blkxor(void * dest, const void * src, size_t len)
{
	size_t * D = dest;
	const size_t * S = src;
	size_t L = len / sizeof(size_t);
	size_t i;

	for (i = 0; i < L; i++)
		D[i] ^= S[i];
}

/**
 * salsa20_8(B):
 * Apply the salsa20/8 core to the provided block.
 */
static void
salsa20_8(uint32_t B[16])
{
	uint32_t x[16];
	size_t i;

	blkcpy(x, B, 64);
	for (i = 0; i < 8; i += 2) {
#define R(a,b) (((a) << (b)) | ((a) >> (32 - (b))))
		/* Operate on columns. */
		x[ 4] ^= R(x[ 0]+x[12], 7);  x[ 8] ^= R(x[ 4]+x[ 0], 9);
		x[12] ^= R(x[ 8]+x[ 4],13);  x[ 0] ^= R(x[12]+x[ 8],18);

		x[ 9] ^= R(x[ 5]+x[ 1], 7);  x[13] ^= R(x[ 9]+x[ 5], 9);
		x[ 1] ^= R(x[13]+x[ 9],13);  x[ 5] ^= R(x[ 1]+x[13],18);

		x[14] ^= R(x[10]+x[ 6], 7);  x[ 2] ^= R(x[14]+x[10], 9);
		x[ 6] ^= R(x[ 2]+x[14],13);  x[10] ^= R(x[ 6]+x[ 2],18);

		x[ 3] ^= R(x[15]+x[11], 7);  x[ 7] ^= R(x[ 3]+x[15], 9);
		x[11] ^= R(x[ 7]+x[ 3],13);  x[15] ^= R(x[11]+x[ 7],18);

		/* Operate on rows. */
		x[ 1] ^= R(x[ 0]+x[ 3], 7);  x[ 2] ^= R(x[ 1]+x[ 0], 9);
		x[ 3] ^= R(x[ 2]+x[ 1],13);  x[ 0] ^= R(x[ 3]+x[ 2],18);

		x[ 6] ^= R(x[ 5]+x[ 4], 7);  x[ 7] ^= R(x[ 6]+x[ 5], 9);
		x[ 4] ^= R(x[ 7]+x[ 6],13);  x[ 5] ^= R(x[ 4]+x[ 7],18);

		x[11] ^= R(x[10]+x[ 9], 7);  x[ 8] ^= R(x[11]+x[10], 9);
		x[ 9] ^= R(x[ 8]+x[11],13);  x[10] ^= R(x[ 9]+x[ 8],18);

		x[12] ^= R(x[15]+x[14], 7);  x[13] ^= R(x[12]+x[15], 9);
		x[14] ^= R(x[13]+x[12],13);  x[15] ^= R(x[14]+x[13],18);
#undef R
	}
	for (i = 0; i < 16; i++)
		B[i] += x[i];
}

/**
 * blockmix_salsa8(Bin, Bout, X, r):
 * Compute Bout = BlockMix_{salsa20/8, r}(Bin).  The input Bin must be 128r
 * bytes in length; the output Bout must also be the same size.  The
 * temporary space X must be 64 bytes.
 */
static void
blockmix_salsa8(const uint32_t * Bin, uint32_t * Bout, uint32_t * X, size_t r)
{
	size_t i;

	/* 1: X <-- B_{2r - 1} */
	blkcpy(X, &Bin[(2 * r - 1) * 16], 64);

	/* 2: for i = 0 to 2r - 1 do */
	for (i = 0; i < 2 * r; i += 2) {
		/* 3: X <-- H(X \xor B_i) */
		blkxor(X, &Bin[i * 16], 64);
		salsa20_8(X);

		/* 4: Y_i <-- X */
		/* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */
		blkcpy(&Bout[i * 8], X, 64);

		/* 3: X <-- H(X \xor B_i) */
		blkxor(X, &Bin[i * 16 + 16], 64);
		salsa20_8(X);

		/* 4: Y_i <-- X */
		/* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */
		blkcpy(&Bout[i * 8 + r * 16], X, 64);
	}
}

/**
 * integerify(B, r):
 * Return the result of parsing B_{2r-1} as a little-endian integer.
 */
static uint64_t
integerify(const void * B, size_t r)
{
	const uint32_t * X = (const void *)((uintptr_t)(B) + (2 * r - 1) * 64);

	return (((uint64_t)(X[1]) << 32) + X[0]);
}

/**
 * crypto_scrypt_smix(B, r, N, V, XY):
 * Compute B = SMix_r(B, N).  The input B must be 128r bytes in length;
 * the temporary storage V must be 128rN bytes in length; the temporary
 * storage XY must be 256r + 64 bytes in length.  The value N must be a
 * power of 2 greater than 1.  The arrays B, V, and XY must be aligned to a
 * multiple of 64 bytes.
 */
void
crypto_scrypt_smix(uint8_t * B, size_t r, uint64_t N, void * _V, void * XY)
{
	uint32_t * X = XY;
	uint32_t * Y = (void *)((uint8_t *)(XY) + 128 * r);
	uint32_t * Z = (void *)((uint8_t *)(XY) + 256 * r);
	uint32_t * V = _V;
	uint64_t i;
	uint64_t j;
	size_t k;

	/* 1: X <-- B */
	for (k = 0; k < 32 * r; k++)
		X[k] = le32dec(&B[4 * k]);

	/* 2: for i = 0 to N - 1 do */
	for (i = 0; i < N; i += 2) {
		/* 3: V_i <-- X */
		blkcpy(&V[i * (32 * r)], X, 128 * r);

		/* 4: X <-- H(X) */
		blockmix_salsa8(X, Y, Z, r);

		/* 3: V_i <-- X */
		blkcpy(&V[(i + 1) * (32 * r)], Y, 128 * r);

		/* 4: X <-- H(X) */
		blockmix_salsa8(Y, X, Z, r);
	}

	/* 6: for i = 0 to N - 1 do */
	for (i = 0; i < N; i += 2) {
		/* 7: j <-- Integerify(X) mod N */
		j = integerify(X, r) & (N - 1);

		/* 8: X <-- H(X \xor V_j) */
		blkxor(X, &V[j * (32 * r)], 128 * r);
		blockmix_salsa8(X, Y, Z, r);

		/* 7: j <-- Integerify(X) mod N */
		j = integerify(Y, r) & (N - 1);

		/* 8: X <-- H(X \xor V_j) */
		blkxor(Y, &V[j * (32 * r)], 128 * r);
		blockmix_salsa8(Y, X, Z, r);
	}

	/* 10: B' <-- X */
	for (k = 0; k < 32 * r; k++)
		le32enc(&B[4 * k], X[k]);
}


================================================
FILE: ext/scrypt/crypto_scrypt_smix.h
================================================
#ifndef _CRYPTO_SCRYPT_SMIX_H_
#define _CRYPTO_SCRYPT_SMIX_H_

/**
 * crypto_scrypt_smix(B, r, N, V, XY):
 * Compute B = SMix_r(B, N).  The input B must be 128r bytes in length;
 * the temporary storage V must be 128rN bytes in length; the temporary
 * storage XY must be 256r + 64 bytes in length.  The value N must be a
 * power of 2 greater than 1.  The arrays B, V, and XY must be aligned to a
 * multiple of 64 bytes.
 */
void crypto_scrypt_smix(uint8_t *, size_t, uint64_t, void *, void *);

#endif /* !_CRYPTO_SCRYPT_SMIX_H_ */


================================================
FILE: ext/scrypt/crypto_scrypt_smix_sse2.c
================================================
/*-
 * Copyright 2009 Colin Percival
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * This file was originally written by Colin Percival as part of the Tarsnap
 * online backup system.
 */
#include "cpusupport.h"
#ifdef CPUSUPPORT_X86_SSE2

#include <emmintrin.h>
#include <stdint.h>

#include "sysendian.h"

#include "crypto_scrypt_smix_sse2.h"

static void blkcpy(void *, const void *, size_t);
static void blkxor(void *, const void *, size_t);
static void salsa20_8(__m128i *);
static void blockmix_salsa8(const __m128i *, __m128i *, __m128i *, size_t);
static uint64_t integerify(const void *, size_t);

static void
blkcpy(void * dest, const void * src, size_t len)
{
	__m128i * D = dest;
	const __m128i * S = src;
	size_t L = len / 16;
	size_t i;

	for (i = 0; i < L; i++)
		D[i] = S[i];
}

static void
blkxor(void * dest, const void * src, size_t len)
{
	__m128i * D = dest;
	const __m128i * S = src;
	size_t L = len / 16;
	size_t i;

	for (i = 0; i < L; i++)
		D[i] = _mm_xor_si128(D[i], S[i]);
}

/**
 * salsa20_8(B):
 * Apply the salsa20/8 core to the provided block.
 */
static void
salsa20_8(__m128i B[4])
{
	__m128i X0, X1, X2, X3;
	__m128i T;
	size_t i;

	X0 = B[0];
	X1 = B[1];
	X2 = B[2];
	X3 = B[3];

	for (i = 0; i < 8; i += 2) {
		/* Operate on "columns". */
		T = _mm_add_epi32(X0, X3);
		X1 = _mm_xor_si128(X1, _mm_slli_epi32(T, 7));
		X1 = _mm_xor_si128(X1, _mm_srli_epi32(T, 25));
		T = _mm_add_epi32(X1, X0);
		X2 = _mm_xor_si128(X2, _mm_slli_epi32(T, 9));
		X2 = _mm_xor_si128(X2, _mm_srli_epi32(T, 23));
		T = _mm_add_epi32(X2, X1);
		X3 = _mm_xor_si128(X3, _mm_slli_epi32(T, 13));
		X3 = _mm_xor_si128(X3, _mm_srli_epi32(T, 19));
		T = _mm_add_epi32(X3, X2);
		X0 = _mm_xor_si128(X0, _mm_slli_epi32(T, 18));
		X0 = _mm_xor_si128(X0, _mm_srli_epi32(T, 14));

		/* Rearrange data. */
		X1 = _mm_shuffle_epi32(X1, 0x93);
		X2 = _mm_shuffle_epi32(X2, 0x4E);
		X3 = _mm_shuffle_epi32(X3, 0x39);

		/* Operate on "rows". */
		T = _mm_add_epi32(X0, X1);
		X3 = _mm_xor_si128(X3, _mm_slli_epi32(T, 7));
		X3 = _mm_xor_si128(X3, _mm_srli_epi32(T, 25));
		T = _mm_add_epi32(X3, X0);
		X2 = _mm_xor_si128(X2, _mm_slli_epi32(T, 9));
		X2 = _mm_xor_si128(X2, _mm_srli_epi32(T, 23));
		T = _mm_add_epi32(X2, X3);
		X1 = _mm_xor_si128(X1, _mm_slli_epi32(T, 13));
		X1 = _mm_xor_si128(X1, _mm_srli_epi32(T, 19));
		T = _mm_add_epi32(X1, X2);
		X0 = _mm_xor_si128(X0, _mm_slli_epi32(T, 18));
		X0 = _mm_xor_si128(X0, _mm_srli_epi32(T, 14));

		/* Rearrange data. */
		X1 = _mm_shuffle_epi32(X1, 0x39);
		X2 = _mm_shuffle_epi32(X2, 0x4E);
		X3 = _mm_shuffle_epi32(X3, 0x93);
	}

	B[0] = _mm_add_epi32(B[0], X0);
	B[1] = _mm_add_epi32(B[1], X1);
	B[2] = _mm_add_epi32(B[2], X2);
	B[3] = _mm_add_epi32(B[3], X3);
}

/**
 * blockmix_salsa8(Bin, Bout, X, r):
 * Compute Bout = BlockMix_{salsa20/8, r}(Bin).  The input Bin must be 128r
 * bytes in length; the output Bout must also be the same size.  The
 * temporary space X must be 64 bytes.
 */
static void
blockmix_salsa8(const __m128i * Bin, __m128i * Bout, __m128i * X, size_t r)
{
	size_t i;

	/* 1: X <-- B_{2r - 1} */
	blkcpy(X, &Bin[8 * r - 4], 64);

	/* 2: for i = 0 to 2r - 1 do */
	for (i = 0; i < r; i++) {
		/* 3: X <-- H(X \xor B_i) */
		blkxor(X, &Bin[i * 8], 64);
		salsa20_8(X);

		/* 4: Y_i <-- X */
		/* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */
		blkcpy(&Bout[i * 4], X, 64);

		/* 3: X <-- H(X \xor B_i) */
		blkxor(X, &Bin[i * 8 + 4], 64);
		salsa20_8(X);

		/* 4: Y_i <-- X */
		/* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */
		blkcpy(&Bout[(r + i) * 4], X, 64);
	}
}

/**
 * integerify(B, r):
 * Return the result of parsing B_{2r-1} as a little-endian integer.
 * Note that B's layout is permuted compared to the generic implementation.
 */
static uint64_t
integerify(const void * B, size_t r)
{
	const uint32_t * X = (const void *)((uintptr_t)(B) + (2 * r - 1) * 64);

	return (((uint64_t)(X[13]) << 32) + X[0]);
}

/**
 * crypto_scrypt_smix_sse2(B, r, N, V, XY):
 * Compute B = SMix_r(B, N).  The input B must be 128r bytes in length;
 * the temporary storage V must be 128rN bytes in length; the temporary
 * storage XY must be 256r + 64 bytes in length.  The value N must be a
 * power of 2 greater than 1.  The arrays B, V, and XY must be aligned to a
 * multiple of 64 bytes.
 *
 * Use SSE2 instructions.
 */
void
crypto_scrypt_smix_sse2(uint8_t * B, size_t r, uint64_t N, void * V, void * XY)
{
	__m128i * X = XY;
	__m128i * Y = (void *)((uintptr_t)(XY) + 128 * r);
	__m128i * Z = (void *)((uintptr_t)(XY) + 256 * r);
	uint32_t * X32 = (void *)X;
	uint64_t i, j;
	size_t k;

	/* 1: X <-- B */
	for (k = 0; k < 2 * r; k++) {
		for (i = 0; i < 16; i++) {
			X32[k * 16 + i] =
			    le32dec(&B[(k * 16 + (i * 5 % 16)) * 4]);
		}
	}

	/* 2: for i = 0 to N - 1 do */
	for (i = 0; i < N; i += 2) {
		/* 3: V_i <-- X */
		blkcpy((void *)((uintptr_t)(V) + i * 128 * r), X, 128 * r);

		/* 4: X <-- H(X) */
		blockmix_salsa8(X, Y, Z, r);

		/* 3: V_i <-- X */
		blkcpy((void *)((uintptr_t)(V) + (i + 1) * 128 * r),
		    Y, 128 * r);

		/* 4: X <-- H(X) */
		blockmix_salsa8(Y, X, Z, r);
	}

	/* 6: for i = 0 to N - 1 do */
	for (i = 0; i < N; i += 2) {
		/* 7: j <-- Integerify(X) mod N */
		j = integerify(X, r) & (N - 1);

		/* 8: X <-- H(X \xor V_j) */
		blkxor(X, (void *)((uintptr_t)(V) + j * 128 * r), 128 * r);
		blockmix_salsa8(X, Y, Z, r);

		/* 7: j <-- Integerify(X) mod N */
		j = integerify(Y, r) & (N - 1);

		/* 8: X <-- H(X \xor V_j) */
		blkxor(Y, (void *)((uintptr_t)(V) + j * 128 * r), 128 * r);
		blockmix_salsa8(Y, X, Z, r);
	}

	/* 10: B' <-- X */
	for (k = 0; k < 2 * r; k++) {
		for (i = 0; i < 16; i++) {
			le32enc(&B[(k * 16 + (i * 5 % 16)) * 4],
			    X32[k * 16 + i]);
		}
	}
}

#endif /* CPUSUPPORT_X86_SSE2 */


================================================
FILE: ext/scrypt/crypto_scrypt_smix_sse2.h
================================================
#ifndef _CRYPTO_SCRYPT_SMIX_SSE2_H_
#define _CRYPTO_SCRYPT_SMIX_SSE2_H_

/**
 * crypto_scrypt_smix_sse2(B, r, N, V, XY):
 * Compute B = SMix_r(B, N).  The input B must be 128r bytes in length;
 * the temporary storage V must be 128rN bytes in length; the temporary
 * storage XY must be 256r + 64 bytes in length.  The value N must be a
 * power of 2 greater than 1.  The arrays B, V, and XY must be aligned to a
 * multiple of 64 bytes.
 *
 * Use SSE2 instructions.
 */
void crypto_scrypt_smix_sse2(uint8_t *, size_t, uint64_t, void *, void *);

#endif /* !_CRYPTO_SCRYPT_SMIX_SSE2_H_ */


================================================
FILE: ext/scrypt/insecure_memzero.c
================================================
#include <stddef.h>
#include <stdint.h>

#include "insecure_memzero.h"

/* Function which does the zeroing. */
static void
insecure_memzero_func(volatile void * buf, size_t len)
{
	volatile uint8_t * _buf = buf;
	size_t i;

	for (i = 0; i < len; i++)
		_buf[i] = 0;
}

/* Pointer to memory-zeroing function. */
void (* volatile insecure_memzero_ptr)(volatile void *, size_t) =
    insecure_memzero_func;


================================================
FILE: ext/scrypt/insecure_memzero.h
================================================
#ifndef _INSECURE_MEMZERO_H_
#define _INSECURE_MEMZERO_H_

#include <stddef.h>

/* Pointer to memory-zeroing function. */
extern void (* volatile insecure_memzero_ptr)(volatile void *, size_t);

/**
 * insecure_memzero(buf, len):
 * Attempt to zero ${len} bytes at ${buf} in spite of optimizing compilers'
 * best (standards-compliant) attempts to remove the buffer-zeroing.  In
 * particular, to avoid performing the zeroing, a compiler would need to
 * use optimistic devirtualization; recognize that non-volatile objects do not
 * need to be treated as volatile, even if they are accessed via volatile
 * qualified pointers; and perform link-time optimization; in addition to the
 * dead-code elimination which often causes buffer-zeroing to be elided.
 *
 * Note however that zeroing a buffer does not guarantee that the data held
 * in the buffer is not stored elsewhere; in particular, there may be copies
 * held in CPU registers or in anonymous allocations on the stack, even if
 * every named variable is successfully sanitized.  Solving the "wipe data
 * from the system" problem will require a C language extension which does not
 * yet exist.
 *
 * For more information, see:
 * http://www.daemonology.net/blog/2014-09-04-how-to-zero-a-buffer.html
 * http://www.daemonology.net/blog/2014-09-06-zeroing-buffers-is-insufficient.html
 */
static inline void
insecure_memzero(volatile void * buf, size_t len)
{

	(insecure_memzero_ptr)(buf, len);
}

#endif /* !_INSECURE_MEMZERO_H_ */


================================================
FILE: ext/scrypt/memlimit.c
================================================
/*-
 * Copyright 2009 Colin Percival
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * This file was originally written by Colin Percival as part of the Tarsnap
 * online backup system.
 */
#include "scrypt_platform.h"

#include <sys/types.h>
#ifndef __MINGW32__
#include <sys/resource.h>
#endif

#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#ifdef HAVE_SYSCTL_HW_USERMEM
#include <sys/sysctl.h>
#endif
#ifdef HAVE_SYS_SYSINFO_H
#include <sys/sysinfo.h>
#endif

#include <errno.h>
#include <stddef.h>
#include <stdint.h>
#include <unistd.h>

#ifdef DEBUG
#include <stdio.h>
#endif

#include "memlimit.h"

#ifdef HAVE_SYSCTL_HW_USERMEM
static int
memlimit_sysctl_hw_usermem(size_t * memlimit)
{
	int mib[2];
	uint8_t usermembuf[8];
	size_t usermemlen = 8;
	uint64_t usermem;

	/* Ask the kernel how much RAM we have. */
	mib[0] = CTL_HW;
	mib[1] = HW_USERMEM;
	if (sysctl(mib, 2, usermembuf, &usermemlen, NULL, 0))
		return (1);

	/*
	 * Parse as either a uint64_t or a uint32_t based on the length of
	 * output the kernel reports having copied out.  It appears that all
	 * systems providing a sysctl interface for reading integers copy
	 * them out as system-endian values, so we don't need to worry about
	 * parsing them.
	 */
	if (usermemlen == sizeof(uint64_t))
		usermem = *(uint64_t *)usermembuf;
	else if (usermemlen == sizeof(uint32_t))
		usermem = *(uint32_t *)usermembuf;
	else
		return (1);

	/* Return the sysctl value, but clamp to SIZE_MAX if necessary. */
#if UINT64_MAX > SIZE_MAX
	if (usermem > SIZE_MAX)
		*memlimit = SIZE_MAX;
	else
		*memlimit = usermem;
#else
	*memlimit = usermem;
#endif

	/* Success! */
	return (0);
}
#endif

/* If we don't HAVE_STRUCT_SYSINFO, we can't use sysinfo. */
#ifndef HAVE_STRUCT_SYSINFO
#undef HAVE_SYSINFO
#endif

/* If we don't HAVE_STRUCT_SYSINFO_TOTALRAM, we can't use sysinfo. */
#ifndef HAVE_STRUCT_SYSINFO_TOTALRAM
#undef HAVE_SYSINFO
#endif

#ifdef HAVE_SYSINFO
static int
memlimit_sysinfo(size_t * memlimit)
{
	struct sysinfo info;
	uint64_t totalmem;

	/* Get information from the kernel. */
	if (sysinfo(&info))
		return (1);
	totalmem = info.totalram;

	/* If we're on a modern kernel, adjust based on mem_unit. */
#ifdef HAVE_STRUCT_SYSINFO_MEM_UNIT
	totalmem = totalmem * info.mem_unit;
#endif

	/* Return the value, but clamp to SIZE_MAX if necessary. */
#if UINT64_MAX > SIZE_MAX
	if (totalmem > SIZE_MAX)
		*memlimit = SIZE_MAX;
	else
		*memlimit = totalmem;
#else
	*memlimit = totalmem;
#endif

	/* Success! */
	return (0);
}
#endif /* HAVE_SYSINFO */

static int
memlimit_rlimit(size_t * memlimit)
{
#ifndef __MINGW32__
	struct rlimit rl;
	uint64_t memrlimit;

	/* Find the least of... */
	memrlimit = (uint64_t)(-1);

	/* ... RLIMIT_AS... */
#ifdef RLIMIT_AS
	if (getrlimit(RLIMIT_AS, &rl))
		return (1);
	if ((rl.rlim_cur != RLIM_INFINITY) &&
	    ((uint64_t)rl.rlim_cur < memrlimit))
		memrlimit = rl.rlim_cur;
#endif

	/* ... RLIMIT_DATA... */
	if (getrlimit(RLIMIT_DATA, &rl))
		return (1);
	if ((rl.rlim_cur != RLIM_INFINITY) &&
	    ((uint64_t)rl.rlim_cur < memrlimit))
		memrlimit = rl.rlim_cur;

	/* ... and RLIMIT_RSS. */
#ifdef RLIMIT_RSS
	if (getrlimit(RLIMIT_RSS, &rl))
		return (1);
	if ((rl.rlim_cur != RLIM_INFINITY) &&
	    ((uint64_t)rl.rlim_cur < memrlimit))
		memrlimit = rl.rlim_cur;
#endif

	/* Return the value, but clamp to SIZE_MAX if necessary. */
#if UINT64_MAX > SIZE_MAX
	if (memrlimit > SIZE_MAX)
		*memlimit = SIZE_MAX;
	else
		*memlimit = memrlimit;
#else
	*memlimit = memrlimit;
#endif
#else
	*memlimit = SIZE_MAX;
#endif
	/* Success! */
	return (0);
}

#ifdef _SC_PHYS_PAGES

/* Some systems define _SC_PAGESIZE instead of _SC_PAGE_SIZE. */
#ifndef _SC_PAGE_SIZE
#define _SC_PAGE_SIZE _SC_PAGESIZE
#endif

static int
memlimit_sysconf(size_t * memlimit)
{
	long pagesize;
	long physpages;
	uint64_t totalmem;

	/* Set errno to 0 in order to distinguish "no limit" from "error". */
	errno = 0;

	/* Read the two limits. */
	if (((pagesize = sysconf(_SC_PAGE_SIZE)) == -1) ||
	    ((physpages = sysconf(_SC_PHYS_PAGES)) == -1)) {
		/* Did an error occur? */
		if (errno != 0)
			return (1);

		/* If not, there is no limit. */
		totalmem = (uint64_t)(-1);
	} else {
		/* Compute the limit. */
		totalmem = (uint64_t)(pagesize) * (uint64_t)(physpages);
	}

	/* Return the value, but clamp to SIZE_MAX if necessary. */
#if UINT64_MAX > SIZE_MAX
	if (totalmem > SIZE_MAX)
		*memlimit = SIZE_MAX;
	else
		*memlimit = totalmem;
#else
	*memlimit = totalmem;
#endif

	/* Success! */
	return (0);
}
#endif

int
memtouse(size_t maxmem, double maxmemfrac, size_t * memlimit)
{
	size_t sysctl_memlimit, sysinfo_memlimit, rlimit_memlimit;
	size_t sysconf_memlimit;
	size_t memlimit_min;
	size_t memavail;

	/* Get memory limits. */
#ifdef HAVE_SYSCTL_HW_USERMEM
	if (memlimit_sysctl_hw_usermem(&sysctl_memlimit))
		return (1);
#else
	sysctl_memlimit = (size_t)(-1);
#endif
#ifdef HAVE_SYSINFO
	if (memlimit_sysinfo(&sysinfo_memlimit))
		return (1);
#else
	sysinfo_memlimit = (size_t)(-1);
#endif
	if (memlimit_rlimit(&rlimit_memlimit))
		return (1);
#ifdef _SC_PHYS_PAGES
	if (memlimit_sysconf(&sysconf_memlimit))
		return (1);
#else
	sysconf_memlimit = (size_t)(-1);
#endif

#ifdef DEBUG
	fprintf(stderr, "Memory limits are %zu %zu %zu %zu\n",
	    sysctl_memlimit, sysinfo_memlimit, rlimit_memlimit,
	    sysconf_memlimit);
#endif

	/* Find the smallest of them. */
	memlimit_min = (size_t)(-1);
	if (memlimit_min > sysctl_memlimit)
		memlimit_min = sysctl_memlimit;
	if (memlimit_min > sysinfo_memlimit)
		memlimit_min = sysinfo_memlimit;
	if (memlimit_min > rlimit_memlimit)
		memlimit_min = rlimit_memlimit;
	if (memlimit_min > sysconf_memlimit)
		memlimit_min = sysconf_memlimit;

	/* Only use the specified fraction of the available memory. */
	if ((maxmemfrac > 0.5) || (maxmemfrac == 0.0))
		maxmemfrac = 0.5;
	memavail = maxmemfrac * memlimit_min;

	/* Don't use more than the specified maximum. */
	if ((maxmem > 0) && (memavail > maxmem))
		memavail = maxmem;

	/* But always allow at least 1 MiB. */
	if (memavail < 1048576)
		memavail = 1048576;

#ifdef DEBUG
	fprintf(stderr, "Allowing up to %zu memory to be used\n", memavail);
#endif

	/* Return limit via the provided pointer. */
	*memlimit = memavail;
	return (0);
}


================================================
FILE: ext/scrypt/memlimit.h
================================================
/*-
 * Copyright 2009 Colin Percival
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * This file was originally written by Colin Percival as part of the Tarsnap
 * online backup system.
 */
#ifndef _MEMLIMIT_H_
#define _MEMLIMIT_H_

#include <stddef.h>

/**
 * memtouse(maxmem, maxmemfrac, memlimit):
 * Examine the system and return via memlimit the amount of RAM which should
 * be used -- the specified fraction of the available RAM, but no more than
 * maxmem, and no less than 1MiB.
 */
int memtouse(size_t, double, size_t *);

#endif /* !_MEMLIMIT_H_ */


================================================
FILE: ext/scrypt/scrypt_calibrate.c
================================================
/*
 *  scrypt_calibrate.c
 *  scrypt
 *
 *  Created by Patrick Hogan on 12/15/10.
 *  Copyright 2010 __MyCompanyName__. All rights reserved.
 *
 */

#include "scrypt_platform.h"

#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "memlimit.h"
#include "scryptenc_cpuperf.h"
#include "sysendian.h"

#include "scrypt_calibrate.h"


static int
pickparams(size_t maxmem, double maxmemfrac, double maxtime, int * logN, uint32_t * r, uint32_t * p)
{
	size_t memlimit;
	double opps;
	double opslimit;
	double maxN, maxrp;
	int rc;

	/* Figure out how much memory to use. */
	if (memtouse(maxmem, maxmemfrac, &memlimit))
		return (1);

	/* Figure out how fast the CPU is. */
	if ((rc = scryptenc_cpuperf(&opps)) != 0)
		return (rc);
	opslimit = opps * maxtime;

	/* Allow a minimum of 2^15 salsa20/8 cores. */
	if (opslimit < 32768)
		opslimit = 32768;

	/* Fix r = 8 for now. */
	*r = 8;

	/*
	 * The memory limit requires that 128Nr <= memlimit, while the CPU
	 * limit requires that 4Nrp <= opslimit.  If opslimit < memlimit/32,
	 * opslimit imposes the stronger limit on N.
	 */
#ifdef DEBUG
	fprintf(stderr, "Requiring 128Nr <= %zu, 4Nrp <= %f\n",
			memlimit, opslimit);
#endif
	if (opslimit < memlimit/32) {
		/* Set p = 1 and choose N based on the CPU limit. */
		*p = 1;
		maxN = opslimit / (*r * 4);
		for (*logN = 1; *logN < 63; *logN += 1) {
			if ((uint64_t)(1) << *logN > maxN / 2)
				break;
		}
	} else {
		/* Set N based on the memory limit. */
		maxN = memlimit / (*r * 128);
		for (*logN = 1; *logN < 63; *logN += 1) {
			if ((uint64_t)(1) << *logN > maxN / 2)
				break;
		}

		/* Choose p based on the CPU limit. */
		maxrp = (opslimit / 4) / ((uint64_t)(1) << *logN);
		if (maxrp > 0x3fffffff)
			maxrp = 0x3fffffff;
		*p = (uint32_t)(maxrp) / *r;
	}

#ifdef DEBUG
	fprintf(stderr, "N = %zu r = %d p = %d\n",
			(size_t)(1) << *logN, (int)(*r), (int)(*p));
#endif

	/* Success! */
	return (0);
}

int
calibrate(size_t maxmem, double maxmemfrac, double maxtime, uint64_t * n, uint32_t * r, uint32_t * p)
{
	int logN = 0;
	int result = pickparams( maxmem, maxmemfrac, maxtime, & logN, r, p );
	if (result == 0)
	{
		*n = (uint64_t)(1) << logN;
	}
	return result;
}

================================================
FILE: ext/scrypt/scrypt_calibrate.h
================================================
/*
 *  scrypt_calibrate.h
 *  scrypt
 *
 *  Created by Patrick Hogan on 12/15/10.
 *
 */

#ifndef _SCRYPT_CALIBRATE_H_
#define _SCRYPT_CALIBRATE_H_

#include <stdint.h>
#include <stdio.h>

int calibrate( size_t maxmem, double maxmemfrac, double maxtime, uint64_t * n, uint32_t * r, uint32_t * p );

#endif




================================================
FILE: ext/scrypt/scrypt_ext.c
================================================
#include "scrypt_ext.h"
#include "scrypt_calibrate.h"
#include "crypto_scrypt.h"


typedef struct {
  uint64_t n;
  uint32_t r;
  uint32_t p;
} Calibration;


RBFFI_EXPORT int sc_calibrate(size_t maxmem, double maxmemfrac, double maxtime, Calibration *result)
{
    return calibrate(maxmem, maxmemfrac, maxtime, &result->n, &result->r, &result->p);    // 0 == success
}


================================================
FILE: ext/scrypt/scrypt_ext.h
================================================
#ifndef SCRYPT_EXT_H
#define SCRYPT_EXT_H 1

#ifndef RBFFI_EXPORT
# ifdef __cplusplus
#  define RBFFI_EXPORT extern "C"
# else
#  define RBFFI_EXPORT
# endif
#endif


#endif /* SCRYPT_EXT_H */


================================================
FILE: ext/scrypt/scrypt_platform.h
================================================
#ifndef _SCRYPT_PLATFORM_H_
#define	_SCRYPT_PLATFORM_H_

#endif


================================================
FILE: ext/scrypt/scryptenc_cpuperf.c
================================================
/*-
 * Copyright 2009 Colin Percival
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * This file was originally written by Colin Percival as part of the Tarsnap
 * online backup system.
 */
#include "scrypt_platform.h"

#include <sys/time.h>

#include <stdint.h>
#include <stdio.h>
#include <time.h>

#include "crypto_scrypt.h"

#include "scryptenc_cpuperf.h"

#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
struct timespec {
	long tv_sec;
	long tv_nsec;
};
#endif

#ifdef HAVE_CLOCK_GETTIME

static clock_t clocktouse;

static int
getclockres(double * resd)
{
	struct timespec res;

	/*
	 * Try clocks in order of preference until we find one which works.
	 * (We assume that if clock_getres works, clock_gettime will, too.)
	 * The use of if/else/if/else/if/else rather than if/elif/elif/else
	 * is ugly but legal, and allows us to #ifdef things appropriately.
	 */
#ifdef CLOCK_VIRTUAL
	if (clock_getres(CLOCK_VIRTUAL, &res) == 0)
		clocktouse = CLOCK_VIRTUAL;
	else
#endif
#ifdef CLOCK_MONOTONIC
	if (clock_getres(CLOCK_MONOTONIC, &res) == 0)
		clocktouse = CLOCK_MONOTONIC;
	else
#endif
	if (clock_getres(CLOCK_REALTIME, &res) == 0)
		clocktouse = CLOCK_REALTIME;
	else
		return (-1);

	/* Convert clock resolution to a double. */
	*resd = res.tv_sec + res.tv_nsec * 0.000000001;

	return (0);
}

static int
getclocktime(struct timespec * ts)
{

	if (clock_gettime(clocktouse, ts))
		return (-1);

	return (0);
}

#else
static int
getclockres(double * resd)
{

	*resd = 1.0 / CLOCKS_PER_SEC;

	return (0);
}

static int
getclocktime(struct timespec * ts)
{
	struct timeval tv;

	if (gettimeofday(&tv, NULL))
		return (-1);
	ts->tv_sec = tv.tv_sec;
	ts->tv_nsec = tv.tv_usec * 1000;

	return (0);
}
#endif

static int
getclockdiff(struct timespec * st, double * diffd)
{
	struct timespec en;

	if (getclocktime(&en))
		return (1);
	*diffd = (en.tv_nsec - st->tv_nsec) * 0.000000001 +
			(en.tv_sec - st->tv_sec);

	return (0);
}

/**
 * scryptenc_cpuperf(opps):
 * Estimate the number of salsa20/8 cores which can be executed per second,
 * and return the value via opps.
 */
int
scryptenc_cpuperf(double * opps)
{
	struct timespec st;
	double resd, diffd;
	uint64_t i = 0;

	/* Get the clock resolution. */
	if (getclockres(&resd))
		return (2);

#ifdef DEBUG
	fprintf(stderr, "Clock resolution is %f\n", resd);
#endif

	/* Loop until the clock ticks. */
	if (getclocktime(&st))
		return (2);
	do {
		/* Do an scrypt. */
		if (crypto_scrypt(NULL, 0, NULL, 0, 16, 1, 1, NULL, 0))
			return (3);

		/* Has the clock ticked? */
		if (getclockdiff(&st, &diffd))
			return (2);
		if (diffd > 0)
			break;
	} while (1);

	/* Count how many scrypts we can do before the next tick. */
	if (getclocktime(&st))
		return (2);
	do {
		/* Do an scrypt. */
		if (crypto_scrypt(NULL, 0, NULL, 0, 128, 1, 1, NULL, 0))
			return (3);

		/* We invoked the salsa20/8 core 512 times. */
		i += 512;

		/* Check if we have looped for long enough. */
		if (getclockdiff(&st, &diffd))
			return (2);
		if (diffd > resd)
			break;
	} while (1);

#ifdef DEBUG
	fprintf(stderr, "%ju salsa20/8 cores performed in %f seconds\n",
			(uintmax_t)i, diffd);
#endif

	/* We can do approximately i salsa20/8 cores per diffd seconds. */
	*opps = i / diffd;
	return (0);
}


================================================
FILE: ext/scrypt/scryptenc_cpuperf.h
================================================
/*-
 * Copyright 2009 Colin Percival
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * This file was originally written by Colin Percival as part of the Tarsnap
 * online backup system.
 */
#ifndef _SCRYPTENC_CPUPERF_H_
#define _SCRYPTENC_CPUPERF_H_

/**
 * scryptenc_cpuperf(opps):
 * Estimate the number of salsa20/8 cores which can be executed per second,
 * and return the value via opps.
 */
int scryptenc_cpuperf(double *);

#endif /* !_SCRYPTENC_CPUPERF_H_ */


================================================
FILE: ext/scrypt/sha256.c
================================================
#include <assert.h>
#include <stdint.h>
#include <string.h>

#include "insecure_memzero.h"
#include "sysendian.h"

#include "sha256.h"

/*
 * Encode a length len/4 vector of (uint32_t) into a length len vector of
 * (uint8_t) in big-endian form.  Assumes len is a multiple of 4.
 */
static void
be32enc_vect(uint8_t * dst, const uint32_t * src, size_t len)
{
	size_t i;

	/* Sanity-check. */
	assert(len % 4 == 0);

	/* Encode vector, one word at a time. */
	for (i = 0; i < len / 4; i++)
		be32enc(dst + i * 4, src[i]);
}

/*
 * Decode a big-endian length len vector of (uint8_t) into a length
 * len/4 vector of (uint32_t).  Assumes len is a multiple of 4.
 */
static void
be32dec_vect(uint32_t * dst, const uint8_t * src, size_t len)
{
	size_t i;

	/* Sanity-check. */
	assert(len % 4 == 0);

	/* Decode vector, one word at a time. */
	for (i = 0; i < len / 4; i++)
		dst[i] = be32dec(src + i * 4);
}

/* SHA256 round constants. */
static const uint32_t K[64] = {
	0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
	0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
	0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
	0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
	0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
	0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
	0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
	0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
	0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
	0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
	0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
	0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
	0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
	0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
	0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
	0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};

/* Elementary functions used by SHA256 */
#define Ch(x, y, z)	((x & (y ^ z)) ^ z)
#define Maj(x, y, z)	((x & (y | z)) | (y & z))
#define SHR(x, n)	(x >> n)
#define ROTR(x, n)	((x >> n) | (x << (32 - n)))
#define S0(x)		(ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
#define S1(x)		(ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
#define s0(x)		(ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3))
#define s1(x)		(ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10))

/* SHA256 round function */
#define RND(a, b, c, d, e, f, g, h, k)			\
	h += S1(e) + Ch(e, f, g) + k;			\
	d += h;						\
	h += S0(a) + Maj(a, b, c);

/* Adjusted round function for rotating state */
#define RNDr(S, W, i, ii)			\
	RND(S[(64 - i) % 8], S[(65 - i) % 8],	\
	    S[(66 - i) % 8], S[(67 - i) % 8],	\
	    S[(68 - i) % 8], S[(69 - i) % 8],	\
	    S[(70 - i) % 8], S[(71 - i) % 8],	\
	    W[i + ii] + K[i + ii])

/* Message schedule computation */
#define MSCH(W, ii, i)				\
	W[i + ii + 16] = s1(W[i + ii + 14]) + W[i + ii + 9] + s0(W[i + ii + 1]) + W[i + ii]

/*
 * SHA256 block compression function.  The 256-bit state is transformed via
 * the 512-bit input block to produce a new state.
 */
static void
SHA256_Transform(uint32_t state[static restrict 8],
    const uint8_t block[static restrict 64],
    uint32_t W[static restrict 64], uint32_t S[static restrict 8])
{
	int i;

	/* 1. Prepare the first part of the message schedule W. */
	be32dec_vect(W, block, 64);

	/* 2. Initialize working variables. */
	memcpy(S, state, 32);

	/* 3. Mix. */
	for (i = 0; i < 64; i += 16) {
		RNDr(S, W, 0, i);
		RNDr(S, W, 1, i);
		RNDr(S, W, 2, i);
		RNDr(S, W, 3, i);
		RNDr(S, W, 4, i);
		RNDr(S, W, 5, i);
		RNDr(S, W, 6, i);
		RNDr(S, W, 7, i);
		RNDr(S, W, 8, i);
		RNDr(S, W, 9, i);
		RNDr(S, W, 10, i);
		RNDr(S, W, 11, i);
		RNDr(S, W, 12, i);
		RNDr(S, W, 13, i);
		RNDr(S, W, 14, i);
		RNDr(S, W, 15, i);

		if (i == 48)
			break;
		MSCH(W, 0, i);
		MSCH(W, 1, i);
		MSCH(W, 2, i);
		MSCH(W, 3, i);
		MSCH(W, 4, i);
		MSCH(W, 5, i);
		MSCH(W, 6, i);
		MSCH(W, 7, i);
		MSCH(W, 8, i);
		MSCH(W, 9, i);
		MSCH(W, 10, i);
		MSCH(W, 11, i);
		MSCH(W, 12, i);
		MSCH(W, 13, i);
		MSCH(W, 14, i);
		MSCH(W, 15, i);
	}

	/* 4. Mix local working variables into global state. */
	for (i = 0; i < 8; i++)
		state[i] += S[i];
}

static const uint8_t PAD[64] = {
	0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};

/* Add padding and terminating bit-count. */
static void
SHA256_Pad(SHA256_CTX * ctx, uint32_t tmp32[static restrict 72])
{
	size_t r;

	/* Figure out how many bytes we have buffered. */
	r = (ctx->count >> 3) & 0x3f;

	/* Pad to 56 mod 64, transforming if we finish a block en route. */
	if (r < 56) {
		/* Pad to 56 mod 64. */
		memcpy(&ctx->buf[r], PAD, 56 - r);
	} else {
		/* Finish the current block and mix. */
		memcpy(&ctx->buf[r], PAD, 64 - r);
		SHA256_Transform(ctx->state, ctx->buf, &tmp32[0], &tmp32[64]);

		/* The start of the final block is all zeroes. */
		memset(&ctx->buf[0], 0, 56);
	}

	/* Add the terminating bit-count. */
	be64enc(&ctx->buf[56], ctx->count);

	/* Mix in the final block. */
	SHA256_Transform(ctx->state, ctx->buf, &tmp32[0], &tmp32[64]);
}

/* Magic initialization constants. */
static const uint32_t initstate[8] = {
	0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
	0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19
};

/**
 * SHA256_Init(ctx):
 * Initialize the SHA256 context ${ctx}.
 */
void
SHA256_Init(SHA256_CTX * ctx)
{

	/* Zero bits processed so far. */
	ctx->count = 0;

	/* Initialize state. */
	memcpy(ctx->state, initstate, sizeof(initstate));
}

/**
 * SHA256_Update(ctx, in, len):
 * Input ${len} bytes from ${in} into the SHA256 context ${ctx}.
 */
static void
_SHA256_Update(SHA256_CTX * ctx, const void * in, size_t len,
    uint32_t tmp32[static restrict 72])
{
	uint32_t r;
	const uint8_t * src = in;

	/* Return immediately if we have nothing to do. */
	if (len == 0)
		return;

	/* Number of bytes left in the buffer from previous updates. */
	r = (ctx->count >> 3) & 0x3f;

	/* Update number of bits. */
	ctx->count += (uint64_t)(len) << 3;

	/* Handle the case where we don't need to perform any transforms. */
	if (len < 64 - r) {
		memcpy(&ctx->buf[r], src, len);
		return;
	}

	/* Finish the current block. */
	memcpy(&ctx->buf[r], src, 64 - r);
	SHA256_Transform(ctx->state, ctx->buf, &tmp32[0], &tmp32[64]);
	src += 64 - r;
	len -= 64 - r;

	/* Perform complete blocks. */
	while (len >= 64) {
		SHA256_Transform(ctx->state, src, &tmp32[0], &tmp32[64]);
		src += 64;
		len -= 64;
	}

	/* Copy left over data into buffer. */
	memcpy(ctx->buf, src, len);
}

/* Wrapper function for intermediate-values sanitization. */
void
SHA256_Update(SHA256_CTX * ctx, const void * in, size_t len)
{
	uint32_t tmp32[72];

	/* Call the real function. */
	_SHA256_Update(ctx, in, len, tmp32);

	/* Clean the stack. */
	insecure_memzero(tmp32, 288);
}

/**
 * SHA256_Final(digest, ctx):
 * Output the SHA256 hash of the data input to the context ${ctx} into the
 * buffer ${digest}.
 */
static void
_SHA256_Final(uint8_t digest[32], SHA256_CTX * ctx,
    uint32_t tmp32[static restrict 72])
{

	/* Add padding. */
	SHA256_Pad(ctx, tmp32);

	/* Write the hash. */
	be32enc_vect(digest, ctx->state, 32);
}

/* Wrapper function for intermediate-values sanitization. */
void
SHA256_Final(uint8_t digest[32], SHA256_CTX * ctx)
{
	uint32_t tmp32[72];

	/* Call the real function. */
	_SHA256_Final(digest, ctx, tmp32);

	/* Clear the context state. */
	insecure_memzero(ctx, sizeof(SHA256_CTX));

	/* Clean the stack. */
	insecure_memzero(tmp32, 288);
}

/**
 * SHA256_Buf(in, len, digest):
 * Compute the SHA256 hash of ${len} bytes from $in} and write it to ${digest}.
 */
void
SHA256_Buf(const void * in, size_t len, uint8_t digest[32])
{
	SHA256_CTX ctx;
	uint32_t tmp32[72];

	SHA256_Init(&ctx);
	_SHA256_Update(&ctx, in, len, tmp32);
	_SHA256_Final(digest, &ctx, tmp32);

	/* Clean the stack. */
	insecure_memzero(&ctx, sizeof(SHA256_CTX));
	insecure_memzero(tmp32, 288);
}

/**
 * HMAC_SHA256_Init(ctx, K, Klen):
 * Initialize the HMAC-SHA256 context ${ctx} with ${Klen} bytes of key from
 * ${K}.
 */
static void
_HMAC_SHA256_Init(HMAC_SHA256_CTX * ctx, const void * _K, size_t Klen,
    uint32_t tmp32[static restrict 72], uint8_t pad[static restrict 64],
    uint8_t khash[static restrict 32])
{
	const uint8_t * K = _K;
	size_t i;

	/* If Klen > 64, the key is really SHA256(K). */
	if (Klen > 64) {
		SHA256_Init(&ctx->ictx);
		_SHA256_Update(&ctx->ictx, K, Klen, tmp32);
		_SHA256_Final(khash, &ctx->ictx, tmp32);
		K = khash;
		Klen = 32;
	}

	/* Inner SHA256 operation is SHA256(K xor [block of 0x36] || data). */
	SHA256_Init(&ctx->ictx);
	memset(pad, 0x36, 64);
	for (i = 0; i < Klen; i++)
		pad[i] ^= K[i];
	_SHA256_Update(&ctx->ictx, pad, 64, tmp32);

	/* Outer SHA256 operation is SHA256(K xor [block of 0x5c] || hash). */
	SHA256_Init(&ctx->octx);
	memset(pad, 0x5c, 64);
	for (i = 0; i < Klen; i++)
		pad[i] ^= K[i];
	_SHA256_Update(&ctx->octx, pad, 64, tmp32);
}

/* Wrapper function for intermediate-values sanitization. */
void
HMAC_SHA256_Init(HMAC_SHA256_CTX * ctx, const void * _K, size_t Klen)
{
	uint32_t tmp32[72];
	uint8_t pad[64];
	uint8_t khash[32];

	/* Call the real function. */
	_HMAC_SHA256_Init(ctx, _K, Klen, tmp32, pad, khash);

	/* Clean the stack. */
	insecure_memzero(tmp32, 288);
	insecure_memzero(khash, 32);
	insecure_memzero(pad, 64);
}

/**
 * HMAC_SHA256_Update(ctx, in, len):
 * Input ${len} bytes from ${in} into the HMAC-SHA256 context ${ctx}.
 */
static void
_HMAC_SHA256_Update(HMAC_SHA256_CTX * ctx, const void * in, size_t len,
    uint32_t tmp32[static restrict 72])
{

	/* Feed data to the inner SHA256 operation. */
	_SHA256_Update(&ctx->ictx, in, len, tmp32);
}

/* Wrapper function for intermediate-values sanitization. */
void
HMAC_SHA256_Update(HMAC_SHA256_CTX * ctx, const void * in, size_t len)
{
	uint32_t tmp32[72];

	/* Call the real function. */
	_HMAC_SHA256_Update(ctx, in, len, tmp32);

	/* Clean the stack. */
	insecure_memzero(tmp32, 288);
}

/**
 * HMAC_SHA256_Final(digest, ctx):
 * Output the HMAC-SHA256 of the data input to the context ${ctx} into the
 * buffer ${digest}.
 */
static void
_HMAC_SHA256_Final(uint8_t digest[32], HMAC_SHA256_CTX * ctx,
    uint32_t tmp32[static restrict 72], uint8_t ihash[static restrict 32])
{

	/* Finish the inner SHA256 operation. */
	_SHA256_Final(ihash, &ctx->ictx, tmp32);

	/* Feed the inner hash to the outer SHA256 operation. */
	_SHA256_Update(&ctx->octx, ihash, 32, tmp32);

	/* Finish the outer SHA256 operation. */
	_SHA256_Final(digest, &ctx->octx, tmp32);
}

/* Wrapper function for intermediate-values sanitization. */
void
HMAC_SHA256_Final(uint8_t digest[32], HMAC_SHA256_CTX * ctx)
{
	uint32_t tmp32[72];
	uint8_t ihash[32];

	/* Call the real function. */
	_HMAC_SHA256_Final(digest, ctx, tmp32, ihash);

	/* Clean the stack. */
	insecure_memzero(tmp32, 288);
	insecure_memzero(ihash, 32);
}

/**
 * HMAC_SHA256_Buf(K, Klen, in, len, digest):
 * Compute the HMAC-SHA256 of ${len} bytes from ${in} using the key ${K} of
 * length ${Klen}, and write the result to ${digest}.
 */
void
HMAC_SHA256_Buf(const void * K, size_t Klen, const void * in, size_t len,
    uint8_t digest[32])
{
	HMAC_SHA256_CTX ctx;
	uint32_t tmp32[72];
	uint8_t tmp8[96];

	_HMAC_SHA256_Init(&ctx, K, Klen, tmp32, &tmp8[0], &tmp8[64]);
	_HMAC_SHA256_Update(&ctx, in, len, tmp32);
	_HMAC_SHA256_Final(digest, &ctx, tmp32, &tmp8[0]);

	/* Clean the stack. */
	insecure_memzero(&ctx, sizeof(HMAC_SHA256_CTX));
	insecure_memzero(tmp32, 288);
	insecure_memzero(tmp8, 96);
}

/**
 * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen):
 * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and
 * write the output to buf.  The value dkLen must be at most 32 * (2^32 - 1).
 */
void
PBKDF2_SHA256(const uint8_t * passwd, size_t passwdlen, const uint8_t * salt,
    size_t saltlen, uint64_t c, uint8_t * buf, size_t dkLen)
{
	HMAC_SHA256_CTX Phctx, PShctx, hctx;
	uint32_t tmp32[72];
	uint8_t tmp8[96];
	size_t i;
	uint8_t ivec[4];
	uint8_t U[32];
	uint8_t T[32];
	uint64_t j;
	int k;
	size_t clen;

	/* Sanity-check. */
	assert(dkLen <= 32 * (size_t)(UINT32_MAX));

	/* Compute HMAC state after processing P. */
	_HMAC_SHA256_Init(&Phctx, passwd, passwdlen,
	    tmp32, &tmp8[0], &tmp8[64]);

	/* Compute HMAC state after processing P and S. */
	memcpy(&PShctx, &Phctx, sizeof(HMAC_SHA256_CTX));
	_HMAC_SHA256_Update(&PShctx, salt, saltlen, tmp32);

	/* Iterate through the blocks. */
	for (i = 0; i * 32 < dkLen; i++) {
		/* Generate INT(i + 1). */
		be32enc(ivec, (uint32_t)(i + 1));

		/* Compute U_1 = PRF(P, S || INT(i)). */
		memcpy(&hctx, &PShctx, sizeof(HMAC_SHA256_CTX));
		_HMAC_SHA256_Update(&hctx, ivec, 4, tmp32);
		_HMAC_SHA256_Final(U, &hctx, tmp32, tmp8);

		/* T_i = U_1 ... */
		memcpy(T, U, 32);

		for (j = 2; j <= c; j++) {
			/* Compute U_j. */
			memcpy(&hctx, &Phctx, sizeof(HMAC_SHA256_CTX));
			_HMAC_SHA256_Update(&hctx, U, 32, tmp32);
			_HMAC_SHA256_Final(U, &hctx, tmp32, tmp8);

			/* ... xor U_j ... */
			for (k = 0; k < 32; k++)
				T[k] ^= U[k];
		}

		/* Copy as many bytes as necessary into buf. */
		clen = dkLen - i * 32;
		if (clen > 32)
			clen = 32;
		memcpy(&buf[i * 32], T, clen);
	}

	/* Clean the stack. */
	insecure_memzero(&Phctx, sizeof(HMAC_SHA256_CTX));
	insecure_memzero(&PShctx, sizeof(HMAC_SHA256_CTX));
	insecure_memzero(&hctx, sizeof(HMAC_SHA256_CTX));
	insecure_memzero(tmp32, 288);
	insecure_memzero(tmp8, 96);
	insecure_memzero(U, 32);
	insecure_memzero(T, 32);
}


================================================
FILE: ext/scrypt/sha256.h
================================================
#ifndef _SHA256_H_
#define _SHA256_H_

#include <stddef.h>
#include <stdint.h>

/*
 * Use #defines in order to avoid namespace collisions with anyone else's
 * SHA256 code (e.g., the code in OpenSSL).
 */
#define SHA256_Init libcperciva_SHA256_Init
#define SHA256_Update libcperciva_SHA256_Update
#define SHA256_Final libcperciva_SHA256_Final
#define SHA256_Buf libcperciva_SHA256_Buf
#define SHA256_CTX libcperciva_SHA256_CTX
#define HMAC_SHA256_Init libcperciva_HMAC_SHA256_Init
#define HMAC_SHA256_Update libcperciva_HMAC_SHA256_Update
#define HMAC_SHA256_Final libcperciva_HMAC_SHA256_Final
#define HMAC_SHA256_Buf libcperciva_HMAC_SHA256_Buf
#define HMAC_SHA256_CTX libcperciva_HMAC_SHA256_CTX

/* Context structure for SHA256 operations. */
typedef struct {
	uint32_t state[8];
	uint64_t count;
	uint8_t buf[64];
} SHA256_CTX;

/**
 * SHA256_Init(ctx):
 * Initialize the SHA256 context ${ctx}.
 */
void SHA256_Init(SHA256_CTX *);

/**
 * SHA256_Update(ctx, in, len):
 * Input ${len} bytes from ${in} into the SHA256 context ${ctx}.
 */
void SHA256_Update(SHA256_CTX *, const void *, size_t);

/**
 * SHA256_Final(digest, ctx):
 * Output the SHA256 hash of the data input to the context ${ctx} into the
 * buffer ${digest}.
 */
void SHA256_Final(uint8_t[32], SHA256_CTX *);

/**
 * SHA256_Buf(in, len, digest):
 * Compute the SHA256 hash of ${len} bytes from $in} and write it to ${digest}.
 */
void SHA256_Buf(const void *, size_t, uint8_t[32]);

/* Context structure for HMAC-SHA256 operations. */
typedef struct {
	SHA256_CTX ictx;
	SHA256_CTX octx;
} HMAC_SHA256_CTX;

/**
 * HMAC_SHA256_Init(ctx, K, Klen):
 * Initialize the HMAC-SHA256 context ${ctx} with ${Klen} bytes of key from
 * ${K}.
 */
void HMAC_SHA256_Init(HMAC_SHA256_CTX *, const void *, size_t);

/**
 * HMAC_SHA256_Update(ctx, in, len):
 * Input ${len} bytes from ${in} into the HMAC-SHA256 context ${ctx}.
 */
void HMAC_SHA256_Update(HMAC_SHA256_CTX *, const void *, size_t);

/**
 * HMAC_SHA256_Final(digest, ctx):
 * Output the HMAC-SHA256 of the data input to the context ${ctx} into the
 * buffer ${digest}.
 */
void HMAC_SHA256_Final(uint8_t[32], HMAC_SHA256_CTX *);

/**
 * HMAC_SHA256_Buf(K, Klen, in, len, digest):
 * Compute the HMAC-SHA256 of ${len} bytes from ${in} using the key ${K} of
 * length ${Klen}, and write the result to ${digest}.
 */
void HMAC_SHA256_Buf(const void *, size_t, const void *, size_t, uint8_t[32]);

/**
 * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen):
 * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and
 * write the output to buf.  The value dkLen must be at most 32 * (2^32 - 1).
 */
void PBKDF2_SHA256(const uint8_t *, size_t, const uint8_t *, size_t,
    uint64_t, uint8_t *, size_t);

#endif /* !_SHA256_H_ */


================================================
FILE: ext/scrypt/sysendian.h
================================================
/*-
 * Copyright 2007-2009 Colin Percival
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * This file was originally written by Colin Percival as part of the Tarsnap
 * online backup system.
 */
#ifndef _SYSENDIAN_H_
#define _SYSENDIAN_H_

#include "scrypt_platform.h"

/* If we don't have be64enc, the <sys/endian.h> we have isn't usable. */
#if !HAVE_DECL_BE64ENC
#undef HAVE_SYS_ENDIAN_H
#endif

#ifdef HAVE_SYS_ENDIAN_H

#include <sys/endian.h>

#else

#include <stdint.h>

static inline uint32_t
be32dec(const void *pp)
{
	const uint8_t *p = (uint8_t const *)pp;

	return ((uint32_t)(p[3]) + ((uint32_t)(p[2]) << 8) +
		((uint32_t)(p[1]) << 16) + ((uint32_t)(p[0]) << 24));
}

static inline void
be32enc(void *pp, uint32_t x)
{
	uint8_t * p = (uint8_t *)pp;

	p[3] = x & 0xff;
	p[2] = (x >> 8) & 0xff;
	p[1] = (x >> 16) & 0xff;
	p[0] = (x >> 24) & 0xff;
}

static inline uint64_t
be64dec(const void *pp)
{
	const uint8_t *p = (uint8_t const *)pp;

	return ((uint64_t)(p[7]) + ((uint64_t)(p[6]) << 8) +
		((uint64_t)(p[5]) << 16) + ((uint64_t)(p[4]) << 24) +
		((uint64_t)(p[3]) << 32) + ((uint64_t)(p[2]) << 40) +
		((uint64_t)(p[1]) << 48) + ((uint64_t)(p[0]) << 56));
}

static inline void
be64enc(void *pp, uint64_t x)
{
	uint8_t * p = (uint8_t *)pp;

	p[7] = x & 0xff;
	p[6] = (x >> 8) & 0xff;
	p[5] = (x >> 16) & 0xff;
	p[4] = (x >> 24) & 0xff;
	p[3] = (x >> 32) & 0xff;
	p[2] = (x >> 40) & 0xff;
	p[1] = (x >> 48) & 0xff;
	p[0] = (x >> 56) & 0xff;
}

static inline uint32_t
le32dec(const void *pp)
{
	const uint8_t *p = (uint8_t const *)pp;

	return ((uint32_t)(p[0]) + ((uint32_t)(p[1]) << 8) +
	    ((uint32_t)(p[2]) << 16) + ((uint32_t)(p[3]) << 24));
}

static inline void
le32enc(void *pp, uint32_t x)
{
	uint8_t * p = (uint8_t *)pp;

	p[0] = x & 0xff;
	p[1] = (x >> 8) & 0xff;
	p[2] = (x >> 16) & 0xff;
	p[3] = (x >> 24) & 0xff;
}

static inline uint64_t
le64dec(const void *pp)
{
	const uint8_t *p = (uint8_t const *)pp;

	return ((uint64_t)(p[0]) + ((uint64_t)(p[1]) << 8) +
		((uint64_t)(p[2]) << 16) + ((uint64_t)(p[3]) << 24) +
		((uint64_t)(p[4]) << 32) + ((uint64_t)(p[5]) << 40) +
		((uint64_t)(p[6]) << 48) + ((uint64_t)(p[7]) << 56));
}

static inline void
le64enc(void *pp, uint64_t x)
{
	uint8_t * p = (uint8_t *)pp;

	p[0] = x & 0xff;
	p[1] = (x >> 8) & 0xff;
	p[2] = (x >> 16) & 0xff;
	p[3] = (x >> 24) & 0xff;
	p[4] = (x >> 32) & 0xff;
	p[5] = (x >> 40) & 0xff;
	p[6] = (x >> 48) & 0xff;
	p[7] = (x >> 56) & 0xff;
}
#endif /* !HAVE_SYS_ENDIAN_H */

#endif /* !_SYSENDIAN_H_ */


================================================
FILE: ext/scrypt/warnp.c
================================================
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "warnp.h"

static int initialized = 0;
static char * name = NULL;

/* Free the name string. */
static void
done(void)
{

	free(name);
	name = NULL;
}

/**
 * warnp_setprogname(progname):
 * Set the program name to be used by warn() and warnx() to ${progname}.
 */
void
warnp_setprogname(const char * progname)
{
	const char * p;

	/* Free the name if we already have one. */
	free(name);

	/* Find the last segment of the program name. */
	for (p = progname; progname[0] != '\0'; progname++)
		if (progname[0] == '/')
			p = progname + 1;

	/* Copy the name string. */
	name = malloc(strlen(p) + 1);
	if (name == NULL) {
		/* No cleanup handler needs to be registered on failure. */
		return;
	}
	strncpy(name, p, strlen(p) + 1);
	name[strlen(p)] = '\0';  /* Ensure null termination */

	/* If we haven't already done so, register our exit handler. */
	if (initialized == 0) {
		atexit(done);
		initialized = 1;
	}
}

void
warn(const char * fmt, ...)
{
	va_list ap;

	va_start(ap, fmt);
	fprintf(stderr, "%s", (name != NULL) ? name : "(unknown)");
	if (fmt != NULL) {
		fprintf(stderr, ": ");
		vfprintf(stderr, fmt, ap);
	}
	fprintf(stderr, ": %s\n", strerror(errno));
	va_end(ap);
}

void
warnx(const char * fmt, ...)
{
	va_list ap;

	va_start(ap, fmt);
	fprintf(stderr, "%s", (name != NULL) ? name : "(unknown)");
	if (fmt != NULL) {
		fprintf(stderr, ": ");
		vfprintf(stderr, fmt, ap);
	}
	fprintf(stderr, "\n");
	va_end(ap);
}


================================================
FILE: ext/scrypt/warnp.h
================================================
#ifndef _WARNP_H_
#define _WARNP_H_

#include <errno.h>

/* Avoid namespace collisions with BSD <err.h>. */
#define warn libcperciva_warn
#define warnx libcperciva_warnx

/**
 * warnp_setprogname(progname):
 * Set the program name to be used by warn() and warnx() to ${progname}.
 */
void warnp_setprogname(const char *);
#define WARNP_INIT	do {		\
	if (argv[0] != NULL)		\
		warnp_setprogname(argv[0]);	\
} while (0)

/* As in BSD <err.h>. */
void warn(const char *, ...);
void warnx(const char *, ...);

/*
 * If compiled with DEBUG defined, print __FILE__ and __LINE__.
 */
#ifdef DEBUG
#define warnline	do {				\
	warnx("%s, %d", __FILE__, __LINE__);	\
} while (0)
#else
#define warnline
#endif

/*
 * Call warn(3) or warnx(3) depending upon whether errno == 0; and clear
 * errno (so that the standard error message isn't repeated later).
 */
#define	warnp(...) do {					\
	warnline;					\
	if (errno != 0) {				\
		warn(__VA_ARGS__);		\
		errno = 0;				\
	} else						\
		warnx(__VA_ARGS__);		\
} while (0)

/*
 * Call warnx(3) and set errno == 0.  Unlike warnp, this should be used
 * in cases where we're reporting a problem which we discover ourselves
 * rather than one which is reported to us from a library or the kernel.
 */
#define warn0(...) do {					\
	warnline;					\
	warnx(__VA_ARGS__);			\
	errno = 0;					\
} while (0)

#endif /* !_WARNP_H_ */


================================================
FILE: lib/scrypt/engine.rb
================================================
# frozen_string_literal: true

require 'ffi'
require 'openssl'

module SCrypt
  module Ext
    # Bind the external functions
    attach_function :sc_calibrate,
                    %i[size_t double double pointer],
                    :int,
                    blocking: true

    attach_function :crypto_scrypt,
                    %i[pointer size_t pointer size_t uint64 uint32 uint32 pointer size_t],
                    :int,
                    blocking: true # Use blocking: true for CPU-intensive operations to avoid GIL issues
  end

  class Engine
    # Regular expressions for validation
    COST_PATTERN = /^[0-9a-z]+\$[0-9a-z]+\$[0-9a-z]+\$$/.freeze
    SALT_PATTERN = /^[0-9a-z]+\$[0-9a-z]+\$[0-9a-z]+\$[A-Za-z0-9]{16,64}$/.freeze
    HASH_PATTERN = /^[0-9a-z]+\$[0-9a-z]+\$[0-9a-z]+\$[A-Za-z0-9]{16,64}\$[A-Za-z0-9]{32,1024}$/.freeze

    # Constants for salt handling
    OLD_STYLE_SALT_LENGTH = 40
    SALT_MIN_LENGTH = 16

    DEFAULTS = {
      key_len: 32,
      salt_size: 32,
      max_mem: 16 * 1024 * 1024,
      max_memfrac: 0.5,
      max_time: 0.2,
      cost: nil
    }.freeze

    # Class variable to store calibrated cost, separate from defaults
    @calibrated_cost = nil

    class << self
      attr_accessor :calibrated_cost
    end

    class Calibration < FFI::Struct
      layout  :n, :uint64,
              :r, :uint32,
              :p, :uint32
    end

    class << self
      def scrypt(secret, salt, *args)
        case args.length
        when 2
          # args is [cost_string, key_len]
          cost_string, key_len = args
          cpu_cost, memory_cost, parallelization = parse_cost_string(cost_string)
          __sc_crypt(secret, salt, cpu_cost, memory_cost, parallelization, key_len)
        when 4
          # args is [n, r, p, key_len]
          cpu_cost, memory_cost, parallelization, key_len = args
          __sc_crypt(secret, salt, cpu_cost, memory_cost, parallelization, key_len)
        else
          raise ArgumentError, 'invalid number of arguments (4 or 6)'
        end
      end

      # Given a secret and a valid salt (see SCrypt::Engine.generate_salt) calculates an scrypt password hash.
      def hash_secret(secret, salt, key_len = DEFAULTS[:key_len])
        raise Errors::InvalidSecret, 'invalid secret' unless valid_secret?(secret)
        raise Errors::InvalidSalt, 'invalid salt' unless valid_salt?(salt)

        cost = autodetect_cost(salt)
        salt_only = extract_salt_from_string(salt)

        if old_style_hash?(salt_only)
          generate_old_style_hash(secret, salt, cost)
        else
          generate_new_style_hash(secret, salt, salt_only, cost, key_len)
        end
      end

      # Generates a random salt with a given computational cost.  Uses a saved
      # cost if SCrypt::Engine.calibrate! has been called.
      #
      # Options:
      # <tt>:cost</tt> is a cost string returned by SCrypt::Engine.calibrate
      def generate_salt(options = {})
        options = DEFAULTS.merge(options)
        cost = options[:cost] || @calibrated_cost || calibrate(options)
        salt = OpenSSL::Random.random_bytes(options[:salt_size]).unpack('H*').first.rjust(SALT_MIN_LENGTH, '0')

        salt = avoid_old_style_collision(salt)
        cost + salt
      end

      # Returns true if +cost+ is a valid cost, false if not.
      def valid_cost?(cost)
        !COST_PATTERN.match(cost).nil?
      end

      # Returns true if +salt+ is a valid salt, false if not.
      def valid_salt?(salt)
        !SALT_PATTERN.match(salt).nil?
      end

      # Returns true if +secret+ is a valid secret, false if not.
      def valid_secret?(secret)
        secret.respond_to?(:to_s)
      end

      # Returns the cost value which will result in computation limits less than the given options.
      #
      # Options:
      # <tt>:max_time</tt> specifies the maximum number of seconds the computation should take.
      # <tt>:max_mem</tt> specifies the maximum number of bytes the computation should take.
      # A value of 0 specifies no upper limit. The minimum is always 1 MB.
      # <tt>:max_memfrac</tt> specifies the maximum memory in a fraction of available resources to use.
      # Any value equal to 0 or greater than 0.5 will result in 0.5 being used.
      #
      # Example:
      #
      #   # should take less than 200ms
      #   SCrypt::Engine.calibrate(:max_time => 0.2)
      #
      def calibrate(options = {})
        options = DEFAULTS.merge(options)
        '%x$%x$%x$' % __sc_calibrate(options[:max_mem], options[:max_memfrac], options[:max_time])
      end

      # Calls SCrypt::Engine.calibrate and saves the cost string for future calls to
      # SCrypt::Engine.generate_salt.
      def calibrate!(options = {})
        @calibrated_cost = calibrate(options)
      end

      # Computes the memory use of the given +cost+
      def memory_use(cost)
        cpu_cost, memory_cost, parallelization = parse_cost_string(cost)
        (128 * memory_cost * parallelization) + (256 * memory_cost) + (128 * memory_cost * cpu_cost)
      end

      # Autodetects the cost from the salt string.
      def autodetect_cost(salt)
        salt[/^[0-9a-z]+\$[0-9a-z]+\$[0-9a-z]+\$/]
      end

      private

      # Extracts the salt portion from a salt string
      def extract_salt_from_string(salt)
        salt[/\$([A-Za-z0-9]{16,64})$/, 1]
      end

      # Checks if this is an old-style hash based on salt length
      def old_style_hash?(salt_only)
        salt_only.length == OLD_STYLE_SALT_LENGTH
      end

      # Generates old-style hash with SHA1
      def generate_old_style_hash(secret, salt, cost)
        "#{salt}$#{Digest::SHA1.hexdigest(scrypt(secret.to_s, salt, cost, 256))}"
      end

      # Generates new-style hash
      def generate_new_style_hash(secret, salt, salt_only, cost, key_len)
        processed_salt = [salt_only.sub(/^(00)+/, '')].pack('H*')
        hash_bytes = scrypt(secret.to_s, processed_salt, cost, key_len)
        "#{salt}$#{hash_bytes.unpack('H*').first.rjust(key_len * 2, '0')}"
      end

      # Avoids collision with old-style hash detection
      def avoid_old_style_collision(salt)
        if salt.length == OLD_STYLE_SALT_LENGTH
          # If salt is 40 characters, the regexp will think that it is an old-style hash, so add a '0'.
          "0#{salt}"
        else
          salt
        end
      end

      # Parses a cost string into its component values
      def parse_cost_string(cost_string)
        cost_string.split('$').map { |component| component.to_i(16) }
      end

      def __sc_calibrate(max_mem, max_memfrac, max_time)
        raise ArgumentError, 'max_mem must be non-negative' if max_mem.negative?
        raise ArgumentError, 'max_memfrac must be between 0 and 1' unless (0..1).cover?(max_memfrac)
        raise ArgumentError, 'max_time must be positive' if max_time <= 0

        calibration = Calibration.new
        ret_val = SCrypt::Ext.sc_calibrate(max_mem, max_memfrac, max_time, calibration)

        raise "calibration error: return value #{ret_val}" unless ret_val.zero?

        [calibration[:n], calibration[:r], calibration[:p]]
      end

      def __sc_crypt(secret, salt, cpu_cost, memory_cost, parallelization, key_len)
        raise ArgumentError, 'secret cannot be nil' if secret.nil?
        raise ArgumentError, 'salt cannot be nil' if salt.nil?
        raise ArgumentError, 'key_len must be positive' if key_len <= 0
        raise ArgumentError, 'cpu_cost must be positive' if cpu_cost <= 0
        raise ArgumentError, 'memory_cost must be positive' if memory_cost <= 0
        raise ArgumentError, 'parallelization must be positive' if parallelization <= 0

        result = nil

        FFI::MemoryPointer.new(:char, key_len) do |buffer|
          ret_val = SCrypt::Ext.crypto_scrypt(
            secret, secret.bytesize, salt, salt.bytesize,
            cpu_cost, memory_cost, parallelization,
            buffer, key_len
          )

          raise "scrypt error: return value #{ret_val}" unless ret_val.zero?

          result = buffer.read_string(key_len)
        end

        result
      end
    end
  end
end


================================================
FILE: lib/scrypt/errors.rb
================================================
# frozen_string_literal: true

module SCrypt
  module Errors
    # The salt parameter provided is invalid.
    class InvalidSalt   < StandardError; end

    # The hash parameter provided is invalid.
    class InvalidHash   < StandardError; end

    # The secret parameter provided is invalid.
    class InvalidSecret < StandardError; end
  end
end


================================================
FILE: lib/scrypt/password.rb
================================================
# frozen_string_literal: true

module SCrypt
  # A password management class which allows you to safely store users' passwords and compare them.
  #
  # Example usage:
  #
  #   include "scrypt"
  #
  #   # hash a user's password
  #   @password = Password.create("my grand secret")
  #   @password #=> "2000$8$1$f5f2fa5fe5484a7091f1299768fbe92b5a7fbc77$6a385f22c54d92c314b71a4fd5ef33967c93d679"
  #
  #   # store it safely
  #   @user.update_attribute(:password, @password)
  #
  #   # read it back
  #   @user.reload!
  #   @db_password = Password.new(@user.password)
  #
  #   # compare it after retrieval
  #   @db_password == "my grand secret" #=> true
  #   @db_password == "a paltry guess"  #=> false
  #
  class Password < String
    # Key length constraints
    MIN_KEY_LENGTH = 16
    MAX_KEY_LENGTH = 512
    # Salt size constraints
    MIN_SALT_SIZE = 8
    MAX_SALT_SIZE = 32

    # The hash portion of the stored password hash.
    attr_reader :digest
    # The salt of the store password hash
    attr_reader :salt
    # The cost factor used to create the hash.
    attr_reader :cost

    class << self
      # Hashes a secret, returning a SCrypt::Password instance.
      # Takes five options (optional), which will determine the salt/key's length and
      # the cost limits of the computation.
      # <tt>:key_len</tt> specifies the length in bytes of the key you want to generate.
      # The default is 32 bytes (256 bits). Minimum is 16 bytes (128 bits). Maximum is 512 bytes (4096 bits).
      # <tt>:salt_size</tt> specifies the size in bytes of the random salt you want to generate.
      # The default and minimum is 8 bytes (64 bits). Maximum is 32 bytes (256 bits).
      # <tt>:max_time</tt> specifies the maximum number of seconds the computation should take.
      # <tt>:max_mem</tt> specifies the maximum number of bytes the computation should take.
      # A value of 0 specifies no upper limit. The minimum is always 1 MB.
      # <tt>:max_memfrac</tt> specifies the maximum memory in a fraction of available resources to use.
      # Any value equal to 0 or greater than 0.5 will result in 0.5 being used.
      # The scrypt key derivation function is designed to be far more secure against hardware
      # brute-force attacks than alternative functions such as PBKDF2 or bcrypt.
      # The designers of scrypt estimate that on modern (2009) hardware, if 5 seconds are spent
      # computing a derived key, the cost of a hardware brute-force attack against scrypt is roughly
      # 4000 times greater than the cost of a similar attack against bcrypt (to find the same password),
      # and 20000 times greater than a similar attack against PBKDF2.
      # Default options will result in calculation time of approx. 200 ms with 1 MB memory use.
      #
      # Example:
      #   @password = SCrypt::Password.create("my secret", :max_time => 0.25)
      #
      def create(secret, options = {})
        options = SCrypt::Engine::DEFAULTS.merge(options)

        options[:key_len] = clamp_key_length(options[:key_len])
        options[:salt_size] = clamp_salt_size(options[:salt_size])

        salt = SCrypt::Engine.generate_salt(options)
        hash = SCrypt::Engine.hash_secret(secret, salt, options[:key_len])

        Password.new(hash)
      end

      private

      # Clamps key length to valid range
      def clamp_key_length(key_len)
        return MIN_KEY_LENGTH if key_len < MIN_KEY_LENGTH
        return MAX_KEY_LENGTH if key_len > MAX_KEY_LENGTH

        key_len
      end

      # Clamps salt size to valid range
      def clamp_salt_size(salt_size)
        return MIN_SALT_SIZE if salt_size < MIN_SALT_SIZE
        return MAX_SALT_SIZE if salt_size > MAX_SALT_SIZE

        salt_size
      end
    end

    # Initializes a SCrypt::Password instance with the data from a stored hash.
    def initialize(raw_hash)
      raise Errors::InvalidHash, 'invalid hash' unless valid_hash?(raw_hash)

      replace(raw_hash)

      @cost, @salt, @digest = split_hash(to_s)
    end

    # Compares a potential secret against the hash. Returns true if the secret is the original secret, false otherwise.
    def ==(other)
      SecurityUtils.secure_compare(self, SCrypt::Engine.hash_secret(other, @cost + @salt, digest.length / 2))
    end
    alias is_password? ==

    private

    # Returns true if +h+ is a valid hash.
    def valid_hash?(h)
      !SCrypt::Engine::HASH_PATTERN.match(h).nil?
    end

    # call-seq:
    #   split_hash(raw_hash) -> cost, salt, hash
    #
    # Splits +h+ into cost, salt, and hash and returns them in that order.
    def split_hash(hash_string)
      cpu_cost, version, memory_cost, salt, hash = hash_string.split('$')
      cost_string = "#{[cpu_cost, version, memory_cost].join('$')}$"
      [cost_string, salt, hash]
    end
  end
end


================================================
FILE: lib/scrypt/scrypt_ext.rb
================================================
# frozen_string_literal: true

require 'ffi'
require 'ffi-compiler/loader'

module SCrypt
  module Ext
    extend FFI::Library

    begin
      ffi_lib FFI::Compiler::Loader.find('scrypt_ext')
    rescue LoadError => e
      raise LoadError, "Failed to load scrypt extension library: #{e.message}"
    end
  end
end


================================================
FILE: lib/scrypt/security_utils.rb
================================================
# frozen_string_literal: true

# NOTE:: a verbatim copy of https://github.com/rails/rails/blob/c8c660002f4b0e9606de96325f20b95248b6ff2d/activesupport/lib/active_support/security_utils.rb
# Please see the Rails license: https://github.com/rails/rails/blob/master/activesupport/MIT-LICENSE

module SCrypt
  module SecurityUtils
    # Constant time string comparison.
    #
    # The values compared should be of fixed length, such as strings
    # that have already been processed by HMAC. This should not be used
    # on variable length plaintext strings because it could leak length info
    # via timing attacks.
    def self.secure_compare(a, b)
      return false unless a.bytesize == b.bytesize

      l = a.unpack "C#{a.bytesize}"

      res = 0
      b.each_byte { |byte| res |= byte ^ l.shift }
      res.zero?
    end
  end
end


================================================
FILE: lib/scrypt/version.rb
================================================
# frozen_string_literal: true

module SCrypt
  VERSION = '3.1.0'
end


================================================
FILE: lib/scrypt.rb
================================================
# frozen_string_literal: true

# A wrapper for the scrypt algorithm.

require 'scrypt/errors'
require 'scrypt/scrypt_ext'
require 'scrypt/security_utils'

require 'scrypt/engine'
require 'scrypt/password'


================================================
FILE: scrypt.gemspec
================================================
# frozen_string_literal: true

$:.push File.expand_path('lib', __dir__)
require 'scrypt/version'

Gem::Specification.new do |s|
  s.name        = 'scrypt'
  s.version     = SCrypt::VERSION
  s.authors     = ['Patrick Hogan',
                   'Stephen von Takach',
                   'Rene van Paassen',
                   'Johanns Gregorian']
  s.email       = ['pbhogan@gmail.com',
                   'steve@advancedcontrol.com.au',
                   'rene.vanpaassen@gmail.com',
                   'io+scrypt@jsg.io']
  s.cert_chain  = ['certs/pbhogan.pem']
  s.license     = 'BSD-3-Clause'

  s.signing_key = File.expand_path('~/.ssh/gem-private_key.pem') if $0 =~ /gem\z/
  s.metadata['rubygems_mfa_required'] = 'true'

  s.homepage    = 'https://github.com/pbhogan/scrypt'
  s.summary     = 'scrypt password hashing algorithm.'

  s.description = <<-DESC
    The scrypt key derivation function is designed to be far
    more secure against hardware brute-force attacks than
    alternative functions such as PBKDF2 or bcrypt.
  DESC

  s.required_ruby_version = '>= 2.3.0'

  s.add_dependency 'ffi-compiler', '>= 1.0', '< 2.0'
  s.add_dependency 'rake', '~> 13'

  s.extensions = ['ext/scrypt/Rakefile']

  s.files = %w[Rakefile scrypt.gemspec README.md COPYING] + Dir.glob('{lib,spec}/**/*')
  s.files += Dir.glob('ext/scrypt/*')
  s.require_paths = ['lib']
end


================================================
FILE: spec/fixtures/test_vectors.yml
================================================
# SCrypt Test Vectors
# These are the official test vectors from the scrypt specification
# Used to verify our implementation matches the reference

scrypt_vectors:
  - description: "Empty string test"
    password: ""
    salt: ""
    n: 16
    r: 1
    p: 1
    key_len: 64
    expected: "77d6576238657b203b19ca42c18a0497f16b4844e3074ae8dfdffa3fede21442fcd0069ded0948f8326a753a0fc81f17e8d3e0fb2e0d3628cf35e20c38d18906"

  - description: "Standard test vector"
    password: "password"
    salt: "NaCl"
    n: 1024
    r: 8
    p: 16
    key_len: 64
    expected: "fdbabe1c9d3472007856e7190d01e9fe7c6ad7cbc8237830e77376634b3731622eaf30d92e22a3886ff109279d9830dac727afb94a83ee6d8360cbdfa2cc0640"

  - description: "High memory test vector"
    password: "pleaseletmein"
    salt: "SodiumChloride"
    n: 16384
    r: 8
    p: 1
    key_len: 64
    expected: "7023bdcb3afd7348461c06cd81fd38ebfda8fbba904f8e3ea9b543f6545da1f2d5432955613f0fcf62d49705242a9af9e61e85dc0d651e40dfcf017b45575887"

  - description: "Very high memory test (disabled on memory-constrained systems)"
    password: "pleaseletmein"
    salt: "SodiumChloride"
    n: 1048576
    r: 8
    p: 1
    key_len: 64
    expected: "2101cb9b6a511aaeaddbbe09cf70f881ec568d574a2ffd4dabe5ee9820adaa478e56fd8f4ba5d09ffa1c6d927c40f4c337304049e8a952fbcbf45c6fa77a41a4"
    skip_reason: "Memory limited systems (like Raspberry Pi) may fail this test"

hash_secret_vectors:
  - description: "Empty string via hash_secret"
    password: ""
    salt: "10$1$1$0000000000000000"
    key_len: 64
    expected_pattern: "77d6576238657b203b19ca42c18a0497f16b4844e3074ae8dfdffa3fede21442fcd0069ded0948f8326a753a0fc81f17e8d3e0fb2e0d3628cf35e20c38d18906"

  - description: "Standard test via hash_secret"
    password: "password"
    salt: "400$8$10$000000004e61436c"
    key_len: 64
    expected_pattern: "fdbabe1c9d3472007856e7190d01e9fe7c6ad7cbc8237830e77376634b3731622eaf30d92e22a3886ff109279d9830dac727afb94a83ee6d8360cbdfa2cc0640"

  - description: "High memory test via hash_secret"
    password: "pleaseletmein"
    salt: "4000$8$1$536f6469756d43686c6f72696465"
    key_len: 64
    expected_pattern: "7023bdcb3afd7348461c06cd81fd38ebfda8fbba904f8e3ea9b543f6545da1f2d5432955613f0fcf62d49705242a9af9e61e85dc0d651e40dfcf017b45575887"

  - description: "Very high memory test via hash_secret (disabled)"
    password: "pleaseletmein"
    salt: "100000$8$1$536f6469756d43686c6f72696465"
    key_len: 64
    expected_pattern: "2101cb9b6a511aaeaddbbe09cf70f881ec568d574a2ffd4dabe5ee9820adaa478e56fd8f4ba5d09ffa1c6d927c40f4c337304049e8a952fbcbf45c6fa77a41a4"
    skip_reason: "Memory limited systems may fail this test"


================================================
FILE: spec/scrypt/engine_spec.rb
================================================
# frozen_string_literal: true

require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))

describe 'The SCrypt engine' do
  it 'calculates a valid cost factor' do
    first = SCrypt::Engine.calibrate(max_time: 0.2)
    expect(SCrypt::Engine.valid_cost?(first)).to equal(true)
  end
end

describe 'Generating SCrypt salts' do
  it 'produces strings' do
    expect(SCrypt::Engine.generate_salt).to be_an_instance_of(String)
  end

  it 'produces random data' do
    expect(SCrypt::Engine.generate_salt).not_to equal(SCrypt::Engine.generate_salt)
  end

  it 'uses the saved cost factor' do
    # Verify cost is different before saving
    cost = SCrypt::Engine.calibrate(max_time: 0.01)
    expect(SCrypt::Engine.generate_salt).not_to start_with(cost)

    cost = SCrypt::Engine.calibrate!(max_time: 0.01)
    expect(SCrypt::Engine.generate_salt).to start_with(cost)
  end

  it 'resets calibrated cost when setting new calibration' do
    # Set initial calibration
    first_cost = SCrypt::Engine.calibrate!(max_time: 0.01)
    expect(SCrypt::Engine.calibrated_cost).to eq(first_cost)

    # Set different calibration
    second_cost = SCrypt::Engine.calibrate!(max_time: 0.02)
    expect(SCrypt::Engine.calibrated_cost).to eq(second_cost)
    expect(SCrypt::Engine.calibrated_cost).not_to eq(first_cost)
  end
end

describe 'Autodetecting of salt cost' do
  it 'works' do
    expect(SCrypt::Engine.autodetect_cost('2a$08$c3$some_salt')).to eq('2a$08$c3$')
  end
end

describe 'Generating SCrypt hashes' do
  class MyInvalidSecret
    undef to_s
  end

  before do
    @salt = SCrypt::Engine.generate_salt
    @password = 'woo'
  end

  it 'produces a string' do
    expect(SCrypt::Engine.hash_secret(@password, @salt)).to be_an_instance_of(String)
  end

  it 'raises an InvalidSalt error if the salt is invalid' do
    expect { SCrypt::Engine.hash_secret(@password, 'nino') }.to raise_error(SCrypt::Errors::InvalidSalt)
  end

  it 'raises an InvalidSecret error if the secret is invalid' do
    expect { SCrypt::Engine.hash_secret(MyInvalidSecret.new, @salt) }.to raise_error(SCrypt::Errors::InvalidSecret)
    expect { SCrypt::Engine.hash_secret(nil, @salt) }.not_to raise_error
    expect { SCrypt::Engine.hash_secret(false, @salt) }.not_to raise_error
  end

  it 'calls #to_s on the secret and use the return value as the actual secret data' do
    expect(SCrypt::Engine.hash_secret(false, @salt)).to eq(SCrypt::Engine.hash_secret('false', @salt))
  end
end

describe 'SCrypt test vectors' do
  it 'matches results of SCrypt function' do
    TEST_VECTORS['scrypt_vectors'].each do |vector|
      next if vector['skip_reason'] # Skip memory-intensive tests

      result = SCrypt::Engine.scrypt(
        vector['password'],
        vector['salt'],
        vector['n'],
        vector['r'],
        vector['p'],
        vector['key_len']
      ).unpack('H*').first

      expect(result).to eq(vector['expected']), "Failed for: #{vector['description']}"
    end
  end

  it 'matches equivalent results sent through hash_secret() function' do
    TEST_VECTORS['hash_secret_vectors'].each do |vector|
      next if vector['skip_reason'] # Skip memory-intensive tests

      result = SCrypt::Engine.hash_secret(
        vector['password'],
        vector['salt'],
        vector['key_len']
      )

      # hash_secret returns: salt + '$' + hash_digest
      # So we expect: "salt$expected_pattern"
      expected_full_hash = "#{vector['salt']}$#{vector['expected_pattern']}"
      expect(result).to eq(expected_full_hash), "Failed for: #{vector['description']}"
    end
  end
end

describe 'Input validation' do
  describe '#calibrate' do
    it 'raises ArgumentError for negative max_mem' do
      expect do
        SCrypt::Engine.send(:__sc_calibrate, -1, 0.5, 0.2)
      end.to raise_error(ArgumentError, 'max_mem must be non-negative')
    end

    it 'raises ArgumentError for invalid max_memfrac' do
      expect do
        SCrypt::Engine.send(:__sc_calibrate, 1024, -0.1,
                            0.2)
      end.to raise_error(ArgumentError, 'max_memfrac must be between 0 and 1')
      expect do
        SCrypt::Engine.send(:__sc_calibrate, 1024, 1.1,
                            0.2)
      end.to raise_error(ArgumentError, 'max_memfrac must be between 0 and 1')
    end

    it 'raises ArgumentError for non-positive max_time' do
      expect do
        SCrypt::Engine.send(:__sc_calibrate, 1024, 0.5, 0)
      end.to raise_error(ArgumentError, 'max_time must be positive')

      expect do
        SCrypt::Engine.send(:__sc_calibrate, 1024, 0.5, -0.1)
      end.to raise_error(ArgumentError, 'max_time must be positive')
    end
  end

  describe '#scrypt' do
    it 'raises ArgumentError for nil secret' do
      expect do
        SCrypt::Engine.send(:__sc_crypt, nil, 'salt', 16, 1, 1, 32)
      end.to raise_error(ArgumentError, 'secret cannot be nil')
    end

    it 'raises ArgumentError for nil salt' do
      expect do
        SCrypt::Engine.send(:__sc_crypt, 'secret', nil, 16, 1, 1, 32)
      end.to raise_error(ArgumentError, 'salt cannot be nil')
    end

    it 'raises ArgumentError for non-positive parameters' do
      expect do
        SCrypt::Engine.send(:__sc_crypt, 'secret', 'salt', 0, 1, 1, 32)
      end.to raise_error(ArgumentError, 'cpu_cost must be positive')

      expect do
        SCrypt::Engine.send(:__sc_crypt, 'secret', 'salt', 16, 0, 1, 32)
      end.to raise_error(ArgumentError, 'memory_cost must be positive')

      expect do
        SCrypt::Engine.send(:__sc_crypt, 'secret', 'salt', 16, 1, 0, 32)
      end.to raise_error(ArgumentError, 'parallelization must be positive')

      expect do
        SCrypt::Engine.send(:__sc_crypt, 'secret', 'salt', 16, 1, 1,
                            0)
      end.to raise_error(ArgumentError, 'key_len must be positive')
    end
  end
end

describe 'Memory usage calculation' do
  it 'calculates memory usage correctly' do
    cost = '400$8$1$'
    memory = SCrypt::Engine.memory_use(cost)
    n = 0x400
    r = 8
    p = 1
    expected = (128 * r * p) + (256 * r) + (128 * r * n)
    expect(memory).to eq(expected)
  end
end

describe 'Calibrated cost management' do
  after do
    # Reset calibrated cost after each test
    SCrypt::Engine.calibrated_cost = nil
  end

  it 'initializes have no calibrated cost' do
    SCrypt::Engine.calibrated_cost = nil
    expect(SCrypt::Engine.calibrated_cost).to be_nil
  end

  it 'stores and retrieve calibrated cost' do
    cost = SCrypt::Engine.calibrate!(max_time: 0.01)
    expect(SCrypt::Engine.calibrated_cost).to eq(cost)
  end

  it 'uses calibrated cost in generate_salt when available' do
    cost = SCrypt::Engine.calibrate!(max_time: 0.01)
    salt = SCrypt::Engine.generate_salt
    expect(salt).to start_with(cost)
  end
end


================================================
FILE: spec/scrypt/ffi_spec.rb
================================================
# frozen_string_literal: true

require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))

describe 'SCrypt FFI Library Loading' do
  describe 'Extension loading' do
    it 'loads the scrypt extension successfully' do
      # This test verifies that the FFI library loads without error
      # If we get here, the library loaded successfully during require
      expect(SCrypt::Ext).to be_a(Module)
      expect(SCrypt::Ext).to respond_to(:sc_calibrate)
      expect(SCrypt::Ext).to respond_to(:crypto_scrypt)
    end

    it 'has proper FFI function signatures' do
      # Verify that the FFI functions are properly bound
      expect(SCrypt::Ext.method(:sc_calibrate)).to be_a(Method)
      expect(SCrypt::Ext.method(:crypto_scrypt)).to be_a(Method)
    end
  end

  describe 'FFI function behavior' do
    it 'handles basic calibration calls' do
      # Test that the FFI functions are callable
      expect { SCrypt::Engine.calibrate(max_time: 0.01) }.not_to raise_error
    end

    it 'handles basic scrypt calls' do
      salt = SCrypt::Engine.generate_salt(max_time: 0.01)
      expect { SCrypt::Engine.hash_secret('test', salt) }.not_to raise_error
    end
  end
end


================================================
FILE: spec/scrypt/integration_spec.rb
================================================
# frozen_string_literal: true

require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))

describe 'SCrypt Integration Tests' do
  describe 'Full password lifecycle' do
    let(:secret) { 'my_super_secret_password' }
    let(:options) { { max_time: 0.1, max_mem: 8 * 1024 * 1024 } }

    it 'create,s store, and verify passwords correctly' do
      # Create password
      password = SCrypt::Password.create(secret, options)
      expect(password).to be_a(SCrypt::Password)
      expect(password.to_s).to match(/^[0-9a-z]+\$[0-9a-z]+\$[0-9a-z]+\$[A-Za-z0-9]+\$[A-Za-z0-9]+$/)

      # Verify password
      expect(password == secret).to be(true)
      expect(password == 'wrong_password').to be(false)

      # Re-instantiate from stored hash
      stored_hash = password.to_s
      recovered_password = SCrypt::Password.new(stored_hash)

      expect(recovered_password == secret).to be(true)
      expect(recovered_password == 'wrong_password').to be(false)
    end

    it 'handles calibration workflow correctly' do
      # Calibrate for fast testing
      cost = SCrypt::Engine.calibrate!(max_time: 0.05)
      expect(cost).to match(/^[0-9a-z]+\$[0-9a-z]+\$[0-9a-z]+\$$/)

      # Generate salt using calibrated cost
      salt = SCrypt::Engine.generate_salt
      expect(salt).to start_with(cost)

      # Hash secret with calibrated parameters
      hash = SCrypt::Engine.hash_secret(secret, salt)
      expect(hash).to be_a(String)
      expect(hash).to include(salt)

      # Verify the hash
      password = SCrypt::Password.new(hash)
      expect(password == secret).to be(true)

      # Reset calibration
      SCrypt::Engine.calibrated_cost = nil
    end
  end

  describe 'Cross-compatibility tests' do
    it 'is compatible between Engine and Password classes' do
      # Create using Password class
      password1 = SCrypt::Password.create('test_secret', max_time: 0.05)

      # Extract components and recreate using Engine
      cost = password1.cost
      salt_with_cost = cost + password1.salt
      hash2 = SCrypt::Engine.hash_secret('test_secret', salt_with_cost, password1.digest.length / 2)

      # Both should verify the same secret
      password2 = SCrypt::Password.new(hash2)
      expect(password1 == 'test_secret').to be(true)
      expect(password2 == 'test_secret').to be(true)
    end
  end

  describe 'Edge cases and error conditions' do
    it 'handles various secret types' do
      # String secret
      password1 = SCrypt::Password.create('string_secret', max_time: 0.05)
      expect(password1 == 'string_secret').to be(true)

      # Symbol secret
      password2 = SCrypt::Password.create(:symbol_secret, max_time: 0.05)
      expect(password2 == 'symbol_secret').to be(true)

      # Numeric secret
      password3 = SCrypt::Password.create(12_345, max_time: 0.05)
      expect(password3 == '12345').to be(true)

      # Boolean secret
      password4 = SCrypt::Password.create(false, max_time: 0.05)
      expect(password4 == 'false').to be(true)
    end

    it 'handles empty and nil secrets safely' do
      # Empty string
      password1 = SCrypt::Password.create('', max_time: 0.05)
      expect(password1 == '').to be(true)

      # Nil (converts to empty string)
      password2 = SCrypt::Password.create(nil, max_time: 0.05)
      expect(password2 == '').to be(true)
    end

    it 'validates input parameters' do
      # Invalid hash format
      expect { SCrypt::Password.new('invalid_hash') }.to raise_error(SCrypt::Errors::InvalidHash)

      # Invalid salt
      expect { SCrypt::Engine.hash_secret('secret', 'invalid_salt') }.to raise_error(SCrypt::Errors::InvalidSalt)
    end
  end

  describe 'Performance and memory tests' do
    it 'respects memory and time constraints' do
      start_time = Time.now

      # Use very low constraints for fast testing
      password = SCrypt::Password.create('test', max_time: 0.01, max_mem: 1024 * 1024)

      elapsed_time = Time.now - start_time

      # Should complete reasonably quickly (allowing some overhead)
      expect(elapsed_time).to be < 1.0
      expect(password == 'test').to be(true)
    end

    it 'calculates memory usage correctly' do
      cost = SCrypt::Engine.calibrate(max_time: 0.05)
      memory_usage = SCrypt::Engine.memory_use(cost)

      # Memory usage should be a reasonable number
      expect(memory_usage).to be > 0
      expect(memory_usage).to be < 100 * 1024 * 1024 # Less than 100MB
    end
  end
end


================================================
FILE: spec/scrypt/password_spec.rb
================================================
# frozen_string_literal: true

require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))

describe 'Creating a hashed password' do
  before do
    @password = SCrypt::Password.create('s3cr3t', max_time: 0.25)
  end

  it 'returns a SCrypt::Password' do
    expect(@password).to be_an_instance_of(SCrypt::Password)
  end

  it 'returns a valid password' do
    expect { SCrypt::Password.new(@password) }.not_to raise_error
  end

  it 'behaves normally if the secret is not a string' do
    expect { SCrypt::Password.create(nil) }.not_to raise_error
    expect { SCrypt::Password.create(false) }.not_to raise_error
    expect { SCrypt::Password.create(42) }.not_to raise_error
  end

  it 'tolerates empty string secrets' do
    expect { SCrypt::Password.create('') }.not_to raise_error
    expect { SCrypt::Password.create('', max_time: 0.01) }.not_to raise_error
    expect(SCrypt::Password.create('')).to be_an_instance_of(SCrypt::Password)
  end
end

describe 'Reading a hashed password' do
  before do
    @secret = 'my secret'
    @hash = '400$8$d$173a8189751c095a29b933789560b73bf17b2e01$9bf66d74bd6f3ebcf99da3b379b689b89db1cb07'
  end

  it 'reads the cost, salt, and hash' do
    password = SCrypt::Password.new(@hash)
    expect(password.cost).to eq('400$8$d$')
    expect(password.salt).to eq('173a8189751c095a29b933789560b73bf17b2e01')
    expect(password.digest).to eq('9bf66d74bd6f3ebcf99da3b379b689b89db1cb07')
  end

  it 'raises an InvalidHashError when given an invalid hash' do
    expect { SCrypt::Password.new('invalid') }.to raise_error(SCrypt::Errors::InvalidHash)
  end
end

describe 'Comparing a hashed password with a secret' do
  before do
    @secret = 's3cr3t'
    @password = SCrypt::Password.create(@secret, max_time: 0.01)
  end

  it 'compares successfully to the original secret' do
    expect(@password == @secret).to be true
  end

  it 'compares unsuccessfully to anything besides original secret' do
    expect(@password == 'different').to be false
  end
end

describe 'non-default salt sizes' do
  before do
    @secret = 's3cret'
  end

  it 'enforces a minimum salt of 8 bytes' do
    @password = SCrypt::Password.create(@secret, salt_size: 4, max_time: 0.01)
    expect(@password.salt.length).to eq(16) # 8 bytes * 2 (hex encoding)
  end

  it 'allows a salt of 32 bytes' do
    @password = SCrypt::Password.create(@secret, salt_size: 32, max_time: 0.01)
    expect(@password.salt.length).to eq(64) # 32 bytes * 2 (hex encoding)
  end

  it 'enforces a maximum salt of 32 bytes' do
    @password = SCrypt::Password.create(@secret, salt_size: 64, max_time: 0.01)
    expect(@password.salt.length).to eq(64) # 32 bytes * 2 (hex encoding)
  end

  it 'pads a 20-byte salt to not look like a 20-byte SHA1' do
    @password = SCrypt::Password.create(@secret, salt_size: 20)
    expect(@password.salt.length).to eq(41)
  end

  it 'properly compares a non-standard salt hash' do
    @password = SCrypt::Password.create(@secret, salt_size: 16, max_time: 0.01)
    expect(@password == @secret).to be true
  end
end

describe 'non-default key lengths' do
  before do
    @secret = 's3cret'
  end

  it 'enforces a minimum keylength of 16 bytes' do
    @password = SCrypt::Password.create(@secret, key_len: 8, max_time: 0.01)
    expect(@password.digest.length).to eq(32) # 16 bytes * 2 (hex encoding)
  end

  it 'allows a keylength of 512 bytes' do
    @password = SCrypt::Password.create(@secret, key_len: 512, max_time: 0.01)
    expect(@password.digest.length).to eq(1024) # 512 bytes * 2 (hex encoding)
  end

  it 'enforces a maximum keylength of 512 bytes' do
    @password = SCrypt::Password.create(@secret, key_len: 1024, max_time: 0.01)
    expect(@password.digest.length).to eq(1024) # 512 bytes * 2 (hex encoding)
  end

  it 'properly compares a non-standard hash' do
    @password = SCrypt::Password.create(@secret, key_len: 64, max_time: 0.01)
    expect(@password == @secret).to be true
  end
end

describe 'Old-style hashes' do
  before do
    @secret = 'my secret'
    @hash = '400$8$d$173a8189751c095a29b933789560b73bf17b2e01$9bf66d74bd6f3ebcf99da3b379b689b89db1cb07'
  end

  it 'compares successfully' do
    expect(SCrypt::Password.new(@hash) == @secret).to be true
  end
end

describe 'Respecting standard ruby behaviors' do
  it 'hashes as an integer' do
    password = SCrypt::Password.create('secret', max_time: 0.01)
    expect(password.hash).to be_an(Integer)
  end
end

describe 'Password validation and parsing' do
  it 'correctly parses hash components' do
    password = SCrypt::Password.new('400$8$d$173a8189751c095a29b933789560b73bf17b2e01$9bf66d74bd6f3ebcf99da3b379b689b89db1cb07')

    expect(password.cost).to eq('400$8$d$')
    expect(password.salt).to eq('173a8189751c095a29b933789560b73bf17b2e01')
    expect(password.digest).to eq('9bf66d74bd6f3ebcf99da3b379b689b89db1cb07')
  end

  it 'validates hash format strictly' do
    valid_hash = '400$8$d$173a8189751c095a29b933789560b73bf17b2e01$9bf66d74bd6f3ebcf99da3b379b689b89db1cb07'

    expect { SCrypt::Password.new(valid_hash) }.not_to raise_error
    expect { SCrypt::Password.new('invalid') }.to raise_error(SCrypt::Errors::InvalidHash)
    expect { SCrypt::Password.new('') }.to raise_error(SCrypt::Errors::InvalidHash)
    expect { SCrypt::Password.new('400$8$d$') }.to raise_error(SCrypt::Errors::InvalidHash)
  end

  it 'handles alias method correctly' do
    password = SCrypt::Password.create('secret', max_time: 0.01)

    expect(password.is_password?('secret')).to be true
    expect(password.is_password?('wrong')).to be false
  end
end

describe 'Parameter boundary testing' do
  it 'enforces minimum and maximum key lengths correctly' do
    # Test minimum key length (should be clamped to 16)
    password_min = SCrypt::Password.create('secret', key_len: 8, max_time: 0.01)
    expect(password_min.digest.length).to eq(32) # 16 bytes * 2 (hex encoding)

    # Test maximum key length (should be clamped to 512)
    password_max = SCrypt::Password.create('secret', key_len: 1024, max_time: 0.01)
    expect(password_max.digest.length).to eq(1024) # 512 bytes * 2 (hex encoding)
  end

  it 'enforces minimum and maximum salt sizes correctly' do
    # Test minimum salt size (should be clamped to 8)
    password_min = SCrypt::Password.create('secret', salt_size: 4, max_time: 0.01)
    expect(password_min.salt.length).to eq(16) # 8 bytes * 2 (hex encoding)

    # Test maximum salt size (should be clamped to 32)
    password_max = SCrypt::Password.create('secret', salt_size: 64, max_time: 0.01)
    expect(password_max.salt.length).to eq(64) # 32 bytes * 2 (hex encoding)
  end
end


================================================
FILE: spec/scrypt/utils_spec.rb
================================================
# frozen_string_literal: true

require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))

describe 'Security Utils' do
  describe '.secure_compare' do
    it 'performs a string comparison correctly' do
      expect(SCrypt::SecurityUtils.secure_compare('a', 'a')).to equal(true)
      expect(SCrypt::SecurityUtils.secure_compare('a', 'b')).to equal(false)
      expect(SCrypt::SecurityUtils.secure_compare('aa', 'aa')).to equal(true)
      expect(SCrypt::SecurityUtils.secure_compare('aa', 'ab')).to equal(false)
    end

    it 'returns false for different length strings' do
      expect(SCrypt::SecurityUtils.secure_compare('aa', 'aaa')).to equal(false)
      expect(SCrypt::SecurityUtils.secure_compare('aaa', 'aa')).to equal(false)
      expect(SCrypt::SecurityUtils.secure_compare('', 'a')).to equal(false)
      expect(SCrypt::SecurityUtils.secure_compare('a', '')).to equal(false)
    end

    it 'handles empty strings correctly' do
      expect(SCrypt::SecurityUtils.secure_compare('', '')).to equal(true)
    end

    it 'handles binary data correctly' do
      binary1 = "\x00\x01\x02\x03"
      binary2 = "\x00\x01\x02\x03"
      binary3 = "\x00\x01\x02\x04"

      expect(SCrypt::SecurityUtils.secure_compare(binary1, binary2)).to equal(true)
      expect(SCrypt::SecurityUtils.secure_compare(binary1, binary3)).to equal(false)
    end

    it 'handles unicode strings correctly' do
      unicode1 = 'héllo'
      unicode2 = 'héllo'
      unicode3 = 'hello'

      expect(SCrypt::SecurityUtils.secure_compare(unicode1, unicode2)).to equal(true)
      expect(SCrypt::SecurityUtils.secure_compare(unicode1, unicode3)).to equal(false)
    end

    it 'is resistant to timing attacks' do
      # This test ensures the function takes constant time regardless of where differences occur
      long_string1 = ('a' * 1000) + 'x'
      long_string2 = ('a' * 1000) + 'y'
      long_string3 = 'x' + ('a' * 1000)
      long_string4 = 'y' + ('a' * 1000)

      # All of these should return false and take similar time
      expect(SCrypt::SecurityUtils.secure_compare(long_string1, long_string2)).to equal(false)
      expect(SCrypt::SecurityUtils.secure_compare(long_string3, long_string4)).to equal(false)
    end
  end
end


================================================
FILE: spec/spec_helper.rb
================================================
# frozen_string_literal: true

$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + '/../lib'))

require 'rubygems'
require 'rspec'
require 'yaml'
require 'scrypt'

# Load shared examples
Dir[File.expand_path('support/**/*.rb', __dir__)].each { |f| require f }

# Load test fixtures
TEST_VECTORS = YAML.load_file(File.expand_path('fixtures/test_vectors.yml', __dir__)).freeze

RSpec.configure do |config|
  # Use documentation format for better output
  config.default_formatter = 'doc' if config.files_to_run.one?

  # Run specs in random order to surface order dependencies
  config.order = :random

  # Seed global randomization in this process using the `--seed` CLI option
  Kernel.srand config.seed

  # Allow more verbose output when running a single file
  config.filter_run_when_matching :focus

  # Enable expect syntax (recommended)
  config.expect_with :rspec do |expectations|
    expectations.include_chain_clauses_in_custom_matcher_descriptions = true
    # Disable deprecated should syntax
    expectations.syntax = :expect
  end

  # Configure mocks
  config.mock_with :rspec do |mocks|
    mocks.verify_partial_doubles = true
  end

  # Enable shared context metadata behavior
  config.shared_context_metadata_behavior = :apply_to_host_groups

  # Configure warnings and deprecations
  config.warnings = true
  config.raise_errors_for_deprecations!
end


================================================
FILE: spec/support/shared_examples.rb
================================================
# frozen_string_literal: true

# Shared examples for SCrypt tests
RSpec.shared_examples 'a valid scrypt hash' do
  it 'has the correct format' do
    expect(subject).to match(/^[0-9a-z]+\$[0-9a-z]+\$[0-9a-z]+\$[A-Za-z0-9]+\$[A-Za-z0-9]+$/)
  end

  it 'is a string' do
    expect(subject).to be_a(String)
  end
end

RSpec.shared_examples 'a valid cost string' do
  it 'has the correct format' do
    expect(subject).to match(/^[0-9a-z]+\$[0-9a-z]+\$[0-9a-z]+\$$/)
  end

  it 'is valid according to Engine.valid_cost?' do
    expect(SCrypt::Engine.valid_cost?(subject)).to be(true)
  end
end

RSpec.shared_examples 'a valid salt string' do
  it 'has the correct format' do
    expect(subject).to match(/^[0-9a-z]+\$[0-9a-z]+\$[0-9a-z]+\$[A-Za-z0-9]{16,64}$/)
  end

  it 'is valid according to Engine.valid_salt?' do
    expect(SCrypt::Engine.valid_salt?(subject)).to be(true)
  end
end

RSpec.shared_examples 'proper input validation' do |method, args, error_class, error_message|
  it "raises #{error_class} for invalid input" do
    expect { subject.send(method, *args) }.to raise_error(error_class, error_message)
  end
end

RSpec.shared_examples 'deterministic output' do |method, args|
  it 'produces the same output for the same input' do
    result1 = subject.send(method, *args)
    result2 = subject.send(method, *args)
    expect(result1).to eq(result2)
  end
end


================================================
FILE: spec/support/test_helpers.rb
================================================
# frozen_string_literal: true

module TestHelpers
  # Common test data
  VALID_SECRETS = [
    'simple_password',
    'complex_password_123!@#',
    '',
    'unicode_tésting',
    '🔒secure🔑'
  ].freeze

  INVALID_HASH_FORMATS = [
    '',
    'invalid',
    '400$8$d$invalid',
    '400$8$d$173a8189751c095a29b933789560b73bf17b2e01',
    '400$8$d$173a8189751c095a29b933789560b73bf17b2e01$'
  ].freeze

  INVALID_SALT_FORMATS = [
    '',
    'invalid',
    'nino',
    '400$8$d$'
  ].freeze

  # Helper methods
  def self.generate_test_password(secret = 'test_secret', options = {})
    default_options = { max_time: 0.05 }
    SCrypt::Password.create(secret, default_options.merge(options))
  end

  def self.generate_test_salt(options = {})
    default_options = { max_time: 0.05 }
    SCrypt::Engine.generate_salt(default_options.merge(options))
  end

  def self.reset_calibration
    SCrypt::Engine.calibrated_cost = nil
  end
end

# Include helper methods in RSpec
RSpec.configure do |config|
  config.include TestHelpers
end
Download .txt
gitextract_x0o4l56k/

├── .document
├── .github/
│   └── workflows/
│       └── ruby.yml
├── .gitignore
├── .rdoc_options
├── .rspec
├── .rubocop.yml
├── .ruby-gemset
├── .ruby-version
├── CHANGELOG.md
├── COPYING
├── Gemfile
├── README.md
├── Rakefile
├── certs/
│   ├── pbhogan.pem
│   └── stakach.pem
├── checksum/
│   └── scrypt-3.0.6.gem.sha512
├── ext/
│   ├── alt-impl/
│   │   ├── crypto_scrypt-nosse.c
│   │   └── crypto_scrypt-ref.c
│   └── scrypt/
│       ├── Rakefile
│       ├── cpusupport.h
│       ├── crypto_scrypt.c
│       ├── crypto_scrypt.h
│       ├── crypto_scrypt_internal.h
│       ├── crypto_scrypt_smix.c
│       ├── crypto_scrypt_smix.h
│       ├── crypto_scrypt_smix_sse2.c
│       ├── crypto_scrypt_smix_sse2.h
│       ├── insecure_memzero.c
│       ├── insecure_memzero.h
│       ├── memlimit.c
│       ├── memlimit.h
│       ├── scrypt_calibrate.c
│       ├── scrypt_calibrate.h
│       ├── scrypt_ext.c
│       ├── scrypt_ext.h
│       ├── scrypt_platform.h
│       ├── scryptenc_cpuperf.c
│       ├── scryptenc_cpuperf.h
│       ├── sha256.c
│       ├── sha256.h
│       ├── sysendian.h
│       ├── warnp.c
│       └── warnp.h
├── lib/
│   ├── scrypt/
│   │   ├── engine.rb
│   │   ├── errors.rb
│   │   ├── password.rb
│   │   ├── scrypt_ext.rb
│   │   ├── security_utils.rb
│   │   └── version.rb
│   └── scrypt.rb
├── scrypt.gemspec
└── spec/
    ├── fixtures/
    │   └── test_vectors.yml
    ├── scrypt/
    │   ├── engine_spec.rb
    │   ├── ffi_spec.rb
    │   ├── integration_spec.rb
    │   ├── password_spec.rb
    │   └── utils_spec.rb
    ├── spec_helper.rb
    └── support/
        ├── shared_examples.rb
        └── test_helpers.rb
Download .txt
SYMBOL INDEX (128 symbols across 23 files)

FILE: ext/alt-impl/crypto_scrypt-nosse.c
  function blkcpy (line 53) | static void
  function blkxor (line 65) | static void
  function salsa20_8 (line 81) | static void
  function blockmix_salsa8 (line 127) | static void
  function integerify (line 159) | static uint64_t
  function smix (line 175) | static void
  function crypto_scrypt (line 235) | int

FILE: ext/alt-impl/crypto_scrypt-ref.c
  function blkcpy (line 48) | static void
  function blkxor (line 57) | static void
  function salsa20_8 (line 70) | static void
  function blockmix_salsa8 (line 128) | static void
  function integerify (line 158) | static uint64_t
  function smix (line 172) | static void
  function crypto_scrypt (line 215) | int

FILE: ext/scrypt/crypto_scrypt.c
  function _crypto_scrypt (line 59) | static int
  type scrypt_test (line 169) | struct scrypt_test {
  function testsmix (line 194) | static int
  function selectsmix (line 210) | static void
  function crypto_scrypt (line 246) | int

FILE: ext/scrypt/crypto_scrypt_smix.c
  function blkcpy (line 42) | static void
  function blkxor (line 54) | static void
  function salsa20_8 (line 70) | static void
  function blockmix_salsa8 (line 116) | static void
  function integerify (line 148) | static uint64_t
  function crypto_scrypt_smix (line 164) | void

FILE: ext/scrypt/crypto_scrypt_smix_sse2.c
  function blkcpy (line 45) | static void
  function blkxor (line 57) | static void
  function salsa20_8 (line 73) | static void
  function blockmix_salsa8 (line 137) | static void
  function integerify (line 170) | static uint64_t
  function crypto_scrypt_smix_sse2 (line 188) | void

FILE: ext/scrypt/insecure_memzero.c
  function insecure_memzero_func (line 7) | static void

FILE: ext/scrypt/insecure_memzero.h
  function insecure_memzero (line 30) | static inline void

FILE: ext/scrypt/memlimit.c
  function memlimit_sysctl_hw_usermem (line 58) | static int
  function memlimit_sysinfo (line 112) | static int
  function memlimit_rlimit (line 143) | static int
  function memlimit_sysconf (line 201) | static int
  function memtouse (line 240) | int

FILE: ext/scrypt/scrypt_calibrate.c
  function pickparams (line 26) | static int
  function calibrate (line 92) | int

FILE: ext/scrypt/scrypt_ext.c
  type Calibration (line 6) | typedef struct {
  function RBFFI_EXPORT (line 13) | RBFFI_EXPORT int sc_calibrate(size_t maxmem, double maxmemfrac, double m...

FILE: ext/scrypt/scryptenc_cpuperf.c
  type timespec (line 42) | struct timespec {
  function getclockres (line 52) | static int
  function getclocktime (line 84) | static int
  function getclockres (line 95) | static int
  function getclocktime (line 104) | static int
  function getclockdiff (line 118) | static int
  function scryptenc_cpuperf (line 136) | int

FILE: ext/scrypt/sha256.c
  function be32enc_vect (line 14) | static void
  function be32dec_vect (line 31) | static void
  function SHA256_Transform (line 96) | static void
  function SHA256_Pad (line 161) | static void
  function SHA256_Init (line 199) | void
  function _SHA256_Update (line 214) | static void
  function SHA256_Update (line 255) | void
  function _SHA256_Final (line 272) | static void
  function SHA256_Final (line 285) | void
  function SHA256_Buf (line 304) | void
  function _HMAC_SHA256_Init (line 324) | static void
  function HMAC_SHA256_Init (line 357) | void
  function _HMAC_SHA256_Update (line 377) | static void
  function HMAC_SHA256_Update (line 387) | void
  function _HMAC_SHA256_Final (line 404) | static void
  function HMAC_SHA256_Final (line 420) | void
  function HMAC_SHA256_Buf (line 439) | void
  function PBKDF2_SHA256 (line 462) | void

FILE: ext/scrypt/sha256.h
  type SHA256_CTX (line 23) | typedef struct {
  type HMAC_SHA256_CTX (line 55) | typedef struct {

FILE: ext/scrypt/sysendian.h
  function be32dec (line 47) | static inline uint32_t
  function be32enc (line 56) | static inline void
  function be64dec (line 67) | static inline uint64_t
  function be64enc (line 78) | static inline void
  function le32dec (line 93) | static inline uint32_t
  function le32enc (line 102) | static inline void
  function le64dec (line 113) | static inline uint64_t
  function le64enc (line 124) | static inline void

FILE: ext/scrypt/warnp.c
  function done (line 13) | static void
  function warnp_setprogname (line 25) | void
  function warn (line 54) | void
  function warnx (line 69) | void

FILE: lib/scrypt/engine.rb
  type SCrypt (line 6) | module SCrypt
    type Ext (line 7) | module Ext
    class Engine (line 20) | class Engine
      class Calibration (line 46) | class Calibration < FFI::Struct
      method scrypt (line 53) | def scrypt(secret, salt, *args)
      method hash_secret (line 70) | def hash_secret(secret, salt, key_len = DEFAULTS[:key_len])
      method generate_salt (line 89) | def generate_salt(options = {})
      method valid_cost? (line 99) | def valid_cost?(cost)
      method valid_salt? (line 104) | def valid_salt?(salt)
      method valid_secret? (line 109) | def valid_secret?(secret)
      method calibrate (line 127) | def calibrate(options = {})
      method calibrate! (line 134) | def calibrate!(options = {})
      method memory_use (line 139) | def memory_use(cost)
      method autodetect_cost (line 145) | def autodetect_cost(salt)
      method extract_salt_from_string (line 152) | def extract_salt_from_string(salt)
      method old_style_hash? (line 157) | def old_style_hash?(salt_only)
      method generate_old_style_hash (line 162) | def generate_old_style_hash(secret, salt, cost)
      method generate_new_style_hash (line 167) | def generate_new_style_hash(secret, salt, salt_only, cost, key_len)
      method avoid_old_style_collision (line 174) | def avoid_old_style_collision(salt)
      method parse_cost_string (line 184) | def parse_cost_string(cost_string)
      method __sc_calibrate (line 188) | def __sc_calibrate(max_mem, max_memfrac, max_time)
      method __sc_crypt (line 201) | def __sc_crypt(secret, salt, cpu_cost, memory_cost, parallelization,...

FILE: lib/scrypt/errors.rb
  type SCrypt (line 3) | module SCrypt
    type Errors (line 4) | module Errors
      class InvalidSalt (line 6) | class InvalidSalt   < StandardError; end
      class InvalidHash (line 9) | class InvalidHash   < StandardError; end
      class InvalidSecret (line 12) | class InvalidSecret < StandardError; end

FILE: lib/scrypt/password.rb
  type SCrypt (line 3) | module SCrypt
    class Password (line 25) | class Password < String
      method create (line 64) | def create(secret, options = {})
      method clamp_key_length (line 79) | def clamp_key_length(key_len)
      method clamp_salt_size (line 87) | def clamp_salt_size(salt_size)
      method initialize (line 96) | def initialize(raw_hash)
      method == (line 105) | def ==(other)
      method valid_hash? (line 113) | def valid_hash?(h)
      method split_hash (line 121) | def split_hash(hash_string)

FILE: lib/scrypt/scrypt_ext.rb
  type SCrypt (line 6) | module SCrypt
    type Ext (line 7) | module Ext

FILE: lib/scrypt/security_utils.rb
  type SCrypt (line 6) | module SCrypt
    type SecurityUtils (line 7) | module SecurityUtils
      function secure_compare (line 14) | def self.secure_compare(a, b)

FILE: lib/scrypt/version.rb
  type SCrypt (line 3) | module SCrypt

FILE: spec/scrypt/engine_spec.rb
  class MyInvalidSecret (line 49) | class MyInvalidSecret

FILE: spec/support/test_helpers.rb
  type TestHelpers (line 3) | module TestHelpers
    function generate_test_password (line 29) | def self.generate_test_password(secret = 'test_secret', options = {})
    function generate_test_salt (line 34) | def self.generate_test_salt(options = {})
    function reset_calibration (line 39) | def self.reset_calibration
Condensed preview — 60 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (167K chars).
[
  {
    "path": ".document",
    "chars": 31,
    "preview": "README.md\nCOPYING\n/lib/**/*.rb\n"
  },
  {
    "path": ".github/workflows/ruby.yml",
    "chars": 1106,
    "preview": "# This workflow uses actions that are not certified by GitHub.\n# They are provided by a third-party and are governed by\n"
  },
  {
    "path": ".gitignore",
    "chars": 4243,
    "preview": "\n# Created by https://www.gitignore.io/api/c,ruby,macos,rubymine,visualstudiocode\n# Edit at https://www.gitignore.io/?te"
  },
  {
    "path": ".rdoc_options",
    "chars": 175,
    "preview": "---\nmain_page: README.md\ntitle: SCrypt Ruby Documentation\n\ncharset: UTF-8\nencoding: UTF-8\nforce_update: true\nline_number"
  },
  {
    "path": ".rspec",
    "chars": 53,
    "preview": "--require spec_helper\n--color\n--format documentation\n"
  },
  {
    "path": ".rubocop.yml",
    "chars": 324,
    "preview": "\n# require: rubocop-rspec\n\nplugins:\n  - rubocop-performance\n  - rubocop-rake\n  - rubocop-rspec\n\nAllCops:\n  Include:\n    "
  },
  {
    "path": ".ruby-gemset",
    "chars": 6,
    "preview": "scrypt"
  },
  {
    "path": ".ruby-version",
    "chars": 11,
    "preview": "ruby-3.4.5\n"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 1483,
    "preview": "3.0.7\n-----\n\nChanges:\n\n* Replaced `scanf` usage to avoid the need for a runtime dependency with the upcoming Ruby 2.7.\n*"
  },
  {
    "path": "COPYING",
    "chars": 1518,
    "preview": "Copyright 2010 Patrick Hogan <pbhogan@gmail.com>\n\nOriginal implementation of scrypt by Colin Percival.\nThis product incl"
  },
  {
    "path": "Gemfile",
    "chars": 347,
    "preview": "# frozen_string_literal: true\n\nsource 'https://rubygems.org'\n\ngemspec\n\ngroup :development, :test do\n  gem 'irb'\n  gem 'r"
  },
  {
    "path": "README.md",
    "chars": 7037,
    "preview": "# scrypt\n\nA Ruby library providing a secure password hashing solution using the scrypt key derivation function.\n\n[![Gem "
  },
  {
    "path": "Rakefile",
    "chars": 2573,
    "preview": "# frozen_string_literal: true\n\nrequire 'bundler/setup'\nrequire 'bundler/gem_tasks'\nrequire 'digest/sha2'\n\nrequire 'ffi'\n"
  },
  {
    "path": "certs/pbhogan.pem",
    "chars": 1594,
    "preview": "-----BEGIN CERTIFICATE-----\nMIIEbDCCAtSgAwIBAgIBATANBgkqhkiG9w0BAQsFADA+MRAwDgYDVQQDDAdwYmhv\nZ2FuMRUwEwYKCZImiZPyLGQBGRY"
  },
  {
    "path": "certs/stakach.pem",
    "chars": 1614,
    "preview": "-----BEGIN CERTIFICATE-----\nMIIEfDCCAuSgAwIBAgIBATANBgkqhkiG9w0BAQsFADBCMQ4wDAYDVQQDDAVzdGV2\nZTEbMBkGCgmSJomT8ixkARkWC2F"
  },
  {
    "path": "checksum/scrypt-3.0.6.gem.sha512",
    "chars": 128,
    "preview": "fb1b89bddfd5fa440994aad7f3edc6cce588c41018bf60ba82eab927863e243025c2e25094be2dfefdbe21a022dec62bdd072284ff83e472071791ff"
  },
  {
    "path": "ext/alt-impl/crypto_scrypt-nosse.c",
    "chars": 9046,
    "preview": "/*-\n * Copyright 2009 Colin Percival\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, wi"
  },
  {
    "path": "ext/alt-impl/crypto_scrypt-ref.c",
    "chars": 7524,
    "preview": "/*-\n * Copyright 2009 Colin Percival\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, wi"
  },
  {
    "path": "ext/scrypt/Rakefile",
    "chars": 773,
    "preview": "require 'ffi-compiler/compile_task'\n\ntarget_cpu = RbConfig::CONFIG['target_cpu']\n\nFFI::Compiler::CompileTask.new('scrypt"
  },
  {
    "path": "ext/scrypt/cpusupport.h",
    "chars": 5254,
    "preview": "#ifndef _CPUSUPPORT_H_\n#define _CPUSUPPORT_H_\n\n/*\n * To enable support for non-portable CPU features at compile time, on"
  },
  {
    "path": "ext/scrypt/crypto_scrypt.c",
    "chars": 7152,
    "preview": "/*-\n * Copyright 2009 Colin Percival\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, wi"
  },
  {
    "path": "ext/scrypt/crypto_scrypt.h",
    "chars": 2102,
    "preview": "/*-\n * Copyright 2009 Colin Percival\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, wi"
  },
  {
    "path": "ext/scrypt/crypto_scrypt_internal.h",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "ext/scrypt/crypto_scrypt_smix.c",
    "chars": 6188,
    "preview": "/*-\n * Copyright 2009 Colin Percival\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, wi"
  },
  {
    "path": "ext/scrypt/crypto_scrypt_smix.h",
    "chars": 535,
    "preview": "#ifndef _CRYPTO_SCRYPT_SMIX_H_\n#define _CRYPTO_SCRYPT_SMIX_H_\n\n/**\n * crypto_scrypt_smix(B, r, N, V, XY):\n * Compute B ="
  },
  {
    "path": "ext/scrypt/crypto_scrypt_smix_sse2.c",
    "chars": 7024,
    "preview": "/*-\n * Copyright 2009 Colin Percival\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, wi"
  },
  {
    "path": "ext/scrypt/crypto_scrypt_smix_sse2.h",
    "chars": 589,
    "preview": "#ifndef _CRYPTO_SCRYPT_SMIX_SSE2_H_\n#define _CRYPTO_SCRYPT_SMIX_SSE2_H_\n\n/**\n * crypto_scrypt_smix_sse2(B, r, N, V, XY):"
  },
  {
    "path": "ext/scrypt/insecure_memzero.c",
    "chars": 404,
    "preview": "#include <stddef.h>\n#include <stdint.h>\n\n#include \"insecure_memzero.h\"\n\n/* Function which does the zeroing. */\nstatic vo"
  },
  {
    "path": "ext/scrypt/insecure_memzero.h",
    "chars": 1492,
    "preview": "#ifndef _INSECURE_MEMZERO_H_\n#define _INSECURE_MEMZERO_H_\n\n#include <stddef.h>\n\n/* Pointer to memory-zeroing function. *"
  },
  {
    "path": "ext/scrypt/memlimit.c",
    "chars": 7504,
    "preview": "/*-\n * Copyright 2009 Colin Percival\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, wi"
  },
  {
    "path": "ext/scrypt/memlimit.h",
    "chars": 1827,
    "preview": "/*-\n * Copyright 2009 Colin Percival\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, wi"
  },
  {
    "path": "ext/scrypt/scrypt_calibrate.c",
    "chars": 2252,
    "preview": "/*\n *  scrypt_calibrate.c\n *  scrypt\n *\n *  Created by Patrick Hogan on 12/15/10.\n *  Copyright 2010 __MyCompanyName__. "
  },
  {
    "path": "ext/scrypt/scrypt_calibrate.h",
    "chars": 308,
    "preview": "/*\n *  scrypt_calibrate.h\n *  scrypt\n *\n *  Created by Patrick Hogan on 12/15/10.\n *\n */\n\n#ifndef _SCRYPT_CALIBRATE_H_\n#"
  },
  {
    "path": "ext/scrypt/scrypt_ext.c",
    "chars": 370,
    "preview": "#include \"scrypt_ext.h\"\n#include \"scrypt_calibrate.h\"\n#include \"crypto_scrypt.h\"\n\n\ntypedef struct {\n  uint64_t n;\n  uint"
  },
  {
    "path": "ext/scrypt/scrypt_ext.h",
    "chars": 193,
    "preview": "#ifndef SCRYPT_EXT_H\n#define SCRYPT_EXT_H 1\n\n#ifndef RBFFI_EXPORT\n# ifdef __cplusplus\n#  define RBFFI_EXPORT extern \"C\"\n"
  },
  {
    "path": "ext/scrypt/scrypt_platform.h",
    "chars": 64,
    "preview": "#ifndef _SCRYPT_PLATFORM_H_\n#define\t_SCRYPT_PLATFORM_H_\n\n#endif\n"
  },
  {
    "path": "ext/scrypt/scryptenc_cpuperf.c",
    "chars": 4525,
    "preview": "/*-\n * Copyright 2009 Colin Percival\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, wi"
  },
  {
    "path": "ext/scrypt/scryptenc_cpuperf.h",
    "chars": 1734,
    "preview": "/*-\n * Copyright 2009 Colin Percival\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, wi"
  },
  {
    "path": "ext/scrypt/sha256.c",
    "chars": 13445,
    "preview": "#include <assert.h>\n#include <stdint.h>\n#include <string.h>\n\n#include \"insecure_memzero.h\"\n#include \"sysendian.h\"\n\n#incl"
  },
  {
    "path": "ext/scrypt/sha256.h",
    "chars": 2771,
    "preview": "#ifndef _SHA256_H_\n#define _SHA256_H_\n\n#include <stddef.h>\n#include <stdint.h>\n\n/*\n * Use #defines in order to avoid nam"
  },
  {
    "path": "ext/scrypt/sysendian.h",
    "chars": 3776,
    "preview": "/*-\n * Copyright 2007-2009 Colin Percival\n * All rights reserved.\n *\n * Redistribution and use in source and binary form"
  },
  {
    "path": "ext/scrypt/warnp.c",
    "chars": 1541,
    "preview": "#include <errno.h>\n#include <stdarg.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"warnp.h\"\n\ns"
  },
  {
    "path": "ext/scrypt/warnp.h",
    "chars": 1365,
    "preview": "#ifndef _WARNP_H_\n#define _WARNP_H_\n\n#include <errno.h>\n\n/* Avoid namespace collisions with BSD <err.h>. */\n#define warn"
  },
  {
    "path": "lib/scrypt/engine.rb",
    "chars": 8120,
    "preview": "# frozen_string_literal: true\n\nrequire 'ffi'\nrequire 'openssl'\n\nmodule SCrypt\n  module Ext\n    # Bind the external funct"
  },
  {
    "path": "lib/scrypt/errors.rb",
    "chars": 348,
    "preview": "# frozen_string_literal: true\n\nmodule SCrypt\n  module Errors\n    # The salt parameter provided is invalid.\n    class Inv"
  },
  {
    "path": "lib/scrypt/password.rb",
    "chars": 4820,
    "preview": "# frozen_string_literal: true\n\nmodule SCrypt\n  # A password management class which allows you to safely store users' pas"
  },
  {
    "path": "lib/scrypt/scrypt_ext.rb",
    "chars": 316,
    "preview": "# frozen_string_literal: true\n\nrequire 'ffi'\nrequire 'ffi-compiler/loader'\n\nmodule SCrypt\n  module Ext\n    extend FFI::L"
  },
  {
    "path": "lib/scrypt/security_utils.rb",
    "chars": 837,
    "preview": "# frozen_string_literal: true\n\n# NOTE:: a verbatim copy of https://github.com/rails/rails/blob/c8c660002f4b0e9606de96325"
  },
  {
    "path": "lib/scrypt/version.rb",
    "chars": 69,
    "preview": "# frozen_string_literal: true\n\nmodule SCrypt\n  VERSION = '3.1.0'\nend\n"
  },
  {
    "path": "lib/scrypt.rb",
    "chars": 205,
    "preview": "# frozen_string_literal: true\n\n# A wrapper for the scrypt algorithm.\n\nrequire 'scrypt/errors'\nrequire 'scrypt/scrypt_ext"
  },
  {
    "path": "scrypt.gemspec",
    "chars": 1371,
    "preview": "# frozen_string_literal: true\n\n$:.push File.expand_path('lib', __dir__)\nrequire 'scrypt/version'\n\nGem::Specification.new"
  },
  {
    "path": "spec/fixtures/test_vectors.yml",
    "chars": 2661,
    "preview": "# SCrypt Test Vectors\n# These are the official test vectors from the scrypt specification\n# Used to verify our implement"
  },
  {
    "path": "spec/scrypt/engine_spec.rb",
    "chars": 6798,
    "preview": "# frozen_string_literal: true\n\nrequire File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))\n\ndescrib"
  },
  {
    "path": "spec/scrypt/ffi_spec.rb",
    "chars": 1198,
    "preview": "# frozen_string_literal: true\n\nrequire File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))\n\ndescrib"
  },
  {
    "path": "spec/scrypt/integration_spec.rb",
    "chars": 4466,
    "preview": "# frozen_string_literal: true\n\nrequire File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))\n\ndescrib"
  },
  {
    "path": "spec/scrypt/password_spec.rb",
    "chars": 6647,
    "preview": "# frozen_string_literal: true\n\nrequire File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))\n\ndescrib"
  },
  {
    "path": "spec/scrypt/utils_spec.rb",
    "chars": 2249,
    "preview": "# frozen_string_literal: true\n\nrequire File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))\n\ndescrib"
  },
  {
    "path": "spec/spec_helper.rb",
    "chars": 1379,
    "preview": "# frozen_string_literal: true\n\n$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + '/../lib'))\n\nrequire 'rubyge"
  },
  {
    "path": "spec/support/shared_examples.rb",
    "chars": 1375,
    "preview": "# frozen_string_literal: true\n\n# Shared examples for SCrypt tests\nRSpec.shared_examples 'a valid scrypt hash' do\n  it 'h"
  },
  {
    "path": "spec/support/test_helpers.rb",
    "chars": 1029,
    "preview": "# frozen_string_literal: true\n\nmodule TestHelpers\n  # Common test data\n  VALID_SECRETS = [\n    'simple_password',\n    'c"
  }
]

About this extraction

This page contains the full source code of the pbhogan/scrypt GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 60 files (152.2 KB), approximately 52.2k tokens, and a symbol index with 128 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!