refactor: move build system and don't bundle code
This commit is contained in:
parent
7acfd37d61
commit
e2dd9a34a9
|
@ -1,38 +0,0 @@
|
|||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Desktop (please complete the following information):**
|
||||
- OS: [e.g. iOS]
|
||||
- Browser [e.g. chrome, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Smartphone (please complete the following information):**
|
||||
- Device: [e.g. iPhone6]
|
||||
- OS: [e.g. iOS8.1]
|
||||
- Browser [e.g. stock browser, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
|
@ -1,20 +0,0 @@
|
|||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
|
@ -1,116 +0,0 @@
|
|||
name: build, test (node and browser), coverage, publish to NPM
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*.*.*"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Git checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Use Node.js 18
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18.x
|
||||
registry-url: "https://registry.npmjs.org"
|
||||
|
||||
- name: install
|
||||
run: npm ci
|
||||
|
||||
- name: build
|
||||
run: npm run build
|
||||
|
||||
nodetests:
|
||||
name: tests in Node.js
|
||||
needs: [build]
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
node-version: [16.x, 18.x, 20.x]
|
||||
# When set to true, GitHub cancels all in-progress jobs if any matrix job fails.
|
||||
fail-fast: false
|
||||
# The maximum number of jobs that can run simultaneously. Set to 1 if you can't run tests in parallel
|
||||
# max-parallel: 1
|
||||
steps:
|
||||
- name: Git checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
registry-url: "https://registry.npmjs.org"
|
||||
|
||||
- name: install
|
||||
run: npm i
|
||||
|
||||
- name: node esm tests
|
||||
run: npm run test:node-esm
|
||||
# env:
|
||||
# VARIABLE1: ${{ secrets.VARIABLE1 }}
|
||||
# VARIABLE2: ${{ secrets.VARIABLE2 }}
|
||||
|
||||
- name: node cjs tests
|
||||
run: npm run test:node-cjs
|
||||
# env:
|
||||
# VARIABLE1: ${{ secrets.VARIABLE1 }}
|
||||
# VARIABLE2: ${{ secrets.VARIABLE2 }}
|
||||
|
||||
browsertests:
|
||||
needs: [build]
|
||||
name: tests in browser
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Git checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Use Node.js 18
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18.x
|
||||
registry-url: "https://registry.npmjs.org"
|
||||
|
||||
- name: install
|
||||
run: npm ci
|
||||
|
||||
- name: browser tests
|
||||
run: npm run test:browser-headless
|
||||
# env:
|
||||
# VARIABLE1: ${{ secrets.VARIABLE1 }}
|
||||
# VARIABLE2: ${{ secrets.VARIABLE2 }}
|
||||
|
||||
publish:
|
||||
needs: [nodetests, browsertests]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Git checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install Node.js, NPM and Yarn
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: "18.x"
|
||||
registry-url: "https://registry.npmjs.org"
|
||||
|
||||
- name: install
|
||||
run: npm ci
|
||||
|
||||
- name: coverage
|
||||
run: npm run coverage
|
||||
|
||||
- name: send report to coveralls.io
|
||||
uses: coverallsapp/github-action@master
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: NPM publish
|
||||
run: npm publish --access public
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
@ -0,0 +1,13 @@
|
|||
name: Build/Publish
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
- develop-*
|
||||
|
||||
jobs:
|
||||
main:
|
||||
uses: lumeweb/github-node-deploy-workflow/.github/workflows/main.yml@master
|
||||
secrets: inherit
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"preset": [
|
||||
"@lumeweb/node-library-preset"
|
||||
]
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"typescript.tsdk": "node_modules/typescript/lib"
|
||||
}
|
|
@ -1,128 +0,0 @@
|
|||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, religion, or sexual identity
|
||||
and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the
|
||||
overall community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or
|
||||
advances of any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email
|
||||
address, without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official e-mail address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
.
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series
|
||||
of actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or
|
||||
permanent ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within
|
||||
the community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.0, available at
|
||||
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
||||
|
||||
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
||||
enforcement ladder](https://github.com/mozilla/diversity).
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
https://www.contributor-covenant.org/faq. Translations are available at
|
||||
https://www.contributor-covenant.org/translations.
|
|
@ -1,168 +0,0 @@
|
|||
#! /usr/bin/env node
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const glob = require('glob')
|
||||
const minimatch = require('minimatch').minimatch
|
||||
const rimraf = require('rimraf')
|
||||
const runScript = require('../run-script.cjs')
|
||||
|
||||
const rootDir = path.join(__dirname, '../..')
|
||||
|
||||
const pkgJson = require(path.join(rootDir, 'package.json'))
|
||||
|
||||
const mochaTsRelativeDir = pkgJson.directories['mocha-ts']
|
||||
const mochaTsDir = path.join(rootDir, mochaTsRelativeDir)
|
||||
|
||||
// clean .mocha-ts directory
|
||||
rimraf.sync(mochaTsDir)
|
||||
|
||||
const semaphorePath = `${mochaTsRelativeDir}/semaphore`
|
||||
|
||||
const tempDir = mochaTsDir
|
||||
fs.mkdirSync(tempDir, { recursive: true })
|
||||
|
||||
const usage = `Usage: mocha-ts [options] [spec]
|
||||
|
||||
mocha against ts tests and modules
|
||||
|
||||
Arguments:
|
||||
spec One or more files, directories, or globs to test (default:
|
||||
"{src/ts/**/*.spec.ts,test/**/*.ts}")
|
||||
|
||||
Options:
|
||||
-w, --watch run in watch mode. Since mocha only supports CJS in watch
|
||||
mode. This option implies -cjs as well (default: false)
|
||||
-cjs, --commonjs run tests against the CJS bundle instead of the ESM one
|
||||
(default: false)
|
||||
-h, --help display help for command
|
||||
|
||||
`
|
||||
|
||||
function parse () {
|
||||
const args = process.argv.slice(2)
|
||||
|
||||
const help = getBooleanOption(args, '--help', '-h')
|
||||
if (help) {
|
||||
console.log(usage)
|
||||
process.exit()
|
||||
}
|
||||
|
||||
const requiredFile = getOption(args, '--require')
|
||||
|
||||
const watch = getBooleanOption(args, '--watch', '-w')
|
||||
|
||||
const commonjs = getBooleanOption(args, '--commonjs', '-cjs')
|
||||
if (commonjs === false && watch === true) {
|
||||
console.log('ERROR: mocha in watch mode only supports commonjs')
|
||||
console.log(usage)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
let testsGlob = args.pop()
|
||||
if (testsGlob === undefined) {
|
||||
testsGlob = '{src/ts/**/*.spec.ts,test/**/*.ts}'
|
||||
} else {
|
||||
testsGlob = testsGlob.replace(/^['"]/, '').replace(/['"]$/, '') // Let us remove surrounding quotes in string (it gives issues in windows)
|
||||
}
|
||||
|
||||
const mochaArgs = []
|
||||
|
||||
if (requiredFile !== '') {
|
||||
mochaArgs.push('--require')
|
||||
mochaArgs.push(requiredFile)
|
||||
}
|
||||
mochaArgs.push('--require')
|
||||
mochaArgs.push('build/testing/mocha/mocha-init.cjs')
|
||||
|
||||
if (watch) {
|
||||
mochaArgs.push('-w')
|
||||
mochaArgs.push('--watch-files')
|
||||
mochaArgs.push(semaphorePath)
|
||||
}
|
||||
|
||||
if (testsGlob.substring(0, 1) === '-') {
|
||||
console.log(usage)
|
||||
process.exit(9)
|
||||
}
|
||||
let filenames = []
|
||||
try {
|
||||
filenames = glob.sync(testsGlob, { cwd: rootDir, matchBase: true })
|
||||
} catch (error) {}
|
||||
if (filenames.length === 0) {
|
||||
console.error('invalid or empty glob pattern: ' + testsGlob)
|
||||
console.log()
|
||||
console.log(usage)
|
||||
process.exit(9)
|
||||
}
|
||||
|
||||
const testFiles = []
|
||||
const jsTestFiles = []
|
||||
|
||||
if (filenames.length > 0) {
|
||||
filenames.forEach(file => {
|
||||
const isTsTestFile = minimatch(file, '{test/**/*.ts,src/**/*.spec.ts}', { matchBase: true })
|
||||
if (isTsTestFile) {
|
||||
testFiles.push(file)
|
||||
const extension = commonjs ? 'cjs' : 'js'
|
||||
jsTestFiles.push(`${mochaTsRelativeDir}/${file.slice(0, -3)}.${extension}`)
|
||||
}
|
||||
})
|
||||
}
|
||||
mochaArgs.push(...jsTestFiles)
|
||||
|
||||
return {
|
||||
mochaArgs,
|
||||
testFiles,
|
||||
commonjs
|
||||
}
|
||||
}
|
||||
|
||||
const processedArgs = parse()
|
||||
const commonjs = processedArgs.commonjs
|
||||
const testFiles = processedArgs.testFiles
|
||||
const mochaArgs = processedArgs.mochaArgs
|
||||
|
||||
// prepare setup for mocha (it should be written to a JSON file that will be loaded by the mocha-init.cjs)
|
||||
const mochaSetup = {
|
||||
testFiles,
|
||||
commonjs
|
||||
}
|
||||
fs.writeFileSync(path.join(tempDir, 'testSetup.json'), JSON.stringify(mochaSetup, undefined, 2), { encoding: 'utf-8' })
|
||||
|
||||
if (commonjs) {
|
||||
console.log('\x1b[33mℹ [mocha-ts] Running tests against the CommonJS module \x1b[0m\n')
|
||||
} else {
|
||||
console.log('\x1b[33mℹ [mocha-ts] Running tests against the ESM module \x1b[0m\n')
|
||||
}
|
||||
|
||||
const rollupBuilder = require('../testing/mocha/builders/RollupBuilder.cjs').rollupBuilder
|
||||
|
||||
rollupBuilder.start({ commonjs, watch: false }).then(() => {
|
||||
rollupBuilder.close()
|
||||
const testsBuilder = require('../testing/mocha/builders/TestsBuilder.cjs').testBuilder
|
||||
testsBuilder.start({ commonjs, testFiles }).then(() => {
|
||||
testsBuilder.close()
|
||||
// Now run mocha
|
||||
runScript(path.join(rootDir, 'node_modules/mocha/bin/mocha'), mochaArgs)
|
||||
})
|
||||
})
|
||||
|
||||
function getBooleanOption (args, ...optionNames) {
|
||||
let found = false
|
||||
optionNames.forEach((option) => {
|
||||
const index = args.indexOf(option)
|
||||
if (index > -1) {
|
||||
found = true
|
||||
args.splice(index, 1)
|
||||
}
|
||||
})
|
||||
return found
|
||||
}
|
||||
|
||||
function getOption (args, option) {
|
||||
const index = args.indexOf(option)
|
||||
if (index > -1 && index < args.length - 2) {
|
||||
return args.splice(index, 2)[1]
|
||||
}
|
||||
return ''
|
||||
}
|
|
@ -1,205 +0,0 @@
|
|||
'use strict'
|
||||
|
||||
const fs = require('fs')
|
||||
const TypeDoc = require('typedoc')
|
||||
const path = require('path')
|
||||
const json5 = require('json5')
|
||||
const pkgJson = require('../package.json')
|
||||
const rimraf = require('rimraf')
|
||||
|
||||
const rootDir = path.join(__dirname, '..')
|
||||
|
||||
const templateFilePath = path.join(rootDir, pkgJson.directories.src, 'docs/index.md')
|
||||
let template = fs.readFileSync(templateFilePath, { encoding: 'utf-8' })
|
||||
|
||||
async function main () {
|
||||
// Generate API doc with typedoc
|
||||
await typedoc()
|
||||
|
||||
// Translate relaitive links to project's root
|
||||
replaceRelativeLinks()
|
||||
|
||||
// Let us replace variables and badges
|
||||
variableReplacements()
|
||||
|
||||
const readmeFile = path.join(rootDir, 'README.md')
|
||||
fs.writeFileSync(readmeFile, template)
|
||||
}
|
||||
|
||||
main()
|
||||
/* ------------------------------------------------------------------------- |
|
||||
| UTILITY FUNCTIONS |
|
||||
| ------------------------------------------------------------------------- */
|
||||
|
||||
function camelise (str) {
|
||||
return str.replace(/-([a-z])/g,
|
||||
function (m, w) {
|
||||
return w.toUpperCase()
|
||||
})
|
||||
}
|
||||
|
||||
async function typedoc () {
|
||||
const app = new TypeDoc.Application()
|
||||
|
||||
// prepare tsconfig
|
||||
const tsConfigPath = path.join(rootDir, 'tsconfig.json')
|
||||
const tempTsConfigPath = path.join(rootDir, '.tsconfig.json')
|
||||
|
||||
const tsConfig = json5.parse(fs.readFileSync(tsConfigPath, 'utf8'))
|
||||
tsConfig.include = ['src/ts/**/*', 'build/typings/**/*.d.ts']
|
||||
tsConfig.exclude = ['src/**/*.spec.ts']
|
||||
fs.writeFileSync(tempTsConfigPath, JSON.stringify(tsConfig, undefined, 2))
|
||||
|
||||
// If you want TypeDoc to load tsconfig.json / typedoc.json files
|
||||
app.options.addReader(new TypeDoc.TSConfigReader())
|
||||
// app.options.addReader(new TypeDoc.TypeDocReader())
|
||||
|
||||
app.bootstrap({
|
||||
// typedoc options here
|
||||
tsconfig: tempTsConfigPath,
|
||||
entryPoints: ['src/ts/index.ts'],
|
||||
disableSources: true,
|
||||
plugin: ['typedoc-plugin-markdown'],
|
||||
includeVersion: true,
|
||||
entryDocument: 'API.md',
|
||||
readme: 'none',
|
||||
hideBreadcrumbs: true,
|
||||
excludePrivate: true
|
||||
})
|
||||
|
||||
const project = app.convert()
|
||||
|
||||
if (project) {
|
||||
// Project may not have converted correctly
|
||||
const output = path.join(rootDir, './docs')
|
||||
|
||||
// Rendered docs
|
||||
await app.generateDocs(project, output)
|
||||
}
|
||||
|
||||
rimraf.sync(tempTsConfigPath)
|
||||
}
|
||||
|
||||
function getRepositoryData () {
|
||||
let ret
|
||||
if (typeof pkgJson.repository === 'string') {
|
||||
const repodata = pkgJson.repository.split(/[:/]/)
|
||||
const repoProvider = repodata[0]
|
||||
if (repoProvider === 'github' || repoProvider === 'gitlab' || repoProvider === 'bitbucket') {
|
||||
ret = {
|
||||
repoProvider,
|
||||
repoUsername: repodata[1],
|
||||
repoName: repodata.slice(2).join('/')
|
||||
}
|
||||
}
|
||||
} else if (typeof pkgJson.repository === 'object' && pkgJson.repository.type === 'git' && pkgJson.repository.url !== 'undefined') {
|
||||
const regex = /(?:.+?\+)?http[s]?:\/\/(?<repoProvider>[\w._-]+)\.\w{2,3}\/(?<repoUsername>[\w._-]+)\/(?<repoName>[\w._\-/]+?)\.git/
|
||||
const match = pkgJson.repository.url.match(regex)
|
||||
ret = {
|
||||
repoProvider: match[1],
|
||||
repoUsername: match[2],
|
||||
repoName: match[3],
|
||||
repoDirectory: pkgJson.repository.directory
|
||||
}
|
||||
}
|
||||
if (typeof ret === 'object') {
|
||||
if (typeof pkgJson.nodeBrowserSkel === 'object' && typeof pkgJson.nodeBrowserSkel.git === 'object' && typeof pkgJson.nodeBrowserSkel.git.branch === 'string') {
|
||||
ret.branch = pkgJson.nodeBrowserSkel.git.branch
|
||||
} else {
|
||||
ret.branch = (ret.repoProvider === 'github') ? 'main' : 'master'
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
function variableReplacements () {
|
||||
const { repoProvider, repoUsername, repoName, repoDirectory, branch } = getRepositoryData() || {}
|
||||
|
||||
const regex = /^(?:(?<scope>@.*?)\/)?(?<name>.*)/ // We are going to take only the package name part if there is a scope, e.g. @my-org/package-name
|
||||
const { name } = pkgJson.name.match(regex).groups
|
||||
const camelCaseName = camelise(name)
|
||||
|
||||
const iifeBundlePath = pkgJson.exports['./iife-browser-bundle'] !== undefined ? path.relative('.', pkgJson.exports['./iife-browser-bundle']) : undefined
|
||||
const esmBundlePath = pkgJson.exports['./esm-browser-bundle'] !== undefined ? path.relative('.', pkgJson.exports['./esm-browser-bundle']) : undefined
|
||||
const umdBundlePath = pkgJson.exports['./umd-browser-bundle'] !== undefined ? path.relative('.', pkgJson.exports['./umd-browser-bundle']) : undefined
|
||||
|
||||
let useWorkflowBadge = false
|
||||
let useCoverallsBadge = false
|
||||
if (pkgJson.nodeBrowserSkel !== undefined && pkgJson.nodeBrowserSkel.badges !== undefined) {
|
||||
if (pkgJson.nodeBrowserSkel.badges.workflow === true) {
|
||||
useWorkflowBadge = true
|
||||
}
|
||||
if (pkgJson.nodeBrowserSkel.badges.coveralls === true) {
|
||||
useCoverallsBadge = true
|
||||
}
|
||||
}
|
||||
|
||||
let iifeBundle, esmBundle, umdBundle, workflowBadge, coverallsBadge
|
||||
|
||||
if (repoProvider) {
|
||||
switch (repoProvider) {
|
||||
case 'github':
|
||||
iifeBundle = iifeBundlePath !== undefined ? `[IIFE bundle](https://raw.githubusercontent.com/${repoUsername}/${repoName}/${branch}/${repoDirectory !== undefined ? repoDirectory + '/' : ''}${iifeBundlePath})` : undefined
|
||||
esmBundle = esmBundlePath !== undefined ? `[ESM bundle](https://raw.githubusercontent.com/${repoUsername}/${repoName}/${branch}/${repoDirectory !== undefined ? repoDirectory + '/' : ''}${esmBundlePath})` : undefined
|
||||
umdBundle = umdBundlePath !== undefined ? `[UMD bundle](https://raw.githubusercontent.com/${repoUsername}/${repoName}/${branch}/${repoDirectory !== undefined ? repoDirectory + '/' : ''}${umdBundlePath})` : undefined
|
||||
workflowBadge = useWorkflowBadge ? `[![Node.js CI](https://github.com/${repoUsername}/${repoName}/actions/workflows/build-and-test.yml/badge.svg)](https://github.com/${repoUsername}/${repoName}/actions/workflows/build-and-test.yml)` : undefined
|
||||
coverallsBadge = useCoverallsBadge ? `[![Coverage Status](https://coveralls.io/repos/github/${repoUsername}/${repoName}/badge.svg?branch=${branch})](https://coveralls.io/github/${repoUsername}/${repoName}?branch=${branch})` : undefined
|
||||
break
|
||||
|
||||
case 'gitlab':
|
||||
iifeBundle = iifeBundlePath !== undefined ? `[IIFE bundle](https://gitlab.com/${repoUsername}/${repoName}/-/raw/${branch}/${repoDirectory !== undefined ? repoDirectory + '/' : ''}${iifeBundlePath}?inline=false)` : undefined
|
||||
esmBundle = esmBundlePath !== undefined ? `[ESM bundle](https://gitlab.com/${repoUsername}/${repoName}/-/raw/${branch}/${repoDirectory !== undefined ? repoDirectory + '/' : ''}${esmBundlePath}?inline=false)` : undefined
|
||||
umdBundle = umdBundlePath !== undefined ? `[UMD bundle](https://gitlab.com/${repoUsername}/${repoName}/-/raw/${branch}/${repoDirectory !== undefined ? repoDirectory + '/' : ''}${umdBundlePath}?inline=false)` : undefined
|
||||
break
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
template = template
|
||||
.replace(/\{\{PKG_NAME\}\}/g, pkgJson.name)
|
||||
.replace(/\{\{PKG_LICENSE\}\}/g, pkgJson.license.replace('-', '_'))
|
||||
.replace(/\{\{PKG_DESCRIPTION\}\}/g, pkgJson.description)
|
||||
.replace(/\{\{PKG_CAMELCASE\}\}/g, camelCaseName)
|
||||
.replace(/\{\{IIFE_BUNDLE\}\}/g, iifeBundle || 'IIFE bundle')
|
||||
.replace(/\{\{ESM_BUNDLE\}\}/g, esmBundle || 'ESM bundle')
|
||||
.replace(/\{\{UMD_BUNDLE\}\}/g, umdBundle || 'UMD bundle')
|
||||
|
||||
if (repoProvider && repoProvider === 'github') {
|
||||
template = template.replace(/\{\{GITHUB_ACTIONS_BADGES\}\}\n/gs, (workflowBadge ? `${workflowBadge}\n` : '') + (coverallsBadge ? `${coverallsBadge}\n` : ''))
|
||||
} else {
|
||||
template = template.replace(/\{\{GITHUB_ACTIONS_BADGES\}\}\n/gs, '')
|
||||
}
|
||||
}
|
||||
|
||||
function replaceRelativeLinks () {
|
||||
const replacements = []
|
||||
const relativePathRegex = /(\[[\w\s\d]+\]\()(?!(?:http:\/\/)|(?:https:\/\/))([\w\d;,/?:@&=+$-_.!~*'()\\#]+)\)/g
|
||||
const matches = template.matchAll(relativePathRegex)
|
||||
if (matches) {
|
||||
for (const match of matches) {
|
||||
const index = (match.index ?? 0) + match[1].length
|
||||
const filepath = match[2]
|
||||
if (!path.isAbsolute(filepath)) {
|
||||
const absoluteFilePath = path.join(path.dirname(templateFilePath), filepath)
|
||||
if (!fs.existsSync(absoluteFilePath)) {
|
||||
console.warn(`File ${absoluteFilePath} is linked in your index.md but it does not exist. Ignoring`)
|
||||
} else {
|
||||
const replacement = path.relative(rootDir, absoluteFilePath)
|
||||
replacements.push({ index, length: filepath.length, replacement })
|
||||
}
|
||||
}
|
||||
}
|
||||
const sortedReplacements = replacements.sort((a, b) => a.index - b.index)
|
||||
let ret = ''
|
||||
let index = 0
|
||||
for (const replacement of sortedReplacements) {
|
||||
ret += template.slice(index, replacement.index)
|
||||
ret += replacement.replacement
|
||||
index = replacement.index + replacement.length
|
||||
}
|
||||
ret += template.slice(index)
|
||||
template = ret
|
||||
}
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
import { mkdirSync, writeFileSync } from 'fs'
|
||||
import ts from 'typescript'
|
||||
import { join, dirname, extname } from 'path'
|
||||
import { sync } from 'rimraf'
|
||||
import * as url from 'url'
|
||||
const __dirname = url.fileURLToPath(new URL('.', import.meta.url))
|
||||
|
||||
const { readJsonConfigFile, sys, parseJsonSourceFileConfigFileContent, createCompilerHost, createProgram } = ts
|
||||
|
||||
const rootDir = join(__dirname, '..')
|
||||
const srcFile = join(rootDir, 'src/ts/index.ts')
|
||||
|
||||
const tsConfigPath = join(rootDir, 'tsconfig.json')
|
||||
|
||||
const configFile = readJsonConfigFile(tsConfigPath, (file) => {
|
||||
return sys.readFile(file)
|
||||
})
|
||||
|
||||
const tsConfig = parseJsonSourceFileConfigFileContent(configFile, sys, dirname(tsConfigPath))
|
||||
|
||||
export const compile = (outDir) => {
|
||||
const compilerOptions = {
|
||||
...tsConfig.options,
|
||||
removeComments: false,
|
||||
declaration: true,
|
||||
declarationMap: true,
|
||||
emitDeclarationOnly: true,
|
||||
outDir
|
||||
}
|
||||
|
||||
const host = createCompilerHost(compilerOptions)
|
||||
|
||||
host.writeFile = (fileName, contents) => {
|
||||
mkdirSync(dirname(fileName), { recursive: true })
|
||||
writeFileSync(fileName, contents)
|
||||
|
||||
// we also write the .d.cts types
|
||||
let fileName2 = ''
|
||||
if (extname(fileName) === '.ts') {
|
||||
fileName2 = fileName.slice(0, -2) + 'cts'
|
||||
} else { // ext is .d.ts.map
|
||||
fileName2 = fileName.slice(0, -6) + 'cts.map'
|
||||
}
|
||||
writeFileSync(fileName2, contents)
|
||||
}
|
||||
|
||||
// Clear the types dir
|
||||
sync(outDir)
|
||||
// Prepare and emit the d.ts files
|
||||
const program = createProgram([srcFile], compilerOptions, host)
|
||||
program.emit()
|
||||
}
|
|
@ -1,240 +0,0 @@
|
|||
'use strict'
|
||||
|
||||
import commonjs from '@rollup/plugin-commonjs'
|
||||
import inject from '@rollup/plugin-inject'
|
||||
import json from '@rollup/plugin-json'
|
||||
import { nodeResolve as resolve } from '@rollup/plugin-node-resolve'
|
||||
import replace from '@rollup/plugin-replace'
|
||||
import terser from '@rollup/plugin-terser'
|
||||
import rollupPluginTs from '@rollup/plugin-typescript'
|
||||
import { existsSync, readFileSync } from 'fs'
|
||||
import { builtinModules } from 'module'
|
||||
import { join } from 'path'
|
||||
import dts from 'rollup-plugin-dts'
|
||||
import { compile } from './rollup-plugin-dts.js'
|
||||
|
||||
import * as url from 'url'
|
||||
const __dirname = url.fileURLToPath(new URL('.', import.meta.url))
|
||||
|
||||
const rootDir = join(__dirname, '..')
|
||||
const pkgJson = JSON.parse(readFileSync(join(rootDir, 'package.json')))
|
||||
const pkgJsonLock = JSON.parse(readFileSync(join(rootDir, 'package-lock.json')))
|
||||
const srcDir = join(rootDir, 'src', 'ts')
|
||||
|
||||
const tsConfigPath = join(rootDir, 'tsconfig.json')
|
||||
|
||||
function camelise (str) {
|
||||
return str.replace(/-([a-z])/g,
|
||||
function (m, w) {
|
||||
return w.toUpperCase()
|
||||
})
|
||||
}
|
||||
|
||||
function isDevDependency (moduleName) {
|
||||
const packageEntry = pkgJsonLock.packages['node_modules/' + moduleName]
|
||||
return (packageEntry ?? {}).dev === true
|
||||
}
|
||||
|
||||
const regex = /^(?:(?<scope>@.*?)\/)?(?<name>.*)/ // We are going to take only the package name part if there is a scope, e.g. @my-org/package-name
|
||||
const { name } = pkgJson.name.match(regex).groups
|
||||
const pkgCamelisedName = camelise(name)
|
||||
|
||||
const input = join(srcDir, 'index.ts')
|
||||
if (existsSync(input) !== true) throw new Error('The entry point should be index.ts')
|
||||
|
||||
const tsPluginOptions = {
|
||||
tsconfig: tsConfigPath,
|
||||
outDir: undefined,
|
||||
include: ['src/ts/**/*', 'build/typings/**/*.d.ts'],
|
||||
exclude: ['src/**/*.spec.ts']
|
||||
}
|
||||
|
||||
function compileDts (outDir) {
|
||||
return {
|
||||
name: 'compile-dts',
|
||||
closeBundle () {
|
||||
compile(outDir)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function resolveOnly (module) { // if a dev dependency is imported we will resolve it so that the dist modules always work
|
||||
const moduleNameMatch = module.match(/^(?:@[a-z0-9_-]+\/)?(?:node:)?[a-z0-9_-]+/)
|
||||
if (moduleNameMatch === null || moduleNameMatch.length !== 1) {
|
||||
return false
|
||||
}
|
||||
const moduleName = moduleNameMatch[0].replace(/^node:/, '')
|
||||
// don't resolve if it is a native module
|
||||
if (builtinModules.includes(moduleName)) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (isDevDependency(moduleName)) {
|
||||
console.warn(`\x1b[33m⚠ WARM: dev dependency \x1b[0m${module}\x1b[33m being bundled. Should it be a dependency instead?\x1b[0m`)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
const tmpDeclarationsDir = join(rootDir, '.types')
|
||||
|
||||
export default [
|
||||
{ // Browser ESM
|
||||
input,
|
||||
output: [
|
||||
{
|
||||
file: join(rootDir, pkgJson.exports['.'].default.default),
|
||||
format: 'es',
|
||||
plugins: [
|
||||
terser()
|
||||
]
|
||||
}
|
||||
],
|
||||
plugins: [
|
||||
replace({
|
||||
IS_BROWSER: true,
|
||||
environment: 'browser',
|
||||
_MODULE_TYPE: "'ESM'",
|
||||
_NPM_PKG_VERSION: `'${process.env.npm_package_version}'` ?? "'0.0.1'",
|
||||
preventAssignment: true
|
||||
}),
|
||||
rollupPluginTs(tsPluginOptions),
|
||||
commonjs({ extensions: ['.js', '.cjs', '.jsx', '.cjsx'] }),
|
||||
json(),
|
||||
resolve({
|
||||
browser: true,
|
||||
exportConditions: ['browser', 'default'],
|
||||
mainFields: ['browser', 'module', 'main'],
|
||||
resolveOnly
|
||||
})
|
||||
]
|
||||
},
|
||||
{ // Browser bundles
|
||||
input,
|
||||
output: [
|
||||
{
|
||||
file: join(rootDir, pkgJson.exports['./esm-browser-bundle-nomin']),
|
||||
format: 'es'
|
||||
},
|
||||
{
|
||||
file: join(rootDir, pkgJson.exports['./esm-browser-bundle']),
|
||||
format: 'es',
|
||||
plugins: [terser()]
|
||||
},
|
||||
{
|
||||
file: join(rootDir, pkgJson.exports['./iife-browser-bundle']),
|
||||
format: 'iife',
|
||||
name: pkgCamelisedName,
|
||||
plugins: [terser()]
|
||||
},
|
||||
{
|
||||
file: join(rootDir, pkgJson.exports['./umd-browser-bundle']),
|
||||
format: 'umd',
|
||||
name: pkgCamelisedName,
|
||||
plugins: [terser()]
|
||||
}
|
||||
],
|
||||
plugins: [
|
||||
replace({
|
||||
IS_BROWSER: true,
|
||||
environment: 'browser',
|
||||
_MODULE_TYPE: "'BUNDLE'",
|
||||
_NPM_PKG_VERSION: `'${process.env.npm_package_version}'` ?? "'0.0.1'",
|
||||
preventAssignment: true
|
||||
}),
|
||||
rollupPluginTs({
|
||||
...tsPluginOptions,
|
||||
sourceMap: false
|
||||
}),
|
||||
commonjs({ extensions: ['.js', '.cjs', '.jsx', '.cjsx'] }),
|
||||
json(),
|
||||
resolve({ browser: true })
|
||||
]
|
||||
},
|
||||
{ // Node CJS
|
||||
input,
|
||||
output: [
|
||||
{
|
||||
file: join(rootDir, pkgJson.exports['.'].node.require.default),
|
||||
format: 'cjs',
|
||||
exports: 'auto',
|
||||
interop: 'auto',
|
||||
dynamicImportInCjs: false,
|
||||
plugins: [terser()]
|
||||
}
|
||||
],
|
||||
plugins: [
|
||||
replace({
|
||||
'await import(': 'require(',
|
||||
delimiters: ['', ''],
|
||||
preventAssignment: true
|
||||
}),
|
||||
replace({
|
||||
IS_BROWSER: false,
|
||||
environment: 'nodejs',
|
||||
_MODULE_TYPE: "'CJS'",
|
||||
_NPM_PKG_VERSION: `'${process.env.npm_package_version}'` ?? "'0.0.1'",
|
||||
preventAssignment: true
|
||||
}),
|
||||
rollupPluginTs(tsPluginOptions),
|
||||
inject({
|
||||
crypto: ['crypto', 'webcrypto']
|
||||
}),
|
||||
commonjs({ extensions: ['.js', '.cjs', '.jsx', '.cjsx'] }),
|
||||
json(),
|
||||
resolve({
|
||||
exportConditions: ['node'],
|
||||
resolveOnly
|
||||
})
|
||||
]
|
||||
},
|
||||
{ // Node ESM and type declarations
|
||||
input,
|
||||
output: [
|
||||
{
|
||||
file: join(rootDir, pkgJson.exports['.'].node.import.default),
|
||||
format: 'es',
|
||||
plugins: [terser()]
|
||||
}
|
||||
],
|
||||
plugins: [
|
||||
replace({
|
||||
IS_BROWSER: false,
|
||||
environment: 'nodejs',
|
||||
_MODULE_TYPE: "'ESM'",
|
||||
_NPM_PKG_VERSION: `'${process.env.npm_package_version}'` ?? "'0.0.1'",
|
||||
__filename: 'fileURLToPath(import.meta.url)',
|
||||
__dirname: 'fileURLToPath(new URL(\'.\', import.meta.url))',
|
||||
preventAssignment: true
|
||||
}),
|
||||
rollupPluginTs(tsPluginOptions),
|
||||
compileDts(tmpDeclarationsDir),
|
||||
inject({
|
||||
crypto: ['crypto', 'webcrypto'],
|
||||
fileURLToPath: ['url', 'fileURLToPath']
|
||||
}),
|
||||
commonjs({ extensions: ['.js', '.cjs', '.jsx', '.cjsx'] }),
|
||||
json(),
|
||||
resolve({
|
||||
exportConditions: ['node'],
|
||||
resolveOnly
|
||||
})
|
||||
]
|
||||
},
|
||||
{
|
||||
input: join(tmpDeclarationsDir, 'index.d.ts'),
|
||||
output: [{ file: 'dist/index.d.ts', format: 'es' }],
|
||||
plugins: [
|
||||
dts({
|
||||
respectExternal: true
|
||||
})
|
||||
],
|
||||
external: (module) => {
|
||||
if (/^[./]/.test(module)) {
|
||||
return false
|
||||
}
|
||||
return !resolveOnly(module)
|
||||
}
|
||||
}
|
||||
]
|
|
@ -1,26 +0,0 @@
|
|||
const childProcess = require('child_process')
|
||||
|
||||
const rootDir = require('path').join(__dirname, '../')
|
||||
|
||||
function runScript (scriptPath, args) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const cmd = childProcess.fork(scriptPath, args, {
|
||||
cwd: rootDir
|
||||
})
|
||||
|
||||
cmd.on('error', (error) => {
|
||||
reject(error)
|
||||
})
|
||||
|
||||
// execute the callback once the process has finished running
|
||||
cmd.on('exit', function (code) {
|
||||
if (code !== 0) {
|
||||
const error = new Error('exit code ' + code)
|
||||
reject(error)
|
||||
}
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = runScript
|
Binary file not shown.
Before Width: | Height: | Size: 326 B |
|
@ -1,120 +0,0 @@
|
|||
const path = require('path')
|
||||
|
||||
const puppeteer = require('puppeteer')
|
||||
const minimatch = require('minimatch').minimatch
|
||||
const glob = require('glob')
|
||||
const rootDir = path.join(__dirname, '../../..')
|
||||
const pkgJson = require(path.join(rootDir, 'package.json'))
|
||||
|
||||
const browserTests = async (
|
||||
{
|
||||
logWarnings = false,
|
||||
serverPort = 38000,
|
||||
keepServerRunning = false,
|
||||
puppeteerOptions = {
|
||||
headless: false,
|
||||
devtools: true
|
||||
}
|
||||
}, testFiles) => {
|
||||
const server = require('./server.cjs').server
|
||||
await server.init(testFiles)
|
||||
await server.listen(serverPort)
|
||||
const browser = await puppeteer.launch(puppeteerOptions)
|
||||
const page = (await browser.pages())[0]
|
||||
page.on('console', function (message) {
|
||||
const ignore = message.type() === 'warning' && !logWarnings
|
||||
if (ignore) return
|
||||
|
||||
let text = (message.args().length > 0) ? message.args()[0].remoteObject().value : message.text()
|
||||
const args = []
|
||||
if (message.args() !== undefined && message.args().length > 1) {
|
||||
for (let i = 1; i < message.args().length; i++) {
|
||||
args.push(message.args()[i].remoteObject().value)
|
||||
}
|
||||
}
|
||||
|
||||
if (message.type() === 'error' && message.location()) {
|
||||
text = `${message.location().url} : ${text}`
|
||||
}
|
||||
let consoleType = 'log'
|
||||
switch (message.type()) {
|
||||
case 'error':
|
||||
consoleType = 'error'
|
||||
break
|
||||
case 'warning':
|
||||
consoleType = 'warn'
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
console[consoleType](text, ...args)
|
||||
})
|
||||
|
||||
page.on('error', function (err) { page.emit(new Error(err)) })
|
||||
|
||||
page.on('close', async () => {
|
||||
await close()
|
||||
})
|
||||
|
||||
page.goto('http://localhost:38000/').then(async () => {
|
||||
const watchDog = page.waitForFunction('_mocha.state === \'stopped\'', { timeout: 0 })
|
||||
await watchDog.catch(async (reason) => {
|
||||
console.error(reason)
|
||||
})
|
||||
if (puppeteerOptions.headless === 'new') {
|
||||
await close()
|
||||
}
|
||||
}).catch(async (reason) => {
|
||||
console.error(reason)
|
||||
})
|
||||
|
||||
async function close () {
|
||||
console.log('Closing browser tests...')
|
||||
await browser.close().catch(() => {})
|
||||
if (keepServerRunning !== true) {
|
||||
await server.close().catch(() => {})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function processedTestFiles (testFilesStr) {
|
||||
if (testFilesStr === undefined) {
|
||||
testFilesStr = [pkgJson.directories.test + '/**/*.ts', pkgJson.directories.src + '/**/*.spec.ts']
|
||||
} else {
|
||||
// Let us first remove surrounding quotes in string (it gives issues in windows)
|
||||
testFilesStr = testFilesStr.replace(/^['"]/, '').replace(/['"]$/, '')
|
||||
}
|
||||
const filenames = glob.sync(testFilesStr, { cwd: rootDir, matchBase: true })
|
||||
if (filenames.length === 0) {
|
||||
throw new Error('no test files found for ' + testFilesStr)
|
||||
} else {
|
||||
filenames.forEach(file => {
|
||||
const isTsTestFile = minimatch(file, '{test/**/*.ts,src/**/*.spec.ts}', { matchBase: true })
|
||||
if (!isTsTestFile) {
|
||||
throw new Error(`test file '${file}' not found`)
|
||||
}
|
||||
})
|
||||
}
|
||||
return filenames
|
||||
}
|
||||
|
||||
const opts = {
|
||||
// puppeteer options
|
||||
puppeteerOptions: {
|
||||
headless: false,
|
||||
devtools: true,
|
||||
// slowMo: 100,
|
||||
timeout: 0
|
||||
},
|
||||
logWarnings: false, // log warnings in Node console (usually not needed)
|
||||
keepServerRunning: false, // keep server running until manually closed with ctrl-c. In combination with puppeteerOptions.headless (or just connecting any browser to the test page) allows debugging in browser
|
||||
serverPort: 38000
|
||||
}
|
||||
|
||||
const args = process.argv.slice(2)
|
||||
if (args[0] === 'headless') {
|
||||
opts.puppeteerOptions.headless = 'new'
|
||||
args.shift()
|
||||
}
|
||||
|
||||
browserTests(opts, processedTestFiles(args[0]))
|
|
@ -1,211 +0,0 @@
|
|||
'use strict'
|
||||
|
||||
const fs = require('fs')
|
||||
const http = require('http')
|
||||
const path = require('path')
|
||||
const pkgJson = require('../../../package.json')
|
||||
require('dotenv').config()
|
||||
|
||||
const rollup = require('rollup')
|
||||
const resolve = require('@rollup/plugin-node-resolve').nodeResolve
|
||||
const replace = require('@rollup/plugin-replace')
|
||||
const typescriptPlugin = require('@rollup/plugin-typescript')
|
||||
const commonjs = require('@rollup/plugin-commonjs')
|
||||
const json = require('@rollup/plugin-json')
|
||||
const multi = require('@rollup/plugin-multi-entry')
|
||||
const runScript = require('../../run-script.cjs')
|
||||
|
||||
const rootDir = path.join(__dirname, '..', '..', '..')
|
||||
|
||||
const regex = /^(?:(?<scope>@.*?)\/)?(?<name>.*)/ // We are going to take only the package name part if there is a scope, e.g. @my-org/package-name
|
||||
const { name } = pkgJson.name.match(regex).groups
|
||||
|
||||
const indexHtml = `<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||
<title>${name}</title>
|
||||
<script src="/mocha.js"></script>
|
||||
<script src="/chai.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
</body>
|
||||
<div id="mocha"></div>
|
||||
<script>
|
||||
mocha.setup({
|
||||
ui: 'bdd',
|
||||
reporter: 'spec',
|
||||
color: 'true',
|
||||
timeout: 90000
|
||||
})
|
||||
</script>
|
||||
<script type="module">
|
||||
import './tests.js'
|
||||
window._mocha = mocha.run()
|
||||
</script>
|
||||
</html>`
|
||||
|
||||
const tsBundleOptions = {
|
||||
tsconfig: path.join(rootDir, 'tsconfig.json'),
|
||||
outDir: undefined, // ignore outDir in tsconfig.json
|
||||
sourceMap: false
|
||||
// include: ['src/ts/**/*', 'build/typings/**/*.d.ts']
|
||||
}
|
||||
|
||||
async function buildTests (testFiles) {
|
||||
// create a bundle
|
||||
const inputOptions = {
|
||||
input: testFiles,
|
||||
plugins: [
|
||||
multi(),
|
||||
replace({
|
||||
IS_BROWSER: true,
|
||||
_MODULE_TYPE: "'ESM'",
|
||||
_NPM_PKG_VERSION: `'${process.env.npm_package_version}'` ?? "'0.0.1'",
|
||||
preventAssignment: true
|
||||
}),
|
||||
typescriptPlugin(tsBundleOptions),
|
||||
commonjs({ extensions: ['.js', '.cjs', '.jsx', '.cjsx'] }),
|
||||
json(),
|
||||
resolve({ browser: true }),
|
||||
replace({
|
||||
'#pkg': `/${name}.esm.js`,
|
||||
delimiters: ['', ''],
|
||||
preventAssignment: true
|
||||
})
|
||||
],
|
||||
external: [`/${name}.esm.js`]
|
||||
}
|
||||
const bundle = await rollup.rollup(inputOptions)
|
||||
const { output } = await bundle.generate({ format: 'es' })
|
||||
await bundle.close()
|
||||
let bundledCode = output[0].code
|
||||
const replacements = _getEnvVarsReplacements(bundledCode)
|
||||
for (const replacement in replacements) {
|
||||
const regExp = new RegExp(replacement, 'g')
|
||||
bundledCode = bundledCode.replace(regExp, replacements[replacement])
|
||||
}
|
||||
return bundledCode
|
||||
}
|
||||
|
||||
class TestServer {
|
||||
constructor () {
|
||||
this.server = http.createServer()
|
||||
}
|
||||
|
||||
async init (testFiles) {
|
||||
/** Let us first check if the necessary files are built, and if not, build */
|
||||
if (!fs.existsSync(pkgJson.exports['./esm-browser-bundle-nomin'])) {
|
||||
await runScript(path.join(rootDir, 'node_modules', '.bin', 'rollup'), ['-c', 'build/rollup.config.js'])
|
||||
}
|
||||
|
||||
const tests = await buildTests(testFiles)
|
||||
this.server.on('request', function (req, res) {
|
||||
if (req.url === `/${name}.esm.js`) {
|
||||
fs.readFile(path.join(rootDir, pkgJson.exports['./esm-browser-bundle-nomin']), function (err, data) {
|
||||
if (err) {
|
||||
res.writeHead(404)
|
||||
res.end(JSON.stringify(err))
|
||||
return
|
||||
}
|
||||
res.writeHead(200, { 'Content-Type': 'text/javascript' })
|
||||
res.end(data)
|
||||
})
|
||||
} else if (req.url === '/index.html' || req.url === '/') {
|
||||
res.writeHead(200)
|
||||
res.end(indexHtml)
|
||||
} else if (req.url === '/tests.js') {
|
||||
res.writeHead(200, { 'Content-Type': 'text/javascript' })
|
||||
res.end(tests)
|
||||
} else if (req.url === '/mocha.js') {
|
||||
fs.readFile(path.join(rootDir, 'node_modules/mocha/mocha.js'), function (err, data) {
|
||||
if (err) {
|
||||
res.writeHead(404)
|
||||
res.end(JSON.stringify(err))
|
||||
return
|
||||
}
|
||||
res.writeHead(200, { 'Content-Type': 'text/javascript' })
|
||||
res.end(data)
|
||||
})
|
||||
} else if (req.url === '/mocha.js.map') {
|
||||
fs.readFile(path.join(rootDir, 'node_modules/mocha/mocha.js.map'), function (err, data) {
|
||||
if (err) {
|
||||
res.writeHead(404)
|
||||
res.end(JSON.stringify(err))
|
||||
return
|
||||
}
|
||||
res.writeHead(200, { 'Content-Type': 'text/javascript' })
|
||||
res.end(data)
|
||||
})
|
||||
} else if (req.url === '/chai.js' || req.url === '/chai') {
|
||||
fs.readFile(path.join(rootDir, 'node_modules/chai/chai.js'), function (err, data) {
|
||||
if (err) {
|
||||
res.writeHead(404)
|
||||
res.end(JSON.stringify(err))
|
||||
return
|
||||
}
|
||||
res.writeHead(200, { 'Content-Type': 'text/javascript' })
|
||||
res.end(data)
|
||||
})
|
||||
} else if (req.url === '/favicon.ico') {
|
||||
fs.readFile(path.join(__dirname, 'favicon.ico'), function (err, data) {
|
||||
if (err) {
|
||||
res.writeHead(404)
|
||||
res.end(JSON.stringify(err))
|
||||
return
|
||||
}
|
||||
res.writeHead(200, { 'Content-Type': 'application/ico' })
|
||||
res.end(data)
|
||||
})
|
||||
} else {
|
||||
res.writeHead(404)
|
||||
res.end()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
listen (port = 38080) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.server.listen(port, error => {
|
||||
if (error) return reject(error)
|
||||
console.log(`Testing server listenning at http://localhost:${port}`)
|
||||
return resolve()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
close () {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.server.close(error => (error) ? reject(error) : resolve())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function _getEnvVarsReplacements (testsCode) {
|
||||
const replacements = {}
|
||||
const missingEnvVars = []
|
||||
for (const match of testsCode.matchAll(/process\.env\.(\w+)/g)) {
|
||||
const envVar = match[1]
|
||||
if (process.env[envVar] !== undefined) {
|
||||
replacements[match[0]] = '`' + process.env[envVar] + '`'
|
||||
} else {
|
||||
replacements[match[0]] = undefined
|
||||
}
|
||||
}
|
||||
for (const match of testsCode.matchAll(/process\.env\[['"](\w+)['"]\]/g)) {
|
||||
const envVar = match[1]
|
||||
if (process.env[envVar] !== undefined) {
|
||||
replacements[match[0]] = '`' + process.env[envVar] + '`'
|
||||
} else {
|
||||
replacements[match[0]] = undefined
|
||||
}
|
||||
}
|
||||
if (missingEnvVars.length > 0) {
|
||||
console.warn('The following environment variables are missing in your .env file and will be replaced with "undefined": ' + [...(new Set(missingEnvVars)).values()].join(', '))
|
||||
}
|
||||
return replacements
|
||||
}
|
||||
|
||||
exports.server = new TestServer()
|
|
@ -1,62 +0,0 @@
|
|||
const EventEmitter = require('events')
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
|
||||
module.exports = class Builder extends EventEmitter {
|
||||
constructor (semaphoreFile, name = 'builder') {
|
||||
super()
|
||||
this.name = name
|
||||
fs.mkdirSync(path.dirname(semaphoreFile), { recursive: true })
|
||||
|
||||
this.semaphoreFile = semaphoreFile
|
||||
if (!fs.existsSync(this.semaphoreFile)) {
|
||||
fs.writeFileSync(this.semaphoreFile, '', { encoding: 'utf8' })
|
||||
}
|
||||
|
||||
this._ready = false
|
||||
|
||||
this.on('message', (...message) => {
|
||||
if (message !== undefined) {
|
||||
console.log(`\x1b[33mℹ [${this.name}]`, ...message, '\x1b[0m')
|
||||
}
|
||||
})
|
||||
|
||||
this.on('error', (...error) => {
|
||||
if (error !== undefined) {
|
||||
console.error(`\x1b[31m❗ [${this.name}]`, ...error, '\x1b[0m')
|
||||
}
|
||||
})
|
||||
|
||||
this.on('ready', (updateSemaphore = true) => {
|
||||
const now = Date.now()
|
||||
if (updateSemaphore) {
|
||||
fs.utimesSync(this.semaphoreFile, now, now)
|
||||
}
|
||||
|
||||
this._ready = true
|
||||
})
|
||||
|
||||
this.on('busy', () => {
|
||||
this._ready = false
|
||||
})
|
||||
}
|
||||
|
||||
ready () {
|
||||
return new Promise(resolve => {
|
||||
if (this._ready === true) return resolve()
|
||||
this.once('ready', () => {
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
async start () {
|
||||
|
||||
}
|
||||
|
||||
async close () {}
|
||||
|
||||
clean () {
|
||||
fs.rmSync(this.semaphoreFile, { force: true })
|
||||
}
|
||||
}
|
|
@ -1,158 +0,0 @@
|
|||
const EventEmitter = require('events')
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
|
||||
const rollup = require('rollup')
|
||||
const loadAndParseConfigFile = require('rollup/loadConfigFile').loadConfigFile
|
||||
|
||||
const Builder = require('./Builder.cjs')
|
||||
|
||||
const rootDir = path.join(__dirname, '../../../../')
|
||||
|
||||
const pkgJson = require(path.join(rootDir, 'package.json'))
|
||||
|
||||
const mochaTsRelativeDir = pkgJson.directories['mocha-ts']
|
||||
const mochaTsDir = path.join(rootDir, mochaTsRelativeDir)
|
||||
|
||||
class RollupBuilder extends Builder {
|
||||
constructor ({ name, configPath, tempDir }) {
|
||||
super(path.join(tempDir, 'semaphore'), name)
|
||||
this.tempDir = tempDir
|
||||
this.configPath = configPath
|
||||
this.firstBuild = true
|
||||
}
|
||||
|
||||
async start ({ watch = false, commonjs = false }) {
|
||||
await super.start()
|
||||
|
||||
this.watch = watch
|
||||
this.commonjs = commonjs
|
||||
this.watchedModule = commonjs ? pkgJson.exports['.'].node.require.default : pkgJson.exports['.'].node.import.default
|
||||
|
||||
const { options } = await loadAndParseConfigFile(this.configPath)
|
||||
|
||||
// Instead of compiling all the outputs let us just take the one we are using with mocha (either cjs or esm)
|
||||
const rollupOptions = options.filter(bundle => {
|
||||
const file = (bundle.output[0].dir !== undefined)
|
||||
? path.join(bundle.output[0].dir, bundle.output[0].entryFileNames)
|
||||
: bundle.output[0].file
|
||||
return file === path.join(rootDir, this.watchedModule)
|
||||
})[0]
|
||||
if (rollupOptions.output.length > 1) {
|
||||
rollupOptions.output = rollupOptions.output[0]
|
||||
}
|
||||
|
||||
rollupOptions.output[0].sourcemap = 'inline'
|
||||
rollupOptions.output[0].sourcemapExcludeSources = true
|
||||
|
||||
this.builder = new RollupBundler({ rollupOptions, watch: this.watch, watchedModule: this.watchedModule })
|
||||
|
||||
this.builder.on('event', event => {
|
||||
let updateSemaphore = true
|
||||
switch (event.code) {
|
||||
case 'START':
|
||||
this.emit('busy')
|
||||
if (this.firstBuild === true) {
|
||||
this.emit('message', 'building your module...')
|
||||
} else {
|
||||
this.emit('message', 'file changes detected. Rebuilding module files...')
|
||||
}
|
||||
break
|
||||
|
||||
case 'BUNDLE_END':
|
||||
if (event.result) event.result.close()
|
||||
break
|
||||
|
||||
case 'END':
|
||||
if (event.result) event.result.close()
|
||||
|
||||
// fs.mkdirSync(path.join(this.tempDir, path.dirname(this.watchedModule)), { recursive: true })
|
||||
// // console.log(path.join(this.tempDir, path.dirname(this.watchedModule)))
|
||||
// fs.copyFileSync(this.watchedModule, path.join(this.tempDir, this.watchedModule))
|
||||
|
||||
if (this.firstBuild) {
|
||||
this.firstBuild = false
|
||||
updateSemaphore = false
|
||||
}
|
||||
this.emit('ready', updateSemaphore)
|
||||
break
|
||||
|
||||
case 'ERROR':
|
||||
if (event.result) event.result.close()
|
||||
this.emit('error', event.error)
|
||||
fs.writeFileSync(path.join(rootDir, this.watchedModule), '', 'utf8')
|
||||
// fs.writeFileSync(path.join(this.tempDir, this.watchedModule), '', 'utf8')
|
||||
this.emit('ready')
|
||||
break
|
||||
|
||||
default:
|
||||
this.emit('busy')
|
||||
break
|
||||
}
|
||||
})
|
||||
|
||||
this.builder.start()
|
||||
|
||||
return await this.ready()
|
||||
}
|
||||
|
||||
async close () {
|
||||
await super.close()
|
||||
this.builder.close()
|
||||
}
|
||||
}
|
||||
|
||||
class RollupBundler extends EventEmitter {
|
||||
constructor ({ rollupOptions, watchedModule, watch = false }) {
|
||||
super()
|
||||
this.rollupOptions = rollupOptions
|
||||
this.watch = watch
|
||||
this.watchedModule = watchedModule
|
||||
}
|
||||
|
||||
async start () {
|
||||
if (this.watch === true) {
|
||||
this.watcher = rollup.watch(this.rollupOptions)
|
||||
|
||||
this.watcher.on('event', event => {
|
||||
this.emit('event', event)
|
||||
})
|
||||
} else {
|
||||
await this._bundle()
|
||||
// if (!fs.existsSync(path.join(rootDir, this.watchedModule))) {
|
||||
// await this._bundle()
|
||||
// } else {
|
||||
// this.emit('event', { code: 'END', noBuild: true })
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
async _bundle () {
|
||||
this.emit('event', { code: 'START' })
|
||||
for (const optionsObj of [].concat(this.rollupOptions)) {
|
||||
try {
|
||||
const bundle = await rollup.rollup(optionsObj)
|
||||
try {
|
||||
await Promise.all(optionsObj.output.map(bundle.write))
|
||||
this.emit('event', { code: 'BUNDLE_END' })
|
||||
} catch (error) {
|
||||
this.emit('event', { code: 'ERROR', error })
|
||||
}
|
||||
} catch (error) {
|
||||
this.emit('event', { code: 'ERROR', error })
|
||||
}
|
||||
}
|
||||
this.emit('event', { code: 'END' })
|
||||
}
|
||||
|
||||
close () {
|
||||
if (this.watcher !== undefined) this.watcher.close()
|
||||
}
|
||||
}
|
||||
|
||||
exports.RollupBuilder = RollupBuilder
|
||||
exports.rollupBuilder = new RollupBuilder({
|
||||
name: 'rollup',
|
||||
configPath: path.join(rootDir, pkgJson.directories.build, 'rollup.config.js'),
|
||||
tempDir: mochaTsDir
|
||||
})
|
|
@ -1,194 +0,0 @@
|
|||
const path = require('path')
|
||||
const fs = require('fs')
|
||||
|
||||
const ts = require('typescript')
|
||||
const json5 = require('json5')
|
||||
|
||||
const Builder = require('./Builder.cjs')
|
||||
|
||||
const rootDir = path.join(__dirname, '../../../../')
|
||||
|
||||
const pkgJson = require(path.join(rootDir, 'package.json'))
|
||||
|
||||
const mochaTsRelativeDir = pkgJson.directories['mocha-ts']
|
||||
const mochaTsDir = path.join(rootDir, mochaTsRelativeDir)
|
||||
|
||||
const formatHost = {
|
||||
getCanonicalFileName: path => path,
|
||||
getCurrentDirectory: ts.sys.getCurrentDirectory,
|
||||
getNewLine: () => ts.sys.newLine
|
||||
}
|
||||
|
||||
function fileChecksum (filePath) {
|
||||
return require('crypto')
|
||||
.createHash('md5')
|
||||
.update(fs.readFileSync(filePath, { encoding: 'utf-8' }), 'utf8')
|
||||
.digest('hex')
|
||||
}
|
||||
|
||||
function renameJsToCjs (dir, fileList = []) {
|
||||
const files = fs.readdirSync(dir)
|
||||
|
||||
files.forEach(file => {
|
||||
const srcFile = path.join(dir, file)
|
||||
if (fs.statSync(srcFile).isDirectory()) {
|
||||
fileList = renameJsToCjs(srcFile, fileList)
|
||||
} else {
|
||||
const match = file.match(/(.*)\.js$/)
|
||||
if (match !== null) {
|
||||
const filename = match[1]
|
||||
const dstFile = path.join(dir, `${filename}.cjs`)
|
||||
fs.renameSync(srcFile, dstFile)
|
||||
const fileContents = fs.readFileSync(dstFile, 'utf8')
|
||||
const updatedFileContents = fileContents.replace(/(require\([`'"])(\..*[^.]{5})([`'"])/g, '$1$2.cjs$3')
|
||||
fs.writeFileSync(dstFile, updatedFileContents, { encoding: 'utf8' })
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function fixJsonAssertsInESMTests (dir, fileList = []) {
|
||||
const files = fs.readdirSync(dir)
|
||||
|
||||
files.forEach(file => {
|
||||
const srcFile = path.join(dir, file)
|
||||
if (fs.statSync(srcFile).isDirectory()) {
|
||||
fileList = fixJsonAssertsInESMTests(srcFile, fileList)
|
||||
} else {
|
||||
const match = file.match(/(.*)\.js$/)
|
||||
if (match !== null) {
|
||||
const fileContents = fs.readFileSync(srcFile, 'utf8')
|
||||
const updatedFileContents = fileContents.replace(/(import\([`'"]\..*\.json[`'"])\)/g, '$1, { assert: { type: "json" } })')
|
||||
fs.writeFileSync(srcFile, updatedFileContents, { encoding: 'utf8' })
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
class TestsBuilder extends Builder {
|
||||
constructor ({ name, configPath, tempDir }) {
|
||||
super(path.join(tempDir, 'semaphore'), name)
|
||||
|
||||
this.tempDir = tempDir
|
||||
|
||||
if (fs.existsSync(configPath) !== true) throw new Error(`Couldn't find a tsconfig file at ${configPath}`)
|
||||
|
||||
this.tsConfigPath = configPath
|
||||
|
||||
this.testFilesChecksums = {}
|
||||
}
|
||||
|
||||
async start ({ testFiles = [], commonjs = false }) {
|
||||
await super.start()
|
||||
|
||||
this.commonjs = commonjs
|
||||
|
||||
const tsConfig = json5.parse(fs.readFileSync(this.tsConfigPath, 'utf8'))
|
||||
|
||||
if (testFiles.length > 0) {
|
||||
delete tsConfig.files
|
||||
tsConfig.include = ['build/typings/**/*.d.ts'].concat(testFiles)
|
||||
for (let i = 0; i < testFiles.length; i++) {
|
||||
this.testFilesChecksums[testFiles[i]] = fileChecksum(testFiles[i])
|
||||
}
|
||||
} else {
|
||||
tsConfig.include = ['build/typings/**/*.d.ts', 'test/**/*', 'src/ts/**/*.spec.ts']
|
||||
}
|
||||
tsConfig.exclude = ['src/ts/**/!(.spec).ts']
|
||||
|
||||
if (this.commonjs) {
|
||||
tsConfig.compilerOptions.module = 'commonjs'
|
||||
}
|
||||
// "noResolve": true
|
||||
// tsConfig.compilerOptions.noResolve = true
|
||||
|
||||
// we don't need declaration files
|
||||
tsConfig.compilerOptions.declaration = false
|
||||
|
||||
// we need to emit files
|
||||
tsConfig.compilerOptions.noEmit = false
|
||||
|
||||
// source mapping eases debuging
|
||||
tsConfig.compilerOptions.inlineSourceMap = true
|
||||
|
||||
tsConfig.compilerOptions.rootDir = '.'
|
||||
|
||||
// Removed typeroots (it causes issues)
|
||||
tsConfig.compilerOptions.typeRoots = undefined
|
||||
|
||||
tsConfig.compilerOptions.outDir = path.isAbsolute(this.tempDir) ? path.relative(rootDir, this.tempDir) : this.tempDir
|
||||
|
||||
this.tempTsConfigPath = path.join(rootDir, '.tsconfig.json')
|
||||
|
||||
fs.writeFileSync(this.tempTsConfigPath, JSON.stringify(tsConfig, undefined, 2), { encoding: 'utf-8' })
|
||||
|
||||
const createProgram = ts.createSemanticDiagnosticsBuilderProgram
|
||||
|
||||
const reportDiagnostic = (diagnostic) => {
|
||||
const filePath = path.relative(rootDir, diagnostic.file.fileName)
|
||||
const tranpiledJsPath = `${path.join(this.tempDir, filePath).slice(0, -3)}.js`
|
||||
const errorLine = diagnostic.file.text.slice(0, diagnostic.start).split(/\r\n|\r|\n/).length
|
||||
if (fs.existsSync(tranpiledJsPath)) {
|
||||
fs.writeFileSync(tranpiledJsPath, '', 'utf8')
|
||||
}
|
||||
this.emit('error', `[Error ${diagnostic.code}]`, `${filePath}:${errorLine}`, ':', ts.flattenDiagnosticMessageText(diagnostic.messageText, formatHost.getNewLine()))
|
||||
}
|
||||
|
||||
const reportWatchStatusChanged = (diagnostic, newLine, options, errorCount) => {
|
||||
if (errorCount !== undefined) {
|
||||
// only change semaphore if test files are modified
|
||||
let updateSemaphore = false
|
||||
for (let i = 0; i < testFiles.length; i++) {
|
||||
const checksum = fileChecksum(testFiles[i])
|
||||
if (this.testFilesChecksums[testFiles[i]] !== checksum) {
|
||||
updateSemaphore = true
|
||||
this.testFilesChecksums[testFiles[i]] = checksum
|
||||
}
|
||||
}
|
||||
if (this.commonjs) {
|
||||
renameJsToCjs(mochaTsDir)
|
||||
} else {
|
||||
fixJsonAssertsInESMTests(mochaTsDir)
|
||||
}
|
||||
this.emit('ready', updateSemaphore)
|
||||
} else {
|
||||
this.emit('busy')
|
||||
if (diagnostic.code === 6031) {
|
||||
this.emit('message', 'transpiling your tests...')
|
||||
} else if (diagnostic.code === 6032) {
|
||||
this.emit('message', 'file changes detected. Transpiling your tests...')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Note that there is another overload for `createWatchCompilerHost` that takes
|
||||
// a set of root files.
|
||||
this.host = ts.createWatchCompilerHost(
|
||||
this.tempTsConfigPath,
|
||||
{},
|
||||
ts.sys,
|
||||
createProgram,
|
||||
reportDiagnostic,
|
||||
reportWatchStatusChanged
|
||||
)
|
||||
|
||||
// `createWatchProgram` creates an initial program, watches files, and updates
|
||||
// the program over time.
|
||||
this.watcher = ts.createWatchProgram(this.host)
|
||||
this.watcher.getProgram()
|
||||
return await this.ready()
|
||||
}
|
||||
|
||||
async close () {
|
||||
await super.close()
|
||||
this.watcher.close()
|
||||
fs.unlinkSync(this.tempTsConfigPath)
|
||||
}
|
||||
}
|
||||
|
||||
exports.TestsBuilder = TestsBuilder
|
||||
exports.testBuilder = new TestsBuilder({
|
||||
name: 'tsc',
|
||||
configPath: path.join(rootDir, 'tsconfig.json'),
|
||||
tempDir: mochaTsDir
|
||||
})
|
|
@ -1,68 +0,0 @@
|
|||
'use strict'
|
||||
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const chai = require('chai')
|
||||
const rimraf = require('rimraf')
|
||||
require('dotenv').config()
|
||||
|
||||
const rollupBuilder = require('./builders/RollupBuilder.cjs').rollupBuilder
|
||||
const testsBuilder = require('./builders/TestsBuilder.cjs').testBuilder
|
||||
|
||||
const rootDir = path.join(__dirname, '../../../')
|
||||
const pkgJson = require(path.join(rootDir, 'package.json'))
|
||||
|
||||
const mochaTsRelativeDir = pkgJson.directories['mocha-ts']
|
||||
const tempDir = path.join(rootDir, mochaTsRelativeDir)
|
||||
|
||||
global.chai = chai
|
||||
global.IS_BROWSER = false
|
||||
|
||||
const watch = process.argv.includes('--watch') || process.argv.includes('-w')
|
||||
|
||||
const setup = JSON.parse(fs.readFileSync(path.join(tempDir, 'testSetup.json'), 'utf-8'))
|
||||
|
||||
const testFiles = setup.testFiles
|
||||
let commonjs = setup.commonjs
|
||||
|
||||
commonjs = watch ? true : commonjs // mocha in watch mode only supports commonjs
|
||||
|
||||
global._MODULE_TYPE = commonjs ? 'CJS' : 'ESM'
|
||||
|
||||
exports.mochaGlobalSetup = async function () {
|
||||
if (watch) {
|
||||
await rollupBuilder.start({ commonjs, watch })
|
||||
testsBuilder.start({ testFiles, commonjs })
|
||||
}
|
||||
}
|
||||
|
||||
exports.mochaHooks = {
|
||||
beforeAll: [
|
||||
async function () {
|
||||
this.timeout('120000')
|
||||
|
||||
if (watch) {
|
||||
await Promise.all([rollupBuilder.ready(), testsBuilder.ready()])
|
||||
|
||||
// reset any transpiled module (just delete the cache so it is fully reloaded)
|
||||
for (const key in require.cache) {
|
||||
const relativePath = path.relative(rootDir, key)
|
||||
if (relativePath.startsWith(`.mocha-ts${path.sep}`) || relativePath.startsWith(`dist${path.sep}`)) {
|
||||
delete require.cache[key]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
exports.mochaGlobalTeardown = async function () {
|
||||
if (watch) {
|
||||
await testsBuilder.close()
|
||||
await rollupBuilder.close()
|
||||
}
|
||||
// I use the sync version of rimraf precisely because it blocks the
|
||||
// main thread and thus the mocha watcher, which otherwise would complain
|
||||
// about files being deleted
|
||||
rimraf.sync(tempDir, { disableGlob: true })
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
declare const IS_BROWSER: boolean
|
||||
declare const _MODULE_TYPE: string
|
||||
declare const _NPM_PKG_VERSION: string
|
|
@ -1,533 +0,0 @@
|
|||
function n(n){return n>=0?n:-n}function t(n){if("number"==typeof n&&(n=BigInt(n)),1n===n)return 1;let t=1;do{t++;}while((n>>=1n)>1n);return t}function r(n,t){if("number"==typeof n&&(n=BigInt(n)),"number"==typeof t&&(t=BigInt(t)),n<=0n||t<=0n)throw new RangeError("a and b MUST be > 0");let r=0n,e=1n,o=1n,i=0n;for(;0n!==n;){const u=t/n,f=t%n,g=r-o*u,c=e-i*u;t=n,n=f,r=o,e=i,o=g,i=c;}return {g:t,x:r,y:e}}function e(n,t){if("number"==typeof n&&(n=BigInt(n)),"number"==typeof t&&(t=BigInt(t)),t<=0n)throw new RangeError("n must be > 0");const r=n%t;return r<0n?r+t:r}function o(n,t){const o=r(e(n,t),t);if(1n!==o.g)throw new RangeError(`${n.toString()} does not have inverse modulo ${t.toString()}`);return e(o.x,t)}function i(n,t,r){if(n.length!==t.length)throw new RangeError("The remainders and modulos arrays should have the same length");const i=r??t.reduce(((n,t)=>n*t),1n);return t.reduce(((t,r,u)=>{const f=i/r;return e(t+f*o(f,r)%i*n[u]%i,i)}),0n)}function u(t,r){let e="number"==typeof t?BigInt(n(t)):n(t),o="number"==typeof r?BigInt(n(r)):n(r);if(0n===e)return o;if(0n===o)return e;let i=0n;for(;0n===(1n&(e|o));)e>>=1n,o>>=1n,i++;for(;0n===(1n&e);)e>>=1n;do{for(;0n===(1n&o);)o>>=1n;if(e>o){const n=e;e=o,o=n;}o-=e;}while(0n!==o);return e<<i}function f(t,r){return "number"==typeof t&&(t=BigInt(t)),"number"==typeof r&&(r=BigInt(r)),0n===t&&0n===r?BigInt(0):n(t/u(t,r)*r)}function g(n,t){return n>=t?n:t}function c(n,t){return n>=t?t:n}function m(n,t){const r=BigInt(t);return e(n.map((n=>BigInt(n)%r)).reduce(((n,t)=>n+t%r),0n),r)}function p(n,t){const r=BigInt(t);return e(n.map((n=>BigInt(n)%r)).reduce(((n,t)=>n*t%r),1n),r)}function a(n){return n.map((n=>n[0]**(n[1]-1n)*(n[0]-1n))).reduce(((n,t)=>t*n),1n)}function s(t,r,u,f){if("number"==typeof t&&(t=BigInt(t)),"number"==typeof r&&(r=BigInt(r)),"number"==typeof u&&(u=BigInt(u)),u<=0n)throw new RangeError("n must be > 0");if(1n===u)return 0n;if(t=e(t,u),r<0n)return o(s(t,n(r),u,f),u);if(void 0!==f)return function(n,t,r,e){const o=e.map((n=>n[0]**n[1])),u=e.map((n=>a([n]))),f=u.map(((r,e)=>s(n,t%r,o[e])));return i(f,o,r)}(t,r,u,function(n){const t={};return n.forEach((n=>{if("bigint"==typeof n||"number"==typeof n){const r=String(n);void 0===t[r]?t[r]={p:BigInt(n),k:1n}:t[r].k+=1n;}else {const r=String(n[0]);void 0===t[r]?t[r]={p:BigInt(n[0]),k:BigInt(n[1])}:t[r].k+=BigInt(n[1]);}})),Object.values(t).map((n=>[n.p,n.k]))}(f));let g=1n;for(;r>0;)r%2n===1n&&(g=g*t%u),r/=2n,t=t**2n%u;return g}
|
||||
|
||||
function fromBuffer(buf) {
|
||||
let ret = 0n;
|
||||
for (const i of buf.values()) {
|
||||
const bi = BigInt(i);
|
||||
ret = (ret << 8n) + bi;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
function randBytes(byteLength, forceLength = false) {
|
||||
if (byteLength < 1)
|
||||
throw new RangeError('byteLength MUST be > 0');
|
||||
return new Promise(function (resolve, reject) {
|
||||
{
|
||||
const buf = new Uint8Array(byteLength);
|
||||
if (byteLength <= 65536) {
|
||||
self.crypto.getRandomValues(buf);
|
||||
}
|
||||
else {
|
||||
for (let i = 0; i < Math.ceil(byteLength / 65536); i++) {
|
||||
const begin = i * 65536;
|
||||
const end = ((begin + 65535) < byteLength) ? begin + 65535 : byteLength - 1;
|
||||
self.crypto.getRandomValues(buf.subarray(begin, end));
|
||||
}
|
||||
}
|
||||
if (forceLength)
|
||||
buf[0] = buf[0] | 128;
|
||||
resolve(buf);
|
||||
}
|
||||
});
|
||||
}
|
||||
function randBytesSync(byteLength, forceLength = false) {
|
||||
if (byteLength < 1)
|
||||
throw new RangeError('byteLength MUST be > 0');
|
||||
{
|
||||
const buf = new Uint8Array(byteLength);
|
||||
if (byteLength <= 65536) {
|
||||
self.crypto.getRandomValues(buf);
|
||||
}
|
||||
else {
|
||||
for (let i = 0; i < Math.ceil(byteLength / 65536); i++) {
|
||||
const begin = i * 65536;
|
||||
const end = ((begin + 65535) < byteLength) ? begin + 65535 : byteLength - 1;
|
||||
self.crypto.getRandomValues(buf.subarray(begin, end));
|
||||
}
|
||||
}
|
||||
if (forceLength)
|
||||
buf[0] = buf[0] | 128;
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
function randBits(bitLength, forceLength = false) {
|
||||
if (bitLength < 1)
|
||||
throw new RangeError('bitLength MUST be > 0');
|
||||
const byteLength = Math.ceil(bitLength / 8);
|
||||
const bitLengthMod8 = bitLength % 8;
|
||||
return new Promise((resolve, reject) => {
|
||||
randBytes(byteLength, false).then(function (rndBytes) {
|
||||
if (bitLengthMod8 !== 0) {
|
||||
rndBytes[0] = rndBytes[0] & (2 ** bitLengthMod8 - 1);
|
||||
}
|
||||
if (forceLength) {
|
||||
const mask = (bitLengthMod8 !== 0) ? 2 ** (bitLengthMod8 - 1) : 128;
|
||||
rndBytes[0] = rndBytes[0] | mask;
|
||||
}
|
||||
resolve(rndBytes);
|
||||
});
|
||||
});
|
||||
}
|
||||
function randBitsSync(bitLength, forceLength = false) {
|
||||
if (bitLength < 1)
|
||||
throw new RangeError('bitLength MUST be > 0');
|
||||
const byteLength = Math.ceil(bitLength / 8);
|
||||
const rndBytes = randBytesSync(byteLength, false);
|
||||
const bitLengthMod8 = bitLength % 8;
|
||||
if (bitLengthMod8 !== 0) {
|
||||
rndBytes[0] = rndBytes[0] & (2 ** bitLengthMod8 - 1);
|
||||
}
|
||||
if (forceLength) {
|
||||
const mask = (bitLengthMod8 !== 0) ? 2 ** (bitLengthMod8 - 1) : 128;
|
||||
rndBytes[0] = rndBytes[0] | mask;
|
||||
}
|
||||
return rndBytes;
|
||||
}
|
||||
|
||||
function randBetween(max, min = 1n) {
|
||||
if (max <= min)
|
||||
throw new RangeError('Arguments MUST be: max > min');
|
||||
const interval = max - min;
|
||||
const bitLen = t(interval);
|
||||
let rnd;
|
||||
do {
|
||||
const buf = randBitsSync(bitLen);
|
||||
rnd = fromBuffer(buf);
|
||||
} while (rnd > interval);
|
||||
return rnd + min;
|
||||
}
|
||||
|
||||
function _workerUrl(workerCode) {
|
||||
workerCode = `(() => {${workerCode}})()`;
|
||||
const _blob = new Blob([workerCode], { type: 'text/javascript' });
|
||||
return window.URL.createObjectURL(_blob);
|
||||
}
|
||||
let _useWorkers = false;
|
||||
{
|
||||
if (self.Worker !== undefined)
|
||||
_useWorkers = true;
|
||||
}
|
||||
|
||||
function isProbablyPrime(w, iterations = 16, disableWorkers = false) {
|
||||
if (typeof w === 'number') {
|
||||
w = BigInt(w);
|
||||
}
|
||||
if (w < 0n)
|
||||
throw RangeError('w MUST be >= 0');
|
||||
{
|
||||
return new Promise((resolve, reject) => {
|
||||
const worker = new Worker(_isProbablyPrimeWorkerUrl());
|
||||
worker.onmessage = (event) => {
|
||||
if (event?.data?._bcu?.isPrime !== undefined) {
|
||||
worker.terminate();
|
||||
resolve(event.data._bcu.isPrime);
|
||||
}
|
||||
};
|
||||
worker.onmessageerror = (event) => {
|
||||
reject(event);
|
||||
};
|
||||
const msg = {
|
||||
_bcu: {
|
||||
rnd: w,
|
||||
iterations,
|
||||
id: 0
|
||||
}
|
||||
};
|
||||
worker.postMessage(msg);
|
||||
});
|
||||
}
|
||||
}
|
||||
function _isProbablyPrime(w, iterations) {
|
||||
if (w === 2n)
|
||||
return true;
|
||||
else if ((w & 1n) === 0n || w === 1n)
|
||||
return false;
|
||||
const firstPrimes = [
|
||||
3n,
|
||||
5n,
|
||||
7n,
|
||||
11n,
|
||||
13n,
|
||||
17n,
|
||||
19n,
|
||||
23n,
|
||||
29n,
|
||||
31n,
|
||||
37n,
|
||||
41n,
|
||||
43n,
|
||||
47n,
|
||||
53n,
|
||||
59n,
|
||||
61n,
|
||||
67n,
|
||||
71n,
|
||||
73n,
|
||||
79n,
|
||||
83n,
|
||||
89n,
|
||||
97n,
|
||||
101n,
|
||||
103n,
|
||||
107n,
|
||||
109n,
|
||||
113n,
|
||||
127n,
|
||||
131n,
|
||||
137n,
|
||||
139n,
|
||||
149n,
|
||||
151n,
|
||||
157n,
|
||||
163n,
|
||||
167n,
|
||||
173n,
|
||||
179n,
|
||||
181n,
|
||||
191n,
|
||||
193n,
|
||||
197n,
|
||||
199n,
|
||||
211n,
|
||||
223n,
|
||||
227n,
|
||||
229n,
|
||||
233n,
|
||||
239n,
|
||||
241n,
|
||||
251n,
|
||||
257n,
|
||||
263n,
|
||||
269n,
|
||||
271n,
|
||||
277n,
|
||||
281n,
|
||||
283n,
|
||||
293n,
|
||||
307n,
|
||||
311n,
|
||||
313n,
|
||||
317n,
|
||||
331n,
|
||||
337n,
|
||||
347n,
|
||||
349n,
|
||||
353n,
|
||||
359n,
|
||||
367n,
|
||||
373n,
|
||||
379n,
|
||||
383n,
|
||||
389n,
|
||||
397n,
|
||||
401n,
|
||||
409n,
|
||||
419n,
|
||||
421n,
|
||||
431n,
|
||||
433n,
|
||||
439n,
|
||||
443n,
|
||||
449n,
|
||||
457n,
|
||||
461n,
|
||||
463n,
|
||||
467n,
|
||||
479n,
|
||||
487n,
|
||||
491n,
|
||||
499n,
|
||||
503n,
|
||||
509n,
|
||||
521n,
|
||||
523n,
|
||||
541n,
|
||||
547n,
|
||||
557n,
|
||||
563n,
|
||||
569n,
|
||||
571n,
|
||||
577n,
|
||||
587n,
|
||||
593n,
|
||||
599n,
|
||||
601n,
|
||||
607n,
|
||||
613n,
|
||||
617n,
|
||||
619n,
|
||||
631n,
|
||||
641n,
|
||||
643n,
|
||||
647n,
|
||||
653n,
|
||||
659n,
|
||||
661n,
|
||||
673n,
|
||||
677n,
|
||||
683n,
|
||||
691n,
|
||||
701n,
|
||||
709n,
|
||||
719n,
|
||||
727n,
|
||||
733n,
|
||||
739n,
|
||||
743n,
|
||||
751n,
|
||||
757n,
|
||||
761n,
|
||||
769n,
|
||||
773n,
|
||||
787n,
|
||||
797n,
|
||||
809n,
|
||||
811n,
|
||||
821n,
|
||||
823n,
|
||||
827n,
|
||||
829n,
|
||||
839n,
|
||||
853n,
|
||||
857n,
|
||||
859n,
|
||||
863n,
|
||||
877n,
|
||||
881n,
|
||||
883n,
|
||||
887n,
|
||||
907n,
|
||||
911n,
|
||||
919n,
|
||||
929n,
|
||||
937n,
|
||||
941n,
|
||||
947n,
|
||||
953n,
|
||||
967n,
|
||||
971n,
|
||||
977n,
|
||||
983n,
|
||||
991n,
|
||||
997n,
|
||||
1009n,
|
||||
1013n,
|
||||
1019n,
|
||||
1021n,
|
||||
1031n,
|
||||
1033n,
|
||||
1039n,
|
||||
1049n,
|
||||
1051n,
|
||||
1061n,
|
||||
1063n,
|
||||
1069n,
|
||||
1087n,
|
||||
1091n,
|
||||
1093n,
|
||||
1097n,
|
||||
1103n,
|
||||
1109n,
|
||||
1117n,
|
||||
1123n,
|
||||
1129n,
|
||||
1151n,
|
||||
1153n,
|
||||
1163n,
|
||||
1171n,
|
||||
1181n,
|
||||
1187n,
|
||||
1193n,
|
||||
1201n,
|
||||
1213n,
|
||||
1217n,
|
||||
1223n,
|
||||
1229n,
|
||||
1231n,
|
||||
1237n,
|
||||
1249n,
|
||||
1259n,
|
||||
1277n,
|
||||
1279n,
|
||||
1283n,
|
||||
1289n,
|
||||
1291n,
|
||||
1297n,
|
||||
1301n,
|
||||
1303n,
|
||||
1307n,
|
||||
1319n,
|
||||
1321n,
|
||||
1327n,
|
||||
1361n,
|
||||
1367n,
|
||||
1373n,
|
||||
1381n,
|
||||
1399n,
|
||||
1409n,
|
||||
1423n,
|
||||
1427n,
|
||||
1429n,
|
||||
1433n,
|
||||
1439n,
|
||||
1447n,
|
||||
1451n,
|
||||
1453n,
|
||||
1459n,
|
||||
1471n,
|
||||
1481n,
|
||||
1483n,
|
||||
1487n,
|
||||
1489n,
|
||||
1493n,
|
||||
1499n,
|
||||
1511n,
|
||||
1523n,
|
||||
1531n,
|
||||
1543n,
|
||||
1549n,
|
||||
1553n,
|
||||
1559n,
|
||||
1567n,
|
||||
1571n,
|
||||
1579n,
|
||||
1583n,
|
||||
1597n
|
||||
];
|
||||
for (let i = 0; i < firstPrimes.length && (firstPrimes[i] <= w); i++) {
|
||||
const p = firstPrimes[i];
|
||||
if (w === p)
|
||||
return true;
|
||||
else if (w % p === 0n)
|
||||
return false;
|
||||
}
|
||||
let a = 0n;
|
||||
const d = w - 1n;
|
||||
let aux = d;
|
||||
while (aux % 2n === 0n) {
|
||||
aux /= 2n;
|
||||
++a;
|
||||
}
|
||||
const m = d / (2n ** a);
|
||||
do {
|
||||
const b = randBetween(d, 2n);
|
||||
let z = s(b, m, w);
|
||||
if (z === 1n || z === d)
|
||||
continue;
|
||||
let j = 1;
|
||||
while (j < a) {
|
||||
z = s(z, 2n, w);
|
||||
if (z === d)
|
||||
break;
|
||||
if (z === 1n)
|
||||
return false;
|
||||
j++;
|
||||
}
|
||||
if (z !== d)
|
||||
return false;
|
||||
} while (--iterations !== 0);
|
||||
return true;
|
||||
}
|
||||
function _isProbablyPrimeWorkerUrl() {
|
||||
let workerCode = `
|
||||
'use strict';
|
||||
const ${r.name} = ${r.toString()};
|
||||
const ${o.name} = ${o.toString()};
|
||||
const ${s.name} = ${s.toString()};
|
||||
const ${e.name} = ${e.toString()};
|
||||
const ${randBitsSync.name} = ${randBitsSync.toString()};
|
||||
const ${randBytesSync.name} = ${randBytesSync.toString()};
|
||||
const ${randBetween.name} = ${randBetween.toString()};
|
||||
const ${isProbablyPrime.name} = ${_isProbablyPrime.toString()};
|
||||
${t.toString()};
|
||||
${fromBuffer.toString()};`;
|
||||
workerCode += `
|
||||
onmessage = async function(msg) {
|
||||
if (msg !== undefined && msg.data !== undefined && msg.data._bcu !== undefined && msg.data._bcu.id !== undefined && msg.data._bcu.iterations !== undefined && msg.data._bcu.rnd !== undefined) {
|
||||
const msgToParent = {
|
||||
_bcu: {
|
||||
isPrime: await ${isProbablyPrime.name}(msg.data._bcu.rnd, msg.data._bcu.iterations),
|
||||
value: msg.data._bcu.rnd,
|
||||
id: msg.data._bcu.id
|
||||
}
|
||||
};
|
||||
postMessage(msgToParent);
|
||||
}
|
||||
}`;
|
||||
return _workerUrl(workerCode);
|
||||
}
|
||||
|
||||
function prime(bitLength, iterations = 16) {
|
||||
if (bitLength < 1)
|
||||
throw new RangeError('bitLength MUST be > 0');
|
||||
if (!_useWorkers) {
|
||||
let rnd = 0n;
|
||||
do {
|
||||
rnd = fromBuffer(randBitsSync(bitLength, true));
|
||||
} while (!_isProbablyPrime(rnd, iterations));
|
||||
return new Promise((resolve) => { resolve(rnd); });
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
const workerList = [];
|
||||
const _onmessage = (msg, newWorker) => {
|
||||
if (msg._bcu.isPrime) {
|
||||
for (let j = 0; j < workerList.length; j++) {
|
||||
workerList[j].terminate();
|
||||
}
|
||||
while (workerList.length > 0) {
|
||||
workerList.pop();
|
||||
}
|
||||
resolve(msg._bcu.value);
|
||||
}
|
||||
else {
|
||||
const buf = randBitsSync(bitLength, true);
|
||||
const rnd = fromBuffer(buf);
|
||||
try {
|
||||
const msgToWorker = {
|
||||
_bcu: {
|
||||
rnd,
|
||||
iterations,
|
||||
id: msg._bcu.id
|
||||
}
|
||||
};
|
||||
newWorker.postMessage(msgToWorker);
|
||||
}
|
||||
catch (error) {
|
||||
}
|
||||
}
|
||||
};
|
||||
{
|
||||
const workerURL = _isProbablyPrimeWorkerUrl();
|
||||
for (let i = 0; i < self.navigator.hardwareConcurrency - 1; i++) {
|
||||
const newWorker = new Worker(workerURL);
|
||||
newWorker.onmessage = (event) => _onmessage(event.data, newWorker);
|
||||
workerList.push(newWorker);
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < workerList.length; i++) {
|
||||
randBits(bitLength, true).then(function (buf) {
|
||||
const rnd = fromBuffer(buf);
|
||||
workerList[i].postMessage({
|
||||
_bcu: {
|
||||
rnd,
|
||||
iterations,
|
||||
id: i
|
||||
}
|
||||
});
|
||||
}).catch(reject);
|
||||
}
|
||||
});
|
||||
}
|
||||
function primeSync(bitLength, iterations = 16) {
|
||||
if (bitLength < 1)
|
||||
throw new RangeError('bitLength MUST be > 0');
|
||||
let rnd = 0n;
|
||||
do {
|
||||
rnd = fromBuffer(randBitsSync(bitLength, true));
|
||||
} while (!_isProbablyPrime(rnd, iterations));
|
||||
return rnd;
|
||||
}
|
||||
|
||||
export { n as abs, t as bitLength, i as crt, r as eGcd, u as gcd, isProbablyPrime, f as lcm, g as max, c as min, m as modAdd, o as modInv, p as modMultiply, s as modPow, a as phi, prime, primeSync, randBetween, randBits, randBitsSync, randBytes, randBytesSync, e as toZn };
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,257 +0,0 @@
|
|||
/// <reference types="node" />
|
||||
/**
|
||||
* Absolute value. abs(a)==a if a>=0. abs(a)==-a if a<0
|
||||
*
|
||||
* @param a
|
||||
*
|
||||
* @returns The absolute value of a
|
||||
*/
|
||||
declare function abs(a: number | bigint): number | bigint;
|
||||
|
||||
/**
|
||||
* Returns the (minimum) length of a number expressed in bits.
|
||||
*
|
||||
* @param a
|
||||
* @returns The bit length
|
||||
*/
|
||||
declare function bitLength(a: number | bigint): number;
|
||||
|
||||
/**
|
||||
* Chinese remainder theorem states that if one knows the remainders of the Euclidean division of an integer n by several integers, then one can determine uniquely the remainder of the division of n by the product of these integers, under the condition that the divisors are pairwise coprime (no two divisors share a common factor other than 1). Provided that n_i are pairwise coprime, and a_i any integers, this function returns a solution for the following system of equations:
|
||||
x ≡ a_1 mod n_1
|
||||
x ≡ a_2 mod n_2
|
||||
⋮
|
||||
x ≡ a_k mod n_k
|
||||
*
|
||||
* @param remainders the array of remainders a_i. For example [17n, 243n, 344n]
|
||||
* @param modulos the array of modulos n_i. For example [769n, 2017n, 47701n]
|
||||
* @param modulo the product of all modulos. Provided here just to save some operations if it is already known
|
||||
* @returns x
|
||||
*/
|
||||
declare function crt(remainders: bigint[], modulos: bigint[], modulo?: bigint): bigint;
|
||||
|
||||
interface Egcd {
|
||||
g: bigint;
|
||||
x: bigint;
|
||||
y: bigint;
|
||||
}
|
||||
/**
|
||||
* An iterative implementation of the extended euclidean algorithm or extended greatest common divisor algorithm.
|
||||
* Take positive integers a, b as input, and return a triple (g, x, y), such that ax + by = g = gcd(a, b).
|
||||
*
|
||||
* @param a
|
||||
* @param b
|
||||
*
|
||||
* @throws {@link RangeError} if a or b are <= 0
|
||||
*
|
||||
* @returns A triple (g, x, y), such that ax + by = g = gcd(a, b).
|
||||
*/
|
||||
declare function eGcd(a: number | bigint, b: number | bigint): Egcd;
|
||||
|
||||
/**
|
||||
* Greatest common divisor of two integers based on the iterative binary algorithm.
|
||||
*
|
||||
* @param a
|
||||
* @param b
|
||||
*
|
||||
* @returns The greatest common divisor of a and b
|
||||
*/
|
||||
declare function gcd(a: number | bigint, b: number | bigint): bigint;
|
||||
|
||||
/**
|
||||
* The least common multiple computed as abs(a*b)/gcd(a,b)
|
||||
* @param a
|
||||
* @param b
|
||||
*
|
||||
* @returns The least common multiple of a and b
|
||||
*/
|
||||
declare function lcm(a: number | bigint, b: number | bigint): bigint;
|
||||
|
||||
/**
|
||||
* Maximum. max(a,b)==a if a>=b. max(a,b)==b if a<b
|
||||
*
|
||||
* @param a
|
||||
* @param b
|
||||
*
|
||||
* @returns Maximum of numbers a and b
|
||||
*/
|
||||
declare function max(a: number | bigint, b: number | bigint): number | bigint;
|
||||
|
||||
/**
|
||||
* Minimum. min(a,b)==b if a>=b. min(a,b)==a if a<b
|
||||
*
|
||||
* @param a
|
||||
* @param b
|
||||
*
|
||||
* @returns Minimum of numbers a and b
|
||||
*/
|
||||
declare function min(a: number | bigint, b: number | bigint): number | bigint;
|
||||
|
||||
/**
|
||||
* Modular addition of (a_1 + ... + a_r) mod n
|
||||
* @param addends an array of the numbers a_i to add. For example [3, 12353251235n, 1243, -12341232545990n]
|
||||
* @param n the modulo
|
||||
* @returns The smallest positive integer that is congruent with (a_1 + ... + a_r) mod n
|
||||
*/
|
||||
declare function modAdd(addends: Array<number | bigint>, n: number | bigint): bigint;
|
||||
|
||||
/**
|
||||
* Modular inverse.
|
||||
*
|
||||
* @param a The number to find an inverse for
|
||||
* @param n The modulo
|
||||
*
|
||||
* @throws {@link RangeError} if a does not have inverse modulo n
|
||||
*
|
||||
* @returns The inverse modulo n
|
||||
*/
|
||||
declare function modInv(a: number | bigint, n: number | bigint): bigint;
|
||||
|
||||
/**
|
||||
* Modular addition of (a_1 * ... * a_r) mod n
|
||||
* @param factors an array of the numbers a_i to multiply. For example [3, 12353251235n, 1243, -12341232545990n]
|
||||
* @param n the modulo
|
||||
* @returns The smallest positive integer that is congruent with (a_1 * ... * a_r) mod n
|
||||
*/
|
||||
declare function modMultiply(factors: Array<number | bigint>, n: number | bigint): bigint;
|
||||
|
||||
type PrimePower = [number | bigint, number | bigint];
|
||||
type PrimeFactor = number | bigint | PrimePower;
|
||||
/**
|
||||
* Modular exponentiation b**e mod n. Currently using the right-to-left binary method if the prime factorization is not provided, or the chinese remainder theorem otherwise.
|
||||
*
|
||||
* @param b base
|
||||
* @param e exponent
|
||||
* @param n modulo
|
||||
* @param primeFactorization an array of the prime factors, for example [5n, 5n, 13n, 27n], or prime powers as [p, k], for instance [[5, 2], [13, 1], [27, 1]]. If the prime factorization is provided the chinese remainder theorem is used to greatly speed up the exponentiation.
|
||||
*
|
||||
* @throws {@link RangeError} if n <= 0
|
||||
*
|
||||
* @returns b**e mod n
|
||||
*/
|
||||
declare function modPow(b: number | bigint, e: number | bigint, n: number | bigint, primeFactorization?: PrimeFactor[]): bigint;
|
||||
|
||||
type PrimeFactorization = Array<[bigint, bigint]>;
|
||||
/**
|
||||
* A function that computes the Euler's totien function of a number n, whose prime power factorization is known
|
||||
*
|
||||
* @param primeFactorization an array of arrays containing the prime power factorization of a number n. For example, for n = (p1**k1)*(p2**k2)*...*(pr**kr), one should provide [[p1, k1], [p2, k2], ... , [pr, kr]]
|
||||
* @returns phi((p1**k1)*(p2**k2)*...*(pr**kr))
|
||||
*/
|
||||
declare function phi(primeFactorization: PrimeFactorization): bigint;
|
||||
|
||||
/**
|
||||
* Finds the smallest positive element that is congruent to a in modulo n
|
||||
*
|
||||
* @remarks
|
||||
* a and b must be the same type, either number or bigint
|
||||
*
|
||||
* @param a - An integer
|
||||
* @param n - The modulo
|
||||
*
|
||||
* @throws {@link RangeError} if n <= 0
|
||||
*
|
||||
* @returns A bigint with the smallest positive representation of a modulo n
|
||||
*/
|
||||
declare function toZn(a: number | bigint, n: number | bigint): bigint;
|
||||
|
||||
/**
|
||||
* The test first tries if any of the first 250 small primes are a factor of the input number and then passes several
|
||||
* iterations of Miller-Rabin Probabilistic Primality Test (FIPS 186-4 C.3.1)
|
||||
*
|
||||
* @param w - A positive integer to be tested for primality
|
||||
* @param iterations - The number of iterations for the primality test. The value shall be consistent with Table C.1, C.2 or C.3 of FIPS 186-4
|
||||
* @param disableWorkers - Disable the use of workers for the primality test
|
||||
*
|
||||
* @throws {@link RangeError} if w<0
|
||||
*
|
||||
* @returns A promise that resolves to a boolean that is either true (a probably prime number) or false (definitely composite)
|
||||
*/
|
||||
declare function isProbablyPrime(w: number | bigint, iterations?: number, disableWorkers?: boolean): Promise<boolean>;
|
||||
|
||||
/**
|
||||
* A probably-prime (Miller-Rabin), cryptographically-secure, random-number generator.
|
||||
* The browser version uses web workers to parallelise prime look up. Therefore, it does not lock the UI
|
||||
* main process, and it can be much faster (if several cores or cpu are available).
|
||||
* The node version can also use worker_threads if they are available (enabled by default with Node 11 and
|
||||
* and can be enabled at runtime executing node --experimental-worker with node >=10.5.0).
|
||||
*
|
||||
* @param bitLength - The required bit length for the generated prime
|
||||
* @param iterations - The number of iterations for the Miller-Rabin Probabilistic Primality Test
|
||||
*
|
||||
* @throws {@link RangeError} if bitLength < 1
|
||||
*
|
||||
* @returns A promise that resolves to a bigint probable prime of bitLength bits.
|
||||
*/
|
||||
declare function prime(bitLength: number, iterations?: number): Promise<bigint>;
|
||||
/**
|
||||
* A probably-prime (Miller-Rabin), cryptographically-secure, random-number generator.
|
||||
* The sync version is NOT RECOMMENDED since it won't use workers and thus it'll be slower and may freeze thw window in browser's javascript. Please consider using prime() instead.
|
||||
*
|
||||
* @param bitLength - The required bit length for the generated prime
|
||||
* @param iterations - The number of iterations for the Miller-Rabin Probabilistic Primality Test
|
||||
*
|
||||
* @throws {@link RangeError} if bitLength < 1
|
||||
*
|
||||
* @returns A bigint probable prime of bitLength bits.
|
||||
*/
|
||||
declare function primeSync(bitLength: number, iterations?: number): bigint;
|
||||
|
||||
/**
|
||||
* Returns a cryptographically secure random integer between [min,max].
|
||||
* @param max Returned value will be <= max
|
||||
* @param min Returned value will be >= min
|
||||
*
|
||||
* @throws {@link RangeError} if max <= min
|
||||
*
|
||||
* @returns A cryptographically secure random bigint between [min,max]
|
||||
*/
|
||||
declare function randBetween(max: bigint, min?: bigint): bigint;
|
||||
|
||||
/**
|
||||
* Secure random bits for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()
|
||||
*
|
||||
* @param bitLength - The desired number of random bits
|
||||
* @param forceLength - Set to true if you want to force the output to have a specific bit length. It basically forces the msb to be 1
|
||||
*
|
||||
* @throws {@link RangeError} if bitLength < 1
|
||||
*
|
||||
* @returns A Promise that resolves to a UInt8Array/Buffer (Browser/Node.js) filled with cryptographically secure random bits
|
||||
*/
|
||||
declare function randBits(bitLength: number, forceLength?: boolean): Promise<Uint8Array | Buffer>;
|
||||
/**
|
||||
* Secure random bits for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()
|
||||
* @param bitLength - The desired number of random bits
|
||||
* @param forceLength - Set to true if you want to force the output to have a specific bit length. It basically forces the msb to be 1
|
||||
*
|
||||
* @throws {@link RangeError} if bitLength < 1
|
||||
*
|
||||
* @returns A Uint8Array/Buffer (Browser/Node.js) filled with cryptographically secure random bits
|
||||
*/
|
||||
declare function randBitsSync(bitLength: number, forceLength?: boolean): Uint8Array | Buffer;
|
||||
|
||||
/**
|
||||
* Secure random bytes for both node and browsers. Node version uses crypto.randomBytes() and browser one self.crypto.getRandomValues()
|
||||
*
|
||||
* @param byteLength - The desired number of random bytes
|
||||
* @param forceLength - Set to true if you want to force the output to have a bit length of 8*byteLength. It basically forces the msb to be 1
|
||||
*
|
||||
* @throws {@link RangeError} if byteLength < 1
|
||||
*
|
||||
* @returns A promise that resolves to a UInt8Array/Buffer (Browser/Node.js) filled with cryptographically secure random bytes
|
||||
*/
|
||||
declare function randBytes(byteLength: number, forceLength?: boolean): Promise<Uint8Array | Buffer>;
|
||||
/**
|
||||
* Secure random bytes for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()
|
||||
* This is the synchronous version, consider using the asynchronous one for improved efficiency.
|
||||
*
|
||||
* @param byteLength - The desired number of random bytes
|
||||
* @param forceLength - Set to true if you want to force the output to have a bit length of 8*byteLength. It basically forces the msb to be 1
|
||||
*
|
||||
* @throws {@link RangeError} if byteLength < 1
|
||||
*
|
||||
* @returns A UInt8Array/Buffer (Browser/Node.js) filled with cryptographically secure random bytes
|
||||
*/
|
||||
declare function randBytesSync(byteLength: number, forceLength?: boolean): Uint8Array | Buffer;
|
||||
|
||||
export { Egcd, PrimeFactor, PrimeFactorization, PrimePower, abs, bitLength, crt, eGcd, gcd, isProbablyPrime, lcm, max, min, modAdd, modInv, modMultiply, modPow, phi, prime, primeSync, randBetween, randBits, randBitsSync, randBytes, randBytesSync, toZn };
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
584
docs/API.md
584
docs/API.md
|
@ -1,584 +0,0 @@
|
|||
# bigint-crypto-utils - v3.3.0
|
||||
|
||||
## Table of contents
|
||||
|
||||
### Interfaces
|
||||
|
||||
- [Egcd](interfaces/Egcd.md)
|
||||
|
||||
### Type Aliases
|
||||
|
||||
- [PrimeFactor](API.md#primefactor)
|
||||
- [PrimeFactorization](API.md#primefactorization)
|
||||
- [PrimePower](API.md#primepower)
|
||||
|
||||
### Functions
|
||||
|
||||
- [abs](API.md#abs)
|
||||
- [bitLength](API.md#bitlength)
|
||||
- [crt](API.md#crt)
|
||||
- [eGcd](API.md#egcd)
|
||||
- [gcd](API.md#gcd)
|
||||
- [isProbablyPrime](API.md#isprobablyprime)
|
||||
- [lcm](API.md#lcm)
|
||||
- [max](API.md#max)
|
||||
- [min](API.md#min)
|
||||
- [modAdd](API.md#modadd)
|
||||
- [modInv](API.md#modinv)
|
||||
- [modMultiply](API.md#modmultiply)
|
||||
- [modPow](API.md#modpow)
|
||||
- [phi](API.md#phi)
|
||||
- [prime](API.md#prime)
|
||||
- [primeSync](API.md#primesync)
|
||||
- [randBetween](API.md#randbetween)
|
||||
- [randBits](API.md#randbits)
|
||||
- [randBitsSync](API.md#randbitssync)
|
||||
- [randBytes](API.md#randbytes)
|
||||
- [randBytesSync](API.md#randbytessync)
|
||||
- [toZn](API.md#tozn)
|
||||
|
||||
## Type Aliases
|
||||
|
||||
### PrimeFactor
|
||||
|
||||
Ƭ **PrimeFactor**: `number` \| `bigint` \| [`PrimePower`](API.md#primepower)
|
||||
|
||||
___
|
||||
|
||||
### PrimeFactorization
|
||||
|
||||
Ƭ **PrimeFactorization**: [`bigint`, `bigint`][]
|
||||
|
||||
___
|
||||
|
||||
### PrimePower
|
||||
|
||||
Ƭ **PrimePower**: [`number` \| `bigint`, `number` \| `bigint`]
|
||||
|
||||
## Functions
|
||||
|
||||
### abs
|
||||
|
||||
▸ **abs**(`a`): `number` \| `bigint`
|
||||
|
||||
Absolute value. abs(a)==a if a>=0. abs(a)==-a if a<0
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| :------ | :------ |
|
||||
| `a` | `number` \| `bigint` |
|
||||
|
||||
#### Returns
|
||||
|
||||
`number` \| `bigint`
|
||||
|
||||
The absolute value of a
|
||||
|
||||
___
|
||||
|
||||
### bitLength
|
||||
|
||||
▸ **bitLength**(`a`): `number`
|
||||
|
||||
Returns the (minimum) length of a number expressed in bits.
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| :------ | :------ |
|
||||
| `a` | `number` \| `bigint` |
|
||||
|
||||
#### Returns
|
||||
|
||||
`number`
|
||||
|
||||
The bit length
|
||||
|
||||
___
|
||||
|
||||
### crt
|
||||
|
||||
▸ **crt**(`remainders`, `modulos`, `modulo?`): `bigint`
|
||||
|
||||
Chinese remainder theorem states that if one knows the remainders of the Euclidean division of an integer n by several integers, then one can determine uniquely the remainder of the division of n by the product of these integers, under the condition that the divisors are pairwise coprime (no two divisors share a common factor other than 1). Provided that n_i are pairwise coprime, and a_i any integers, this function returns a solution for the following system of equations:
|
||||
x ≡ a_1 mod n_1
|
||||
x ≡ a_2 mod n_2
|
||||
⋮
|
||||
x ≡ a_k mod n_k
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
| :------ | :------ | :------ |
|
||||
| `remainders` | `bigint`[] | the array of remainders a_i. For example [17n, 243n, 344n] |
|
||||
| `modulos` | `bigint`[] | the array of modulos n_i. For example [769n, 2017n, 47701n] |
|
||||
| `modulo?` | `bigint` | the product of all modulos. Provided here just to save some operations if it is already known |
|
||||
|
||||
#### Returns
|
||||
|
||||
`bigint`
|
||||
|
||||
x
|
||||
|
||||
___
|
||||
|
||||
### eGcd
|
||||
|
||||
▸ **eGcd**(`a`, `b`): [`Egcd`](interfaces/Egcd.md)
|
||||
|
||||
An iterative implementation of the extended euclidean algorithm or extended greatest common divisor algorithm.
|
||||
Take positive integers a, b as input, and return a triple (g, x, y), such that ax + by = g = gcd(a, b).
|
||||
|
||||
**`Throws`**
|
||||
|
||||
RangeError if a or b are <= 0
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| :------ | :------ |
|
||||
| `a` | `number` \| `bigint` |
|
||||
| `b` | `number` \| `bigint` |
|
||||
|
||||
#### Returns
|
||||
|
||||
[`Egcd`](interfaces/Egcd.md)
|
||||
|
||||
A triple (g, x, y), such that ax + by = g = gcd(a, b).
|
||||
|
||||
___
|
||||
|
||||
### gcd
|
||||
|
||||
▸ **gcd**(`a`, `b`): `bigint`
|
||||
|
||||
Greatest common divisor of two integers based on the iterative binary algorithm.
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| :------ | :------ |
|
||||
| `a` | `number` \| `bigint` |
|
||||
| `b` | `number` \| `bigint` |
|
||||
|
||||
#### Returns
|
||||
|
||||
`bigint`
|
||||
|
||||
The greatest common divisor of a and b
|
||||
|
||||
___
|
||||
|
||||
### isProbablyPrime
|
||||
|
||||
▸ **isProbablyPrime**(`w`, `iterations?`, `disableWorkers?`): `Promise`<`boolean`\>
|
||||
|
||||
The test first tries if any of the first 250 small primes are a factor of the input number and then passes several
|
||||
iterations of Miller-Rabin Probabilistic Primality Test (FIPS 186-4 C.3.1)
|
||||
|
||||
**`Throws`**
|
||||
|
||||
RangeError if w<0
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Default value | Description |
|
||||
| :------ | :------ | :------ | :------ |
|
||||
| `w` | `number` \| `bigint` | `undefined` | A positive integer to be tested for primality |
|
||||
| `iterations` | `number` | `16` | The number of iterations for the primality test. The value shall be consistent with Table C.1, C.2 or C.3 of FIPS 186-4 |
|
||||
| `disableWorkers` | `boolean` | `false` | Disable the use of workers for the primality test |
|
||||
|
||||
#### Returns
|
||||
|
||||
`Promise`<`boolean`\>
|
||||
|
||||
A promise that resolves to a boolean that is either true (a probably prime number) or false (definitely composite)
|
||||
|
||||
___
|
||||
|
||||
### lcm
|
||||
|
||||
▸ **lcm**(`a`, `b`): `bigint`
|
||||
|
||||
The least common multiple computed as abs(a*b)/gcd(a,b)
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| :------ | :------ |
|
||||
| `a` | `number` \| `bigint` |
|
||||
| `b` | `number` \| `bigint` |
|
||||
|
||||
#### Returns
|
||||
|
||||
`bigint`
|
||||
|
||||
The least common multiple of a and b
|
||||
|
||||
___
|
||||
|
||||
### max
|
||||
|
||||
▸ **max**(`a`, `b`): `number` \| `bigint`
|
||||
|
||||
Maximum. max(a,b)==a if a>=b. max(a,b)==b if a<b
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| :------ | :------ |
|
||||
| `a` | `number` \| `bigint` |
|
||||
| `b` | `number` \| `bigint` |
|
||||
|
||||
#### Returns
|
||||
|
||||
`number` \| `bigint`
|
||||
|
||||
Maximum of numbers a and b
|
||||
|
||||
___
|
||||
|
||||
### min
|
||||
|
||||
▸ **min**(`a`, `b`): `number` \| `bigint`
|
||||
|
||||
Minimum. min(a,b)==b if a>=b. min(a,b)==a if a<b
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| :------ | :------ |
|
||||
| `a` | `number` \| `bigint` |
|
||||
| `b` | `number` \| `bigint` |
|
||||
|
||||
#### Returns
|
||||
|
||||
`number` \| `bigint`
|
||||
|
||||
Minimum of numbers a and b
|
||||
|
||||
___
|
||||
|
||||
### modAdd
|
||||
|
||||
▸ **modAdd**(`addends`, `n`): `bigint`
|
||||
|
||||
Modular addition of (a_1 + ... + a_r) mod n
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
| :------ | :------ | :------ |
|
||||
| `addends` | (`number` \| `bigint`)[] | an array of the numbers a_i to add. For example [3, 12353251235n, 1243, -12341232545990n] |
|
||||
| `n` | `number` \| `bigint` | the modulo |
|
||||
|
||||
#### Returns
|
||||
|
||||
`bigint`
|
||||
|
||||
The smallest positive integer that is congruent with (a_1 + ... + a_r) mod n
|
||||
|
||||
___
|
||||
|
||||
### modInv
|
||||
|
||||
▸ **modInv**(`a`, `n`): `bigint`
|
||||
|
||||
Modular inverse.
|
||||
|
||||
**`Throws`**
|
||||
|
||||
RangeError if a does not have inverse modulo n
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
| :------ | :------ | :------ |
|
||||
| `a` | `number` \| `bigint` | The number to find an inverse for |
|
||||
| `n` | `number` \| `bigint` | The modulo |
|
||||
|
||||
#### Returns
|
||||
|
||||
`bigint`
|
||||
|
||||
The inverse modulo n
|
||||
|
||||
___
|
||||
|
||||
### modMultiply
|
||||
|
||||
▸ **modMultiply**(`factors`, `n`): `bigint`
|
||||
|
||||
Modular addition of (a_1 * ... * a_r) mod n
|
||||
*
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
| :------ | :------ | :------ |
|
||||
| `factors` | (`number` \| `bigint`)[] | an array of the numbers a_i to multiply. For example [3, 12353251235n, 1243, -12341232545990n] * |
|
||||
| `n` | `number` \| `bigint` | the modulo * |
|
||||
|
||||
#### Returns
|
||||
|
||||
`bigint`
|
||||
|
||||
The smallest positive integer that is congruent with (a_1 * ... * a_r) mod n
|
||||
|
||||
___
|
||||
|
||||
### modPow
|
||||
|
||||
▸ **modPow**(`b`, `e`, `n`, `primeFactorization?`): `bigint`
|
||||
|
||||
Modular exponentiation b**e mod n. Currently using the right-to-left binary method if the prime factorization is not provided, or the chinese remainder theorem otherwise.
|
||||
|
||||
**`Throws`**
|
||||
|
||||
RangeError if n <= 0
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
| :------ | :------ | :------ |
|
||||
| `b` | `number` \| `bigint` | base |
|
||||
| `e` | `number` \| `bigint` | exponent |
|
||||
| `n` | `number` \| `bigint` | modulo |
|
||||
| `primeFactorization?` | [`PrimeFactor`](API.md#primefactor)[] | an array of the prime factors, for example [5n, 5n, 13n, 27n], or prime powers as [p, k], for instance [[5, 2], [13, 1], [27, 1]]. If the prime factorization is provided the chinese remainder theorem is used to greatly speed up the exponentiation. |
|
||||
|
||||
#### Returns
|
||||
|
||||
`bigint`
|
||||
|
||||
b**e mod n
|
||||
|
||||
___
|
||||
|
||||
### phi
|
||||
|
||||
▸ **phi**(`primeFactorization`): `bigint`
|
||||
|
||||
A function that computes the Euler's totien function of a number n, whose prime power factorization is known
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
| :------ | :------ | :------ |
|
||||
| `primeFactorization` | [`PrimeFactorization`](API.md#primefactorization) | an array of arrays containing the prime power factorization of a number n. For example, for n = (p1**k1)*(p2**k2)*...*(pr**kr), one should provide [[p1, k1], [p2, k2], ... , [pr, kr]] |
|
||||
|
||||
#### Returns
|
||||
|
||||
`bigint`
|
||||
|
||||
phi((p1**k1)*(p2**k2)*...*(pr**kr))
|
||||
|
||||
___
|
||||
|
||||
### prime
|
||||
|
||||
▸ **prime**(`bitLength`, `iterations?`): `Promise`<`bigint`\>
|
||||
|
||||
A probably-prime (Miller-Rabin), cryptographically-secure, random-number generator.
|
||||
The browser version uses web workers to parallelise prime look up. Therefore, it does not lock the UI
|
||||
main process, and it can be much faster (if several cores or cpu are available).
|
||||
The node version can also use worker_threads if they are available (enabled by default with Node 11 and
|
||||
and can be enabled at runtime executing node --experimental-worker with node >=10.5.0).
|
||||
|
||||
**`Throws`**
|
||||
|
||||
RangeError if bitLength < 1
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Default value | Description |
|
||||
| :------ | :------ | :------ | :------ |
|
||||
| `bitLength` | `number` | `undefined` | The required bit length for the generated prime |
|
||||
| `iterations` | `number` | `16` | The number of iterations for the Miller-Rabin Probabilistic Primality Test |
|
||||
|
||||
#### Returns
|
||||
|
||||
`Promise`<`bigint`\>
|
||||
|
||||
A promise that resolves to a bigint probable prime of bitLength bits.
|
||||
|
||||
___
|
||||
|
||||
### primeSync
|
||||
|
||||
▸ **primeSync**(`bitLength`, `iterations?`): `bigint`
|
||||
|
||||
A probably-prime (Miller-Rabin), cryptographically-secure, random-number generator.
|
||||
The sync version is NOT RECOMMENDED since it won't use workers and thus it'll be slower and may freeze thw window in browser's javascript. Please consider using prime() instead.
|
||||
|
||||
**`Throws`**
|
||||
|
||||
RangeError if bitLength < 1
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Default value | Description |
|
||||
| :------ | :------ | :------ | :------ |
|
||||
| `bitLength` | `number` | `undefined` | The required bit length for the generated prime |
|
||||
| `iterations` | `number` | `16` | The number of iterations for the Miller-Rabin Probabilistic Primality Test |
|
||||
|
||||
#### Returns
|
||||
|
||||
`bigint`
|
||||
|
||||
A bigint probable prime of bitLength bits.
|
||||
|
||||
___
|
||||
|
||||
### randBetween
|
||||
|
||||
▸ **randBetween**(`max`, `min?`): `bigint`
|
||||
|
||||
Returns a cryptographically secure random integer between [min,max].
|
||||
|
||||
**`Throws`**
|
||||
|
||||
RangeError if max <= min
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
| :------ | :------ | :------ |
|
||||
| `max` | `bigint` | Returned value will be <= max |
|
||||
| `min` | `bigint` | Returned value will be >= min |
|
||||
|
||||
#### Returns
|
||||
|
||||
`bigint`
|
||||
|
||||
A cryptographically secure random bigint between [min,max]
|
||||
|
||||
___
|
||||
|
||||
### randBits
|
||||
|
||||
▸ **randBits**(`bitLength`, `forceLength?`): `Promise`<`Uint8Array` \| `Buffer`\>
|
||||
|
||||
Secure random bits for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()
|
||||
|
||||
**`Throws`**
|
||||
|
||||
RangeError if bitLength < 1
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Default value | Description |
|
||||
| :------ | :------ | :------ | :------ |
|
||||
| `bitLength` | `number` | `undefined` | The desired number of random bits |
|
||||
| `forceLength` | `boolean` | `false` | Set to true if you want to force the output to have a specific bit length. It basically forces the msb to be 1 |
|
||||
|
||||
#### Returns
|
||||
|
||||
`Promise`<`Uint8Array` \| `Buffer`\>
|
||||
|
||||
A Promise that resolves to a UInt8Array/Buffer (Browser/Node.js) filled with cryptographically secure random bits
|
||||
|
||||
___
|
||||
|
||||
### randBitsSync
|
||||
|
||||
▸ **randBitsSync**(`bitLength`, `forceLength?`): `Uint8Array` \| `Buffer`
|
||||
|
||||
Secure random bits for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()
|
||||
|
||||
**`Throws`**
|
||||
|
||||
RangeError if bitLength < 1
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Default value | Description |
|
||||
| :------ | :------ | :------ | :------ |
|
||||
| `bitLength` | `number` | `undefined` | The desired number of random bits |
|
||||
| `forceLength` | `boolean` | `false` | Set to true if you want to force the output to have a specific bit length. It basically forces the msb to be 1 |
|
||||
|
||||
#### Returns
|
||||
|
||||
`Uint8Array` \| `Buffer`
|
||||
|
||||
A Uint8Array/Buffer (Browser/Node.js) filled with cryptographically secure random bits
|
||||
|
||||
___
|
||||
|
||||
### randBytes
|
||||
|
||||
▸ **randBytes**(`byteLength`, `forceLength?`): `Promise`<`Uint8Array` \| `Buffer`\>
|
||||
|
||||
Secure random bytes for both node and browsers. Node version uses crypto.randomBytes() and browser one self.crypto.getRandomValues()
|
||||
|
||||
**`Throws`**
|
||||
|
||||
RangeError if byteLength < 1
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Default value | Description |
|
||||
| :------ | :------ | :------ | :------ |
|
||||
| `byteLength` | `number` | `undefined` | The desired number of random bytes |
|
||||
| `forceLength` | `boolean` | `false` | Set to true if you want to force the output to have a bit length of 8*byteLength. It basically forces the msb to be 1 |
|
||||
|
||||
#### Returns
|
||||
|
||||
`Promise`<`Uint8Array` \| `Buffer`\>
|
||||
|
||||
A promise that resolves to a UInt8Array/Buffer (Browser/Node.js) filled with cryptographically secure random bytes
|
||||
|
||||
___
|
||||
|
||||
### randBytesSync
|
||||
|
||||
▸ **randBytesSync**(`byteLength`, `forceLength?`): `Uint8Array` \| `Buffer`
|
||||
|
||||
Secure random bytes for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()
|
||||
This is the synchronous version, consider using the asynchronous one for improved efficiency.
|
||||
|
||||
**`Throws`**
|
||||
|
||||
RangeError if byteLength < 1
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Default value | Description |
|
||||
| :------ | :------ | :------ | :------ |
|
||||
| `byteLength` | `number` | `undefined` | The desired number of random bytes |
|
||||
| `forceLength` | `boolean` | `false` | Set to true if you want to force the output to have a bit length of 8*byteLength. It basically forces the msb to be 1 |
|
||||
|
||||
#### Returns
|
||||
|
||||
`Uint8Array` \| `Buffer`
|
||||
|
||||
A UInt8Array/Buffer (Browser/Node.js) filled with cryptographically secure random bytes
|
||||
|
||||
___
|
||||
|
||||
### toZn
|
||||
|
||||
▸ **toZn**(`a`, `n`): `bigint`
|
||||
|
||||
Finds the smallest positive element that is congruent to a in modulo n
|
||||
|
||||
**`Remarks`**
|
||||
|
||||
a and b must be the same type, either number or bigint
|
||||
|
||||
**`Throws`**
|
||||
|
||||
RangeError if n <= 0
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
| :------ | :------ | :------ |
|
||||
| `a` | `number` \| `bigint` | An integer |
|
||||
| `n` | `number` \| `bigint` | The modulo |
|
||||
|
||||
#### Returns
|
||||
|
||||
`bigint`
|
||||
|
||||
A bigint with the smallest positive representation of a modulo n
|
|
@ -1,27 +0,0 @@
|
|||
# Interface: Egcd
|
||||
|
||||
## Table of contents
|
||||
|
||||
### Properties
|
||||
|
||||
- [g](Egcd.md#g)
|
||||
- [x](Egcd.md#x)
|
||||
- [y](Egcd.md#y)
|
||||
|
||||
## Properties
|
||||
|
||||
### g
|
||||
|
||||
• **g**: `bigint`
|
||||
|
||||
___
|
||||
|
||||
### x
|
||||
|
||||
• **x**: `bigint`
|
||||
|
||||
___
|
||||
|
||||
### y
|
||||
|
||||
• **y**: `bigint`
|
|
@ -1,54 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>bigint-crypto-utils</title>
|
||||
<meta charset="UTF-8" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="status">Still computing in background...</div>
|
||||
<p>Look for the results in the JS console (Developer Tools)</p>
|
||||
<script type="module">
|
||||
import * as bigintCryptoUtils from '../dist/bundles/esm.js'
|
||||
/* A BigInt with value 666 can be declared calling the bigint constructor as
|
||||
BigInt('666') or with the shorter 666n.
|
||||
Notice that you can also pass a number to the constructor, e.g. BigInt(666).
|
||||
However, it is not recommended since values over 2**53 - 1 won't be safe but
|
||||
no warning will be raised.
|
||||
*/
|
||||
const a = BigInt('5')
|
||||
const b = BigInt('2')
|
||||
const n = 19n
|
||||
|
||||
console.log(bigintCryptoUtils.modPow(a, b, n)) // prints 6
|
||||
|
||||
console.log(bigintCryptoUtils.modInv(2n, 5n)) // prints 3
|
||||
|
||||
console.log(bigintCryptoUtils.modInv(BigInt('3'), BigInt('5'))) // prints 2
|
||||
|
||||
console.log(bigintCryptoUtils.randBetween(2n ** 256n)) // Prints a cryptographically secure random number between 1 and 2**256 bits.
|
||||
|
||||
async function primeTesting() {
|
||||
// Output of a probable prime of 2048 bits
|
||||
console.log(await bigintCryptoUtils.prime(2048))
|
||||
|
||||
// Testing if a number is a probable prime (Miller-Rabin)
|
||||
const number = 13139188972124309083000292697519085211422620620787723340749020496498012413131881656428777288953095338604061035790562501399090389032827482643578651715752317n
|
||||
const isPrime = await bigintCryptoUtils.isProbablyPrime(number)
|
||||
if (isPrime) {
|
||||
console.log(`${number} is prime`)
|
||||
} else {
|
||||
console.log(`${number} is composite`)
|
||||
}
|
||||
}
|
||||
|
||||
primeTesting().then(() => {
|
||||
document.getElementById(
|
||||
"status"
|
||||
).innerHTML = 'Done!'
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -1,54 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>bigint-crypto-utils</title>
|
||||
<meta charset="UTF-8" />
|
||||
<script src="../dist/bundles/iife.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="status">Still computing in background...</div>
|
||||
<p>Look for the results in the JS console (Developer Tools)</p>
|
||||
<script>
|
||||
/* A BigInt with value 666 can be declared calling the bigint constructor as
|
||||
BigInt('666') or with the shorter 666n.
|
||||
Notice that you can also pass a number to the constructor, e.g. BigInt(666).
|
||||
However, it is not recommended since values over 2**53 - 1 won't be safe but
|
||||
no warning will be raised.
|
||||
*/
|
||||
const a = BigInt('5')
|
||||
const b = BigInt('2')
|
||||
const n = 19n
|
||||
|
||||
console.log(bigintCryptoUtils.modPow(a, b, n)) // prints 6
|
||||
|
||||
console.log(bigintCryptoUtils.modInv(2n, 5n)) // prints 3
|
||||
|
||||
console.log(bigintCryptoUtils.modInv(BigInt('3'), BigInt('5'))) // prints 2
|
||||
|
||||
console.log(bigintCryptoUtils.randBetween(2n ** 256n)) // Prints a cryptographically secure random number between 1 and 2**256 bits.
|
||||
|
||||
async function primeTesting() {
|
||||
// Output of a probable prime of 2048 bits
|
||||
console.log(await bigintCryptoUtils.prime(2048))
|
||||
|
||||
// Testing if a number is a probable prime (Miller-Rabin)
|
||||
const number = 13139188972124309083000292697519085211422620620787723340749020496498012413131881656428777288953095338604061035790562501399090389032827482643578651715752317n
|
||||
const isPrime = await bigintCryptoUtils.isProbablyPrime(number)
|
||||
if (isPrime) {
|
||||
console.log(`${number} is prime`)
|
||||
} else {
|
||||
console.log(`${number} is composite`)
|
||||
}
|
||||
}
|
||||
|
||||
primeTesting().then(() => {
|
||||
document.getElementById(
|
||||
"status"
|
||||
).innerHTML = 'Done!'
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -1,36 +0,0 @@
|
|||
const bigintCryptoUtils = require('..')
|
||||
// const bigintCryptoUtils = require('bigint-crypto-utils')
|
||||
|
||||
/* A BigInt with value 666 can be declared calling the bigint constructor as
|
||||
BigInt('666') or with the shorter 666n.
|
||||
Notice that you can also pass a number to the constructor, e.g. BigInt(666).
|
||||
However, it is not recommended since values over 2**53 - 1 won't be safe but
|
||||
no warning will be raised.
|
||||
*/
|
||||
const a = BigInt('5')
|
||||
const b = BigInt('2')
|
||||
const n = 19n
|
||||
|
||||
console.log(bigintCryptoUtils.modPow(a, b, n)) // prints 6
|
||||
|
||||
console.log(bigintCryptoUtils.modInv(2n, 5n)) // prints 3
|
||||
|
||||
console.log(bigintCryptoUtils.modInv(BigInt('3'), BigInt('5'))) // prints 2
|
||||
|
||||
console.log(bigintCryptoUtils.randBetween(2n ** 256n)) // Prints a cryptographically secure random number between 1 and 2**256 bits.
|
||||
|
||||
async function primeTesting () {
|
||||
// Output of a probable prime of 2048 bits
|
||||
console.log(await bigintCryptoUtils.prime(2048))
|
||||
|
||||
// Testing if a number is a probable prime (Miller-Rabin)
|
||||
const number = 13139188972124309083000292697519085211422620620787723340749020496498012413131881656428777288953095338604061035790562501399090389032827482643578651715752317n
|
||||
const isPrime = await bigintCryptoUtils.isProbablyPrime(number)
|
||||
if (isPrime) {
|
||||
console.log(`${number} is prime`)
|
||||
} else {
|
||||
console.log(`${number} is composite`)
|
||||
}
|
||||
}
|
||||
|
||||
primeTesting()
|
|
@ -1,38 +0,0 @@
|
|||
import * as bigintCryptoUtils from '#pkg'
|
||||
// const bigintCryptoUtils = require('bigint-crypto-utils')
|
||||
|
||||
/* A BigInt with value 666 can be declared calling the bigint constructor as
|
||||
BigInt('666') or with the shorter 666n.
|
||||
Notice that you can also pass a number to the constructor, e.g. BigInt(666).
|
||||
However, it is not recommended since values over 2**53 - 1 won't be safe but
|
||||
no warning will be raised.
|
||||
*/
|
||||
const a = BigInt('5')
|
||||
const b = BigInt('2')
|
||||
const n = 19n
|
||||
|
||||
console.log(bigintCryptoUtils.modPow(a, b, n)) // prints 6
|
||||
|
||||
console.log(bigintCryptoUtils.modInv(2n, 5n)) // prints 3
|
||||
|
||||
console.log(bigintCryptoUtils.modInv(BigInt('3'), BigInt('5'))) // prints 2
|
||||
|
||||
console.log(bigintCryptoUtils.randBetween(2n ** 256n)) // Prints a cryptographically secure random number between 1 and 2**256 bits.
|
||||
|
||||
async function primeTesting () {
|
||||
// Output of a probable prime of 2048 bits
|
||||
console.log(await bigintCryptoUtils.prime(2048))
|
||||
|
||||
// Testing if a number is a probable prime (Miller-Rabin)
|
||||
const number = 13139188972124309083000292697519085211422620620787723340749020496498012413131881656428777288953095338604061035790562501399090389032827482643578651715752317n
|
||||
const isPrime = await bigintCryptoUtils.isProbablyPrime(number)
|
||||
if (isPrime) {
|
||||
console.log(`${number} is prime`)
|
||||
} else {
|
||||
console.log(`${number} is composite`)
|
||||
}
|
||||
}
|
||||
|
||||
primeTesting()
|
||||
|
||||
export {}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
214
package.json
214
package.json
|
@ -1,169 +1,55 @@
|
|||
{
|
||||
"name": "bigint-crypto-utils",
|
||||
"version": "3.3.0",
|
||||
"description": "Arbitrary precision modular arithmetic, cryptographically secure random numbers and strong probable prime generation/testing. It works in modern browsers, Angular, React, Node.js, etc. since it uses the native JS implementation of BigInt",
|
||||
"keywords": [
|
||||
"modular arithmetics",
|
||||
"crypto",
|
||||
"prime",
|
||||
"random",
|
||||
"rng",
|
||||
"prng",
|
||||
"primality test",
|
||||
"BigInt",
|
||||
"angular",
|
||||
"react"
|
||||
],
|
||||
"license": "MIT",
|
||||
"author": {
|
||||
"name": "Juan Hernández Serrano",
|
||||
"email": "j.hernandez@upc.edu",
|
||||
"url": "https://github.com/juanelas"
|
||||
},
|
||||
"repository": "github:juanelas/bigint-crypto-utils",
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"type": "module",
|
||||
"main": "./dist/index.node.cjs",
|
||||
"browser": "./dist/index.browser.esm.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"node": {
|
||||
"module": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"default": "./dist/index.node.esm.js"
|
||||
},
|
||||
"import": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"default": "./dist/index.node.esm.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"default": "./dist/index.node.cjs"
|
||||
}
|
||||
},
|
||||
"script": "./dist/bundle.iife.js",
|
||||
"default": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"default": "./dist/index.browser.esm.js"
|
||||
}
|
||||
},
|
||||
"./esm-browser-bundle": "./dist/bundle.esm.min.js",
|
||||
"./esm-browser-bundle-nomin": "./dist/bundle.esm.js",
|
||||
"./iife-browser-bundle": "./dist/bundle.iife.js",
|
||||
"./umd-browser-bundle": "./dist/bundle.umd.js",
|
||||
"./types": "./dist/index.d.ts"
|
||||
},
|
||||
"imports": {
|
||||
"#pkg": {
|
||||
"require": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"default": "./dist/index.node.cjs"
|
||||
},
|
||||
"import": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"default": "./dist/index.node.esm.js"
|
||||
},
|
||||
"default": {
|
||||
"types": "./dist/esm/index.d.ts",
|
||||
"default": "./dist/index.browser.esm.js"
|
||||
}
|
||||
}
|
||||
},
|
||||
"directories": {
|
||||
"build": "./build",
|
||||
"dist": "./dist",
|
||||
"docs": "./docs",
|
||||
"src": "./src",
|
||||
"test": "./test",
|
||||
"benchmark": "./benchmark",
|
||||
"mocha-ts": "./.mocha-ts"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "run-s lint:src build:js lint:test docs",
|
||||
"build:js": "rollup -c build/rollup.config.js",
|
||||
"postbuild:js": "rimraf .types",
|
||||
"clean": "rimraf .mocha-ts coverage dist .types docs",
|
||||
"coverage": "c8 --clean --check-coverage --exclude \"{src/ts/**/*.spec.ts,test,test-vectors,build}\" --exclude-after-remap --reporter=text --reporter=lcov node ./build/bin/mocha-ts.cjs --commonjs ",
|
||||
"docs": "node build/build.docs.cjs",
|
||||
"git:add": "git add -A",
|
||||
"lint": "ts-standard --fix",
|
||||
"lint:src": "ts-standard --fix \"src/**/!(*.spec).ts\"",
|
||||
"lint:test": "ts-standard --fix \"{test/**/*.ts,src/**/*.spec.ts}\"",
|
||||
"mocha-ts": "node --experimental-modules --experimental-json-modules --es-module-specifier-resolution=node ./build/bin/mocha-ts.cjs ",
|
||||
"mocha-ts:cjs": "node ./build/bin/mocha-ts.cjs --commonjs ",
|
||||
"mocha-ts:watch": "npm run mocha-ts:cjs -- --watch ",
|
||||
"mocha-ts:browser": "node build/testing/browser/index.cjs ",
|
||||
"mocha-ts:browser-headless": "node build/testing/browser/index.cjs headless ",
|
||||
"preversion": "run-s clean lint:src build:js lint:test coverage test:browser-headless",
|
||||
"version": "run-s docs git:add",
|
||||
"postversion": "git push --follow-tags",
|
||||
"test": "run-s test:node test:browser-headless",
|
||||
"test:browser": "npm run mocha-ts:browser",
|
||||
"test:browser-headless": "npm run mocha-ts:browser-headless",
|
||||
"test:node": "run-s test:node-cjs test:node-esm",
|
||||
"test:node-cjs": "npm run mocha-ts:cjs ",
|
||||
"test:node-esm": "npm run mocha-ts ",
|
||||
"watch": "npm run mocha-ts:watch "
|
||||
},
|
||||
"ts-standard": {
|
||||
"project": "tsconfig.json",
|
||||
"env": [
|
||||
"mocha"
|
||||
"name": "@lumeweb/bigint-crypto-utils",
|
||||
"version": "3.3.0",
|
||||
"description": "Arbitrary precision modular arithmetic, cryptographically secure random numbers and strong probable prime generation/testing. It works in modern browsers, Angular, React, Node.js, etc. since it uses the native JS implementation of BigInt",
|
||||
"keywords": [
|
||||
"modular arithmetics",
|
||||
"crypto",
|
||||
"prime",
|
||||
"random",
|
||||
"rng",
|
||||
"prng",
|
||||
"primality test",
|
||||
"BigInt",
|
||||
"angular",
|
||||
"react"
|
||||
],
|
||||
"globals": [
|
||||
"IS_BROWSER",
|
||||
"browser",
|
||||
"page",
|
||||
"chai"
|
||||
],
|
||||
"ignore": [
|
||||
"dist/**/*",
|
||||
"examples/**/*",
|
||||
"types/**/*",
|
||||
"benchmark/**/*"
|
||||
]
|
||||
},
|
||||
"nodeBrowserSkel": {
|
||||
"badges": {
|
||||
"workflow": true,
|
||||
"coveralls": true
|
||||
"license": "MIT",
|
||||
"author": {
|
||||
"name": "Juan Hernández Serrano",
|
||||
"email": "j.hernandez@upc.edu",
|
||||
"url": "https://github.com/juanelas"
|
||||
},
|
||||
"git": {
|
||||
"branch": "main"
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "gitea@git.lumeweb.com:LumeWeb/bigint-crypto-utils.git"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"main": "lib/index.js",
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
"@lumeweb/node-library-preset": "^0.2.7",
|
||||
"presetter": "*"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/juanelas/bigint-crypto-utils/issues"
|
||||
},
|
||||
"readme": "ERROR: No README data found!",
|
||||
"homepage": "https://github.com/juanelas/bigint-crypto-utils#readme",
|
||||
"_id": "bigint-crypto-utils@3.3.0",
|
||||
"scripts": {
|
||||
"prepare": "presetter bootstrap",
|
||||
"build": "run build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@lumeweb/bigint-mod-arith": "^1.0.0"
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
],
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-commonjs": "^25.0.2",
|
||||
"@rollup/plugin-inject": "^5.0.3",
|
||||
"@rollup/plugin-json": "^6.0.0",
|
||||
"@rollup/plugin-multi-entry": "^6.0.0",
|
||||
"@rollup/plugin-node-resolve": "^15.0.1",
|
||||
"@rollup/plugin-replace": "^5.0.1",
|
||||
"@rollup/plugin-terser": "^0.4.0",
|
||||
"@rollup/plugin-typescript": "^11.1.0",
|
||||
"@types/chai": "^4.2.22",
|
||||
"@types/mocha": "^10.0.0",
|
||||
"bigint-mod-arith": "^3.3.1",
|
||||
"c8": "^8.0.0",
|
||||
"chai": "^4.3.3",
|
||||
"dotenv": "^16.0.3",
|
||||
"glob": "^10.0.0",
|
||||
"json5": "^2.2.0",
|
||||
"minimatch": "^9.0.0",
|
||||
"mocha": "^10.0.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"pirates": "^4.0.1",
|
||||
"puppeteer": "^20.7.3",
|
||||
"rimraf": "^5.0.0",
|
||||
"rollup": "^3.20.2",
|
||||
"rollup-plugin-dts": "^5.3.0",
|
||||
"ts-standard": "^12.0.2",
|
||||
"tslib": "^2.3.1",
|
||||
"typedoc": "~0.23.0",
|
||||
"typedoc-plugin-markdown": "~3.14.0",
|
||||
"typescript": "^4.4.3"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,85 +0,0 @@
|
|||
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
|
||||
[![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)
|
||||
{{GITHUB_ACTIONS_BADGES}}
|
||||
|
||||
# {{PKG_NAME}}
|
||||
|
||||
Arbitrary precision modular arithmetic, cryptographically secure random numbers and strong probable prime generation/testing.
|
||||
|
||||
It relies on the native JS implementation of ([BigInt](https://tc39.es/ecma262/#sec-bigint-objects)). It can be used by any [Web Browser or webview supporting BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt#Browser_compatibility) and with Node.js (>=10.4.0). The bundles can be imported directly by the browser or in Angular projects, React apps, Node.js, etc.
|
||||
|
||||
Secure random numbers are generated using the native crypto implementation of the browsers ([Web Cryptography API](https://w3c.github.io/webcrypto/)) or [Node.js Crypto](https://nodejs.org/dist/latest/docs/api/crypto.html). Strong probable prime generation and testing use Miller-Rabin primality tests and are automatically sped up using parallel workers both in browsers and Node.js.
|
||||
|
||||
> The operations supported on BigInts are not constant time. BigInt can be therefore **[unsuitable for use in cryptography](https://www.chosenplaintext.ca/articles/beginners-guide-constant-time-cryptography.html).** Many platforms provide native support for cryptography, such as [Web Cryptography API](https://w3c.github.io/webcrypto/) or [Node.js Crypto](https://nodejs.org/dist/latest/docs/api/crypto.html).
|
||||
|
||||
## Usage
|
||||
|
||||
`{{PKG_NAME}}` can be imported to your project with `npm`:
|
||||
|
||||
```console
|
||||
npm install {{PKG_NAME}}
|
||||
```
|
||||
|
||||
Then either require (Node.js CJS):
|
||||
|
||||
```javascript
|
||||
const {{PKG_CAMELCASE}} = require('{{PKG_NAME}}')
|
||||
```
|
||||
|
||||
or import (JavaScript ES module):
|
||||
|
||||
```javascript
|
||||
import * as {{PKG_CAMELCASE}} from '{{PKG_NAME}}'
|
||||
```
|
||||
|
||||
The appropriate version for browser or node is automatically exported.
|
||||
|
||||
> `{{PKG_NAME}}` uses [ES2020 BigInt](https://tc39.es/ecma262/#sec-bigint-objects), so take into account that:
|
||||
>
|
||||
> 1. If you experience issues using webpack/babel to create your production bundles, you may edit the supported browsers list and leave only [supported browsers and versions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt#Browser_compatibility). The browsers list is usually located in your project's `package.json` or the `.browserslistrc` file.
|
||||
> 2. In order to use `{{PKG_NAME}}` with TypeScript you need to set `target`, and `lib` and `module` if in use, to `ES2020` in your project's `tsconfig.json`.
|
||||
|
||||
You can also download the {{IIFE_BUNDLE}}, the {{ESM_BUNDLE}} or the {{UMD_BUNDLE}} and manually add it to your project, or, if you have already installed `{{PKG_NAME}}` in your project, just get the bundles from `node_modules/{{PKG_NAME}}/dist/bundles/`.
|
||||
|
||||
An example of usage could be (complete examples can be found in the [examples](https://github.com/juanelas/bigint-crypto-utils/tree/master/examples) directory):
|
||||
|
||||
```typescript
|
||||
/* A BigInt with value 666 can be declared calling the bigint constructor as
|
||||
BigInt('666') or with the shorter 666n.
|
||||
Notice that you can also pass a number to the constructor, e.g. BigInt(666).
|
||||
However, it is not recommended since values over 2**53 - 1 won't be safe but
|
||||
no warning will be raised.
|
||||
*/
|
||||
const a = BigInt('5')
|
||||
const b = BigInt('2')
|
||||
const n = 19n
|
||||
|
||||
console.log(bigintCryptoUtils.modPow(a, b, n)) // prints 6
|
||||
|
||||
console.log(bigintCryptoUtils.modInv(2n, 5n)) // prints 3
|
||||
|
||||
console.log(bigintCryptoUtils.modInv(BigInt('3'), BigInt('5'))) // prints 2
|
||||
|
||||
console.log(bigintCryptoUtils.randBetween(2n ** 256n)) // prints a cryptographically secure random number between 1 and 2**256 (both included).
|
||||
|
||||
async function primeTesting (): void {
|
||||
// Let us print out a probable prime of 2048 bits
|
||||
console.log(await bigintCryptoUtils.prime(2048))
|
||||
|
||||
// Testing if number is a probable prime (Miller-Rabin)
|
||||
const number = 27n
|
||||
const isPrime = await bigintCryptoUtils.isProbablyPrime(number)
|
||||
if (isPrime === true) {
|
||||
console.log(`${number} is prime`)
|
||||
} else {
|
||||
console.log(`${number} is composite`)
|
||||
}
|
||||
}
|
||||
|
||||
primeTesting()
|
||||
|
||||
```
|
||||
|
||||
## API reference documentation
|
||||
|
||||
[Check the API](./docs/API.md)
|
|
@ -0,0 +1,8 @@
|
|||
export function fromBuffer(buf: Uint8Array | Buffer): bigint {
|
||||
let ret = 0n;
|
||||
for (const i of buf.values()) {
|
||||
const bi = BigInt(i);
|
||||
ret = (ret << 8n) + bi;
|
||||
}
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
export * from "@lumeweb/bigint-mod-arith";
|
||||
|
||||
export { isProbablyPrime } from "./isProbablyPrime.js";
|
||||
export { prime, primeSync } from "./prime.js";
|
||||
export { randBetween } from "./randBetween.js";
|
||||
export { randBits, randBitsSync } from "./randBits.js";
|
||||
export { randBytes, randBytesSync } from "./randBytes.js";
|
|
@ -1,9 +1,20 @@
|
|||
import { eGcd, modInv, modPow, toZn, bitLength } from 'bigint-mod-arith'
|
||||
import { fromBuffer } from './fromBuffer.js'
|
||||
import { randBetween } from './randBetween.js'
|
||||
import { randBitsSync } from './randBits.js'
|
||||
import { randBytesSync } from './randBytes.js'
|
||||
import { _useWorkers, _workerUrl, WorkerToMainMsg, MainToWorkerMsg } from './workerUtils.js'
|
||||
import {
|
||||
eGcd,
|
||||
modInv,
|
||||
modPow,
|
||||
toZn,
|
||||
bitLength,
|
||||
} from "@lumeweb/bigint-mod-arith";
|
||||
import { fromBuffer } from "./fromBuffer.js";
|
||||
import { randBetween } from "./randBetween.js";
|
||||
import { randBitsSync } from "./randBits.js";
|
||||
import { randBytesSync } from "./randBytes.js";
|
||||
import {
|
||||
_useWorkers,
|
||||
_workerUrl,
|
||||
WorkerToMainMsg,
|
||||
MainToWorkerMsg,
|
||||
} from "./workerUtils.js";
|
||||
|
||||
/**
|
||||
* The test first tries if any of the first 250 small primes are a factor of the input number and then passes several
|
||||
|
@ -17,74 +28,81 @@ import { _useWorkers, _workerUrl, WorkerToMainMsg, MainToWorkerMsg } from './wor
|
|||
*
|
||||
* @returns A promise that resolves to a boolean that is either true (a probably prime number) or false (definitely composite)
|
||||
*/
|
||||
export function isProbablyPrime (w: number|bigint, iterations: number = 16, disableWorkers: boolean = false): Promise<boolean> { // eslint-disable-line
|
||||
if (typeof w === 'number') {
|
||||
w = BigInt(w)
|
||||
export function isProbablyPrime(
|
||||
w: number | bigint,
|
||||
iterations: number = 16,
|
||||
disableWorkers: boolean = false,
|
||||
): Promise<boolean> {
|
||||
// eslint-disable-line
|
||||
if (typeof w === "number") {
|
||||
w = BigInt(w);
|
||||
}
|
||||
if (w < 0n) throw RangeError('w MUST be >= 0')
|
||||
if (w < 0n) throw RangeError("w MUST be >= 0");
|
||||
|
||||
if (!IS_BROWSER) { // Node.js
|
||||
if (!true) {
|
||||
// Node.js
|
||||
if (!disableWorkers && _useWorkers) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const worker = new workerThreads.Worker(__filename)
|
||||
const worker = new workerThreads.Worker(__filename);
|
||||
|
||||
worker.on('message', (data?: WorkerToMainMsg) => {
|
||||
worker.on("message", (data?: WorkerToMainMsg) => {
|
||||
if (data?._bcu?.isPrime !== undefined) {
|
||||
worker.terminate().catch(reject)
|
||||
resolve(data._bcu.isPrime)
|
||||
worker.terminate().catch(reject);
|
||||
resolve(data._bcu.isPrime);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
worker.on('error', reject)
|
||||
worker.on("error", reject);
|
||||
|
||||
const msg: MainToWorkerMsg = {
|
||||
_bcu: {
|
||||
rnd: w as bigint,
|
||||
iterations,
|
||||
id: 0
|
||||
}
|
||||
}
|
||||
worker.postMessage(msg)
|
||||
})
|
||||
id: 0,
|
||||
},
|
||||
};
|
||||
worker.postMessage(msg);
|
||||
});
|
||||
} else {
|
||||
return new Promise((resolve) => {
|
||||
resolve(_isProbablyPrime(w as bigint, iterations))
|
||||
})
|
||||
resolve(_isProbablyPrime(w as bigint, iterations));
|
||||
});
|
||||
}
|
||||
} else { // browser
|
||||
} else {
|
||||
// browser
|
||||
return new Promise((resolve, reject) => {
|
||||
const worker = new Worker(_isProbablyPrimeWorkerUrl())
|
||||
const worker = new Worker(_isProbablyPrimeWorkerUrl());
|
||||
|
||||
worker.onmessage = (event) => {
|
||||
if (event?.data?._bcu?.isPrime !== undefined) {
|
||||
worker.terminate()
|
||||
resolve(event.data._bcu.isPrime)
|
||||
worker.terminate();
|
||||
resolve(event.data._bcu.isPrime);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
worker.onmessageerror = (event) => {
|
||||
reject(event)
|
||||
}
|
||||
reject(event);
|
||||
};
|
||||
|
||||
const msg: MainToWorkerMsg = {
|
||||
_bcu: {
|
||||
rnd: w as bigint,
|
||||
iterations,
|
||||
id: 0
|
||||
}
|
||||
}
|
||||
worker.postMessage(msg)
|
||||
})
|
||||
id: 0,
|
||||
},
|
||||
};
|
||||
worker.postMessage(msg);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function _isProbablyPrime (w: bigint, iterations: number): boolean {
|
||||
export function _isProbablyPrime(w: bigint, iterations: number): boolean {
|
||||
/*
|
||||
PREFILTERING. Even values but 2 are not primes, so don't test.
|
||||
1 is not a prime and the M-R algorithm needs w>1.
|
||||
*/
|
||||
if (w === 2n) return true
|
||||
else if ((w & 1n) === 0n || w === 1n) return false
|
||||
if (w === 2n) return true;
|
||||
else if ((w & 1n) === 0n || w === 1n) return false;
|
||||
|
||||
/*
|
||||
Test if any of the first 250 small primes are a factor of w. 2 is not tested because it was already tested above.
|
||||
|
@ -339,13 +357,13 @@ export function _isProbablyPrime (w: bigint, iterations: number): boolean {
|
|||
1571n,
|
||||
1579n,
|
||||
1583n,
|
||||
1597n
|
||||
]
|
||||
1597n,
|
||||
];
|
||||
|
||||
for (let i = 0; i < firstPrimes.length && (firstPrimes[i] <= w); i++) {
|
||||
const p = firstPrimes[i]
|
||||
if (w === p) return true
|
||||
else if (w % p === 0n) return false
|
||||
for (let i = 0; i < firstPrimes.length && firstPrimes[i] <= w; i++) {
|
||||
const p = firstPrimes[i];
|
||||
if (w === p) return true;
|
||||
else if (w % p === 0n) return false;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -367,34 +385,34 @@ export function _isProbablyPrime (w: bigint, iterations: number): boolean {
|
|||
Comment: Increment i for the do-loop in step 4.
|
||||
5. Return PROBABLY PRIME.
|
||||
*/
|
||||
let a = 0n
|
||||
const d = w - 1n
|
||||
let aux = d
|
||||
let a = 0n;
|
||||
const d = w - 1n;
|
||||
let aux = d;
|
||||
while (aux % 2n === 0n) {
|
||||
aux /= 2n
|
||||
++a
|
||||
aux /= 2n;
|
||||
++a;
|
||||
}
|
||||
|
||||
const m = d / (2n ** a)
|
||||
const m = d / 2n ** a;
|
||||
|
||||
do {
|
||||
const b = randBetween(d, 2n)
|
||||
let z = modPow(b, m, w)
|
||||
if (z === 1n || z === d) continue
|
||||
let j = 1
|
||||
const b = randBetween(d, 2n);
|
||||
let z = modPow(b, m, w);
|
||||
if (z === 1n || z === d) continue;
|
||||
let j = 1;
|
||||
while (j < a) {
|
||||
z = modPow(z, 2n, w)
|
||||
if (z === d) break
|
||||
if (z === 1n) return false
|
||||
j++
|
||||
z = modPow(z, 2n, w);
|
||||
if (z === d) break;
|
||||
if (z === 1n) return false;
|
||||
j++;
|
||||
}
|
||||
if (z !== d) return false
|
||||
} while (--iterations !== 0)
|
||||
if (z !== d) return false;
|
||||
} while (--iterations !== 0);
|
||||
|
||||
return true
|
||||
return true;
|
||||
}
|
||||
|
||||
export function _isProbablyPrimeWorkerUrl (): string {
|
||||
export function _isProbablyPrimeWorkerUrl(): string {
|
||||
// Let's us first add all the required functions
|
||||
let workerCode = `
|
||||
'use strict';
|
||||
|
@ -407,7 +425,7 @@ export function _isProbablyPrimeWorkerUrl (): string {
|
|||
const ${randBetween.name} = ${randBetween.toString()};
|
||||
const ${isProbablyPrime.name} = ${_isProbablyPrime.toString()};
|
||||
${bitLength.toString()};
|
||||
${fromBuffer.toString()};`
|
||||
${fromBuffer.toString()};`;
|
||||
|
||||
workerCode += `
|
||||
onmessage = async function(msg) {
|
||||
|
@ -421,30 +439,36 @@ export function _isProbablyPrimeWorkerUrl (): string {
|
|||
};
|
||||
postMessage(msgToParent);
|
||||
}
|
||||
}`
|
||||
}`;
|
||||
|
||||
return _workerUrl(workerCode)
|
||||
return _workerUrl(workerCode);
|
||||
}
|
||||
|
||||
if (!IS_BROWSER && _useWorkers) { // node.js with support for workers
|
||||
if (!true && _useWorkers) {
|
||||
// node.js with support for workers
|
||||
try {
|
||||
var workerThreads = await import('worker_threads') // eslint-disable-line no-var
|
||||
const isWorker = !(workerThreads.isMainThread)
|
||||
if (isWorker && workerThreads.parentPort !== null) { // worker
|
||||
const parentPort = workerThreads.parentPort
|
||||
parentPort.on('message', function (data: MainToWorkerMsg | any) { // Let's start once we are called
|
||||
if (data?._bcu?.iterations !== undefined && data?._bcu?.rnd !== undefined) {
|
||||
const isPrime = _isProbablyPrime(data._bcu.rnd, data._bcu.iterations)
|
||||
var workerThreads = await import("worker_threads"); // eslint-disable-line no-var
|
||||
const isWorker = !workerThreads.isMainThread;
|
||||
if (isWorker && workerThreads.parentPort !== null) {
|
||||
// worker
|
||||
const parentPort = workerThreads.parentPort;
|
||||
parentPort.on("message", function (data: MainToWorkerMsg | any) {
|
||||
// Let's start once we are called
|
||||
if (
|
||||
data?._bcu?.iterations !== undefined &&
|
||||
data?._bcu?.rnd !== undefined
|
||||
) {
|
||||
const isPrime = _isProbablyPrime(data._bcu.rnd, data._bcu.iterations);
|
||||
const msg: WorkerToMainMsg = {
|
||||
_bcu: {
|
||||
isPrime,
|
||||
value: data._bcu.rnd,
|
||||
id: data._bcu.id
|
||||
}
|
||||
}
|
||||
parentPort.postMessage(msg)
|
||||
id: data._bcu.id,
|
||||
},
|
||||
};
|
||||
parentPort.postMessage(msg);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
} catch (error) {}
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
import { fromBuffer } from "./fromBuffer.js";
|
||||
import {
|
||||
_isProbablyPrime,
|
||||
_isProbablyPrimeWorkerUrl,
|
||||
} from "./isProbablyPrime.js";
|
||||
import { randBits, randBitsSync } from "./randBits.js";
|
||||
import {
|
||||
_useWorkers,
|
||||
WorkerToMainMsg,
|
||||
MainToWorkerMsg,
|
||||
} from "./workerUtils.js";
|
||||
import type { Worker as NodeWorker } from "worker_threads";
|
||||
|
||||
if (!true) var os = await import("os"); // eslint-disable-line no-var
|
||||
if (!true) {
|
||||
try {
|
||||
var workerThreads = await import("worker_threads"); // eslint-disable-line no-var
|
||||
} catch {}
|
||||
}
|
||||
|
||||
/**
|
||||
* A probably-prime (Miller-Rabin), cryptographically-secure, random-number generator.
|
||||
* The browser version uses web workers to parallelise prime look up. Therefore, it does not lock the UI
|
||||
* main process, and it can be much faster (if several cores or cpu are available).
|
||||
* The node version can also use worker_threads if they are available (enabled by default with Node 11 and
|
||||
* and can be enabled at runtime executing node --experimental-worker with node >=10.5.0).
|
||||
*
|
||||
* @param bitLength - The required bit length for the generated prime
|
||||
* @param iterations - The number of iterations for the Miller-Rabin Probabilistic Primality Test
|
||||
*
|
||||
* @throws {@link RangeError} if bitLength < 1
|
||||
*
|
||||
* @returns A promise that resolves to a bigint probable prime of bitLength bits.
|
||||
*/
|
||||
export function prime(
|
||||
bitLength: number,
|
||||
iterations: number = 16,
|
||||
): Promise<bigint> {
|
||||
// eslint-disable-line
|
||||
if (bitLength < 1) throw new RangeError("bitLength MUST be > 0");
|
||||
|
||||
/* c8 ignore start */
|
||||
if (!_useWorkers) {
|
||||
// If there is no support for workers
|
||||
let rnd = 0n;
|
||||
do {
|
||||
rnd = fromBuffer(randBitsSync(bitLength, true));
|
||||
} while (!_isProbablyPrime(rnd, iterations));
|
||||
return new Promise((resolve) => {
|
||||
resolve(rnd);
|
||||
});
|
||||
}
|
||||
/* c8 ignore stop */
|
||||
return new Promise((resolve, reject) => {
|
||||
const workerList: Array<NodeWorker | Worker> = [];
|
||||
const _onmessage = (
|
||||
msg: WorkerToMainMsg,
|
||||
newWorker: Worker | NodeWorker,
|
||||
): void => {
|
||||
if (msg._bcu.isPrime) {
|
||||
// if a prime number has been found, stop all the workers, and return it
|
||||
for (let j = 0; j < workerList.length; j++) {
|
||||
workerList[j].terminate(); // eslint-disable-line @typescript-eslint/no-floating-promises
|
||||
}
|
||||
while (workerList.length > 0) {
|
||||
workerList.pop();
|
||||
}
|
||||
resolve(msg._bcu.value);
|
||||
} else {
|
||||
// if a composite is found, make the worker test another random number
|
||||
const buf = randBitsSync(bitLength, true);
|
||||
const rnd = fromBuffer(buf);
|
||||
try {
|
||||
const msgToWorker: MainToWorkerMsg = {
|
||||
_bcu: {
|
||||
rnd,
|
||||
iterations,
|
||||
id: msg._bcu.id,
|
||||
},
|
||||
};
|
||||
newWorker.postMessage(msgToWorker);
|
||||
} catch (error) {
|
||||
// The worker has already terminated. There is nothing to handle here
|
||||
}
|
||||
}
|
||||
};
|
||||
if (true) {
|
||||
// browser
|
||||
const workerURL = _isProbablyPrimeWorkerUrl();
|
||||
for (let i = 0; i < self.navigator.hardwareConcurrency - 1; i++) {
|
||||
const newWorker = new Worker(workerURL);
|
||||
newWorker.onmessage = (event) => _onmessage(event.data, newWorker);
|
||||
workerList.push(newWorker);
|
||||
}
|
||||
} else {
|
||||
// Node.js
|
||||
}
|
||||
for (let i = 0; i < workerList.length; i++) {
|
||||
randBits(bitLength, true)
|
||||
.then(function (buf: Uint8Array | Buffer) {
|
||||
const rnd = fromBuffer(buf);
|
||||
workerList[i].postMessage({
|
||||
_bcu: {
|
||||
rnd,
|
||||
iterations,
|
||||
id: i,
|
||||
},
|
||||
});
|
||||
})
|
||||
.catch(reject);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* A probably-prime (Miller-Rabin), cryptographically-secure, random-number generator.
|
||||
* The sync version is NOT RECOMMENDED since it won't use workers and thus it'll be slower and may freeze thw window in browser's javascript. Please consider using prime() instead.
|
||||
*
|
||||
* @param bitLength - The required bit length for the generated prime
|
||||
* @param iterations - The number of iterations for the Miller-Rabin Probabilistic Primality Test
|
||||
*
|
||||
* @throws {@link RangeError} if bitLength < 1
|
||||
*
|
||||
* @returns A bigint probable prime of bitLength bits.
|
||||
*/
|
||||
export function primeSync(bitLength: number, iterations: number = 16): bigint {
|
||||
if (bitLength < 1) throw new RangeError("bitLength MUST be > 0");
|
||||
let rnd = 0n;
|
||||
do {
|
||||
rnd = fromBuffer(randBitsSync(bitLength, true));
|
||||
} while (!_isProbablyPrime(rnd, iterations));
|
||||
return rnd;
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
import { bitLength } from "@lumeweb/bigint-mod-arith";
|
||||
import { fromBuffer } from "./fromBuffer.js";
|
||||
import { randBitsSync } from "./randBits.js";
|
||||
|
||||
/**
|
||||
* Returns a cryptographically secure random integer between [min,max].
|
||||
* @param max Returned value will be <= max
|
||||
* @param min Returned value will be >= min
|
||||
*
|
||||
* @throws {@link RangeError} if max <= min
|
||||
*
|
||||
* @returns A cryptographically secure random bigint between [min,max]
|
||||
*/
|
||||
export function randBetween(max: bigint, min: bigint = 1n): bigint {
|
||||
if (max <= min) throw new RangeError("Arguments MUST be: max > min");
|
||||
const interval = max - min;
|
||||
const bitLen = bitLength(interval);
|
||||
let rnd;
|
||||
do {
|
||||
const buf = randBitsSync(bitLen);
|
||||
rnd = fromBuffer(buf);
|
||||
} while (rnd > interval);
|
||||
return rnd + min;
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
import { randBytes, randBytesSync } from './randBytes.js'
|
||||
import { randBytes, randBytesSync } from "./randBytes.js";
|
||||
|
||||
/**
|
||||
* Secure random bits for both node and browsers. Node version uses crypto.randomFill() and browser one self.crypto.getRandomValues()
|
||||
|
@ -10,25 +10,30 @@ import { randBytes, randBytesSync } from './randBytes.js'
|
|||
*
|
||||
* @returns A Promise that resolves to a UInt8Array/Buffer (Browser/Node.js) filled with cryptographically secure random bits
|
||||
*/
|
||||
export function randBits (bitLength: number, forceLength: boolean = false): Promise<Uint8Array|Buffer> { // eslint-disable-line
|
||||
if (bitLength < 1) throw new RangeError('bitLength MUST be > 0')
|
||||
export function randBits(
|
||||
bitLength: number,
|
||||
forceLength: boolean = false,
|
||||
): Promise<Uint8Array | Buffer> {
|
||||
// eslint-disable-line
|
||||
if (bitLength < 1) throw new RangeError("bitLength MUST be > 0");
|
||||
|
||||
const byteLength = Math.ceil(bitLength / 8)
|
||||
const bitLengthMod8 = bitLength % 8
|
||||
const byteLength = Math.ceil(bitLength / 8);
|
||||
const bitLengthMod8 = bitLength % 8;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
randBytes(byteLength, false).then(function (rndBytes) { // eslint-disable-line
|
||||
randBytes(byteLength, false).then(function (rndBytes) {
|
||||
// eslint-disable-line
|
||||
if (bitLengthMod8 !== 0) {
|
||||
// Fill with 0's the extra bits
|
||||
rndBytes[0] = rndBytes[0] & (2 ** bitLengthMod8 - 1)
|
||||
rndBytes[0] = rndBytes[0] & (2 ** bitLengthMod8 - 1);
|
||||
}
|
||||
if (forceLength) {
|
||||
const mask = (bitLengthMod8 !== 0) ? 2 ** (bitLengthMod8 - 1) : 128
|
||||
rndBytes[0] = rndBytes[0] | mask
|
||||
const mask = bitLengthMod8 !== 0 ? 2 ** (bitLengthMod8 - 1) : 128;
|
||||
rndBytes[0] = rndBytes[0] | mask;
|
||||
}
|
||||
resolve(rndBytes)
|
||||
})
|
||||
})
|
||||
resolve(rndBytes);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -40,19 +45,22 @@ export function randBits (bitLength: number, forceLength: boolean = false): Prom
|
|||
*
|
||||
* @returns A Uint8Array/Buffer (Browser/Node.js) filled with cryptographically secure random bits
|
||||
*/
|
||||
export function randBitsSync (bitLength: number, forceLength: boolean = false): Uint8Array | Buffer {
|
||||
if (bitLength < 1) throw new RangeError('bitLength MUST be > 0')
|
||||
export function randBitsSync(
|
||||
bitLength: number,
|
||||
forceLength: boolean = false,
|
||||
): Uint8Array | Buffer {
|
||||
if (bitLength < 1) throw new RangeError("bitLength MUST be > 0");
|
||||
|
||||
const byteLength = Math.ceil(bitLength / 8)
|
||||
const rndBytes = randBytesSync(byteLength, false)
|
||||
const bitLengthMod8 = bitLength % 8
|
||||
const byteLength = Math.ceil(bitLength / 8);
|
||||
const rndBytes = randBytesSync(byteLength, false);
|
||||
const bitLengthMod8 = bitLength % 8;
|
||||
if (bitLengthMod8 !== 0) {
|
||||
// Fill with 0's the extra bits
|
||||
rndBytes[0] = rndBytes[0] & (2 ** bitLengthMod8 - 1)
|
||||
rndBytes[0] = rndBytes[0] & (2 ** bitLengthMod8 - 1);
|
||||
}
|
||||
if (forceLength) {
|
||||
const mask = (bitLengthMod8 !== 0) ? 2 ** (bitLengthMod8 - 1) : 128
|
||||
rndBytes[0] = rndBytes[0] | mask
|
||||
const mask = bitLengthMod8 !== 0 ? 2 ** (bitLengthMod8 - 1) : 128;
|
||||
rndBytes[0] = rndBytes[0] | mask;
|
||||
}
|
||||
return rndBytes
|
||||
return rndBytes;
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
if (!IS_BROWSER) var crypto = await import('crypto') // eslint-disable-line no-var
|
||||
if (!true) var crypto = await import("crypto"); // eslint-disable-line no-var
|
||||
|
||||
/**
|
||||
* Secure random bytes for both node and browsers. Node version uses crypto.randomBytes() and browser one self.crypto.getRandomValues()
|
||||
|
@ -10,34 +10,40 @@ if (!IS_BROWSER) var crypto = await import('crypto') // eslint-disable-line no-v
|
|||
*
|
||||
* @returns A promise that resolves to a UInt8Array/Buffer (Browser/Node.js) filled with cryptographically secure random bytes
|
||||
*/
|
||||
export function randBytes (byteLength: number, forceLength = false): Promise<Uint8Array|Buffer> { // eslint-disable-line
|
||||
if (byteLength < 1) throw new RangeError('byteLength MUST be > 0')
|
||||
export function randBytes(
|
||||
byteLength: number,
|
||||
forceLength = false,
|
||||
): Promise<Uint8Array | Buffer> {
|
||||
// eslint-disable-line
|
||||
if (byteLength < 1) throw new RangeError("byteLength MUST be > 0");
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
if (!IS_BROWSER) {
|
||||
if (!true) {
|
||||
crypto.randomBytes(byteLength, function (err, buf: Buffer) {
|
||||
if (err !== null) reject(err)
|
||||
if (err !== null) reject(err);
|
||||
// If fixed length is required we put the first bit to 1 -> to get the necessary bitLength
|
||||
if (forceLength) buf[0] = buf[0] | 128
|
||||
resolve(buf)
|
||||
})
|
||||
} else { // browser
|
||||
const buf = new Uint8Array(byteLength)
|
||||
if (forceLength) buf[0] = buf[0] | 128;
|
||||
resolve(buf);
|
||||
});
|
||||
} else {
|
||||
// browser
|
||||
const buf = new Uint8Array(byteLength);
|
||||
// the maximum number of bytes of entropy available via self.crypto.getRandomValues is 65536
|
||||
if (byteLength <= 65536) {
|
||||
self.crypto.getRandomValues(buf)
|
||||
self.crypto.getRandomValues(buf);
|
||||
} else {
|
||||
for (let i = 0; i < Math.ceil(byteLength / 65536); i++) {
|
||||
const begin = i * 65536
|
||||
const end = ((begin + 65535) < byteLength) ? begin + 65535 : byteLength - 1
|
||||
self.crypto.getRandomValues(buf.subarray(begin, end))
|
||||
const begin = i * 65536;
|
||||
const end =
|
||||
begin + 65535 < byteLength ? begin + 65535 : byteLength - 1;
|
||||
self.crypto.getRandomValues(buf.subarray(begin, end));
|
||||
}
|
||||
}
|
||||
// If fixed length is required we put the first bit to 1 -> to get the necessary bitLength
|
||||
if (forceLength) buf[0] = buf[0] | 128
|
||||
resolve(buf)
|
||||
if (forceLength) buf[0] = buf[0] | 128;
|
||||
resolve(buf);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -51,30 +57,35 @@ export function randBytes (byteLength: number, forceLength = false): Promise<Uin
|
|||
*
|
||||
* @returns A UInt8Array/Buffer (Browser/Node.js) filled with cryptographically secure random bytes
|
||||
*/
|
||||
export function randBytesSync (byteLength: number, forceLength: boolean = false): Uint8Array | Buffer {
|
||||
if (byteLength < 1) throw new RangeError('byteLength MUST be > 0')
|
||||
export function randBytesSync(
|
||||
byteLength: number,
|
||||
forceLength: boolean = false,
|
||||
): Uint8Array | Buffer {
|
||||
if (byteLength < 1) throw new RangeError("byteLength MUST be > 0");
|
||||
|
||||
/* eslint-disable no-lone-blocks */
|
||||
if (!IS_BROWSER) { // node
|
||||
const buf = crypto.randomBytes(byteLength)
|
||||
if (!true) {
|
||||
// node
|
||||
const buf = crypto.randomBytes(byteLength);
|
||||
// If fixed length is required we put the first bit to 1 -> to get the necessary bitLength
|
||||
if (forceLength) buf[0] = buf[0] | 128
|
||||
return buf
|
||||
} else { // browser
|
||||
const buf = new Uint8Array(byteLength)
|
||||
if (forceLength) buf[0] = buf[0] | 128;
|
||||
return buf;
|
||||
} else {
|
||||
// browser
|
||||
const buf = new Uint8Array(byteLength);
|
||||
// the maximum number of bytes of entropy available via self.crypto.getRandomValues is 65536
|
||||
if (byteLength <= 65536) {
|
||||
self.crypto.getRandomValues(buf)
|
||||
self.crypto.getRandomValues(buf);
|
||||
} else {
|
||||
for (let i = 0; i < Math.ceil(byteLength / 65536); i++) {
|
||||
const begin = i * 65536
|
||||
const end = ((begin + 65535) < byteLength) ? begin + 65535 : byteLength - 1
|
||||
self.crypto.getRandomValues(buf.subarray(begin, end))
|
||||
const begin = i * 65536;
|
||||
const end = begin + 65535 < byteLength ? begin + 65535 : byteLength - 1;
|
||||
self.crypto.getRandomValues(buf.subarray(begin, end));
|
||||
}
|
||||
}
|
||||
// If fixed length is required we put the first bit to 1 -> to get the necessary bitLength
|
||||
if (forceLength) buf[0] = buf[0] | 128
|
||||
return buf
|
||||
if (forceLength) buf[0] = buf[0] | 128;
|
||||
return buf;
|
||||
}
|
||||
/* eslint-enable no-lone-blocks */
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
export function fromBuffer (buf: Uint8Array | Buffer): bigint {
|
||||
let ret = 0n
|
||||
for (const i of buf.values()) {
|
||||
const bi = BigInt(i)
|
||||
ret = (ret << 8n) + bi
|
||||
}
|
||||
return ret
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
export * from 'bigint-mod-arith'
|
||||
|
||||
export { isProbablyPrime } from './isProbablyPrime.js'
|
||||
export { prime, primeSync } from './prime.js'
|
||||
export { randBetween } from './randBetween.js'
|
||||
export { randBits, randBitsSync } from './randBits.js'
|
||||
export { randBytes, randBytesSync } from './randBytes.js'
|
116
src/ts/prime.ts
116
src/ts/prime.ts
|
@ -1,116 +0,0 @@
|
|||
import { fromBuffer } from './fromBuffer.js'
|
||||
import { _isProbablyPrime, _isProbablyPrimeWorkerUrl } from './isProbablyPrime.js'
|
||||
import { randBits, randBitsSync } from './randBits.js'
|
||||
import { _useWorkers, WorkerToMainMsg, MainToWorkerMsg } from './workerUtils.js'
|
||||
import type { Worker as NodeWorker } from 'worker_threads'
|
||||
|
||||
if (!IS_BROWSER) var os = await import('os') // eslint-disable-line no-var
|
||||
if (!IS_BROWSER) {
|
||||
try {
|
||||
var workerThreads = await import('worker_threads') // eslint-disable-line no-var
|
||||
} catch {}
|
||||
}
|
||||
|
||||
/**
|
||||
* A probably-prime (Miller-Rabin), cryptographically-secure, random-number generator.
|
||||
* The browser version uses web workers to parallelise prime look up. Therefore, it does not lock the UI
|
||||
* main process, and it can be much faster (if several cores or cpu are available).
|
||||
* The node version can also use worker_threads if they are available (enabled by default with Node 11 and
|
||||
* and can be enabled at runtime executing node --experimental-worker with node >=10.5.0).
|
||||
*
|
||||
* @param bitLength - The required bit length for the generated prime
|
||||
* @param iterations - The number of iterations for the Miller-Rabin Probabilistic Primality Test
|
||||
*
|
||||
* @throws {@link RangeError} if bitLength < 1
|
||||
*
|
||||
* @returns A promise that resolves to a bigint probable prime of bitLength bits.
|
||||
*/
|
||||
export function prime (bitLength: number, iterations: number = 16): Promise<bigint> { // eslint-disable-line
|
||||
if (bitLength < 1) throw new RangeError('bitLength MUST be > 0')
|
||||
|
||||
/* c8 ignore start */
|
||||
if (!_useWorkers) { // If there is no support for workers
|
||||
let rnd = 0n
|
||||
do {
|
||||
rnd = fromBuffer(randBitsSync(bitLength, true))
|
||||
} while (!_isProbablyPrime(rnd, iterations))
|
||||
return new Promise((resolve) => { resolve(rnd) })
|
||||
}
|
||||
/* c8 ignore stop */
|
||||
return new Promise((resolve, reject) => {
|
||||
const workerList: Array<NodeWorker | Worker> = []
|
||||
const _onmessage = (msg: WorkerToMainMsg, newWorker: Worker | NodeWorker): void => {
|
||||
if (msg._bcu.isPrime) {
|
||||
// if a prime number has been found, stop all the workers, and return it
|
||||
for (let j = 0; j < workerList.length; j++) {
|
||||
workerList[j].terminate() // eslint-disable-line @typescript-eslint/no-floating-promises
|
||||
}
|
||||
while (workerList.length > 0) {
|
||||
workerList.pop()
|
||||
}
|
||||
resolve(msg._bcu.value)
|
||||
} else { // if a composite is found, make the worker test another random number
|
||||
const buf = randBitsSync(bitLength, true)
|
||||
const rnd = fromBuffer(buf)
|
||||
try {
|
||||
const msgToWorker: MainToWorkerMsg = {
|
||||
_bcu: {
|
||||
rnd,
|
||||
iterations,
|
||||
id: msg._bcu.id
|
||||
}
|
||||
}
|
||||
newWorker.postMessage(msgToWorker)
|
||||
} catch (error) {
|
||||
// The worker has already terminated. There is nothing to handle here
|
||||
}
|
||||
}
|
||||
}
|
||||
if (IS_BROWSER) { // browser
|
||||
const workerURL = _isProbablyPrimeWorkerUrl()
|
||||
for (let i = 0; i < self.navigator.hardwareConcurrency - 1; i++) {
|
||||
const newWorker = new Worker(workerURL)
|
||||
newWorker.onmessage = (event) => _onmessage(event.data, newWorker)
|
||||
workerList.push(newWorker)
|
||||
}
|
||||
} else { // Node.js
|
||||
for (let i = 0; i < os.cpus().length - 1; i++) {
|
||||
const newWorker = new workerThreads.Worker(__filename)
|
||||
newWorker.on('message', (msg: WorkerToMainMsg) => _onmessage(msg, newWorker))
|
||||
workerList.push(newWorker)
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < workerList.length; i++) {
|
||||
randBits(bitLength, true).then(function (buf: Uint8Array | Buffer) {
|
||||
const rnd = fromBuffer(buf)
|
||||
workerList[i].postMessage({
|
||||
_bcu: {
|
||||
rnd,
|
||||
iterations,
|
||||
id: i
|
||||
}
|
||||
})
|
||||
}).catch(reject)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* A probably-prime (Miller-Rabin), cryptographically-secure, random-number generator.
|
||||
* The sync version is NOT RECOMMENDED since it won't use workers and thus it'll be slower and may freeze thw window in browser's javascript. Please consider using prime() instead.
|
||||
*
|
||||
* @param bitLength - The required bit length for the generated prime
|
||||
* @param iterations - The number of iterations for the Miller-Rabin Probabilistic Primality Test
|
||||
*
|
||||
* @throws {@link RangeError} if bitLength < 1
|
||||
*
|
||||
* @returns A bigint probable prime of bitLength bits.
|
||||
*/
|
||||
export function primeSync (bitLength: number, iterations: number = 16): bigint {
|
||||
if (bitLength < 1) throw new RangeError('bitLength MUST be > 0')
|
||||
let rnd = 0n
|
||||
do {
|
||||
rnd = fromBuffer(randBitsSync(bitLength, true))
|
||||
} while (!_isProbablyPrime(rnd, iterations))
|
||||
return rnd
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
import { bitLength } from 'bigint-mod-arith'
|
||||
import { fromBuffer } from './fromBuffer.js'
|
||||
import { randBitsSync } from './randBits.js'
|
||||
|
||||
/**
|
||||
* Returns a cryptographically secure random integer between [min,max].
|
||||
* @param max Returned value will be <= max
|
||||
* @param min Returned value will be >= min
|
||||
*
|
||||
* @throws {@link RangeError} if max <= min
|
||||
*
|
||||
* @returns A cryptographically secure random bigint between [min,max]
|
||||
*/
|
||||
export function randBetween (max: bigint, min: bigint = 1n): bigint {
|
||||
if (max <= min) throw new RangeError('Arguments MUST be: max > min')
|
||||
const interval = max - min
|
||||
const bitLen = bitLength(interval)
|
||||
let rnd
|
||||
do {
|
||||
const buf = randBitsSync(bitLen)
|
||||
rnd = fromBuffer(buf)
|
||||
} while (rnd > interval)
|
||||
return rnd + min
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
export function _workerUrl (workerCode: string): string {
|
||||
workerCode = `(() => {${workerCode}})()` // encapsulate IIFE
|
||||
const _blob = new Blob([workerCode], { type: 'text/javascript' })
|
||||
return window.URL.createObjectURL(_blob)
|
||||
}
|
||||
|
||||
let _useWorkers = false // The following is just to check whether we can use workers
|
||||
/* eslint-disable no-lone-blocks */
|
||||
if (!IS_BROWSER) { // Node.js
|
||||
try {
|
||||
await import('worker_threads')
|
||||
_useWorkers = true
|
||||
} /* c8 ignore start */ catch (e) {
|
||||
console.log(`[bigint-crypto-utils] WARNING:
|
||||
This node version doesn't support worker_threads. You should enable them in order to greatly speedup the generation of big prime numbers.
|
||||
· With Node >=11 it is enabled by default (consider upgrading).
|
||||
· With Node 10, starting with 10.5.0, you can enable worker_threads at runtime executing node --experimental-worker `)
|
||||
}
|
||||
/* c8 ignore stop */
|
||||
} else { // Native JS
|
||||
if (self.Worker !== undefined) _useWorkers = true
|
||||
}
|
||||
|
||||
export { _useWorkers }
|
||||
|
||||
export interface WorkerToMainMsg {
|
||||
_bcu: {
|
||||
isPrime: boolean
|
||||
value: bigint
|
||||
id: number
|
||||
}
|
||||
}
|
||||
|
||||
export interface MainToWorkerMsg {
|
||||
_bcu: {
|
||||
rnd: bigint
|
||||
iterations: number
|
||||
id: number
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
export function _workerUrl(workerCode: string): string {
|
||||
workerCode = `(() => {${workerCode}})()`; // encapsulate IIFE
|
||||
const _blob = new Blob([workerCode], { type: "text/javascript" });
|
||||
return window.URL.createObjectURL(_blob);
|
||||
}
|
||||
|
||||
let _useWorkers = false; // The following is just to check whether we can use workers
|
||||
/* eslint-disable no-lone-blocks */
|
||||
if (!true) {
|
||||
// Node.js
|
||||
try {
|
||||
await import("worker_threads");
|
||||
_useWorkers = true;
|
||||
} /* c8 ignore start */ catch (e) {
|
||||
console.log(`[bigint-crypto-utils] WARNING:
|
||||
This node version doesn't support worker_threads. You should enable them in order to greatly speedup the generation of big prime numbers.
|
||||
· With Node >=11 it is enabled by default (consider upgrading).
|
||||
· With Node 10, starting with 10.5.0, you can enable worker_threads at runtime executing node --experimental-worker `);
|
||||
}
|
||||
/* c8 ignore stop */
|
||||
} else {
|
||||
// Native JS
|
||||
if (self.Worker !== undefined) _useWorkers = true;
|
||||
}
|
||||
|
||||
export { _useWorkers };
|
||||
|
||||
export interface WorkerToMainMsg {
|
||||
_bcu: {
|
||||
isPrime: boolean;
|
||||
value: bigint;
|
||||
id: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface MainToWorkerMsg {
|
||||
_bcu: {
|
||||
rnd: bigint;
|
||||
iterations: number;
|
||||
id: number;
|
||||
};
|
||||
}
|
|
@ -1,95 +0,0 @@
|
|||
import * as bcu from '#pkg'
|
||||
|
||||
describe('isProbablyPrime', function () {
|
||||
this.timeout(90000)
|
||||
const numbers = [
|
||||
{
|
||||
value: BigInt(1),
|
||||
prime: false,
|
||||
iterations: 16,
|
||||
workers: false
|
||||
},
|
||||
{
|
||||
value: BigInt(2),
|
||||
prime: true,
|
||||
iterations: 16,
|
||||
workers: false
|
||||
},
|
||||
{
|
||||
value: 3,
|
||||
prime: true,
|
||||
iterations: 16,
|
||||
workers: false
|
||||
},
|
||||
{
|
||||
value: BigInt(15),
|
||||
prime: false,
|
||||
iterations: 32,
|
||||
workers: false
|
||||
},
|
||||
{
|
||||
value: 29,
|
||||
prime: true,
|
||||
iterations: 16,
|
||||
workers: false
|
||||
},
|
||||
{
|
||||
value: BigInt('669483106578092405936560831017556154622901950048903016651289'),
|
||||
prime: true,
|
||||
iterations: 24,
|
||||
workers: false
|
||||
},
|
||||
{
|
||||
value: BigInt('2074722246773485207821695222107608587480996474721117292752992589912196684750549658310084416732550077'),
|
||||
prime: true,
|
||||
iterations: 16,
|
||||
workers: false
|
||||
},
|
||||
{
|
||||
value: BigInt('2074722246773485207821695222107608587480996474721117292752992589912196684750549658310084416732550079'),
|
||||
prime: false,
|
||||
iterations: 16,
|
||||
workers: false
|
||||
},
|
||||
{
|
||||
value: BigInt('115922179551495973383410176342643722334557255682879605864838806293659619625004303206250384392546855063844106965156287951749387634112551089284595541103692716528774876311641700929986988023197242224581099872580798960693521778607396791006450968430359009613295725905514216842343121690916290236558767890728449777'),
|
||||
prime: true,
|
||||
iterations: 24,
|
||||
workers: true
|
||||
},
|
||||
{
|
||||
value: BigInt('168694196579467171180863939518634764192343817610869919231900537093664715354591592262546800497540343203057121816378265655992490621138321114570420047522219942818258345349322155251835677199539229050711145144861404607171419723967136221126986330819362088262358855325306938646602003059377699727688477555163239222109') * BigInt('144678545212641449725111562354371812236197961234111744040227045242578772124779004756249085154188369039159690638725821245974978963371615699005072473649705367893567309027634121825164880046600125480885803891136149601797439273507802533807541605261215613891134865916295914192271736572001975016089773532547481638243'),
|
||||
prime: false,
|
||||
iterations: 16,
|
||||
workers: true
|
||||
},
|
||||
{
|
||||
value: BigInt('918145944120889203205646923554374144932845997937845799234617798611046542304088105084854788397071323714642587188481158334265864050544813693415594035822877094557870151480865568334936301231664228940480803192289508235412296324312748621874408067955753620604885023289655277704554716080844406284392300643321715285709865081125252390440327650852470312931679380011885102491340191287595160450544053114365852338670819405357496612993587404998677760882578064637552397840566752638770525765833183986360029736508910848408875329873614164495552615086579144675027852136994842529623698055210822311666048300438808691619782893307972452223713060928388502843564836966586109748062827799521852219158489504529458627699284110902303538160168376473182639384638674469114371472053977558648090155686345760457454061117853710619580819749222459422610617170567016772342291486643520567969321969827786373531753524990712622940069883277763528926899970596407140603912036918433859986491820017690762751824769335720368488097262208835708414085501930989486498185503469986946236128468697606998536541209764920494156326791142098506801288127033229779646920082892258428128572765585196779698362187479280520327053508580551167899837393726371144977951402741307021389967382422805567365901203'),
|
||||
prime: true,
|
||||
iterations: 16,
|
||||
workers: true
|
||||
},
|
||||
{
|
||||
value: BigInt('940719693126280825126763871881743336375040232953039527942717290104060740215493004508206768342926022549956464101136893240409560470269654765366248516968645294076406953865805712688760371102637642013723011744011617678651884521901163090779813242269935310225049805992299292275574585773507915278612311449919050091057023179541184986547995894821648553256021675133997240195429424258757033557367142630663053464438840832073753440939208165158795269598771598124509831433327480118038278887538430675994497384283550890544882369140852048496460551123626856255619494025370171790720106325655890348475483349150258338517508459674722099347335608814922179633411167540545786247819334838979610017735984374883325689517847175539632896026875016305529321705457954181425405794479825617747354596485074451489940385640535898876551301296003465792117006135339109817937663957519031436646579178503423889430062127572272773511424424297800355292430651838502733756881154935252456036638082486459287411002911323257940893413982671660332662880068976408321968046549017547143836993553556640198884769590214676797037397502067035957959952990027503148987727895561468097917730167320715053689862847457761993196945361244822787209076446259359976421264285658106819879849052247546957718175231'),
|
||||
prime: false,
|
||||
iterations: 16,
|
||||
workers: true
|
||||
}
|
||||
]
|
||||
|
||||
for (const num of numbers) {
|
||||
describe(`isProbablyPrime(${num.value}, ${num.iterations}, ${String(!num.workers)})`, function () {
|
||||
it(`should return ${String(num.prime)}`, async function () {
|
||||
let ret
|
||||
if (num.iterations === 16 && num.workers) ret = await bcu.isProbablyPrime(num.value)
|
||||
else ret = await bcu.isProbablyPrime(num.value, num.iterations, !num.workers)
|
||||
chai.expect(ret).to.equal(num.prime)
|
||||
})
|
||||
})
|
||||
}
|
||||
describe('isProbablyPrime(-1)', function () {
|
||||
it('should throw RangeError', function () {
|
||||
chai.expect(() => bcu.isProbablyPrime(-1)).to.throw(RangeError) // eslint-disable-line
|
||||
})
|
||||
})
|
||||
})
|
|
@ -1,37 +0,0 @@
|
|||
import * as bcu from '#pkg'
|
||||
|
||||
describe('Testing prime generation', function () {
|
||||
const bitLengths = [
|
||||
0,
|
||||
8,
|
||||
255,
|
||||
256,
|
||||
258,
|
||||
512,
|
||||
1024,
|
||||
2048,
|
||||
3072
|
||||
]
|
||||
this.timeout(120000)
|
||||
for (const bitLength of bitLengths) {
|
||||
describe(`prime(${bitLength})`, function () {
|
||||
if (bitLength > 0) {
|
||||
it(`should return a random ${bitLength}-bits probable prime`, async function () {
|
||||
const prime = await bcu.prime(bitLength)
|
||||
chai.expect(bcu.bitLength(prime)).to.equal(bitLength)
|
||||
})
|
||||
} else {
|
||||
it('should throw error', function () {
|
||||
chai.expect(() => bcu.prime(bitLength)).to.throw(RangeError) // eslint-disable-line
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
describe('Testing sync (NOT-RECOMMENDED) version: primeSync()', function () {
|
||||
it('should return a random 1024-bits probable prime', function () {
|
||||
const prime = bcu.primeSync(1024, 16)
|
||||
chai.expect(bcu.bitLength(prime)).to.equal(1024)
|
||||
chai.expect(() => bcu.primeSync(0)).to.throw(RangeError)
|
||||
})
|
||||
})
|
||||
})
|
|
@ -1,90 +0,0 @@
|
|||
import * as bcu from '#pkg'
|
||||
|
||||
describe('randBetween', function () {
|
||||
const numbers = [
|
||||
{
|
||||
min: BigInt(1),
|
||||
max: BigInt(2) ** BigInt(234),
|
||||
iterations: 100,
|
||||
error: false,
|
||||
errorMax: false
|
||||
},
|
||||
{
|
||||
min: BigInt('122461641436345153'),
|
||||
max: BigInt(2) ** BigInt(234),
|
||||
iterations: 100,
|
||||
error: false,
|
||||
errorMax: false
|
||||
},
|
||||
{
|
||||
min: BigInt(-41536),
|
||||
max: BigInt(213),
|
||||
iterations: 100,
|
||||
error: false,
|
||||
errorMax: false
|
||||
},
|
||||
{
|
||||
min: BigInt('-41446134643671357134674615124613467356734646146125'),
|
||||
max: BigInt('-125246'),
|
||||
iterations: 100,
|
||||
error: false,
|
||||
errorMax: true
|
||||
},
|
||||
{
|
||||
min: BigInt(146347),
|
||||
max: BigInt(232),
|
||||
iterations: 1,
|
||||
error: true,
|
||||
errorMax: false
|
||||
},
|
||||
{
|
||||
min: BigInt(2),
|
||||
max: BigInt(2),
|
||||
iterations: 1,
|
||||
error: true,
|
||||
errorMax: false
|
||||
},
|
||||
{
|
||||
min: BigInt(1),
|
||||
max: BigInt(-1),
|
||||
iterations: 1,
|
||||
error: true,
|
||||
errorMax: true
|
||||
}
|
||||
]
|
||||
this.timeout(90000)
|
||||
for (const num of numbers) {
|
||||
describe(`randBetween(${num.max}, ${num.min})`, function () {
|
||||
if (!num.error) {
|
||||
it(`[${num.iterations} iterations] should return x such that min <= x <= max`, function () {
|
||||
let ret = true
|
||||
for (let i = 0; i < num.iterations; i++) {
|
||||
const x = bcu.randBetween(num.max, num.min)
|
||||
ret = ret && x >= num.min && x <= num.max
|
||||
}
|
||||
chai.expect(ret).to.equal(true)
|
||||
})
|
||||
} else {
|
||||
it('should throw RangeError (max <=0 || min <0 || min>=max)', function () {
|
||||
chai.expect(() => bcu.randBetween(num.max, num.min)).to.throw(RangeError)
|
||||
})
|
||||
}
|
||||
})
|
||||
describe(`randBetween(${num.max})`, function () {
|
||||
if (!num.errorMax) {
|
||||
it(`[${num.iterations} iterations] should return x such that 1 <= x <= max`, function () {
|
||||
let ret = true
|
||||
for (let i = 0; i < num.iterations; i++) {
|
||||
const x = bcu.randBetween(num.max)
|
||||
ret = ret && x >= BigInt(1) && x <= num.max
|
||||
}
|
||||
chai.expect(ret).to.equal(true)
|
||||
})
|
||||
} else {
|
||||
it('should throw RangeError (max <= min)', function () {
|
||||
chai.expect(() => bcu.randBetween(num.max)).to.throw(RangeError)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
107
test/random.ts
107
test/random.ts
|
@ -1,107 +0,0 @@
|
|||
import * as bcu from '#pkg'
|
||||
|
||||
const iterations = 10
|
||||
const bitLengths = [-1, 0, 3, 8, 16, 511, 2048]
|
||||
const byteLengths = [-7, 0, 1, 8, 33, 40, 65536, 67108864]
|
||||
|
||||
describe('testing randBits', function () {
|
||||
for (const bitLength of bitLengths) {
|
||||
describe(`${iterations} iterations of randBitsSync(${bitLength})`, function () {
|
||||
if (bitLength > 0) {
|
||||
it('should return buffers', function () {
|
||||
let ret = true
|
||||
for (let i = 0; i < iterations; i++) {
|
||||
const randbits = bcu.randBitsSync(bitLength)
|
||||
// console.log(JSON.stringify(randbits))
|
||||
const randbits2 = bcu.randBitsSync(bitLength, true)
|
||||
// console.log(JSON.stringify(randbits2))
|
||||
if (!(((randbits instanceof Uint8Array) && (randbits2 instanceof Uint8Array)) ||
|
||||
((randbits instanceof Buffer) && (randbits2 instanceof Buffer)))) {
|
||||
ret = false
|
||||
break
|
||||
}
|
||||
}
|
||||
chai.expect(ret).to.equal(true)
|
||||
})
|
||||
} else {
|
||||
it('should throw RangeError', function () {
|
||||
chai.expect(() => bcu.randBitsSync(bitLength)).to.throw(RangeError)
|
||||
})
|
||||
}
|
||||
})
|
||||
describe(`${iterations} iterations of randBits(${bitLength})`, function () {
|
||||
if (bitLength > 0) {
|
||||
it('should return buffers', async function () {
|
||||
let ret = true
|
||||
for (let i = 0; i < iterations; i++) {
|
||||
const randbits = await bcu.randBits(bitLength)
|
||||
// console.log(JSON.stringify(randbits))
|
||||
const randbits2 = await bcu.randBits(bitLength, true)
|
||||
// console.log(JSON.stringify(randbits2))
|
||||
if (!(((randbits instanceof Uint8Array) && (randbits2 instanceof Uint8Array)) ||
|
||||
((randbits instanceof Buffer) && (randbits2 instanceof Buffer)))) {
|
||||
ret = false
|
||||
break
|
||||
}
|
||||
}
|
||||
chai.expect(ret).to.equal(true)
|
||||
})
|
||||
} else {
|
||||
it('should throw RangeError', function () {
|
||||
chai.expect(() => bcu.randBits(bitLength)).to.throw(RangeError) // eslint-disable-line
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
describe('testing randBytes', function () {
|
||||
for (const byteLength of byteLengths) {
|
||||
describe(`${iterations} iterations of randBytesSync(${byteLength})`, function () {
|
||||
if (byteLength > 0) {
|
||||
it('should return buffers', function () {
|
||||
let ret = true
|
||||
for (let i = 0; i < iterations; i++) {
|
||||
const randbytes = bcu.randBytesSync(byteLength)
|
||||
// console.log(JSON.stringify(randbits))
|
||||
const randbytes2 = bcu.randBytesSync(byteLength, true)
|
||||
// console.log(JSON.stringify(randbits2))
|
||||
if (!(((randbytes instanceof Uint8Array) && (randbytes2 instanceof Uint8Array)) ||
|
||||
((randbytes instanceof Buffer) && (randbytes2 instanceof Buffer)))) {
|
||||
ret = false
|
||||
}
|
||||
}
|
||||
chai.expect(ret).to.equal(true)
|
||||
})
|
||||
} else {
|
||||
it('should throw RangeError', function () {
|
||||
chai.expect(() => bcu.randBytesSync(byteLength)).to.throw(RangeError)
|
||||
})
|
||||
}
|
||||
})
|
||||
describe(`${iterations} iterations of randBytes(${byteLength})`, function () {
|
||||
if (byteLength > 0) {
|
||||
it('should return buffers of the expected length', async function () {
|
||||
let ret = true
|
||||
for (let i = 0; i < iterations; i++) {
|
||||
const randbytes = await bcu.randBytes(byteLength)
|
||||
chai.expect(randbytes.length).to.equal(byteLength)
|
||||
// console.log(JSON.stringify(randbits))
|
||||
const randbytes2 = await bcu.randBytes(byteLength, true)
|
||||
chai.expect(randbytes2.length).to.equal(byteLength)
|
||||
// console.log(JSON.stringify(randbits2))
|
||||
if (!(((randbytes instanceof Uint8Array) && (randbytes2 instanceof Uint8Array)) ||
|
||||
((randbytes instanceof Buffer) && (randbytes2 instanceof Buffer)))) {
|
||||
ret = false
|
||||
}
|
||||
}
|
||||
chai.expect(ret).to.equal(true)
|
||||
})
|
||||
} else {
|
||||
it('should throw RangeError', function () {
|
||||
chai.expect(() => bcu.randBytes(byteLength)).to.throw(RangeError) // eslint-disable-line
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
|
@ -1,47 +0,0 @@
|
|||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"compilerOptions": {
|
||||
"target": "ES2020", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', 'ES2023', 'ES2023' or 'ESNEXT'. */
|
||||
"module": "ESNext",
|
||||
// "lib": [ "es2020" ], /* Specify library files to be included in the compilation. */
|
||||
"allowJs": true, /* Allow javascript files to be compiled. */
|
||||
"outDir": ".dst", /* If not set we cannot import .js files without a warning that is going to be overwritten. outDir is not going to be used in any case */
|
||||
"checkJs": true, /* Report errors in .js files. */
|
||||
// "jsx": "preserve", /* Specify JSX code generation: 'react', 'react-jsx', 'react-jsxdev', 'preserve' or 'react-native'. */
|
||||
"strict": true, /* Enable all strict type-checking options. */
|
||||
"removeComments": true,
|
||||
|
||||
/* Additional Checks */
|
||||
// "noUnusedLocals": true, /* Report errors on unused locals. */
|
||||
// "noUnusedParameters": true, /* Report errors on unused parameters. */
|
||||
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
|
||||
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
||||
// "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
|
||||
|
||||
/* Module Resolution Options */
|
||||
"moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
|
||||
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
|
||||
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
||||
// "rootDir": ".",
|
||||
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
||||
"typeRoots": [ "node_modules/@types", "build/typings" ], /* List of folders to include type definitions from. */
|
||||
// "types": [], /* Type declaration files to be included in compilation. */
|
||||
"allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
|
||||
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
||||
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
|
||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||
|
||||
/* Experimental Options */
|
||||
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
|
||||
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
|
||||
|
||||
/* Advanced Options */
|
||||
"skipLibCheck": true, /* Skip type checking of declaration files. */
|
||||
"forceConsistentCasingInFileNames": true, /* Disallow inconsistently-cased references to the same file. */
|
||||
"resolveJsonModule": true,
|
||||
"paths": {
|
||||
"#pkg": ["./src/ts/index.ts"]
|
||||
}
|
||||
},
|
||||
"include": ["src/ts/**/*", "build/typings/**/*.d.ts", "test/**/*", "test-vectors/**/*.ts", "benchmark/**/*.ts"]
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
/// <reference types="node" />
|
||||
export declare function fromBuffer(buf: Uint8Array | Buffer): bigint;
|
||||
//# sourceMappingURL=fromBuffer.d.ts.map
|
|
@ -1 +0,0 @@
|
|||
{"version":3,"file":"fromBuffer.d.ts","sourceRoot":"","sources":["../src/ts/fromBuffer.ts"],"names":[],"mappings":";AAAA,wBAAgB,UAAU,CAAE,GAAG,EAAE,UAAU,GAAG,MAAM,GAAG,MAAM,CAO5D"}
|
|
@ -1,3 +0,0 @@
|
|||
/// <reference types="node" />
|
||||
export declare function fromBuffer(buf: Uint8Array | Buffer): bigint;
|
||||
//# sourceMappingURL=fromBuffer.d.ts.map
|
|
@ -1 +0,0 @@
|
|||
{"version":3,"file":"fromBuffer.d.ts","sourceRoot":"","sources":["../src/ts/fromBuffer.ts"],"names":[],"mappings":";AAAA,wBAAgB,UAAU,CAAE,GAAG,EAAE,UAAU,GAAG,MAAM,GAAG,MAAM,CAO5D"}
|
|
@ -1,7 +0,0 @@
|
|||
export { abs, bitLength, eGcd, gcd, lcm, max, min, modInv, modPow, toZn } from 'bigint-mod-arith';
|
||||
export { isProbablyPrime } from './isProbablyPrime.js';
|
||||
export { prime, primeSync } from './prime.js';
|
||||
export { randBetween } from './randBetween.js';
|
||||
export { randBits, randBitsSync } from './randBits.js';
|
||||
export { randBytes, randBytesSync } from './randBytes.js';
|
||||
//# sourceMappingURL=index.d.ts.map
|
|
@ -1 +0,0 @@
|
|||
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/ts/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAA;AAEjG,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AACtD,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AACtD,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA"}
|
|
@ -1,7 +0,0 @@
|
|||
export { abs, bitLength, eGcd, gcd, lcm, max, min, modInv, modPow, toZn } from 'bigint-mod-arith';
|
||||
export { isProbablyPrime } from './isProbablyPrime.js';
|
||||
export { prime, primeSync } from './prime.js';
|
||||
export { randBetween } from './randBetween.js';
|
||||
export { randBits, randBitsSync } from './randBits.js';
|
||||
export { randBytes, randBytesSync } from './randBytes.js';
|
||||
//# sourceMappingURL=index.d.ts.map
|
|
@ -1 +0,0 @@
|
|||
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/ts/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAA;AAEjG,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AACtD,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AACtD,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA"}
|
|
@ -1,4 +0,0 @@
|
|||
export declare function isProbablyPrime(w: number | bigint, iterations?: number, disableWorkers?: boolean): Promise<boolean>;
|
||||
export declare function _isProbablyPrime(w: bigint, iterations: number): boolean;
|
||||
export declare function _isProbablyPrimeWorkerUrl(): string;
|
||||
//# sourceMappingURL=isProbablyPrime.d.ts.map
|
|
@ -1 +0,0 @@
|
|||
{"version":3,"file":"isProbablyPrime.d.ts","sourceRoot":"","sources":["../src/ts/isProbablyPrime.ts"],"names":[],"mappings":"AAmBA,wBAAgB,eAAe,CAAE,CAAC,EAAE,MAAM,GAAC,MAAM,EAAE,UAAU,GAAE,MAAW,EAAE,cAAc,GAAE,OAAe,GAAG,OAAO,CAAC,OAAO,CAAC,CA2D7H;AAED,wBAAgB,gBAAgB,CAAE,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CA0TxE;AAED,wBAAgB,yBAAyB,IAAK,MAAM,CA8BnD"}
|
|
@ -1,4 +0,0 @@
|
|||
export declare function isProbablyPrime(w: number | bigint, iterations?: number, disableWorkers?: boolean): Promise<boolean>;
|
||||
export declare function _isProbablyPrime(w: bigint, iterations: number): boolean;
|
||||
export declare function _isProbablyPrimeWorkerUrl(): string;
|
||||
//# sourceMappingURL=isProbablyPrime.d.ts.map
|
|
@ -1 +0,0 @@
|
|||
{"version":3,"file":"isProbablyPrime.d.ts","sourceRoot":"","sources":["../src/ts/isProbablyPrime.ts"],"names":[],"mappings":"AAmBA,wBAAgB,eAAe,CAAE,CAAC,EAAE,MAAM,GAAC,MAAM,EAAE,UAAU,GAAE,MAAW,EAAE,cAAc,GAAE,OAAe,GAAG,OAAO,CAAC,OAAO,CAAC,CA2D7H;AAED,wBAAgB,gBAAgB,CAAE,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CA0TxE;AAED,wBAAgB,yBAAyB,IAAK,MAAM,CA8BnD"}
|
|
@ -1,3 +0,0 @@
|
|||
export declare function prime(bitLength: number, iterations?: number): Promise<bigint>;
|
||||
export declare function primeSync(bitLength: number, iterations?: number): bigint;
|
||||
//# sourceMappingURL=prime.d.ts.map
|
|
@ -1 +0,0 @@
|
|||
{"version":3,"file":"prime.d.ts","sourceRoot":"","sources":["../src/ts/prime.ts"],"names":[],"mappings":"AA2BA,wBAAgB,KAAK,CAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAE,MAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAoElF;AAaD,wBAAgB,SAAS,CAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAE,MAAW,GAAG,MAAM,CAO7E"}
|
|
@ -1,3 +0,0 @@
|
|||
export declare function prime(bitLength: number, iterations?: number): Promise<bigint>;
|
||||
export declare function primeSync(bitLength: number, iterations?: number): bigint;
|
||||
//# sourceMappingURL=prime.d.ts.map
|
|
@ -1 +0,0 @@
|
|||
{"version":3,"file":"prime.d.ts","sourceRoot":"","sources":["../src/ts/prime.ts"],"names":[],"mappings":"AA2BA,wBAAgB,KAAK,CAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAE,MAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAoElF;AAaD,wBAAgB,SAAS,CAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAE,MAAW,GAAG,MAAM,CAO7E"}
|
|
@ -1,2 +0,0 @@
|
|||
export declare function randBetween(max: bigint, min?: bigint): bigint;
|
||||
//# sourceMappingURL=randBetween.d.ts.map
|
|
@ -1 +0,0 @@
|
|||
{"version":3,"file":"randBetween.d.ts","sourceRoot":"","sources":["../src/ts/randBetween.ts"],"names":[],"mappings":"AAaA,wBAAgB,WAAW,CAAE,GAAG,EAAE,MAAM,EAAE,GAAG,GAAE,MAAW,GAAG,MAAM,CAUlE"}
|
|
@ -1,2 +0,0 @@
|
|||
export declare function randBetween(max: bigint, min?: bigint): bigint;
|
||||
//# sourceMappingURL=randBetween.d.ts.map
|
|
@ -1 +0,0 @@
|
|||
{"version":3,"file":"randBetween.d.ts","sourceRoot":"","sources":["../src/ts/randBetween.ts"],"names":[],"mappings":"AAaA,wBAAgB,WAAW,CAAE,GAAG,EAAE,MAAM,EAAE,GAAG,GAAE,MAAW,GAAG,MAAM,CAUlE"}
|
|
@ -1,4 +0,0 @@
|
|||
/// <reference types="node" />
|
||||
export declare function randBits(bitLength: number, forceLength?: boolean): Promise<Uint8Array | Buffer>;
|
||||
export declare function randBitsSync(bitLength: number, forceLength?: boolean): Uint8Array | Buffer;
|
||||
//# sourceMappingURL=randBits.d.ts.map
|
|
@ -1 +0,0 @@
|
|||
{"version":3,"file":"randBits.d.ts","sourceRoot":"","sources":["../src/ts/randBits.ts"],"names":[],"mappings":";AAYA,wBAAgB,QAAQ,CAAE,SAAS,EAAE,MAAM,EAAE,WAAW,GAAE,OAAe,GAAG,OAAO,CAAC,UAAU,GAAC,MAAM,CAAC,CAmBrG;AAWD,wBAAgB,YAAY,CAAE,SAAS,EAAE,MAAM,EAAE,WAAW,GAAE,OAAe,GAAG,UAAU,GAAG,MAAM,CAelG"}
|
|
@ -1,4 +0,0 @@
|
|||
/// <reference types="node" />
|
||||
export declare function randBits(bitLength: number, forceLength?: boolean): Promise<Uint8Array | Buffer>;
|
||||
export declare function randBitsSync(bitLength: number, forceLength?: boolean): Uint8Array | Buffer;
|
||||
//# sourceMappingURL=randBits.d.ts.map
|
|
@ -1 +0,0 @@
|
|||
{"version":3,"file":"randBits.d.ts","sourceRoot":"","sources":["../src/ts/randBits.ts"],"names":[],"mappings":";AAYA,wBAAgB,QAAQ,CAAE,SAAS,EAAE,MAAM,EAAE,WAAW,GAAE,OAAe,GAAG,OAAO,CAAC,UAAU,GAAC,MAAM,CAAC,CAmBrG;AAWD,wBAAgB,YAAY,CAAE,SAAS,EAAE,MAAM,EAAE,WAAW,GAAE,OAAe,GAAG,UAAU,GAAG,MAAM,CAelG"}
|
|
@ -1,4 +0,0 @@
|
|||
/// <reference types="node" />
|
||||
export declare function randBytes(byteLength: number, forceLength?: boolean): Promise<Uint8Array | Buffer>;
|
||||
export declare function randBytesSync(byteLength: number, forceLength?: boolean): Uint8Array | Buffer;
|
||||
//# sourceMappingURL=randBytes.d.ts.map
|
|
@ -1 +0,0 @@
|
|||
{"version":3,"file":"randBytes.d.ts","sourceRoot":"","sources":["../src/ts/randBytes.ts"],"names":[],"mappings":";AAYA,wBAAgB,SAAS,CAAE,UAAU,EAAE,MAAM,EAAE,WAAW,UAAQ,GAAG,OAAO,CAAC,UAAU,GAAC,MAAM,CAAC,CA4B9F;AAaD,wBAAgB,aAAa,CAAE,UAAU,EAAE,MAAM,EAAE,WAAW,GAAE,OAAe,GAAG,UAAU,GAAG,MAAM,CA0BpG"}
|
|
@ -1,4 +0,0 @@
|
|||
/// <reference types="node" />
|
||||
export declare function randBytes(byteLength: number, forceLength?: boolean): Promise<Uint8Array | Buffer>;
|
||||
export declare function randBytesSync(byteLength: number, forceLength?: boolean): Uint8Array | Buffer;
|
||||
//# sourceMappingURL=randBytes.d.ts.map
|
|
@ -1 +0,0 @@
|
|||
{"version":3,"file":"randBytes.d.ts","sourceRoot":"","sources":["../src/ts/randBytes.ts"],"names":[],"mappings":";AAYA,wBAAgB,SAAS,CAAE,UAAU,EAAE,MAAM,EAAE,WAAW,UAAQ,GAAG,OAAO,CAAC,UAAU,GAAC,MAAM,CAAC,CA4B9F;AAaD,wBAAgB,aAAa,CAAE,UAAU,EAAE,MAAM,EAAE,WAAW,GAAE,OAAe,GAAG,UAAU,GAAG,MAAM,CA0BpG"}
|
|
@ -1,18 +0,0 @@
|
|||
export declare function _workerUrl(workerCode: string): string;
|
||||
declare let _useWorkers: boolean;
|
||||
export { _useWorkers };
|
||||
export interface WorkerToMainMsg {
|
||||
_bcu: {
|
||||
isPrime: boolean;
|
||||
value: bigint;
|
||||
id: number;
|
||||
};
|
||||
}
|
||||
export interface MainToWorkerMsg {
|
||||
_bcu: {
|
||||
rnd: bigint;
|
||||
iterations: number;
|
||||
id: number;
|
||||
};
|
||||
}
|
||||
//# sourceMappingURL=workerUtils.d.ts.map
|
|
@ -1 +0,0 @@
|
|||
{"version":3,"file":"workerUtils.d.ts","sourceRoot":"","sources":["../src/ts/workerUtils.ts"],"names":[],"mappings":"AAAA,wBAAgB,UAAU,CAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAItD;AAED,QAAA,IAAI,WAAW,SAAQ,CAAA;AAiBvB,OAAO,EAAE,WAAW,EAAE,CAAA;AAEtB,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE;QACJ,OAAO,EAAE,OAAO,CAAA;QAChB,KAAK,EAAE,MAAM,CAAA;QACb,EAAE,EAAE,MAAM,CAAA;KACX,CAAA;CACF;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE;QACJ,GAAG,EAAE,MAAM,CAAA;QACX,UAAU,EAAE,MAAM,CAAA;QAClB,EAAE,EAAE,MAAM,CAAA;KACX,CAAA;CACF"}
|
|
@ -1,18 +0,0 @@
|
|||
export declare function _workerUrl(workerCode: string): string;
|
||||
declare let _useWorkers: boolean;
|
||||
export { _useWorkers };
|
||||
export interface WorkerToMainMsg {
|
||||
_bcu: {
|
||||
isPrime: boolean;
|
||||
value: bigint;
|
||||
id: number;
|
||||
};
|
||||
}
|
||||
export interface MainToWorkerMsg {
|
||||
_bcu: {
|
||||
rnd: bigint;
|
||||
iterations: number;
|
||||
id: number;
|
||||
};
|
||||
}
|
||||
//# sourceMappingURL=workerUtils.d.ts.map
|
|
@ -1 +0,0 @@
|
|||
{"version":3,"file":"workerUtils.d.ts","sourceRoot":"","sources":["../src/ts/workerUtils.ts"],"names":[],"mappings":"AAAA,wBAAgB,UAAU,CAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAItD;AAED,QAAA,IAAI,WAAW,SAAQ,CAAA;AAiBvB,OAAO,EAAE,WAAW,EAAE,CAAA;AAEtB,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE;QACJ,OAAO,EAAE,OAAO,CAAA;QAChB,KAAK,EAAE,MAAM,CAAA;QACb,EAAE,EAAE,MAAM,CAAA;KACX,CAAA;CACF;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE;QACJ,GAAG,EAAE,MAAM,CAAA;QACX,UAAU,EAAE,MAAM,CAAA;QAClB,EAAE,EAAE,MAAM,CAAA;KACX,CAAA;CACF"}
|
Loading…
Reference in New Issue