diff --git a/.eslintrc.json b/.eslintrc.json index 94dfd86..fc53c93 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -20,6 +20,12 @@ "plugin:prettier/recommended", "prettier" ], + "ignorePatterns": [ + "**/*.d.ts", + "**/*.js", + "coverage/*", + "lib/*" + ], "rules": { "@typescript-eslint/member-delimiter-style": 0, "@typescript-eslint/no-namespace": [ diff --git a/package-lock.json b/package-lock.json index 9ae5df5..4a1fcc7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -47,6 +47,9 @@ "tsconfig-paths-webpack-plugin": "3.5.1", "typescript": "4.6.3", "webpack-cli": "4.9.2" + }, + "engines": { + "node": ">=16" } }, "node_modules/@ampproject/remapping": { @@ -81,21 +84,21 @@ } }, "node_modules/@babel/core": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.12.tgz", - "integrity": "sha512-44ODe6O1IVz9s2oJE3rZ4trNNKTX9O7KpQpfAP4t8QII/zwrVRHL7i2pxhqtcY7tqMLrrKfMlBKnm1QlrRFs5w==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.0.tgz", + "integrity": "sha512-Xyw74OlJwDijToNi0+6BBI5mLLR5+5R3bcSH80LXzjzEGEUlvNzujEE71BaD/ApEZHAvFI/Mlmp4M5lIkdeeWw==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.12", + "@babel/generator": "^7.18.0", "@babel/helper-compilation-targets": "^7.17.10", - "@babel/helper-module-transforms": "^7.17.12", - "@babel/helpers": "^7.17.9", - "@babel/parser": "^7.17.12", + "@babel/helper-module-transforms": "^7.18.0", + "@babel/helpers": "^7.18.0", + "@babel/parser": "^7.18.0", "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.12", - "@babel/types": "^7.17.12", + "@babel/traverse": "^7.18.0", + "@babel/types": "^7.18.0", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -132,12 +135,12 @@ } }, "node_modules/@babel/generator": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.12.tgz", - "integrity": "sha512-V49KtZiiiLjH/CnIW6OjJdrenrGoyh6AmKQ3k2AZFKozC1h846Q4NYlZ5nqAigPDUXfGzC88+LOUuG8yKd2kCw==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.0.tgz", + "integrity": "sha512-81YO9gGx6voPXlvYdZBliFXAZU8vZ9AZ6z+CjlmcnaeOcYSFbMTpdeDUO9xD9dh/68Vq03I8ZspfUTPfitcDHg==", "dev": true, "dependencies": { - "@babel/types": "^7.17.12", + "@babel/types": "^7.18.0", "@jridgewell/gen-mapping": "^0.3.0", "jsesc": "^2.5.1" }, @@ -236,9 +239,9 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.12.tgz", - "integrity": "sha512-t5s2BeSWIghhFRPh9XMn6EIGmvn8Lmw5RVASJzkIx1mSemubQQBNIZiQD7WzaFmaHIrjAec4x8z9Yx8SjJ1/LA==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.0.tgz", + "integrity": "sha512-kclUYSUBIjlvnzN2++K9f2qzYKFgjmnmjwL4zlmU5f8ZtzgWe8s0rUPSTGy2HmK4P8T52MQsS+HTQAgZd3dMEA==", "dev": true, "dependencies": { "@babel/helper-environment-visitor": "^7.16.7", @@ -247,8 +250,8 @@ "@babel/helper-split-export-declaration": "^7.16.7", "@babel/helper-validator-identifier": "^7.16.7", "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.12", - "@babel/types": "^7.17.12" + "@babel/traverse": "^7.18.0", + "@babel/types": "^7.18.0" }, "engines": { "node": ">=6.9.0" @@ -306,14 +309,14 @@ } }, "node_modules/@babel/helpers": { - "version": "7.17.9", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.9.tgz", - "integrity": "sha512-cPCt915ShDWUEzEp3+UNRktO2n6v49l5RSnG9M5pS24hA+2FAc5si+Pn1i4VVbQQ+jh+bIZhPFQOJOzbrOYY1Q==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.0.tgz", + "integrity": "sha512-AE+HMYhmlMIbho9nbvicHyxFwhrO+xhKB6AhRxzl8w46Yj0VXTZjEsAoBVC7rB2I0jzX+yWyVybnO08qkfx6kg==", "dev": true, "dependencies": { "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.9", - "@babel/types": "^7.17.0" + "@babel/traverse": "^7.18.0", + "@babel/types": "^7.18.0" }, "engines": { "node": ">=6.9.0" @@ -405,9 +408,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.12.tgz", - "integrity": "sha512-FLzHmN9V3AJIrWfOpvRlZCeVg/WLdicSnTMsLur6uDj9TT8ymUlG9XxURdW/XvuygK+2CW0poOJABdA4m/YKxA==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.0.tgz", + "integrity": "sha512-AqDccGC+m5O/iUStSJy3DGRIUFu7WbY/CppZYwrEUB4N0tZlnI8CSTsgL7v5fHVFmUbRv2sd+yy27o8Ydt4MGg==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -579,9 +582,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.17.9", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz", - "integrity": "sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.0.tgz", + "integrity": "sha512-YMQvx/6nKEaucl0MY56mwIG483xk8SDNdlUwb2Ts6FUpr7fm85DxEmsY18LXBNhcTz6tO6JwZV8w1W06v8UKeg==", "dependencies": { "regenerator-runtime": "^0.13.4" }, @@ -616,19 +619,19 @@ } }, "node_modules/@babel/traverse": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.12.tgz", - "integrity": "sha512-zULPs+TbCvOkIFd4FrG53xrpxvCBwLIgo6tO0tJorY7YV2IWFxUfS/lXDJbGgfyYt9ery/Gxj2niwttNnB0gIw==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.0.tgz", + "integrity": "sha512-oNOO4vaoIQoGjDQ84LgtF/IAlxlyqL4TUuoQ7xLkQETFaHkY1F7yazhB4Kt3VcZGL0ZF/jhrEpnXqUb0M7V3sw==", "dev": true, "dependencies": { "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.12", + "@babel/generator": "^7.18.0", "@babel/helper-environment-visitor": "^7.16.7", "@babel/helper-function-name": "^7.17.9", "@babel/helper-hoist-variables": "^7.16.7", "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.17.12", - "@babel/types": "^7.17.12", + "@babel/parser": "^7.18.0", + "@babel/types": "^7.18.0", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -658,9 +661,9 @@ } }, "node_modules/@babel/types": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.12.tgz", - "integrity": "sha512-rH8i29wcZ6x9xjzI5ILHL/yZkbQnCERdHlogKuIb4PUr7do4iT8DPekrTbBLWTnRQm6U0GYABbTMSzijmEqlAg==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.0.tgz", + "integrity": "sha512-vhAmLPAiC8j9K2GnsnLPCIH5wCrPpYIVBCWRBFDCB7Y/BXLqi/O+1RSTTM2bsmg6U/551+FCf9PNPxjABmxHTw==", "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.16.7", @@ -1366,9 +1369,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "17.0.34", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.34.tgz", - "integrity": "sha512-XImEz7XwTvDBtzlTnm8YvMqGW/ErMWBsKZ+hMTvnDIjGCKxwK5Xpc+c/oQjOauwq8M4OS11hEkpjX8rrI/eEgA==", + "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.35.tgz", + "integrity": "sha512-vu1SrqBjbbZ3J6vwY17jBs8Sr/BKA+/a/WtjRG+whKg1iuLFOosq872EXS0eXWILdO36DHQQeku/ZcL6hz2fpg==", "dev": true }, "node_modules/@types/prettier": { @@ -5482,9 +5485,9 @@ } }, "node_modules/postcss": { - "version": "8.4.13", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.13.tgz", - "integrity": "sha512-jtL6eTBrza5MPzy8oJLFuUscHDXTV5KcLlqAWHl5q5WYRfnNRGSmOZmOZ1T6Gy7A99mOZfqungmZMpMmCVJ8ZA==", + "version": "8.4.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", + "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", "dev": true, "funding": [ { @@ -5497,7 +5500,7 @@ } ], "dependencies": { - "nanoid": "^3.3.3", + "nanoid": "^3.3.4", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" }, @@ -7257,21 +7260,21 @@ "dev": true }, "@babel/core": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.12.tgz", - "integrity": "sha512-44ODe6O1IVz9s2oJE3rZ4trNNKTX9O7KpQpfAP4t8QII/zwrVRHL7i2pxhqtcY7tqMLrrKfMlBKnm1QlrRFs5w==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.0.tgz", + "integrity": "sha512-Xyw74OlJwDijToNi0+6BBI5mLLR5+5R3bcSH80LXzjzEGEUlvNzujEE71BaD/ApEZHAvFI/Mlmp4M5lIkdeeWw==", "dev": true, "requires": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.12", + "@babel/generator": "^7.18.0", "@babel/helper-compilation-targets": "^7.17.10", - "@babel/helper-module-transforms": "^7.17.12", - "@babel/helpers": "^7.17.9", - "@babel/parser": "^7.17.12", + "@babel/helper-module-transforms": "^7.18.0", + "@babel/helpers": "^7.18.0", + "@babel/parser": "^7.18.0", "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.12", - "@babel/types": "^7.17.12", + "@babel/traverse": "^7.18.0", + "@babel/types": "^7.18.0", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -7297,12 +7300,12 @@ } }, "@babel/generator": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.12.tgz", - "integrity": "sha512-V49KtZiiiLjH/CnIW6OjJdrenrGoyh6AmKQ3k2AZFKozC1h846Q4NYlZ5nqAigPDUXfGzC88+LOUuG8yKd2kCw==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.0.tgz", + "integrity": "sha512-81YO9gGx6voPXlvYdZBliFXAZU8vZ9AZ6z+CjlmcnaeOcYSFbMTpdeDUO9xD9dh/68Vq03I8ZspfUTPfitcDHg==", "dev": true, "requires": { - "@babel/types": "^7.17.12", + "@babel/types": "^7.18.0", "@jridgewell/gen-mapping": "^0.3.0", "jsesc": "^2.5.1" }, @@ -7378,9 +7381,9 @@ } }, "@babel/helper-module-transforms": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.12.tgz", - "integrity": "sha512-t5s2BeSWIghhFRPh9XMn6EIGmvn8Lmw5RVASJzkIx1mSemubQQBNIZiQD7WzaFmaHIrjAec4x8z9Yx8SjJ1/LA==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.0.tgz", + "integrity": "sha512-kclUYSUBIjlvnzN2++K9f2qzYKFgjmnmjwL4zlmU5f8ZtzgWe8s0rUPSTGy2HmK4P8T52MQsS+HTQAgZd3dMEA==", "dev": true, "requires": { "@babel/helper-environment-visitor": "^7.16.7", @@ -7389,8 +7392,8 @@ "@babel/helper-split-export-declaration": "^7.16.7", "@babel/helper-validator-identifier": "^7.16.7", "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.12", - "@babel/types": "^7.17.12" + "@babel/traverse": "^7.18.0", + "@babel/types": "^7.18.0" } }, "@babel/helper-plugin-utils": { @@ -7430,14 +7433,14 @@ "dev": true }, "@babel/helpers": { - "version": "7.17.9", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.9.tgz", - "integrity": "sha512-cPCt915ShDWUEzEp3+UNRktO2n6v49l5RSnG9M5pS24hA+2FAc5si+Pn1i4VVbQQ+jh+bIZhPFQOJOzbrOYY1Q==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.0.tgz", + "integrity": "sha512-AE+HMYhmlMIbho9nbvicHyxFwhrO+xhKB6AhRxzl8w46Yj0VXTZjEsAoBVC7rB2I0jzX+yWyVybnO08qkfx6kg==", "dev": true, "requires": { "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.9", - "@babel/types": "^7.17.0" + "@babel/traverse": "^7.18.0", + "@babel/types": "^7.18.0" } }, "@babel/highlight": { @@ -7510,9 +7513,9 @@ } }, "@babel/parser": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.12.tgz", - "integrity": "sha512-FLzHmN9V3AJIrWfOpvRlZCeVg/WLdicSnTMsLur6uDj9TT8ymUlG9XxURdW/XvuygK+2CW0poOJABdA4m/YKxA==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.0.tgz", + "integrity": "sha512-AqDccGC+m5O/iUStSJy3DGRIUFu7WbY/CppZYwrEUB4N0tZlnI8CSTsgL7v5fHVFmUbRv2sd+yy27o8Ydt4MGg==", "dev": true }, "@babel/plugin-syntax-async-generators": { @@ -7633,9 +7636,9 @@ } }, "@babel/runtime": { - "version": "7.17.9", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz", - "integrity": "sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.0.tgz", + "integrity": "sha512-YMQvx/6nKEaucl0MY56mwIG483xk8SDNdlUwb2Ts6FUpr7fm85DxEmsY18LXBNhcTz6tO6JwZV8w1W06v8UKeg==", "requires": { "regenerator-runtime": "^0.13.4" } @@ -7663,19 +7666,19 @@ } }, "@babel/traverse": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.12.tgz", - "integrity": "sha512-zULPs+TbCvOkIFd4FrG53xrpxvCBwLIgo6tO0tJorY7YV2IWFxUfS/lXDJbGgfyYt9ery/Gxj2niwttNnB0gIw==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.0.tgz", + "integrity": "sha512-oNOO4vaoIQoGjDQ84LgtF/IAlxlyqL4TUuoQ7xLkQETFaHkY1F7yazhB4Kt3VcZGL0ZF/jhrEpnXqUb0M7V3sw==", "dev": true, "requires": { "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.12", + "@babel/generator": "^7.18.0", "@babel/helper-environment-visitor": "^7.16.7", "@babel/helper-function-name": "^7.17.9", "@babel/helper-hoist-variables": "^7.16.7", "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.17.12", - "@babel/types": "^7.17.12", + "@babel/parser": "^7.18.0", + "@babel/types": "^7.18.0", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -7698,9 +7701,9 @@ } }, "@babel/types": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.12.tgz", - "integrity": "sha512-rH8i29wcZ6x9xjzI5ILHL/yZkbQnCERdHlogKuIb4PUr7do4iT8DPekrTbBLWTnRQm6U0GYABbTMSzijmEqlAg==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.0.tgz", + "integrity": "sha512-vhAmLPAiC8j9K2GnsnLPCIH5wCrPpYIVBCWRBFDCB7Y/BXLqi/O+1RSTTM2bsmg6U/551+FCf9PNPxjABmxHTw==", "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.16.7", @@ -8300,9 +8303,9 @@ "dev": true }, "@types/node": { - "version": "17.0.34", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.34.tgz", - "integrity": "sha512-XImEz7XwTvDBtzlTnm8YvMqGW/ErMWBsKZ+hMTvnDIjGCKxwK5Xpc+c/oQjOauwq8M4OS11hEkpjX8rrI/eEgA==", + "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.35.tgz", + "integrity": "sha512-vu1SrqBjbbZ3J6vwY17jBs8Sr/BKA+/a/WtjRG+whKg1iuLFOosq872EXS0eXWILdO36DHQQeku/ZcL6hz2fpg==", "dev": true }, "@types/prettier": { @@ -11363,12 +11366,12 @@ } }, "postcss": { - "version": "8.4.13", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.13.tgz", - "integrity": "sha512-jtL6eTBrza5MPzy8oJLFuUscHDXTV5KcLlqAWHl5q5WYRfnNRGSmOZmOZ1T6Gy7A99mOZfqungmZMpMmCVJ8ZA==", + "version": "8.4.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", + "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", "dev": true, "requires": { - "nanoid": "^3.3.3", + "nanoid": "^3.3.4", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } diff --git a/package.json b/package.json index 9919a7a..c19e181 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "build": "webpack", "pretest": "npm run sjcl", "test": "tsc -b && node --experimental-vm-modules node_modules/jest/bin/jest.js --ci", - "lint": "eslint ./src/**/*.{ts,tsx}", + "lint": "eslint .", "clean": "rimraf dist" }, "dependencies": { diff --git a/src/blindrsa/blindrsa.test.ts b/src/blindrsa/blindrsa.test.ts new file mode 100644 index 0000000..c58415c --- /dev/null +++ b/src/blindrsa/blindrsa.test.ts @@ -0,0 +1,132 @@ +import blindRSA from './index'; +import { jest } from '@jest/globals'; +import sjcl from './sjcl'; +// Test vector +// https://www.ietf.org/archive/id/draft-irtf-cfrg-rsa-blind-signatures-03.html#appendix-A +import vectors from './testdata/rsablind_vectors.json'; + +function hexToB64URL(x: string): string { + return Buffer.from(x, 'hex').toString('base64url'); +} + +function hexToUint8(x: string): Uint8Array { + return new Uint8Array(Buffer.from(x, 'hex')); +} + +function paramsFromVector(v: typeof vectors[number]): { + n: string; + e: string; + d: string; + p: string; + q: string; + dp: string; + dq: string; + qi: string; +} { + const n = hexToB64URL(v.n); + const e = hexToB64URL(v.e); + const d = hexToB64URL(v.d); + const p = hexToB64URL(v.p); + const q = hexToB64URL(v.q); + + // Calculate CRT values + const bnD = new sjcl.bn(v.d); + const bnP = new sjcl.bn(v.p); + const bnQ = new sjcl.bn(v.q); + const one = new sjcl.bn(1); + const dp = hexToB64URL(bnD.mod(bnP.sub(one)).toString()); + const dq = hexToB64URL(bnD.mod(bnQ.sub(one)).toString()); + const qi = hexToB64URL(bnQ.inverseMod(bnP).toString()); + return { n, e, d, p, q, dp, dq, qi }; +} + +async function keysFromVector( + v: typeof vectors[number], + extractable: boolean, +): Promise { + const params = paramsFromVector(v); + const { n, e } = params; + const publicKey = await crypto.subtle.importKey( + 'jwk', + { kty: 'RSA', ext: true, n, e }, + { name: 'RSA-PSS', hash: 'SHA-384' }, + extractable, + ['verify'], + ); + + const privateKey = await crypto.subtle.importKey( + 'jwk', + { kty: 'RSA', ext: true, ...params }, + { name: 'RSA-PSS', hash: 'SHA-384' }, + extractable, + ['sign'], + ); + return { privateKey, publicKey }; +} + +describe.each(vectors)('BlindRSA-vec$#', (v: typeof vectors[number]) => { + test('test-vector', async () => { + const r_inv = new sjcl.bn(v.inv); + const r = r_inv.inverseMod(new sjcl.bn(v.n)); + const r_bytes = hexToUint8(r.toString().slice(2)); + + const { privateKey, publicKey } = await keysFromVector(v, true); + const msg = hexToUint8(v.msg); + const saltLength = v.salt.length / 2; + + // Mock for randomized blind operation. + jest.spyOn(crypto, 'getRandomValues') + .mockReturnValueOnce(hexToUint8(v.salt)) // mock for random salt + .mockReturnValueOnce(r_bytes); // mock for random blind + + const { blindedMsg, blindInv } = await blindRSA.blind(publicKey, msg, saltLength); + expect(blindedMsg).toStrictEqual(hexToUint8(v.blinded_msg)); + expect(blindInv).toStrictEqual(hexToUint8(v.inv)); + + const blindedSig = await blindRSA.blindSign(privateKey, blindedMsg); + expect(blindedSig).toStrictEqual(hexToUint8(v.blind_sig)); + + const signature = await blindRSA.finalize(publicKey, msg, blindInv, blindedSig, saltLength); + expect(signature).toStrictEqual(hexToUint8(v.sig)); + }); + + test('non-extractable-keys', async () => { + const { privateKey, publicKey } = await keysFromVector(v, false); + const msg = crypto.getRandomValues(new Uint8Array(10)); + const blindedMsg = crypto.getRandomValues(new Uint8Array(32)); + const blindInv = crypto.getRandomValues(new Uint8Array(32)); + const blindedSig = crypto.getRandomValues(new Uint8Array(32)); + const errorMsg = 'key is not extractable'; + + await expect(blindRSA.blind(publicKey, msg, 32)).rejects.toThrow(errorMsg); + await expect(blindRSA.blindSign(privateKey, blindedMsg)).rejects.toThrow(errorMsg); + await expect(blindRSA.finalize(publicKey, msg, blindInv, blindedSig, 32)).rejects.toThrow( + errorMsg, + ); + }); + + test('wrong-key-type', async () => { + const { privateKey, publicKey } = await crypto.subtle.generateKey( + { + name: 'RSASSA-PKCS1-v1_5', // not RSA-PSS. + modulusLength: 2048, + publicExponent: Uint8Array.from([0x01, 0x00, 0x01]), + hash: 'SHA-256', + }, + true, + ['sign', 'verify'], + ); + + const msg = crypto.getRandomValues(new Uint8Array(10)); + const blindedMsg = crypto.getRandomValues(new Uint8Array(32)); + const blindInv = crypto.getRandomValues(new Uint8Array(32)); + const blindedSig = crypto.getRandomValues(new Uint8Array(32)); + const errorMsg = 'key is not RSA-PSS'; + + await expect(blindRSA.blind(publicKey, msg, 32)).rejects.toThrow(errorMsg); + await expect(blindRSA.blindSign(privateKey, blindedMsg)).rejects.toThrow(errorMsg); + await expect(blindRSA.finalize(publicKey, msg, blindInv, blindedSig, 32)).rejects.toThrow( + errorMsg, + ); + }); +}); diff --git a/src/blindrsa/blindrsa.ts b/src/blindrsa/blindrsa.ts new file mode 100644 index 0000000..1234dc6 --- /dev/null +++ b/src/blindrsa/blindrsa.ts @@ -0,0 +1,156 @@ +import { emsa_pss_encode, i2osp, os2ip, rsasp1, rsavp1 } from './util'; + +import sjcl from './sjcl'; + +export async function blind( + publicKey: CryptoKey, + msg: Uint8Array, + saltLength = 0, +): Promise<{ + blindedMsg: Uint8Array; + blindInv: Uint8Array; +}> { + if (publicKey.type !== 'public' || publicKey.algorithm.name !== 'RSA-PSS') { + throw new Error('key is not RSA-PSS'); + } + if (!publicKey.extractable) { + throw new Error('key is not extractable'); + } + + const { modulusLength, hash: hashFn } = publicKey.algorithm as RsaHashedKeyGenParams; + const kBits = modulusLength; + const kLen = Math.ceil(kBits / 8); + const hash = (hashFn as Algorithm).name; + + // 1. encoded_msg = EMSA-PSS-ENCODE(msg, kBits - 1) + // with MGF and HF as defined in the parameters + // 2. If EMSA-PSS-ENCODE raises an error, raise the error and stop + const encoded_msg = await emsa_pss_encode(msg, kBits - 1, { sLen: saltLength, hash }); + + // 3. m = bytes_to_int(encoded_msg) + const m = os2ip(encoded_msg); + const jwkKey = await crypto.subtle.exportKey('jwk', publicKey); + if (!jwkKey.n || !jwkKey.e) { + throw new Error('key has invalid parameters'); + } + const n = new sjcl.bn(Buffer.from(jwkKey.n, 'base64url').toString('hex')); + const e = new sjcl.bn(Buffer.from(jwkKey.e, 'base64url').toString('hex')); + + // 4. r = random_integer_uniform(1, n) + let r: sjcl.bn; + do { + r = os2ip(crypto.getRandomValues(new Uint8Array(kLen))); + } while (r.greaterEquals(n)); + + // 5. r_inv = inverse_mod(r, n) + // 6. If inverse_mod fails, raise an "invalid blind" error + // and stop + let r_inv: sjcl.bn; + try { + r_inv = r.inverseMod(new sjcl.bn(n)); + } catch (e) { + throw new Error('invalid blind'); + } + // 7. x = RSAVP1(pkS, r) + const x = rsavp1({ n, e }, r); + + // 8. z = m * x mod n + const z = m.mulmod(x, n); + + // 9. blinded_msg = int_to_bytes(z, kLen) + const blindedMsg = i2osp(z, kLen); + + // 10. inv = int_to_bytes(r_inv, kLen) + const blindInv = i2osp(r_inv, kLen); + + // 11. output blinded_msg, inv + return { blindedMsg, blindInv }; +} + +export async function finalize( + publicKey: CryptoKey, + msg: Uint8Array, + blindInv: Uint8Array, + blindSig: Uint8Array, + saltLength = 0, +): Promise { + if (publicKey.type !== 'public' || publicKey.algorithm.name !== 'RSA-PSS') { + throw new Error('key is not RSA-PSS'); + } + if (!publicKey.extractable) { + throw new Error('key is not extractable'); + } + const { modulusLength } = publicKey.algorithm as RsaHashedKeyGenParams; + const kLen = Math.ceil(modulusLength / 8); + + // 1. If len(blind_sig) != kLen, raise "unexpected input size" and stop + // 2. If len(inv) != kLen, raise "unexpected input size" and stop + if (blindSig.length != kLen || blindInv.length != kLen) { + throw new Error('unexpected input size'); + } + + // 3. z = bytes_to_int(blind_sig) + const z = os2ip(blindSig); + + // 4. r_inv = bytes_to_int(inv) + const r_inv = os2ip(blindInv); + + // 5. s = z * r_inv mod n + const jwkKey = await crypto.subtle.exportKey('jwk', publicKey); + if (!jwkKey.n) { + throw new Error('key has invalid parameters'); + } + const n = new sjcl.bn(Buffer.from(jwkKey.n, 'base64url').toString('hex')); + const s = z.mulmod(r_inv, n); + + // 6. sig = int_to_bytes(s, kLen) + const sig = i2osp(s, kLen); + + // 7. result = RSASSA-PSS-VERIFY(pkS, msg, sig) + // 8. If result = "valid signature", output sig, else + // raise "invalid signature" and stop + const algorithm = { name: 'RSA-PSS', saltLength }; + if (!(await crypto.subtle.verify(algorithm, publicKey, sig, msg))) { + throw new Error('invalid signature'); + } + + return sig; +} + +export async function blindSign(privateKey: CryptoKey, blindMsg: Uint8Array): Promise { + if (privateKey.type !== 'private' || privateKey.algorithm.name !== 'RSA-PSS') { + throw new Error('key is not RSA-PSS'); + } + if (!privateKey.extractable) { + throw new Error('key is not extractable'); + } + const { modulusLength } = privateKey.algorithm as RsaHashedKeyGenParams; + const kLen = Math.ceil(modulusLength / 8); + + // 1. If len(blinded_msg) != kLen, raise "unexpected input size" + // and stop + if (blindMsg.length != kLen) { + throw new Error('unexpected input size'); + } + + // 2. m = bytes_to_int(blinded_msg) + const m = os2ip(blindMsg); + + // 3. If m >= n, raise "invalid message length" and stop + const jwkKey = await crypto.subtle.exportKey('jwk', privateKey); + if (!jwkKey.n || !jwkKey.d) { + throw new Error('key is not a private key'); + } + const n = new sjcl.bn(Buffer.from(jwkKey.n, 'base64url').toString('hex')); + const d = new sjcl.bn(Buffer.from(jwkKey.d, 'base64url').toString('hex')); + if (m.greaterEquals(n)) { + throw new Error('invalid message length'); + } + + // 4. s = RSASP1(skS, m) + const s = rsasp1({ n, d }, m); + + // 5. blind_sig = int_to_bytes(s, kLen) + // 6. output blind_sig + return i2osp(s, kLen); +} diff --git a/src/blindrsa/index.ts b/src/blindrsa/index.ts new file mode 100644 index 0000000..f92aaa2 --- /dev/null +++ b/src/blindrsa/index.ts @@ -0,0 +1,3 @@ +import { blind, blindSign, finalize } from './blindrsa'; +export default { blindSign, finalize, blind }; +export { blind, blindSign, finalize } from './blindrsa'; diff --git a/src/blindrsa/sjcl.Makefile b/src/blindrsa/sjcl.Makefile new file mode 100644 index 0000000..1470a4c --- /dev/null +++ b/src/blindrsa/sjcl.Makefile @@ -0,0 +1,16 @@ +SJCL_PATH=node_modules/sjcl + +all: + cd ${SJCL_PATH} && \ + ./configure --without-all --with-ecc --with-convenience --compress=none \ + --with-codecBytes --with-codecHex --with-codecArrayBuffer && \ + make + npm i -D dts-gen + npx dts-gen -m sjcl -o -f ./src/sjcl/index + npm un -D dts-gen + echo "export default sjcl;" >> ${SJCL_PATH}/sjcl.js + cp ${SJCL_PATH}/sjcl.js ./src/sjcl/index.js + patch src/sjcl/index.d.ts sjcl.point.patch + +clean: + rm -f src/sjcl/index.js src/sjcl/index.d.ts diff --git a/src/blindrsa/sjcl/index.d.ts b/src/blindrsa/sjcl/index.d.ts new file mode 100644 index 0000000..7e9cf51 --- /dev/null +++ b/src/blindrsa/sjcl/index.d.ts @@ -0,0 +1,4499 @@ +/** Declaration file generated by dts-gen */ + +export class bn { + constructor(it: any); + + add(that: any): any; + + addM(that: any): any; + + bitLength(): any; + + cnormalize(): any; + + copy(): any; + + doubleM(): any; + + equals(that: any): any; + + fullReduce(): any; + + getLimb(i: any): any; + + greaterEquals(that: any): any; + + halveM(): any; + + initWith(it: any): any; + + inverseMod(p: any): any; + + mod(that: any): any; + + montpowermod(x: any, N: any): any; + + mul(that: any): any; + + mulmod(that: any, N: any): any; + + normalize(): any; + + power(l: any): any; + + powermod(x: any, N: any): any; + + reduce(): any; + + square(): any; + + sub(that: any): any; + + subM(that: any): any; + + toBits(len: any): any; + + toString(): any; + + trim(): any; + + static fromBits(bits: any): any; + + static pseudoMersennePrime(exponent: any, coeff: any): any; + + static random(modulus: any, paranoia: any): any; + +} + +export class prng { + constructor(defaultParanoia: any); + + addEntropy(data: any, estimatedEntropy: any, source: any): void; + + addEventListener(name: any, callback: any): void; + + getProgress(paranoia: any): any; + + isReady(paranoia: any): any; + + randomWords(nwords: any, paranoia: any): any; + + removeEventListener(name: any, cb: any): void; + + setDefaultParanoia(paranoia: any, allowZeroParanoia: any): void; + + startCollectors(): void; + + stopCollectors(): void; + +} + +export const codec: { + arrayBuffer: { + fromBits: any; + hexDumpBuffer: any; + toBits: any; + }; + base64: { + fromBits: any; + toBits: any; + }; + base64url: { + fromBits: any; + toBits: any; + }; + bytes: { + fromBits: any; + toBits: any; + }; + hex: { + fromBits: any; + toBits: any; + }; + utf8String: { + fromBits: any; + toBits: any; + }; +}; + +export const keyexchange: { +}; + +export const mode: { + ccm: { + decrypt: any; + encrypt: any; + listenProgress: any; + name: string; + unListenProgress: any; + }; +}; + +export function decrypt(password: any, ciphertext: any, params: any, rp: any): any; + +export function encrypt(password: any, plaintext: any, params: any, rp: any, ...args: any[]): any; + +export namespace bitArray { + function bitLength(a: any): any; + + function bitSlice(a: any, bstart: any, bend: any): any; + + function byteswapM(a: any): any; + + function clamp(a: any, len: any): any; + + function concat(a1: any, a2: any): any; + + function equal(a: any, b: any): any; + + function extract(a: any, bstart: any, blength: any): any; + + function getPartial(x: any): any; + + function partial(len: any, x: any, _end: any): any; + +} + +export namespace bn { + namespace prime { + class p127 { + constructor(it: any); + + fullReduce(): any; + + inverse(): any; + + reduce(): any; + + static fromBits(bits: any): any; + + } + + class p192 { + constructor(it: any); + + fullReduce(): any; + + inverse(): any; + + reduce(): any; + + static fromBits(bits: any): any; + + } + + class p192k { + constructor(it: any); + + fullReduce(): any; + + inverse(): any; + + reduce(): any; + + static fromBits(bits: any): any; + + } + + class p224 { + constructor(it: any); + + fullReduce(): any; + + inverse(): any; + + reduce(): any; + + static fromBits(bits: any): any; + + } + + class p224k { + constructor(it: any); + + fullReduce(): any; + + inverse(): any; + + reduce(): any; + + static fromBits(bits: any): any; + + } + + class p25519 { + constructor(it: any); + + fullReduce(): any; + + inverse(): any; + + reduce(): any; + + static fromBits(bits: any): any; + + } + + class p256 { + constructor(it: any); + + fullReduce(): any; + + inverse(): any; + + reduce(): any; + + static fromBits(bits: any): any; + + } + + class p256k { + constructor(it: any); + + fullReduce(): any; + + inverse(): any; + + reduce(): any; + + static fromBits(bits: any): any; + + } + + class p384 { + constructor(it: any); + + fullReduce(): any; + + inverse(): any; + + reduce(): any; + + static fromBits(bits: any): any; + + } + + class p521 { + constructor(it: any); + + fullReduce(): any; + + inverse(): any; + + reduce(): any; + + static fromBits(bits: any): any; + + } + + namespace p127 { + namespace modulus { + // Too-deep object hierarchy from sjcl.bn.prime.p127.modulus + const add: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p127.modulus + const addM: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p127.modulus + const bitLength: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p127.modulus + const cnormalize: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p127.modulus + const copy: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p127.modulus + const doubleM: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p127.modulus + const equals: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p127.modulus + const fullReduce: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p127.modulus + const getLimb: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p127.modulus + const greaterEquals: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p127.modulus + const halveM: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p127.modulus + const initWith: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p127.modulus + const inverseMod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p127.modulus + const ipv: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p127.modulus + const limbs: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p127.modulus + const maxMul: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p127.modulus + const mod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p127.modulus + const montpowermod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p127.modulus + const mul: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p127.modulus + const mulmod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p127.modulus + const normalize: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p127.modulus + const placeVal: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p127.modulus + const power: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p127.modulus + const powermod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p127.modulus + const radix: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p127.modulus + const radixMask: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p127.modulus + const reduce: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p127.modulus + const square: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p127.modulus + const sub: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p127.modulus + const subM: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p127.modulus + const toBits: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p127.modulus + const toString: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p127.modulus + const trim: any; + + } + + } + + namespace p192 { + namespace modulus { + // Too-deep object hierarchy from sjcl.bn.prime.p192.modulus + const add: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192.modulus + const addM: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192.modulus + const bitLength: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192.modulus + const cnormalize: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192.modulus + const copy: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192.modulus + const doubleM: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192.modulus + const equals: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192.modulus + const fullReduce: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192.modulus + const getLimb: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192.modulus + const greaterEquals: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192.modulus + const halveM: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192.modulus + const initWith: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192.modulus + const inverseMod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192.modulus + const ipv: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192.modulus + const limbs: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192.modulus + const maxMul: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192.modulus + const mod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192.modulus + const montpowermod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192.modulus + const mul: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192.modulus + const mulmod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192.modulus + const normalize: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192.modulus + const placeVal: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192.modulus + const power: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192.modulus + const powermod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192.modulus + const radix: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192.modulus + const radixMask: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192.modulus + const reduce: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192.modulus + const square: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192.modulus + const sub: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192.modulus + const subM: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192.modulus + const toBits: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192.modulus + const toString: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192.modulus + const trim: any; + + } + + } + + namespace p192k { + namespace modulus { + // Too-deep object hierarchy from sjcl.bn.prime.p192k.modulus + const add: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192k.modulus + const addM: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192k.modulus + const bitLength: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192k.modulus + const cnormalize: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192k.modulus + const copy: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192k.modulus + const doubleM: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192k.modulus + const equals: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192k.modulus + const fullReduce: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192k.modulus + const getLimb: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192k.modulus + const greaterEquals: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192k.modulus + const halveM: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192k.modulus + const initWith: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192k.modulus + const inverseMod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192k.modulus + const ipv: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192k.modulus + const limbs: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192k.modulus + const maxMul: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192k.modulus + const mod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192k.modulus + const montpowermod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192k.modulus + const mul: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192k.modulus + const mulmod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192k.modulus + const normalize: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192k.modulus + const placeVal: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192k.modulus + const power: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192k.modulus + const powermod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192k.modulus + const radix: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192k.modulus + const radixMask: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192k.modulus + const reduce: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192k.modulus + const square: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192k.modulus + const sub: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192k.modulus + const subM: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192k.modulus + const toBits: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192k.modulus + const toString: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p192k.modulus + const trim: any; + + } + + } + + namespace p224 { + namespace modulus { + // Too-deep object hierarchy from sjcl.bn.prime.p224.modulus + const add: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224.modulus + const addM: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224.modulus + const bitLength: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224.modulus + const cnormalize: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224.modulus + const copy: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224.modulus + const doubleM: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224.modulus + const equals: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224.modulus + const fullReduce: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224.modulus + const getLimb: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224.modulus + const greaterEquals: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224.modulus + const halveM: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224.modulus + const initWith: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224.modulus + const inverseMod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224.modulus + const ipv: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224.modulus + const limbs: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224.modulus + const maxMul: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224.modulus + const mod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224.modulus + const montpowermod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224.modulus + const mul: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224.modulus + const mulmod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224.modulus + const normalize: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224.modulus + const placeVal: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224.modulus + const power: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224.modulus + const powermod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224.modulus + const radix: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224.modulus + const radixMask: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224.modulus + const reduce: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224.modulus + const square: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224.modulus + const sub: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224.modulus + const subM: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224.modulus + const toBits: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224.modulus + const toString: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224.modulus + const trim: any; + + } + + } + + namespace p224k { + namespace modulus { + // Too-deep object hierarchy from sjcl.bn.prime.p224k.modulus + const add: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224k.modulus + const addM: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224k.modulus + const bitLength: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224k.modulus + const cnormalize: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224k.modulus + const copy: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224k.modulus + const doubleM: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224k.modulus + const equals: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224k.modulus + const fullReduce: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224k.modulus + const getLimb: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224k.modulus + const greaterEquals: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224k.modulus + const halveM: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224k.modulus + const initWith: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224k.modulus + const inverseMod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224k.modulus + const ipv: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224k.modulus + const limbs: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224k.modulus + const maxMul: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224k.modulus + const mod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224k.modulus + const montpowermod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224k.modulus + const mul: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224k.modulus + const mulmod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224k.modulus + const normalize: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224k.modulus + const placeVal: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224k.modulus + const power: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224k.modulus + const powermod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224k.modulus + const radix: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224k.modulus + const radixMask: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224k.modulus + const reduce: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224k.modulus + const square: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224k.modulus + const sub: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224k.modulus + const subM: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224k.modulus + const toBits: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224k.modulus + const toString: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p224k.modulus + const trim: any; + + } + + } + + namespace p25519 { + namespace modulus { + // Too-deep object hierarchy from sjcl.bn.prime.p25519.modulus + const add: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p25519.modulus + const addM: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p25519.modulus + const bitLength: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p25519.modulus + const cnormalize: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p25519.modulus + const copy: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p25519.modulus + const doubleM: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p25519.modulus + const equals: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p25519.modulus + const fullReduce: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p25519.modulus + const getLimb: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p25519.modulus + const greaterEquals: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p25519.modulus + const halveM: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p25519.modulus + const initWith: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p25519.modulus + const inverseMod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p25519.modulus + const ipv: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p25519.modulus + const limbs: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p25519.modulus + const maxMul: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p25519.modulus + const mod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p25519.modulus + const montpowermod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p25519.modulus + const mul: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p25519.modulus + const mulmod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p25519.modulus + const normalize: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p25519.modulus + const placeVal: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p25519.modulus + const power: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p25519.modulus + const powermod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p25519.modulus + const radix: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p25519.modulus + const radixMask: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p25519.modulus + const reduce: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p25519.modulus + const square: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p25519.modulus + const sub: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p25519.modulus + const subM: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p25519.modulus + const toBits: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p25519.modulus + const toString: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p25519.modulus + const trim: any; + + } + + } + + namespace p256 { + namespace modulus { + // Too-deep object hierarchy from sjcl.bn.prime.p256.modulus + const add: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256.modulus + const addM: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256.modulus + const bitLength: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256.modulus + const cnormalize: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256.modulus + const copy: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256.modulus + const doubleM: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256.modulus + const equals: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256.modulus + const fullReduce: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256.modulus + const getLimb: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256.modulus + const greaterEquals: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256.modulus + const halveM: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256.modulus + const initWith: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256.modulus + const inverseMod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256.modulus + const ipv: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256.modulus + const limbs: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256.modulus + const maxMul: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256.modulus + const mod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256.modulus + const montpowermod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256.modulus + const mul: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256.modulus + const mulmod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256.modulus + const normalize: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256.modulus + const placeVal: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256.modulus + const power: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256.modulus + const powermod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256.modulus + const radix: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256.modulus + const radixMask: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256.modulus + const reduce: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256.modulus + const square: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256.modulus + const sub: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256.modulus + const subM: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256.modulus + const toBits: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256.modulus + const toString: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256.modulus + const trim: any; + + } + + } + + namespace p256k { + namespace modulus { + // Too-deep object hierarchy from sjcl.bn.prime.p256k.modulus + const add: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256k.modulus + const addM: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256k.modulus + const bitLength: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256k.modulus + const cnormalize: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256k.modulus + const copy: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256k.modulus + const doubleM: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256k.modulus + const equals: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256k.modulus + const fullReduce: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256k.modulus + const getLimb: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256k.modulus + const greaterEquals: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256k.modulus + const halveM: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256k.modulus + const initWith: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256k.modulus + const inverseMod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256k.modulus + const ipv: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256k.modulus + const limbs: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256k.modulus + const maxMul: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256k.modulus + const mod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256k.modulus + const montpowermod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256k.modulus + const mul: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256k.modulus + const mulmod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256k.modulus + const normalize: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256k.modulus + const placeVal: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256k.modulus + const power: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256k.modulus + const powermod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256k.modulus + const radix: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256k.modulus + const radixMask: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256k.modulus + const reduce: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256k.modulus + const square: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256k.modulus + const sub: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256k.modulus + const subM: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256k.modulus + const toBits: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256k.modulus + const toString: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p256k.modulus + const trim: any; + + } + + } + + namespace p384 { + namespace modulus { + // Too-deep object hierarchy from sjcl.bn.prime.p384.modulus + const add: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p384.modulus + const addM: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p384.modulus + const bitLength: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p384.modulus + const cnormalize: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p384.modulus + const copy: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p384.modulus + const doubleM: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p384.modulus + const equals: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p384.modulus + const fullReduce: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p384.modulus + const getLimb: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p384.modulus + const greaterEquals: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p384.modulus + const halveM: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p384.modulus + const initWith: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p384.modulus + const inverseMod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p384.modulus + const ipv: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p384.modulus + const limbs: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p384.modulus + const maxMul: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p384.modulus + const mod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p384.modulus + const montpowermod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p384.modulus + const mul: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p384.modulus + const mulmod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p384.modulus + const normalize: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p384.modulus + const placeVal: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p384.modulus + const power: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p384.modulus + const powermod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p384.modulus + const radix: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p384.modulus + const radixMask: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p384.modulus + const reduce: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p384.modulus + const square: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p384.modulus + const sub: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p384.modulus + const subM: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p384.modulus + const toBits: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p384.modulus + const toString: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p384.modulus + const trim: any; + + } + + } + + namespace p521 { + namespace modulus { + // Too-deep object hierarchy from sjcl.bn.prime.p521.modulus + const add: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p521.modulus + const addM: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p521.modulus + const bitLength: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p521.modulus + const cnormalize: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p521.modulus + const copy: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p521.modulus + const doubleM: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p521.modulus + const equals: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p521.modulus + const fullReduce: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p521.modulus + const getLimb: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p521.modulus + const greaterEquals: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p521.modulus + const halveM: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p521.modulus + const initWith: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p521.modulus + const inverseMod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p521.modulus + const ipv: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p521.modulus + const limbs: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p521.modulus + const maxMul: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p521.modulus + const mod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p521.modulus + const montpowermod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p521.modulus + const mul: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p521.modulus + const mulmod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p521.modulus + const normalize: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p521.modulus + const placeVal: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p521.modulus + const power: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p521.modulus + const powermod: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p521.modulus + const radix: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p521.modulus + const radixMask: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p521.modulus + const reduce: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p521.modulus + const square: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p521.modulus + const sub: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p521.modulus + const subM: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p521.modulus + const toBits: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p521.modulus + const toString: any; + + // Too-deep object hierarchy from sjcl.bn.prime.p521.modulus + const trim: any; + + } + + } + + } + +} + +export namespace cipher { + class aes { + constructor(key: any); + + decrypt(data: any): any; + + encrypt(data: any): any; + + } + +} + +export namespace ecc { + class curve { + field: any + r: bn + a: any + b: any + G: point + constructor(Field: any, r: any, a: any, b: any, x: any, y: any); + + fromBits(bits: any): any; + + } + + class point { + isIdentity: boolean + x: bn + y: bn + curve: curve + + constructor(curve: any, x: any, y: any); + + constructor(curve: any); + + isValid(): any; + + mult(k: any): any; + + mult2(k: any, k2: any, affine2: any): any; + + multiples(): any; + + negate(): any; + + toBits(): any; + + toJac(): any; + + } + + class pointJac { + constructor(curve: any, x: any, y: any, z: any); + + add(T: any): any; + + doubl(): any; + + isValid(): any; + + mult(k: any, affine: any): any; + + mult2(k1: any, affine: any, k2: any, affine2: any): any; + + negate(): any; + + toAffine(): any; + + } + + const curves: { + c192: { + G: { + curve: any; + isIdentity: boolean; + isValid: any; + mult: any; + mult2: any; + multiples: any; + negate: any; + toBits: any; + toJac: any; + x: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + exponent: number; + factor: number[]; + fullFactor: number[]; + fullMask: number; + fullOffset: number[]; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverse: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + minOffset: number; + mod: any; + modOffset: number; + modulus: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + mod: any; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + offset: number[]; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + y: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + exponent: number; + factor: number[]; + fullFactor: number[]; + fullMask: number; + fullOffset: number[]; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverse: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + minOffset: number; + mod: any; + modOffset: number; + modulus: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + mod: any; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + offset: number[]; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + }; + a: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + exponent: number; + factor: number[]; + fullFactor: number[]; + fullMask: number; + fullOffset: number[]; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverse: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + minOffset: number; + mod: any; + modOffset: number; + modulus: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + mod: any; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + offset: number[]; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + b: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + exponent: number; + factor: number[]; + fullFactor: number[]; + fullMask: number; + fullOffset: number[]; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverse: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + minOffset: number; + mod: any; + modOffset: number; + modulus: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + mod: any; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + offset: number[]; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + field: any; + fromBits: any; + r: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + mod: any; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + }; + c224: { + G: { + curve: any; + isIdentity: boolean; + isValid: any; + mult: any; + mult2: any; + multiples: any; + negate: any; + toBits: any; + toJac: any; + x: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + exponent: number; + factor: number[]; + fullFactor: number[]; + fullMask: number; + fullOffset: number[]; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverse: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + minOffset: number; + mod: any; + modOffset: number; + modulus: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + mod: any; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + offset: number[]; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + y: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + exponent: number; + factor: number[]; + fullFactor: number[]; + fullMask: number; + fullOffset: number[]; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverse: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + minOffset: number; + mod: any; + modOffset: number; + modulus: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + mod: any; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + offset: number[]; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + }; + a: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + exponent: number; + factor: number[]; + fullFactor: number[]; + fullMask: number; + fullOffset: number[]; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverse: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + minOffset: number; + mod: any; + modOffset: number; + modulus: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + mod: any; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + offset: number[]; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + b: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + exponent: number; + factor: number[]; + fullFactor: number[]; + fullMask: number; + fullOffset: number[]; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverse: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + minOffset: number; + mod: any; + modOffset: number; + modulus: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + mod: any; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + offset: number[]; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + field: any; + fromBits: any; + r: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + mod: any; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + }; + c256: { + G: { + curve: any; + isIdentity: boolean; + isValid: any; + mult: any; + mult2: any; + multiples: any; + negate: any; + toBits: any; + toJac: any; + x: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + exponent: number; + factor: number[]; + fullFactor: number[]; + fullMask: number; + fullOffset: number[]; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverse: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + minOffset: number; + mod: any; + modOffset: number; + modulus: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + mod: any; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + offset: number[]; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + y: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + exponent: number; + factor: number[]; + fullFactor: number[]; + fullMask: number; + fullOffset: number[]; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverse: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + minOffset: number; + mod: any; + modOffset: number; + modulus: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + mod: any; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + offset: number[]; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + }; + a: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + exponent: number; + factor: number[]; + fullFactor: number[]; + fullMask: number; + fullOffset: number[]; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverse: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + minOffset: number; + mod: any; + modOffset: number; + modulus: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + mod: any; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + offset: number[]; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + b: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + exponent: number; + factor: number[]; + fullFactor: number[]; + fullMask: number; + fullOffset: number[]; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverse: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + minOffset: number; + mod: any; + modOffset: number; + modulus: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + mod: any; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + offset: number[]; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + field: any; + fromBits: any; + r: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + mod: any; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + }; + c384: { + G: { + curve: any; + isIdentity: boolean; + isValid: any; + mult: any; + mult2: any; + multiples: any; + negate: any; + toBits: any; + toJac: any; + x: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + exponent: number; + factor: number[]; + fullFactor: number[]; + fullMask: number; + fullOffset: number[]; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverse: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + minOffset: number; + mod: any; + modOffset: number; + modulus: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + mod: any; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + offset: number[]; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + y: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + exponent: number; + factor: number[]; + fullFactor: number[]; + fullMask: number; + fullOffset: number[]; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverse: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + minOffset: number; + mod: any; + modOffset: number; + modulus: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + mod: any; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + offset: number[]; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + }; + a: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + exponent: number; + factor: number[]; + fullFactor: number[]; + fullMask: number; + fullOffset: number[]; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverse: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + minOffset: number; + mod: any; + modOffset: number; + modulus: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + mod: any; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + offset: number[]; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + b: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + exponent: number; + factor: number[]; + fullFactor: number[]; + fullMask: number; + fullOffset: number[]; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverse: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + minOffset: number; + mod: any; + modOffset: number; + modulus: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + mod: any; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + offset: number[]; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + field: any; + fromBits: any; + r: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + mod: any; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + }; + c521: { + G: { + curve: any; + isIdentity: boolean; + isValid: any; + mult: any; + mult2: any; + multiples: any; + negate: any; + toBits: any; + toJac: any; + x: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + exponent: number; + factor: number[]; + fullFactor: number[]; + fullMask: number; + fullOffset: number[]; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverse: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + minOffset: number; + mod: any; + modOffset: number; + modulus: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + mod: any; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + offset: number[]; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + y: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + exponent: number; + factor: number[]; + fullFactor: number[]; + fullMask: number; + fullOffset: number[]; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverse: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + minOffset: number; + mod: any; + modOffset: number; + modulus: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + mod: any; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + offset: number[]; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + }; + a: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + exponent: number; + factor: number[]; + fullFactor: number[]; + fullMask: number; + fullOffset: number[]; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverse: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + minOffset: number; + mod: any; + modOffset: number; + modulus: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + mod: any; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + offset: number[]; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + b: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + exponent: number; + factor: number[]; + fullFactor: number[]; + fullMask: number; + fullOffset: number[]; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverse: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + minOffset: number; + mod: any; + modOffset: number; + modulus: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + mod: any; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + offset: number[]; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + field: any; + fromBits: any; + r: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + mod: any; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + }; + k192: { + G: { + curve: any; + isIdentity: boolean; + isValid: any; + mult: any; + mult2: any; + multiples: any; + negate: any; + toBits: any; + toJac: any; + x: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + exponent: number; + factor: number[]; + fullFactor: number[]; + fullMask: number; + fullOffset: number[]; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverse: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + minOffset: number; + mod: any; + modOffset: number; + modulus: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + mod: any; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + offset: number[]; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + y: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + exponent: number; + factor: number[]; + fullFactor: number[]; + fullMask: number; + fullOffset: number[]; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverse: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + minOffset: number; + mod: any; + modOffset: number; + modulus: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + mod: any; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + offset: number[]; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + }; + a: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + exponent: number; + factor: number[]; + fullFactor: number[]; + fullMask: number; + fullOffset: number[]; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverse: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + minOffset: number; + mod: any; + modOffset: number; + modulus: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + mod: any; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + offset: number[]; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + b: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + exponent: number; + factor: number[]; + fullFactor: number[]; + fullMask: number; + fullOffset: number[]; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverse: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + minOffset: number; + mod: any; + modOffset: number; + modulus: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + mod: any; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + offset: number[]; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + field: any; + fromBits: any; + r: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + mod: any; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + }; + k224: { + G: { + curve: any; + isIdentity: boolean; + isValid: any; + mult: any; + mult2: any; + multiples: any; + negate: any; + toBits: any; + toJac: any; + x: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + exponent: number; + factor: number[]; + fullFactor: number[]; + fullMask: number; + fullOffset: number[]; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverse: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + minOffset: number; + mod: any; + modOffset: number; + modulus: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + mod: any; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + offset: number[]; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + y: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + exponent: number; + factor: number[]; + fullFactor: number[]; + fullMask: number; + fullOffset: number[]; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverse: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + minOffset: number; + mod: any; + modOffset: number; + modulus: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + mod: any; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + offset: number[]; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + }; + a: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + exponent: number; + factor: number[]; + fullFactor: number[]; + fullMask: number; + fullOffset: number[]; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverse: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + minOffset: number; + mod: any; + modOffset: number; + modulus: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + mod: any; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + offset: number[]; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + b: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + exponent: number; + factor: number[]; + fullFactor: number[]; + fullMask: number; + fullOffset: number[]; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverse: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + minOffset: number; + mod: any; + modOffset: number; + modulus: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + mod: any; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + offset: number[]; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + field: any; + fromBits: any; + r: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + mod: any; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + }; + k256: { + G: { + curve: any; + isIdentity: boolean; + isValid: any; + mult: any; + mult2: any; + multiples: any; + negate: any; + toBits: any; + toJac: any; + x: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + exponent: number; + factor: number[]; + fullFactor: number[]; + fullMask: number; + fullOffset: number[]; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverse: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + minOffset: number; + mod: any; + modOffset: number; + modulus: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + mod: any; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + offset: number[]; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + y: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + exponent: number; + factor: number[]; + fullFactor: number[]; + fullMask: number; + fullOffset: number[]; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverse: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + minOffset: number; + mod: any; + modOffset: number; + modulus: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + mod: any; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + offset: number[]; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + }; + a: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + exponent: number; + factor: number[]; + fullFactor: number[]; + fullMask: number; + fullOffset: number[]; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverse: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + minOffset: number; + mod: any; + modOffset: number; + modulus: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + mod: any; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + offset: number[]; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + b: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + exponent: number; + factor: number[]; + fullFactor: number[]; + fullMask: number; + fullOffset: number[]; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverse: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + minOffset: number; + mod: any; + modOffset: number; + modulus: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + mod: any; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + offset: number[]; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + field: any; + fromBits: any; + r: { + add: any; + addM: any; + bitLength: any; + cnormalize: any; + copy: any; + doubleM: any; + equals: any; + fullReduce: any; + getLimb: any; + greaterEquals: any; + halveM: any; + initWith: any; + inverseMod: any; + ipv: number; + limbs: number[]; + maxMul: number; + mod: any; + montpowermod: any; + mul: any; + mulmod: any; + normalize: any; + placeVal: number; + power: any; + powermod: any; + radix: number; + radixMask: number; + reduce: any; + square: any; + sub: any; + subM: any; + toBits: any; + toString: any; + trim: any; + }; + }; + }; + + function curveName(curve: any): any; + + function deserialize(key: any): any; + + namespace basicKey { + function generateKeys(cn: any): any; + + function publicKey(curve: any, point: any): any; + + function secretKey(curve: any, exponent: any): any; + + } + + namespace ecdsa { + class publicKey { + constructor(curve: any, point: any, ...args: any[]); + + getType(): any; + + verify(hash: any, rs: any, fakeLegacyVersion: any): any; + + } + + class secretKey { + constructor(curve: any, exponent: any, ...args: any[]); + + getType(): any; + + sign(hash: any, paranoia: any, fakeLegacyVersion: any, fixedKForTesting: any): any; + + } + + function generateKeys(curve: any, paranoia: any, sec: any): any; + + } + + namespace elGamal { + class publicKey { + constructor(curve: any, point: any, ...args: any[]); + + getType(): any; + + kem(paranoia: any): any; + + } + + class secretKey { + constructor(curve: any, exponent: any, ...args: any[]); + + dh(pk: any): any; + + dhJavaEc(pk: any): any; + + getType(): any; + + unkem(tag: any): any; + + } + + function generateKeys(curve: any, paranoia: any, sec: any): any; + + } + +} + +export namespace exception { + function bug(message: any): any; + + function corrupt(message: any): any; + + function invalid(message: any): any; + + function notReady(message: any): any; + +} + +export namespace hash { + class sha256 { + constructor(hash: any); + + finalize(): any; + + reset(): any; + + update(data: any): any; + + static hash(data: any): any; + + } + +} + +export namespace json { + const defaults: { + adata: string; + cipher: string; + iter: number; + ks: number; + mode: string; + ts: number; + v: number; + }; + + function decode(str: any): any; + + function decrypt(password: any, ciphertext: any, params: any, rp: any): any; + + function encode(obj: any): any; + + function encrypt(password: any, plaintext: any, params: any, rp: any, ...args: any[]): any; + +} + +export namespace misc { + class hmac { + constructor(key: any, Hash: any); + + digest(): any; + + encrypt(data: any): any; + + mac(data: any): any; + + reset(): void; + + update(data: any): void; + + } + + function cachedPbkdf2(password: any, obj: any): any; + + function pbkdf2(password: any, salt: any, count: any, length: any, Prff: any): any; + +} + +export namespace random { + function addEntropy(data: any, estimatedEntropy: any, source: any): void; + + function addEventListener(name: any, callback: any): void; + + function getProgress(paranoia: any): any; + + function isReady(paranoia: any): any; + + function randomWords(nwords: any, paranoia: any): any; + + function removeEventListener(name: any, cb: any): void; + + function setDefaultParanoia(paranoia: any, allowZeroParanoia: any): void; + + function startCollectors(): void; + + function stopCollectors(): void; + +} + diff --git a/src/blindrsa/sjcl/index.js b/src/blindrsa/sjcl/index.js new file mode 100644 index 0000000..b59be1e --- /dev/null +++ b/src/blindrsa/sjcl/index.js @@ -0,0 +1,3610 @@ +/** @fileOverview Javascript cryptography implementation. + * + * Crush to remove comments, shorten variable names and + * generally reduce transmission size. + * + * @author Emily Stark + * @author Mike Hamburg + * @author Dan Boneh + */ + +"use strict"; +/*jslint indent: 2, bitwise: false, nomen: false, plusplus: false, white: false, regexp: false */ +/*global document, window, escape, unescape, module, require, Uint32Array */ + +/** + * The Stanford Javascript Crypto Library, top-level namespace. + * @namespace + */ +var sjcl = { + /** + * Symmetric ciphers. + * @namespace + */ + cipher: {}, + + /** + * Hash functions. Right now only SHA256 is implemented. + * @namespace + */ + hash: {}, + + /** + * Key exchange functions. Right now only SRP is implemented. + * @namespace + */ + keyexchange: {}, + + /** + * Cipher modes of operation. + * @namespace + */ + mode: {}, + + /** + * Miscellaneous. HMAC and PBKDF2. + * @namespace + */ + misc: {}, + + /** + * Bit array encoders and decoders. + * @namespace + * + * @description + * The members of this namespace are functions which translate between + * SJCL's bitArrays and other objects (usually strings). Because it + * isn't always clear which direction is encoding and which is decoding, + * the method names are "fromBits" and "toBits". + */ + codec: {}, + + /** + * Exceptions. + * @namespace + */ + exception: { + /** + * Ciphertext is corrupt. + * @constructor + */ + corrupt: function(message) { + this.toString = function() { return "CORRUPT: "+this.message; }; + this.message = message; + }, + + /** + * Invalid parameter. + * @constructor + */ + invalid: function(message) { + this.toString = function() { return "INVALID: "+this.message; }; + this.message = message; + }, + + /** + * Bug or missing feature in SJCL. + * @constructor + */ + bug: function(message) { + this.toString = function() { return "BUG: "+this.message; }; + this.message = message; + }, + + /** + * Something isn't ready. + * @constructor + */ + notReady: function(message) { + this.toString = function() { return "NOT READY: "+this.message; }; + this.message = message; + } + } +}; +/** @fileOverview Low-level AES implementation. + * + * This file contains a low-level implementation of AES, optimized for + * size and for efficiency on several browsers. It is based on + * OpenSSL's aes_core.c, a public-domain implementation by Vincent + * Rijmen, Antoon Bosselaers and Paulo Barreto. + * + * An older version of this implementation is available in the public + * domain, but this one is (c) Emily Stark, Mike Hamburg, Dan Boneh, + * Stanford University 2008-2010 and BSD-licensed for liability + * reasons. + * + * @author Emily Stark + * @author Mike Hamburg + * @author Dan Boneh + */ + +/** + * Schedule out an AES key for both encryption and decryption. This + * is a low-level class. Use a cipher mode to do bulk encryption. + * + * @constructor + * @param {Array} key The key as an array of 4, 6 or 8 words. + */ +sjcl.cipher.aes = function (key) { + if (!this._tables[0][0][0]) { + this._precompute(); + } + + var i, j, tmp, + encKey, decKey, + sbox = this._tables[0][4], decTable = this._tables[1], + keyLen = key.length, rcon = 1; + + if (keyLen !== 4 && keyLen !== 6 && keyLen !== 8) { + throw new sjcl.exception.invalid("invalid aes key size"); + } + + this._key = [encKey = key.slice(0), decKey = []]; + + // schedule encryption keys + for (i = keyLen; i < 4 * keyLen + 28; i++) { + tmp = encKey[i-1]; + + // apply sbox + if (i%keyLen === 0 || (keyLen === 8 && i%keyLen === 4)) { + tmp = sbox[tmp>>>24]<<24 ^ sbox[tmp>>16&255]<<16 ^ sbox[tmp>>8&255]<<8 ^ sbox[tmp&255]; + + // shift rows and add rcon + if (i%keyLen === 0) { + tmp = tmp<<8 ^ tmp>>>24 ^ rcon<<24; + rcon = rcon<<1 ^ (rcon>>7)*283; + } + } + + encKey[i] = encKey[i-keyLen] ^ tmp; + } + + // schedule decryption keys + for (j = 0; i; j++, i--) { + tmp = encKey[j&3 ? i : i - 4]; + if (i<=4 || j<4) { + decKey[j] = tmp; + } else { + decKey[j] = decTable[0][sbox[tmp>>>24 ]] ^ + decTable[1][sbox[tmp>>16 & 255]] ^ + decTable[2][sbox[tmp>>8 & 255]] ^ + decTable[3][sbox[tmp & 255]]; + } + } +}; + +sjcl.cipher.aes.prototype = { + // public + /* Something like this might appear here eventually + name: "AES", + blockSize: 4, + keySizes: [4,6,8], + */ + + /** + * Encrypt an array of 4 big-endian words. + * @param {Array} data The plaintext. + * @return {Array} The ciphertext. + */ + encrypt:function (data) { return this._crypt(data,0); }, + + /** + * Decrypt an array of 4 big-endian words. + * @param {Array} data The ciphertext. + * @return {Array} The plaintext. + */ + decrypt:function (data) { return this._crypt(data,1); }, + + /** + * The expanded S-box and inverse S-box tables. These will be computed + * on the client so that we don't have to send them down the wire. + * + * There are two tables, _tables[0] is for encryption and + * _tables[1] is for decryption. + * + * The first 4 sub-tables are the expanded S-box with MixColumns. The + * last (_tables[01][4]) is the S-box itself. + * + * @private + */ + _tables: [[[],[],[],[],[]],[[],[],[],[],[]]], + + /** + * Expand the S-box tables. + * + * @private + */ + _precompute: function () { + var encTable = this._tables[0], decTable = this._tables[1], + sbox = encTable[4], sboxInv = decTable[4], + i, x, xInv, d=[], th=[], x2, x4, x8, s, tEnc, tDec; + + // Compute double and third tables + for (i = 0; i < 256; i++) { + th[( d[i] = i<<1 ^ (i>>7)*283 )^i]=i; + } + + for (x = xInv = 0; !sbox[x]; x ^= x2 || 1, xInv = th[xInv] || 1) { + // Compute sbox + s = xInv ^ xInv<<1 ^ xInv<<2 ^ xInv<<3 ^ xInv<<4; + s = s>>8 ^ s&255 ^ 99; + sbox[x] = s; + sboxInv[s] = x; + + // Compute MixColumns + x8 = d[x4 = d[x2 = d[x]]]; + tDec = x8*0x1010101 ^ x4*0x10001 ^ x2*0x101 ^ x*0x1010100; + tEnc = d[s]*0x101 ^ s*0x1010100; + + for (i = 0; i < 4; i++) { + encTable[i][x] = tEnc = tEnc<<24 ^ tEnc>>>8; + decTable[i][s] = tDec = tDec<<24 ^ tDec>>>8; + } + } + + // Compactify. Considerable speedup on Firefox. + for (i = 0; i < 5; i++) { + encTable[i] = encTable[i].slice(0); + decTable[i] = decTable[i].slice(0); + } + }, + + /** + * Encryption and decryption core. + * @param {Array} input Four words to be encrypted or decrypted. + * @param dir The direction, 0 for encrypt and 1 for decrypt. + * @return {Array} The four encrypted or decrypted words. + * @private + */ + _crypt:function (input, dir) { + if (input.length !== 4) { + throw new sjcl.exception.invalid("invalid aes block size"); + } + + var key = this._key[dir], + // state variables a,b,c,d are loaded with pre-whitened data + a = input[0] ^ key[0], + b = input[dir ? 3 : 1] ^ key[1], + c = input[2] ^ key[2], + d = input[dir ? 1 : 3] ^ key[3], + a2, b2, c2, + + nInnerRounds = key.length/4 - 2, + i, + kIndex = 4, + out = [0,0,0,0], + table = this._tables[dir], + + // load up the tables + t0 = table[0], + t1 = table[1], + t2 = table[2], + t3 = table[3], + sbox = table[4]; + + // Inner rounds. Cribbed from OpenSSL. + for (i = 0; i < nInnerRounds; i++) { + a2 = t0[a>>>24] ^ t1[b>>16 & 255] ^ t2[c>>8 & 255] ^ t3[d & 255] ^ key[kIndex]; + b2 = t0[b>>>24] ^ t1[c>>16 & 255] ^ t2[d>>8 & 255] ^ t3[a & 255] ^ key[kIndex + 1]; + c2 = t0[c>>>24] ^ t1[d>>16 & 255] ^ t2[a>>8 & 255] ^ t3[b & 255] ^ key[kIndex + 2]; + d = t0[d>>>24] ^ t1[a>>16 & 255] ^ t2[b>>8 & 255] ^ t3[c & 255] ^ key[kIndex + 3]; + kIndex += 4; + a=a2; b=b2; c=c2; + } + + // Last round. + for (i = 0; i < 4; i++) { + out[dir ? 3&-i : i] = + sbox[a>>>24 ]<<24 ^ + sbox[b>>16 & 255]<<16 ^ + sbox[c>>8 & 255]<<8 ^ + sbox[d & 255] ^ + key[kIndex++]; + a2=a; a=b; b=c; c=d; d=a2; + } + + return out; + } +}; + +/** @fileOverview Arrays of bits, encoded as arrays of Numbers. + * + * @author Emily Stark + * @author Mike Hamburg + * @author Dan Boneh + */ + +/** + * Arrays of bits, encoded as arrays of Numbers. + * @namespace + * @description + *

+ * These objects are the currency accepted by SJCL's crypto functions. + *

+ * + *

+ * Most of our crypto primitives operate on arrays of 4-byte words internally, + * but many of them can take arguments that are not a multiple of 4 bytes. + * This library encodes arrays of bits (whose size need not be a multiple of 8 + * bits) as arrays of 32-bit words. The bits are packed, big-endian, into an + * array of words, 32 bits at a time. Since the words are double-precision + * floating point numbers, they fit some extra data. We use this (in a private, + * possibly-changing manner) to encode the number of bits actually present + * in the last word of the array. + *

+ * + *

+ * Because bitwise ops clear this out-of-band data, these arrays can be passed + * to ciphers like AES which want arrays of words. + *

+ */ +sjcl.bitArray = { + /** + * Array slices in units of bits. + * @param {bitArray} a The array to slice. + * @param {Number} bstart The offset to the start of the slice, in bits. + * @param {Number} bend The offset to the end of the slice, in bits. If this is undefined, + * slice until the end of the array. + * @return {bitArray} The requested slice. + */ + bitSlice: function (a, bstart, bend) { + a = sjcl.bitArray._shiftRight(a.slice(bstart/32), 32 - (bstart & 31)).slice(1); + return (bend === undefined) ? a : sjcl.bitArray.clamp(a, bend-bstart); + }, + + /** + * Extract a number packed into a bit array. + * @param {bitArray} a The array to slice. + * @param {Number} bstart The offset to the start of the slice, in bits. + * @param {Number} blength The length of the number to extract. + * @return {Number} The requested slice. + */ + extract: function(a, bstart, blength) { + // FIXME: this Math.floor is not necessary at all, but for some reason + // seems to suppress a bug in the Chromium JIT. + var x, sh = Math.floor((-bstart-blength) & 31); + if ((bstart + blength - 1 ^ bstart) & -32) { + // it crosses a boundary + x = (a[bstart/32|0] << (32 - sh)) ^ (a[bstart/32+1|0] >>> sh); + } else { + // within a single word + x = a[bstart/32|0] >>> sh; + } + return x & ((1< 0 && len) { + a[l-1] = sjcl.bitArray.partial(len, a[l-1] & 0x80000000 >> (len-1), 1); + } + return a; + }, + + /** + * Make a partial word for a bit array. + * @param {Number} len The number of bits in the word. + * @param {Number} x The bits. + * @param {Number} [_end=0] Pass 1 if x has already been shifted to the high side. + * @return {Number} The partial word. + */ + partial: function (len, x, _end) { + if (len === 32) { return x; } + return (_end ? x|0 : x << (32-len)) + len * 0x10000000000; + }, + + /** + * Get the number of bits used by a partial word. + * @param {Number} x The partial word. + * @return {Number} The number of bits used by the partial word. + */ + getPartial: function (x) { + return Math.round(x/0x10000000000) || 32; + }, + + /** + * Compare two arrays for equality in a predictable amount of time. + * @param {bitArray} a The first array. + * @param {bitArray} b The second array. + * @return {boolean} true if a == b; false otherwise. + */ + equal: function (a, b) { + if (sjcl.bitArray.bitLength(a) !== sjcl.bitArray.bitLength(b)) { + return false; + } + var x = 0, i; + for (i=0; i= 32; shift -= 32) { + out.push(carry); + carry = 0; + } + if (shift === 0) { + return out.concat(a); + } + + for (i=0; i>>shift); + carry = a[i] << (32-shift); + } + last2 = a.length ? a[a.length-1] : 0; + shift2 = sjcl.bitArray.getPartial(last2); + out.push(sjcl.bitArray.partial(shift+shift2 & 31, (shift + shift2 > 32) ? carry : out.pop(),1)); + return out; + }, + + /** xor a block of 4 words together. + * @private + */ + _xor4: function(x,y) { + return [x[0]^y[0],x[1]^y[1],x[2]^y[2],x[3]^y[3]]; + }, + + /** byteswap a word array inplace. + * (does not handle partial words) + * @param {sjcl.bitArray} a word array + * @return {sjcl.bitArray} byteswapped array + */ + byteswapM: function(a) { + var i, v, m = 0xff00; + for (i = 0; i < a.length; ++i) { + v = a[i]; + a[i] = (v >>> 24) | ((v >>> 8) & m) | ((v & m) << 8) | (v << 24); + } + return a; + } +}; +/** @fileOverview Bit array codec implementations. + * + * @author Emily Stark + * @author Mike Hamburg + * @author Dan Boneh + */ + +/** + * UTF-8 strings + * @namespace + */ +sjcl.codec.utf8String = { + /** Convert from a bitArray to a UTF-8 string. */ + fromBits: function (arr) { + var out = "", bl = sjcl.bitArray.bitLength(arr), i, tmp; + for (i=0; i>> 8 >>> 8 >>> 8); + tmp <<= 8; + } + return decodeURIComponent(escape(out)); + }, + + /** Convert from a UTF-8 string to a bitArray. */ + toBits: function (str) { + str = unescape(encodeURIComponent(str)); + var out = [], i, tmp=0; + for (i=0; i>>bits) >>> 26); + if (bits < 6) { + ta = arr[i] << (6-bits); + bits += 26; + i++; + } else { + ta <<= 6; + bits -= 6; + } + } + while ((out.length & 3) && !_noEquals) { out += "="; } + return out; + }, + + /** Convert from a base64 string to a bitArray */ + toBits: function(str, _url) { + str = str.replace(/\s|=/g,''); + var out = [], i, bits=0, c = sjcl.codec.base64._chars, ta=0, x; + if (_url) { + c = c.substr(0,62) + '-_'; + } + for (i=0; i 26) { + bits -= 26; + out.push(ta ^ x>>>bits); + ta = x << (32-bits); + } else { + bits += 6; + ta ^= x << (32-bits); + } + } + if (bits&56) { + out.push(sjcl.bitArray.partial(bits&56, ta, 1)); + } + return out; + } +}; + +sjcl.codec.base64url = { + fromBits: function (arr) { return sjcl.codec.base64.fromBits(arr,1,1); }, + toBits: function (str) { return sjcl.codec.base64.toBits(str,1); } +}; +/** @fileOverview Bit array codec implementations. + * + * @author Emily Stark + * @author Mike Hamburg + * @author Dan Boneh + */ + +/** + * Arrays of bytes + * @namespace + */ +sjcl.codec.bytes = { + /** Convert from a bitArray to an array of bytes. */ + fromBits: function (arr) { + var out = [], bl = sjcl.bitArray.bitLength(arr), i, tmp; + for (i=0; i>> 24); + tmp <<= 8; + } + return out; + }, + /** Convert from an array of bytes to a bitArray. */ + toBits: function (bytes) { + var out = [], i, tmp=0; + for (i=0; i 9007199254740991){ + throw new sjcl.exception.invalid("Cannot hash more than 2^53 - 1 bits"); + } + + if (typeof Uint32Array !== 'undefined') { + var c = new Uint32Array(b); + var j = 0; + for (i = 512+ol - ((512+ol) & 511); i <= nl; i+= 512) { + this._block(c.subarray(16 * j, 16 * (j+1))); + j += 1; + } + b.splice(0, 16 * j); + } else { + for (i = 512+ol - ((512+ol) & 511); i <= nl; i+= 512) { + this._block(b.splice(0,16)); + } + } + return this; + }, + + /** + * Complete hashing and output the hash value. + * @return {bitArray} The hash value, an array of 8 big-endian words. + */ + finalize:function () { + var i, b = this._buffer, h = this._h; + + // Round out and push the buffer + b = sjcl.bitArray.concat(b, [sjcl.bitArray.partial(1,1)]); + + // Round out the buffer to a multiple of 16 words, less the 2 length words. + for (i = b.length + 2; i & 15; i++) { + b.push(0); + } + + // append the length + b.push(Math.floor(this._length / 0x100000000)); + b.push(this._length | 0); + + while (b.length) { + this._block(b.splice(0,16)); + } + + this.reset(); + return h; + }, + + /** + * The SHA-256 initialization vector, to be precomputed. + * @private + */ + _init:[], + /* + _init:[0x6a09e667,0xbb67ae85,0x3c6ef372,0xa54ff53a,0x510e527f,0x9b05688c,0x1f83d9ab,0x5be0cd19], + */ + + /** + * The SHA-256 hash key, to be precomputed. + * @private + */ + _key:[], + /* + _key: + [0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2], + */ + + + /** + * Function to precompute _init and _key. + * @private + */ + _precompute: function () { + var i = 0, prime = 2, factor, isPrime; + + function frac(x) { return (x-Math.floor(x)) * 0x100000000 | 0; } + + for (; i<64; prime++) { + isPrime = true; + for (factor=2; factor*factor <= prime; factor++) { + if (prime % factor === 0) { + isPrime = false; + break; + } + } + if (isPrime) { + if (i<8) { + this._init[i] = frac(Math.pow(prime, 1/2)); + } + this._key[i] = frac(Math.pow(prime, 1/3)); + i++; + } + } + }, + + /** + * Perform one cycle of SHA-256. + * @param {Uint32Array|bitArray} w one block of words. + * @private + */ + _block:function (w) { + var i, tmp, a, b, + h = this._h, + k = this._key, + h0 = h[0], h1 = h[1], h2 = h[2], h3 = h[3], + h4 = h[4], h5 = h[5], h6 = h[6], h7 = h[7]; + + /* Rationale for placement of |0 : + * If a value can overflow is original 32 bits by a factor of more than a few + * million (2^23 ish), there is a possibility that it might overflow the + * 53-bit mantissa and lose precision. + * + * To avoid this, we clamp back to 32 bits by |'ing with 0 on any value that + * propagates around the loop, and on the hash state h[]. I don't believe + * that the clamps on h4 and on h0 are strictly necessary, but it's close + * (for h4 anyway), and better safe than sorry. + * + * The clamps on h[] are necessary for the output to be correct even in the + * common case and for short inputs. + */ + for (i=0; i<64; i++) { + // load up the input word for this round + if (i<16) { + tmp = w[i]; + } else { + a = w[(i+1 ) & 15]; + b = w[(i+14) & 15]; + tmp = w[i&15] = ((a>>>7 ^ a>>>18 ^ a>>>3 ^ a<<25 ^ a<<14) + + (b>>>17 ^ b>>>19 ^ b>>>10 ^ b<<15 ^ b<<13) + + w[i&15] + w[(i+9) & 15]) | 0; + } + + tmp = (tmp + h7 + (h4>>>6 ^ h4>>>11 ^ h4>>>25 ^ h4<<26 ^ h4<<21 ^ h4<<7) + (h6 ^ h4&(h5^h6)) + k[i]); // | 0; + + // shift register + h7 = h6; h6 = h5; h5 = h4; + h4 = h3 + tmp | 0; + h3 = h2; h2 = h1; h1 = h0; + + h0 = (tmp + ((h1&h2) ^ (h3&(h1^h2))) + (h1>>>2 ^ h1>>>13 ^ h1>>>22 ^ h1<<30 ^ h1<<19 ^ h1<<10)) | 0; + } + + h[0] = h[0]+h0 | 0; + h[1] = h[1]+h1 | 0; + h[2] = h[2]+h2 | 0; + h[3] = h[3]+h3 | 0; + h[4] = h[4]+h4 | 0; + h[5] = h[5]+h5 | 0; + h[6] = h[6]+h6 | 0; + h[7] = h[7]+h7 | 0; + } +}; + + +/** @fileOverview CCM mode implementation. + * + * Special thanks to Roy Nicholson for pointing out a bug in our + * implementation. + * + * @author Emily Stark + * @author Mike Hamburg + * @author Dan Boneh + */ + +/** + * CTR mode with CBC MAC. + * @namespace + */ +sjcl.mode.ccm = { + /** The name of the mode. + * @constant + */ + name: "ccm", + + _progressListeners: [], + + listenProgress: function (cb) { + sjcl.mode.ccm._progressListeners.push(cb); + }, + + unListenProgress: function (cb) { + var index = sjcl.mode.ccm._progressListeners.indexOf(cb); + if (index > -1) { + sjcl.mode.ccm._progressListeners.splice(index, 1); + } + }, + + _callProgressListener: function (val) { + var p = sjcl.mode.ccm._progressListeners.slice(), i; + + for (i = 0; i < p.length; i += 1) { + p[i](val); + } + }, + + /** Encrypt in CCM mode. + * @static + * @param {Object} prf The pseudorandom function. It must have a block size of 16 bytes. + * @param {bitArray} plaintext The plaintext data. + * @param {bitArray} iv The initialization value. + * @param {bitArray} [adata=[]] The authenticated data. + * @param {Number} [tlen=64] the desired tag length, in bits. + * @return {bitArray} The encrypted data, an array of bytes. + */ + encrypt: function(prf, plaintext, iv, adata, tlen) { + var L, out = plaintext.slice(0), tag, w=sjcl.bitArray, ivl = w.bitLength(iv) / 8, ol = w.bitLength(out) / 8; + tlen = tlen || 64; + adata = adata || []; + + if (ivl < 7) { + throw new sjcl.exception.invalid("ccm: iv must be at least 7 bytes"); + } + + // compute the length of the length + for (L=2; L<4 && ol >>> 8*L; L++) {} + if (L < 15 - ivl) { L = 15-ivl; } + iv = w.clamp(iv,8*(15-L)); + + // compute the tag + tag = sjcl.mode.ccm._computeTag(prf, plaintext, iv, adata, tlen, L); + + // encrypt + out = sjcl.mode.ccm._ctrMode(prf, out, iv, tag, tlen, L); + + return w.concat(out.data, out.tag); + }, + + /** Decrypt in CCM mode. + * @static + * @param {Object} prf The pseudorandom function. It must have a block size of 16 bytes. + * @param {bitArray} ciphertext The ciphertext data. + * @param {bitArray} iv The initialization value. + * @param {bitArray} [adata=[]] adata The authenticated data. + * @param {Number} [tlen=64] tlen the desired tag length, in bits. + * @return {bitArray} The decrypted data. + */ + decrypt: function(prf, ciphertext, iv, adata, tlen) { + tlen = tlen || 64; + adata = adata || []; + var L, + w=sjcl.bitArray, + ivl = w.bitLength(iv) / 8, + ol = w.bitLength(ciphertext), + out = w.clamp(ciphertext, ol - tlen), + tag = w.bitSlice(ciphertext, ol - tlen), tag2; + + + ol = (ol - tlen) / 8; + + if (ivl < 7) { + throw new sjcl.exception.invalid("ccm: iv must be at least 7 bytes"); + } + + // compute the length of the length + for (L=2; L<4 && ol >>> 8*L; L++) {} + if (L < 15 - ivl) { L = 15-ivl; } + iv = w.clamp(iv,8*(15-L)); + + // decrypt + out = sjcl.mode.ccm._ctrMode(prf, out, iv, tag, tlen, L); + + // check the tag + tag2 = sjcl.mode.ccm._computeTag(prf, out.data, iv, adata, tlen, L); + if (!w.equal(out.tag, tag2)) { + throw new sjcl.exception.corrupt("ccm: tag doesn't match"); + } + + return out.data; + }, + + _macAdditionalData: function (prf, adata, iv, tlen, ol, L) { + var mac, tmp, i, macData = [], w=sjcl.bitArray, xor = w._xor4; + + // mac the flags + mac = [w.partial(8, (adata.length ? 1<<6 : 0) | (tlen-2) << 2 | L-1)]; + + // mac the iv and length + mac = w.concat(mac, iv); + mac[3] |= ol; + mac = prf.encrypt(mac); + + if (adata.length) { + // mac the associated data. start with its length... + tmp = w.bitLength(adata)/8; + if (tmp <= 0xFEFF) { + macData = [w.partial(16, tmp)]; + } else if (tmp <= 0xFFFFFFFF) { + macData = w.concat([w.partial(16,0xFFFE)], [tmp]); + } // else ... + + // mac the data itself + macData = w.concat(macData, adata); + for (i=0; i 16) { + throw new sjcl.exception.invalid("ccm: invalid tag length"); + } + + if (adata.length > 0xFFFFFFFF || plaintext.length > 0xFFFFFFFF) { + // I don't want to deal with extracting high words from doubles. + throw new sjcl.exception.bug("ccm: can't deal with 4GiB or more data"); + } + + mac = sjcl.mode.ccm._macAdditionalData(prf, adata, iv, tlen, w.bitLength(plaintext)/8, L); + + // mac the plaintext + for (i=0; i n) { + sjcl.mode.ccm._callProgressListener(i/l); + n += p; + } + ctr[3]++; + enc = prf.encrypt(ctr); + data[i] ^= enc[0]; + data[i+1] ^= enc[1]; + data[i+2] ^= enc[2]; + data[i+3] ^= enc[3]; + } + return { tag:tag, data:w.clamp(data,bl) }; + } +}; +/** @fileOverview HMAC implementation. + * + * @author Emily Stark + * @author Mike Hamburg + * @author Dan Boneh + */ + +/** HMAC with the specified hash function. + * @constructor + * @param {bitArray} key the key for HMAC. + * @param {Object} [Hash=sjcl.hash.sha256] The hash function to use. + */ +sjcl.misc.hmac = function (key, Hash) { + this._hash = Hash = Hash || sjcl.hash.sha256; + var exKey = [[],[]], i, + bs = Hash.prototype.blockSize / 32; + this._baseHash = [new Hash(), new Hash()]; + + if (key.length > bs) { + key = Hash.hash(key); + } + + for (i=0; iUse sjcl.random as a singleton for this class! + *

+ * This random number generator is a derivative of Ferguson and Schneier's + * generator Fortuna. It collects entropy from various events into several + * pools, implemented by streaming SHA-256 instances. It differs from + * ordinary Fortuna in a few ways, though. + *

+ * + *

+ * Most importantly, it has an entropy estimator. This is present because + * there is a strong conflict here between making the generator available + * as soon as possible, and making sure that it doesn't "run on empty". + * In Fortuna, there is a saved state file, and the system is likely to have + * time to warm up. + *

+ * + *

+ * Second, because users are unlikely to stay on the page for very long, + * and to speed startup time, the number of pools increases logarithmically: + * a new pool is created when the previous one is actually used for a reseed. + * This gives the same asymptotic guarantees as Fortuna, but gives more + * entropy to early reseeds. + *

+ * + *

+ * The entire mechanism here feels pretty klunky. Furthermore, there are + * several improvements that should be made, including support for + * dedicated cryptographic functions that may be present in some browsers; + * state files in local storage; cookies containing randomness; etc. So + * look for improvements in future versions. + *

+ * @constructor + */ +sjcl.prng = function(defaultParanoia) { + + /* private */ + this._pools = [new sjcl.hash.sha256()]; + this._poolEntropy = [0]; + this._reseedCount = 0; + this._robins = {}; + this._eventId = 0; + + this._collectorIds = {}; + this._collectorIdNext = 0; + + this._strength = 0; + this._poolStrength = 0; + this._nextReseed = 0; + this._key = [0,0,0,0,0,0,0,0]; + this._counter = [0,0,0,0]; + this._cipher = undefined; + this._defaultParanoia = defaultParanoia; + + /* event listener stuff */ + this._collectorsStarted = false; + this._callbacks = {progress: {}, seeded: {}}; + this._callbackI = 0; + + /* constants */ + this._NOT_READY = 0; + this._READY = 1; + this._REQUIRES_RESEED = 2; + + this._MAX_WORDS_PER_BURST = 65536; + this._PARANOIA_LEVELS = [0,48,64,96,128,192,256,384,512,768,1024]; + this._MILLISECONDS_PER_RESEED = 30000; + this._BITS_PER_RESEED = 80; +}; + +sjcl.prng.prototype = { + /** Generate several random words, and return them in an array. + * A word consists of 32 bits (4 bytes) + * @param {Number} nwords The number of words to generate. + */ + randomWords: function (nwords, paranoia) { + var out = [], i, readiness = this.isReady(paranoia), g; + + if (readiness === this._NOT_READY) { + throw new sjcl.exception.notReady("generator isn't seeded"); + } else if (readiness & this._REQUIRES_RESEED) { + this._reseedFromPools(!(readiness & this._READY)); + } + + for (i=0; i0) { + estimatedEntropy++; + tmp = tmp >>> 1; + } + } + } + this._pools[robin].update([id,this._eventId++,2,estimatedEntropy,t,data.length].concat(data)); + } + break; + + case "string": + if (estimatedEntropy === undefined) { + /* English text has just over 1 bit per character of entropy. + * But this might be HTML or something, and have far less + * entropy than English... Oh well, let's just say one bit. + */ + estimatedEntropy = data.length; + } + this._pools[robin].update([id,this._eventId++,3,estimatedEntropy,t,data.length]); + this._pools[robin].update(data); + break; + + default: + err=1; + } + if (err) { + throw new sjcl.exception.bug("random: addEntropy only supports number, array of numbers or string"); + } + + /* record the new strength */ + this._poolEntropy[robin] += estimatedEntropy; + this._poolStrength += estimatedEntropy; + + /* fire off events */ + if (oldReady === this._NOT_READY) { + if (this.isReady() !== this._NOT_READY) { + this._fireEvent("seeded", Math.max(this._strength, this._poolStrength)); + } + this._fireEvent("progress", this.getProgress()); + } + }, + + /** Is the generator ready? */ + isReady: function (paranoia) { + var entropyRequired = this._PARANOIA_LEVELS[ (paranoia !== undefined) ? paranoia : this._defaultParanoia ]; + + if (this._strength && this._strength >= entropyRequired) { + return (this._poolEntropy[0] > this._BITS_PER_RESEED && (new Date()).valueOf() > this._nextReseed) ? + this._REQUIRES_RESEED | this._READY : + this._READY; + } else { + return (this._poolStrength >= entropyRequired) ? + this._REQUIRES_RESEED | this._NOT_READY : + this._NOT_READY; + } + }, + + /** Get the generator's progress toward readiness, as a fraction */ + getProgress: function (paranoia) { + var entropyRequired = this._PARANOIA_LEVELS[ paranoia ? paranoia : this._defaultParanoia ]; + + if (this._strength >= entropyRequired) { + return 1.0; + } else { + return (this._poolStrength > entropyRequired) ? + 1.0 : + this._poolStrength / entropyRequired; + } + }, + + /** start the built-in entropy collectors */ + startCollectors: function () { + if (this._collectorsStarted) { return; } + + this._eventListener = { + loadTimeCollector: this._bind(this._loadTimeCollector), + mouseCollector: this._bind(this._mouseCollector), + keyboardCollector: this._bind(this._keyboardCollector), + accelerometerCollector: this._bind(this._accelerometerCollector), + touchCollector: this._bind(this._touchCollector) + }; + + if (window.addEventListener) { + window.addEventListener("load", this._eventListener.loadTimeCollector, false); + window.addEventListener("mousemove", this._eventListener.mouseCollector, false); + window.addEventListener("keypress", this._eventListener.keyboardCollector, false); + window.addEventListener("devicemotion", this._eventListener.accelerometerCollector, false); + window.addEventListener("touchmove", this._eventListener.touchCollector, false); + } else if (document.attachEvent) { + document.attachEvent("onload", this._eventListener.loadTimeCollector); + document.attachEvent("onmousemove", this._eventListener.mouseCollector); + document.attachEvent("keypress", this._eventListener.keyboardCollector); + } else { + throw new sjcl.exception.bug("can't attach event"); + } + + this._collectorsStarted = true; + }, + + /** stop the built-in entropy collectors */ + stopCollectors: function () { + if (!this._collectorsStarted) { return; } + + if (window.removeEventListener) { + window.removeEventListener("load", this._eventListener.loadTimeCollector, false); + window.removeEventListener("mousemove", this._eventListener.mouseCollector, false); + window.removeEventListener("keypress", this._eventListener.keyboardCollector, false); + window.removeEventListener("devicemotion", this._eventListener.accelerometerCollector, false); + window.removeEventListener("touchmove", this._eventListener.touchCollector, false); + } else if (document.detachEvent) { + document.detachEvent("onload", this._eventListener.loadTimeCollector); + document.detachEvent("onmousemove", this._eventListener.mouseCollector); + document.detachEvent("keypress", this._eventListener.keyboardCollector); + } + + this._collectorsStarted = false; + }, + + /* use a cookie to store entropy. + useCookie: function (all_cookies) { + throw new sjcl.exception.bug("random: useCookie is unimplemented"); + },*/ + + /** add an event listener for progress or seeded-ness. */ + addEventListener: function (name, callback) { + this._callbacks[name][this._callbackI++] = callback; + }, + + /** remove an event listener for progress or seeded-ness */ + removeEventListener: function (name, cb) { + var i, j, cbs=this._callbacks[name], jsTemp=[]; + + /* I'm not sure if this is necessary; in C++, iterating over a + * collection and modifying it at the same time is a no-no. + */ + + for (j in cbs) { + if (cbs.hasOwnProperty(j) && cbs[j] === cb) { + jsTemp.push(j); + } + } + + for (i=0; i= 1 << this._pools.length) { + this._pools.push(new sjcl.hash.sha256()); + this._poolEntropy.push(0); + } + + /* how strong was this reseed? */ + this._poolStrength -= strength; + if (strength > this._strength) { + this._strength = strength; + } + + this._reseedCount ++; + this._reseed(reseedData); + }, + + _keyboardCollector: function () { + this._addCurrentTimeToEntropy(1); + }, + + _mouseCollector: function (ev) { + var x, y; + + try { + x = ev.x || ev.clientX || ev.offsetX || 0; + y = ev.y || ev.clientY || ev.offsetY || 0; + } catch (err) { + // Event originated from a secure element. No mouse position available. + x = 0; + y = 0; + } + + if (x != 0 && y!= 0) { + this.addEntropy([x,y], 2, "mouse"); + } + + this._addCurrentTimeToEntropy(0); + }, + + _touchCollector: function(ev) { + var touch = ev.touches[0] || ev.changedTouches[0]; + var x = touch.pageX || touch.clientX, + y = touch.pageY || touch.clientY; + + this.addEntropy([x,y],1,"touch"); + + this._addCurrentTimeToEntropy(0); + }, + + _loadTimeCollector: function () { + this._addCurrentTimeToEntropy(2); + }, + + _addCurrentTimeToEntropy: function (estimatedEntropy) { + if (typeof window !== 'undefined' && window.performance && typeof window.performance.now === "function") { + //how much entropy do we want to add here? + this.addEntropy(window.performance.now(), estimatedEntropy, "loadtime"); + } else { + this.addEntropy((new Date()).valueOf(), estimatedEntropy, "loadtime"); + } + }, + _accelerometerCollector: function (ev) { + var ac = ev.accelerationIncludingGravity.x||ev.accelerationIncludingGravity.y||ev.accelerationIncludingGravity.z; + if(window.orientation){ + var or = window.orientation; + if (typeof or === "number") { + this.addEntropy(or, 1, "accelerometer"); + } + } + if (ac) { + this.addEntropy(ac, 2, "accelerometer"); + } + this._addCurrentTimeToEntropy(0); + }, + + _fireEvent: function (name, arg) { + var j, cbs=sjcl.random._callbacks[name], cbsTemp=[]; + /* TODO: there is a race condition between removing collectors and firing them */ + + /* I'm not sure if this is necessary; in C++, iterating over a + * collection and modifying it at the same time is a no-no. + */ + + for (j in cbs) { + if (cbs.hasOwnProperty(j)) { + cbsTemp.push(cbs[j]); + } + } + + for (j=0; j 4)) { + throw new sjcl.exception.invalid("json encrypt: invalid parameters"); + } + + if (typeof password === "string") { + tmp = sjcl.misc.cachedPbkdf2(password, p); + password = tmp.key.slice(0,p.ks/32); + p.salt = tmp.salt; + } else if (sjcl.ecc && password instanceof sjcl.ecc.elGamal.publicKey) { + tmp = password.kem(); + p.kemtag = tmp.tag; + password = tmp.key.slice(0,p.ks/32); + } + if (typeof plaintext === "string") { + plaintext = sjcl.codec.utf8String.toBits(plaintext); + } + if (typeof adata === "string") { + p.adata = adata = sjcl.codec.utf8String.toBits(adata); + } + prp = new sjcl.cipher[p.cipher](password); + + /* return the json data */ + j._add(rp, p); + rp.key = password; + + /* do the encryption */ + if (p.mode === "ccm" && sjcl.arrayBuffer && sjcl.arrayBuffer.ccm && plaintext instanceof ArrayBuffer) { + p.ct = sjcl.arrayBuffer.ccm.encrypt(prp, plaintext, p.iv, adata, p.ts); + } else { + p.ct = sjcl.mode[p.mode].encrypt(prp, plaintext, p.iv, adata, p.ts); + } + + //return j.encode(j._subtract(p, j.defaults)); + return p; + }, + + /** Simple encryption function. + * @param {String|bitArray} password The password or key. + * @param {String} plaintext The data to encrypt. + * @param {Object} [params] The parameters including tag, iv and salt. + * @param {Object} [rp] A returned version with filled-in parameters. + * @return {String} The ciphertext serialized data. + * @throws {sjcl.exception.invalid} if a parameter is invalid. + */ + encrypt: function (password, plaintext, params, rp) { + var j = sjcl.json, p = j._encrypt.apply(j, arguments); + return j.encode(p); + }, + + /** Simple decryption function. + * @param {String|bitArray} password The password or key. + * @param {Object} ciphertext The cipher raw data to decrypt. + * @param {Object} [params] Additional non-default parameters. + * @param {Object} [rp] A returned object with filled parameters. + * @return {String} The plaintext. + * @throws {sjcl.exception.invalid} if a parameter is invalid. + * @throws {sjcl.exception.corrupt} if the ciphertext is corrupt. + */ + _decrypt: function (password, ciphertext, params, rp) { + params = params || {}; + rp = rp || {}; + + var j = sjcl.json, p = j._add(j._add(j._add({},j.defaults),ciphertext), params, true), ct, tmp, prp, adata=p.adata; + if (typeof p.salt === "string") { + p.salt = sjcl.codec.base64.toBits(p.salt); + } + if (typeof p.iv === "string") { + p.iv = sjcl.codec.base64.toBits(p.iv); + } + + if (!sjcl.mode[p.mode] || + !sjcl.cipher[p.cipher] || + (typeof password === "string" && p.iter <= 100) || + (p.ts !== 64 && p.ts !== 96 && p.ts !== 128) || + (p.ks !== 128 && p.ks !== 192 && p.ks !== 256) || + (!p.iv) || + (p.iv.length < 2 || p.iv.length > 4)) { + throw new sjcl.exception.invalid("json decrypt: invalid parameters"); + } + + if (typeof password === "string") { + tmp = sjcl.misc.cachedPbkdf2(password, p); + password = tmp.key.slice(0,p.ks/32); + p.salt = tmp.salt; + } else if (sjcl.ecc && password instanceof sjcl.ecc.elGamal.secretKey) { + password = password.unkem(sjcl.codec.base64.toBits(p.kemtag)).slice(0,p.ks/32); + } + if (typeof adata === "string") { + adata = sjcl.codec.utf8String.toBits(adata); + } + prp = new sjcl.cipher[p.cipher](password); + + /* do the decryption */ + if (p.mode === "ccm" && sjcl.arrayBuffer && sjcl.arrayBuffer.ccm && p.ct instanceof ArrayBuffer) { + ct = sjcl.arrayBuffer.ccm.decrypt(prp, p.ct, p.iv, p.tag, adata, p.ts); + } else { + ct = sjcl.mode[p.mode].decrypt(prp, p.ct, p.iv, adata, p.ts); + } + + /* return the json data */ + j._add(rp, p); + rp.key = password; + + if (params.raw === 1) { + return ct; + } else { + return sjcl.codec.utf8String.fromBits(ct); + } + }, + + /** Simple decryption function. + * @param {String|bitArray} password The password or key. + * @param {String} ciphertext The ciphertext to decrypt. + * @param {Object} [params] Additional non-default parameters. + * @param {Object} [rp] A returned object with filled parameters. + * @return {String} The plaintext. + * @throws {sjcl.exception.invalid} if a parameter is invalid. + * @throws {sjcl.exception.corrupt} if the ciphertext is corrupt. + */ + decrypt: function (password, ciphertext, params, rp) { + var j = sjcl.json; + return j._decrypt(password, j.decode(ciphertext), params, rp); + }, + + /** Encode a flat structure into a JSON string. + * @param {Object} obj The structure to encode. + * @return {String} A JSON string. + * @throws {sjcl.exception.invalid} if obj has a non-alphanumeric property. + * @throws {sjcl.exception.bug} if a parameter has an unsupported type. + */ + encode: function (obj) { + var i, out='{', comma=''; + for (i in obj) { + if (obj.hasOwnProperty(i)) { + if (!i.match(/^[a-z0-9]+$/i)) { + throw new sjcl.exception.invalid("json encode: invalid property name"); + } + out += comma + '"' + i + '":'; + comma = ','; + + switch (typeof obj[i]) { + case 'number': + case 'boolean': + out += obj[i]; + break; + + case 'string': + out += '"' + escape(obj[i]) + '"'; + break; + + case 'object': + out += '"' + sjcl.codec.base64.fromBits(obj[i],0) + '"'; + break; + + default: + throw new sjcl.exception.bug("json encode: unsupported type"); + } + } + } + return out+'}'; + }, + + /** Decode a simple (flat) JSON string into a structure. The ciphertext, + * adata, salt and iv will be base64-decoded. + * @param {String} str The string. + * @return {Object} The decoded structure. + * @throws {sjcl.exception.invalid} if str isn't (simple) JSON. + */ + decode: function (str) { + str = str.replace(/\s/g,''); + if (!str.match(/^\{.*\}$/)) { + throw new sjcl.exception.invalid("json decode: this isn't json!"); + } + var a = str.replace(/^\{|\}$/g, '').split(/,/), out={}, i, m; + for (i=0; i= this.limbs.length) ? 0 : this.limbs[i]; + }, + + /** + * Constant time comparison function. + * Returns 1 if this >= that, or zero otherwise. + */ + greaterEquals: function(that) { + if (typeof that === "number") { that = new this._class(that); } + var less = 0, greater = 0, i, a, b; + i = Math.max(this.limbs.length, that.limbs.length) - 1; + for (; i>= 0; i--) { + a = this.getLimb(i); + b = that.getLimb(i); + greater |= (b - a) & ~less; + less |= (a - b) & ~greater; + } + return (greater | ~less) >>> 31; + }, + + /** + * Convert to a hex string. + */ + toString: function() { + this.fullReduce(); + var out="", i, s, l = this.limbs; + for (i=0; i < this.limbs.length; i++) { + s = l[i].toString(16); + while (i < this.limbs.length - 1 && s.length < 6) { + s = "0" + s; + } + out = s + out; + } + return "0x"+out; + }, + + /** this += that. Does not normalize. */ + addM: function(that) { + if (typeof(that) !== "object") { that = new this._class(that); } + var i, l=this.limbs, ll=that.limbs; + for (i=l.length; i> r; + } + if (carry) { + l.push(carry); + } + return this; + }, + + /** this /= 2, rounded down. Requires normalized; ends up normalized. */ + halveM: function() { + var i, carry=0, tmp, r=this.radix, l=this.limbs; + for (i=l.length-1; i>=0; i--) { + tmp = l[i]; + l[i] = (tmp+carry)>>1; + carry = (tmp&1) << r; + } + if (!l[l.length-1]) { + l.pop(); + } + return this; + }, + + /** this -= that. Does not normalize. */ + subM: function(that) { + if (typeof(that) !== "object") { that = new this._class(that); } + var i, l=this.limbs, ll=that.limbs; + for (i=l.length; i 0; ci--) { + that.halveM(); + if (out.greaterEquals(that)) { + out.subM(that).normalize(); + } + } + return out.trim(); + }, + + /** return inverse mod prime p. p must be odd. Binary extended Euclidean algorithm mod p. */ + inverseMod: function(p) { + var a = new sjcl.bn(1), b = new sjcl.bn(0), x = new sjcl.bn(this), y = new sjcl.bn(p), tmp, i, nz=1; + + if (!(p.limbs[0] & 1)) { + throw (new sjcl.exception.invalid("inverseMod: p must be odd")); + } + + // invariant: y is odd + do { + if (x.limbs[0] & 1) { + if (!x.greaterEquals(y)) { + // x < y; swap everything + tmp = x; x = y; y = tmp; + tmp = a; a = b; b = tmp; + } + x.subM(y); + x.normalize(); + + if (!a.greaterEquals(b)) { + a.addM(p); + } + a.subM(b); + } + + // cut everything in half + x.halveM(); + if (a.limbs[0] & 1) { + a.addM(p); + } + a.normalize(); + a.halveM(); + + // check for termination: x ?= 0 + for (i=nz=0; i>(j + 1) == 0) { break; } + + pow = pow.square(); + } + } + + return out; + }, + + /** this * that mod N */ + mulmod: function(that, N) { + return this.mod(N).mul(that.mod(N)).mod(N); + }, + + /** this ^ x mod N */ + powermod: function(x, N) { + x = new sjcl.bn(x); + N = new sjcl.bn(N); + + // Jump to montpowermod if possible. + if ((N.limbs[0] & 1) == 1) { + var montOut = this.montpowermod(x, N); + + if (montOut != false) { return montOut; } // else go to slow powermod + } + + var i, j, l = x.normalize().trim().limbs, out = new this._class(1), pow = this; + + for (i=0; i>(j + 1) == 0) { break; } + + pow = pow.mulmod(pow, N); + } + } + + return out; + }, + + /** this ^ x mod N with Montomery reduction */ + montpowermod: function(x, N) { + x = new sjcl.bn(x).normalize().trim(); + N = new sjcl.bn(N); + + var i, j, + radix = this.radix, + out = new this._class(1), + pow = this.copy(); + + // Generate R as a cap of N. + var R, s, wind, bitsize = x.bitLength(); + + R = new sjcl.bn({ + limbs: N.copy().normalize().trim().limbs.map(function() { return 0; }) + }); + + for (s = this.radix; s > 0; s--) { + if (((N.limbs[N.limbs.length - 1] >> s) & 1) == 1) { + R.limbs[R.limbs.length - 1] = 1 << s; + break; + } + } + + // Calculate window size as a function of the exponent's size. + if (bitsize == 0) { + return this; + } else if (bitsize < 18) { + wind = 1; + } else if (bitsize < 48) { + wind = 3; + } else if (bitsize < 144) { + wind = 4; + } else if (bitsize < 768) { + wind = 5; + } else { + wind = 6; + } + + // Find R' and N' such that R * R' - N * N' = 1. + var RR = R.copy(), NN = N.copy(), RP = new sjcl.bn(1), NP = new sjcl.bn(0), RT = R.copy(); + + while (RT.greaterEquals(1)) { + RT.halveM(); + + if ((RP.limbs[0] & 1) == 0) { + RP.halveM(); + NP.halveM(); + } else { + RP.addM(NN); + RP.halveM(); + + NP.halveM(); + NP.addM(RR); + } + } + + RP = RP.normalize(); + NP = NP.normalize(); + + RR.doubleM(); + var R2 = RR.mulmod(RR, N); + + // Check whether the invariant holds. + // If it doesn't, we can't use Montgomery reduction on this modulus. + if (!RR.mul(RP).sub(N.mul(NP)).equals(1)) { + return false; + } + + var montIn = function(c) { return montMul(c, R2); }, + montMul = function(a, b) { + // Standard Montgomery reduction + var k, ab, right, abBar, mask = (1 << (s + 1)) - 1; + + ab = a.mul(b); + + right = ab.mul(NP); + right.limbs = right.limbs.slice(0, R.limbs.length); + + if (right.limbs.length == R.limbs.length) { + right.limbs[R.limbs.length - 1] &= mask; + } + + right = right.mul(N); + + abBar = ab.add(right).normalize().trim(); + abBar.limbs = abBar.limbs.slice(R.limbs.length - 1); + + // Division. Equivelent to calling *.halveM() s times. + for (k=0; k < abBar.limbs.length; k++) { + if (k > 0) { + abBar.limbs[k - 1] |= (abBar.limbs[k] & mask) << (radix - s - 1); + } + + abBar.limbs[k] = abBar.limbs[k] >> (s + 1); + } + + if (abBar.greaterEquals(N)) { + abBar.subM(N); + } + + return abBar; + }, + montOut = function(c) { return montMul(c, 1); }; + + pow = montIn(pow); + out = montIn(out); + + // Sliding-Window Exponentiation (HAC 14.85) + var h, precomp = {}, cap = (1 << (wind - 1)) - 1; + + precomp[1] = pow.copy(); + precomp[2] = montMul(pow, pow); + + for (h=1; h<=cap; h++) { + precomp[(2 * h) + 1] = montMul(precomp[(2 * h) - 1], precomp[2]); + } + + var getBit = function(exp, i) { // Gets ith bit of exp. + var off = i % exp.radix; + + return (exp.limbs[Math.floor(i / exp.radix)] & (1 << off)) >> off; + }; + + for (i = x.bitLength() - 1; i >= 0; ) { + if (getBit(x, i) == 0) { + // If the next bit is zero: + // Square, move forward one bit. + out = montMul(out, out); + i = i - 1; + } else { + // If the next bit is one: + // Find the longest sequence of bits after this one, less than `wind` + // bits long, that ends with a 1. Convert the sequence into an + // integer and look up the pre-computed value to add. + var l = i - wind + 1; + + while (getBit(x, l) == 0) { + l++; + } + + var indx = 0; + for (j = l; j <= i; j++) { + indx += getBit(x, j) << (j - l); + out = montMul(out, out); + } + + out = montMul(out, precomp[indx]); + + i = l - 1; + } + } + + return montOut(out); + }, + + trim: function() { + var l = this.limbs, p; + do { + p = l.pop(); + } while (l.length && p === 0); + l.push(p); + return this; + }, + + /** Reduce mod a modulus. Stubbed for subclassing. */ + reduce: function() { + return this; + }, + + /** Reduce and normalize. */ + fullReduce: function() { + return this.normalize(); + }, + + /** Propagate carries. */ + normalize: function() { + var carry=0, i, pv = this.placeVal, ipv = this.ipv, l, m, limbs = this.limbs, ll = limbs.length, mask = this.radixMask; + for (i=0; i < ll || (carry !== 0 && carry !== -1); i++) { + l = (limbs[i]||0) + carry; + m = limbs[i] = l & mask; + carry = (l-m)*ipv; + } + if (carry === -1) { + limbs[i-1] -= pv; + } + this.trim(); + return this; + }, + + /** Constant-time normalize. Does not allocate additional space. */ + cnormalize: function() { + var carry=0, i, ipv = this.ipv, l, m, limbs = this.limbs, ll = limbs.length, mask = this.radixMask; + for (i=0; i < ll-1; i++) { + l = limbs[i] + carry; + m = limbs[i] = l & mask; + carry = (l-m)*ipv; + } + limbs[i] += carry; + return this; + }, + + /** Serialize to a bit array */ + toBits: function(len) { + this.fullReduce(); + len = len || this.exponent || this.bitLength(); + var i = Math.floor((len-1)/24), w=sjcl.bitArray, e = (len + 7 & -8) % this.radix || this.radix, + out = [w.partial(e, this.getLimb(i))]; + for (i--; i >= 0; i--) { + out = w.concat(out, [w.partial(Math.min(this.radix,len), this.getLimb(i))]); + len -= this.radix; + } + return out; + }, + + /** Return the length in bits, rounded up to the nearest byte. */ + bitLength: function() { + this.fullReduce(); + var out = this.radix * (this.limbs.length - 1), + b = this.limbs[this.limbs.length - 1]; + for (; b; b >>>= 1) { + out ++; + } + return out+7 & -8; + } +}; + +/** @memberOf sjcl.bn +* @this { sjcl.bn } +*/ +sjcl.bn.fromBits = function(bits) { + var Class = this, out = new Class(), words=[], w=sjcl.bitArray, t = this.prototype, + l = Math.min(this.bitLength || 0x100000000, w.bitLength(bits)), e = l % t.radix || t.radix; + + words[0] = w.extract(bits, 0, e); + for (; e < l; e += t.radix) { + words.unshift(w.extract(bits, e, t.radix)); + } + + out.limbs = words; + return out; +}; + + + +sjcl.bn.prototype.ipv = 1 / (sjcl.bn.prototype.placeVal = Math.pow(2,sjcl.bn.prototype.radix)); +sjcl.bn.prototype.radixMask = (1 << sjcl.bn.prototype.radix) - 1; + +/** + * Creates a new subclass of bn, based on reduction modulo a pseudo-Mersenne prime, + * i.e. a prime of the form 2^e + sum(a * 2^b),where the sum is negative and sparse. + */ +sjcl.bn.pseudoMersennePrime = function(exponent, coeff) { + /** @constructor + * @private + */ + function p(it) { + this.initWith(it); + /*if (this.limbs[this.modOffset]) { + this.reduce(); + }*/ + } + + var ppr = p.prototype = new sjcl.bn(), i, tmp, mo; + mo = ppr.modOffset = Math.ceil(tmp = exponent / ppr.radix); + ppr.exponent = exponent; + ppr.offset = []; + ppr.factor = []; + ppr.minOffset = mo; + ppr.fullMask = 0; + ppr.fullOffset = []; + ppr.fullFactor = []; + ppr.modulus = p.modulus = new sjcl.bn(Math.pow(2,exponent)); + + ppr.fullMask = 0|-Math.pow(2, exponent % ppr.radix); + + for (i=0; i mo) { + l = limbs.pop(); + ll = limbs.length; + for (k=0; k=0; i--) { + for (j=sjcl.bn.prototype.radix-4; j>=0; j-=4) { + out = out.doubl().doubl().doubl().doubl().add(multiples[k[i]>>j & 0xF]); + } + } + + return out; + }, + + /** + * Multiply this point by k, added to affine2*k2, and return the answer in Jacobian coordinates. + * @param {bigInt} k The coefficient to multiply this by. + * @param {sjcl.ecc.point} affine This point in affine coordinates. + * @param {bigInt} k2 The coefficient to multiply affine2 this by. + * @param {sjcl.ecc.point} affine The other point in affine coordinates. + * @return {sjcl.ecc.pointJac} The result of the multiplication and addition, in Jacobian coordinates. + */ + mult2: function(k1, affine, k2, affine2) { + if (typeof(k1) === "number") { + k1 = [k1]; + } else if (k1.limbs !== undefined) { + k1 = k1.normalize().limbs; + } + + if (typeof(k2) === "number") { + k2 = [k2]; + } else if (k2.limbs !== undefined) { + k2 = k2.normalize().limbs; + } + + var i, j, out = new sjcl.ecc.point(this.curve).toJac(), m1 = affine.multiples(), + m2 = affine2.multiples(), l1, l2; + + for (i=Math.max(k1.length,k2.length)-1; i>=0; i--) { + l1 = k1[i] | 0; + l2 = k2[i] | 0; + for (j=sjcl.bn.prototype.radix-4; j>=0; j-=4) { + out = out.doubl().doubl().doubl().doubl().add(m1[l1>>j & 0xF]).add(m2[l2>>j & 0xF]); + } + } + + return out; + }, + + negate: function() { + return this.toAffine().negate().toJac(); + }, + + isValid: function() { + var z2 = this.z.square(), z4 = z2.square(), z6 = z4.mul(z2); + return this.y.square().equals( + this.curve.b.mul(z6).add(this.x.mul( + this.curve.a.mul(z4).add(this.x.square())))); + } +}; + +/** + * Construct an elliptic curve. Most users will not use this and instead start with one of the NIST curves defined below. + * + * @constructor + * @param {bigInt} p The prime modulus. + * @param {bigInt} r The prime order of the curve. + * @param {bigInt} a The constant a in the equation of the curve y^2 = x^3 + ax + b (for NIST curves, a is always -3). + * @param {bigInt} x The x coordinate of a base point of the curve. + * @param {bigInt} y The y coordinate of a base point of the curve. + */ +sjcl.ecc.curve = function(Field, r, a, b, x, y) { + this.field = Field; + this.r = new sjcl.bn(r); + this.a = new Field(a); + this.b = new Field(b); + this.G = new sjcl.ecc.point(this, new Field(x), new Field(y)); +}; + +sjcl.ecc.curve.prototype.fromBits = function (bits) { + var w = sjcl.bitArray, l = this.field.prototype.exponent + 7 & -8, + p = new sjcl.ecc.point(this, this.field.fromBits(w.bitSlice(bits, 0, l)), + this.field.fromBits(w.bitSlice(bits, l, 2*l))); + if (!p.isValid()) { + throw new sjcl.exception.corrupt("not on the curve!"); + } + return p; +}; + +sjcl.ecc.curves = { + c192: new sjcl.ecc.curve( + sjcl.bn.prime.p192, + "0xffffffffffffffffffffffff99def836146bc9b1b4d22831", + -3, + "0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", + "0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012", + "0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811"), + + c224: new sjcl.ecc.curve( + sjcl.bn.prime.p224, + "0xffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d", + -3, + "0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4", + "0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21", + "0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34"), + + c256: new sjcl.ecc.curve( + sjcl.bn.prime.p256, + "0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", + -3, + "0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", + "0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", + "0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5"), + + c384: new sjcl.ecc.curve( + sjcl.bn.prime.p384, + "0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973", + -3, + "0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef", + "0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7", + "0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f"), + + c521: new sjcl.ecc.curve( + sjcl.bn.prime.p521, + "0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409", + -3, + "0x051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00", + "0xC6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66", + "0x11839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650"), + + k192: new sjcl.ecc.curve( + sjcl.bn.prime.p192k, + "0xfffffffffffffffffffffffe26f2fc170f69466a74defd8d", + 0, + 3, + "0xdb4ff10ec057e9ae26b07d0280b7f4341da5d1b1eae06c7d", + "0x9b2f2f6d9c5628a7844163d015be86344082aa88d95e2f9d"), + + k224: new sjcl.ecc.curve( + sjcl.bn.prime.p224k, + "0x010000000000000000000000000001dce8d2ec6184caf0a971769fb1f7", + 0, + 5, + "0xa1455b334df099df30fc28a169a467e9e47075a90f7e650eb6b7a45c", + "0x7e089fed7fba344282cafbd6f7e319f7c0b0bd59e2ca4bdb556d61a5"), + + k256: new sjcl.ecc.curve( + sjcl.bn.prime.p256k, + "0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", + 0, + 7, + "0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", + "0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8") + +}; + +sjcl.ecc.curveName = function (curve) { + var curcurve; + for (curcurve in sjcl.ecc.curves) { + if (sjcl.ecc.curves.hasOwnProperty(curcurve)) { + if (sjcl.ecc.curves[curcurve] === curve) { + return curcurve; + } + } + } + + throw new sjcl.exception.invalid("no such curve"); +}; + +sjcl.ecc.deserialize = function (key) { + var types = ["elGamal", "ecdsa"]; + + if (!key || !key.curve || !sjcl.ecc.curves[key.curve]) { throw new sjcl.exception.invalid("invalid serialization"); } + if (types.indexOf(key.type) === -1) { throw new sjcl.exception.invalid("invalid type"); } + + var curve = sjcl.ecc.curves[key.curve]; + + if (key.secretKey) { + if (!key.exponent) { throw new sjcl.exception.invalid("invalid exponent"); } + var exponent = new sjcl.bn(key.exponent); + return new sjcl.ecc[key.type].secretKey(curve, exponent); + } else { + if (!key.point) { throw new sjcl.exception.invalid("invalid point"); } + + var point = curve.fromBits(sjcl.codec.hex.toBits(key.point)); + return new sjcl.ecc[key.type].publicKey(curve, point); + } +}; + +/** our basicKey classes +*/ +sjcl.ecc.basicKey = { + /** ecc publicKey. + * @constructor + * @param {curve} curve the elliptic curve + * @param {point} point the point on the curve + */ + publicKey: function(curve, point) { + this._curve = curve; + this._curveBitLength = curve.r.bitLength(); + if (point instanceof Array) { + this._point = curve.fromBits(point); + } else { + this._point = point; + } + + this.serialize = function () { + var curveName = sjcl.ecc.curveName(curve); + return { + type: this.getType(), + secretKey: false, + point: sjcl.codec.hex.fromBits(this._point.toBits()), + curve: curveName + }; + }; + + /** get this keys point data + * @return x and y as bitArrays + */ + this.get = function() { + var pointbits = this._point.toBits(); + var len = sjcl.bitArray.bitLength(pointbits); + var x = sjcl.bitArray.bitSlice(pointbits, 0, len/2); + var y = sjcl.bitArray.bitSlice(pointbits, len/2); + return { x: x, y: y }; + }; + }, + + /** ecc secretKey + * @constructor + * @param {curve} curve the elliptic curve + * @param exponent + */ + secretKey: function(curve, exponent) { + this._curve = curve; + this._curveBitLength = curve.r.bitLength(); + this._exponent = exponent; + + this.serialize = function () { + var exponent = this.get(); + var curveName = sjcl.ecc.curveName(curve); + return { + type: this.getType(), + secretKey: true, + exponent: sjcl.codec.hex.fromBits(exponent), + curve: curveName + }; + }; + + /** get this keys exponent data + * @return {bitArray} exponent + */ + this.get = function () { + return this._exponent.toBits(); + }; + } +}; + +/** @private */ +sjcl.ecc.basicKey.generateKeys = function(cn) { + return function generateKeys(curve, paranoia, sec) { + curve = curve || 256; + + if (typeof curve === "number") { + curve = sjcl.ecc.curves['c'+curve]; + if (curve === undefined) { + throw new sjcl.exception.invalid("no such curve"); + } + } + sec = sec || sjcl.bn.random(curve.r, paranoia); + + var pub = curve.G.mult(sec); + return { pub: new sjcl.ecc[cn].publicKey(curve, pub), + sec: new sjcl.ecc[cn].secretKey(curve, sec) }; + }; +}; + +/** elGamal keys */ +sjcl.ecc.elGamal = { + /** generate keys + * @function + * @param curve + * @param {int} paranoia Paranoia for generation (default 6) + * @param {secretKey} sec secret Key to use. used to get the publicKey for ones secretKey + */ + generateKeys: sjcl.ecc.basicKey.generateKeys("elGamal"), + /** elGamal publicKey. + * @constructor + * @augments sjcl.ecc.basicKey.publicKey + */ + publicKey: function (curve, point) { + sjcl.ecc.basicKey.publicKey.apply(this, arguments); + }, + /** elGamal secretKey + * @constructor + * @augments sjcl.ecc.basicKey.secretKey + */ + secretKey: function (curve, exponent) { + sjcl.ecc.basicKey.secretKey.apply(this, arguments); + } +}; + +sjcl.ecc.elGamal.publicKey.prototype = { + /** Kem function of elGamal Public Key + * @param paranoia paranoia to use for randomization. + * @return {object} key and tag. unkem(tag) with the corresponding secret key results in the key returned. + */ + kem: function(paranoia) { + var sec = sjcl.bn.random(this._curve.r, paranoia), + tag = this._curve.G.mult(sec).toBits(), + key = sjcl.hash.sha256.hash(this._point.mult(sec).toBits()); + return { key: key, tag: tag }; + }, + + getType: function() { + return "elGamal"; + } +}; + +sjcl.ecc.elGamal.secretKey.prototype = { + /** UnKem function of elGamal Secret Key + * @param {bitArray} tag The Tag to decrypt. + * @return {bitArray} decrypted key. + */ + unkem: function(tag) { + return sjcl.hash.sha256.hash(this._curve.fromBits(tag).mult(this._exponent).toBits()); + }, + + /** Diffie-Hellmann function + * @param {elGamal.publicKey} pk The Public Key to do Diffie-Hellmann with + * @return {bitArray} diffie-hellmann result for this key combination. + */ + dh: function(pk) { + return sjcl.hash.sha256.hash(pk._point.mult(this._exponent).toBits()); + }, + + /** Diffie-Hellmann function, compatible with Java generateSecret + * @param {elGamal.publicKey} pk The Public Key to do Diffie-Hellmann with + * @return {bitArray} undigested X value, diffie-hellmann result for this key combination, + * compatible with Java generateSecret(). + */ + dhJavaEc: function(pk) { + return pk._point.mult(this._exponent).x.toBits(); + }, + + getType: function() { + return "elGamal"; + } +}; + +/** ecdsa keys */ +sjcl.ecc.ecdsa = { + /** generate keys + * @function + * @param curve + * @param {int} paranoia Paranoia for generation (default 6) + * @param {secretKey} sec secret Key to use. used to get the publicKey for ones secretKey + */ + generateKeys: sjcl.ecc.basicKey.generateKeys("ecdsa") +}; + +/** ecdsa publicKey. +* @constructor +* @augments sjcl.ecc.basicKey.publicKey +*/ +sjcl.ecc.ecdsa.publicKey = function (curve, point) { + sjcl.ecc.basicKey.publicKey.apply(this, arguments); +}; + +/** specific functions for ecdsa publicKey. */ +sjcl.ecc.ecdsa.publicKey.prototype = { + /** Diffie-Hellmann function + * @param {bitArray} hash hash to verify. + * @param {bitArray} rs signature bitArray. + * @param {boolean} fakeLegacyVersion use old legacy version + */ + verify: function(hash, rs, fakeLegacyVersion) { + if (sjcl.bitArray.bitLength(hash) > this._curveBitLength) { + hash = sjcl.bitArray.clamp(hash, this._curveBitLength); + } + var w = sjcl.bitArray, + R = this._curve.r, + l = this._curveBitLength, + r = sjcl.bn.fromBits(w.bitSlice(rs,0,l)), + ss = sjcl.bn.fromBits(w.bitSlice(rs,l,2*l)), + s = fakeLegacyVersion ? ss : ss.inverseMod(R), + hG = sjcl.bn.fromBits(hash).mul(s).mod(R), + hA = r.mul(s).mod(R), + r2 = this._curve.G.mult2(hG, hA, this._point).x; + if (r.equals(0) || ss.equals(0) || r.greaterEquals(R) || ss.greaterEquals(R) || !r2.equals(r)) { + if (fakeLegacyVersion === undefined) { + return this.verify(hash, rs, true); + } else { + throw (new sjcl.exception.corrupt("signature didn't check out")); + } + } + return true; + }, + + getType: function() { + return "ecdsa"; + } +}; + +/** ecdsa secretKey +* @constructor +* @augments sjcl.ecc.basicKey.publicKey +*/ +sjcl.ecc.ecdsa.secretKey = function (curve, exponent) { + sjcl.ecc.basicKey.secretKey.apply(this, arguments); +}; + +/** specific functions for ecdsa secretKey. */ +sjcl.ecc.ecdsa.secretKey.prototype = { + /** Diffie-Hellmann function + * @param {bitArray} hash hash to sign. + * @param {int} paranoia paranoia for random number generation + * @param {boolean} fakeLegacyVersion use old legacy version + */ + sign: function(hash, paranoia, fakeLegacyVersion, fixedKForTesting) { + if (sjcl.bitArray.bitLength(hash) > this._curveBitLength) { + hash = sjcl.bitArray.clamp(hash, this._curveBitLength); + } + var R = this._curve.r, + l = R.bitLength(), + k = fixedKForTesting || sjcl.bn.random(R.sub(1), paranoia).add(1), + r = this._curve.G.mult(k).x.mod(R), + ss = sjcl.bn.fromBits(hash).add(r.mul(this._exponent)), + s = fakeLegacyVersion ? ss.inverseMod(R).mul(k).mod(R) + : ss.mul(k.inverseMod(R)).mod(R); + return sjcl.bitArray.concat(r.toBits(l), s.toBits(l)); + }, + + getType: function() { + return "ecdsa"; + } +}; +/** @fileOverview Bit array codec implementations. + * + * @author Marco Munizaga + */ + +//patch arraybuffers if they don't exist +if (typeof(ArrayBuffer) === 'undefined') { + (function(globals){ + "use strict"; + globals.ArrayBuffer = function(){}; + globals.DataView = function(){}; + }(this)); +} + +/** + * ArrayBuffer + * @namespace + */ +sjcl.codec.arrayBuffer = { + /** Convert from a bitArray to an ArrayBuffer. + * Will default to 8byte padding if padding is undefined*/ + fromBits: function (arr, padding, padding_count) { + var out, i, ol, tmp, smallest; + padding = padding==undefined ? true : padding; + padding_count = padding_count || 8; + + if (arr.length === 0) { + return new ArrayBuffer(0); + } + + ol = sjcl.bitArray.bitLength(arr)/8; + + //check to make sure the bitLength is divisible by 8, if it isn't + //we can't do anything since arraybuffers work with bytes, not bits + if ( sjcl.bitArray.bitLength(arr)%8 !== 0 ) { + throw new sjcl.exception.invalid("Invalid bit size, must be divisble by 8 to fit in an arraybuffer correctly"); + } + + if (padding && ol%padding_count !== 0){ + ol += padding_count - (ol%padding_count); + } + + + //padded temp for easy copying + tmp = new DataView(new ArrayBuffer(arr.length*4)); + for (i=0; i= width ? n : new Array(width - n.length + 1).join('0') + n; + }; + + for (var i = 0; i < stringBufferView.byteLength; i+=2) { + if (i%16 == 0) string += ('\n'+(i).toString(16)+'\t'); + string += ( pad(stringBufferView.getUint16(i).toString(16),4) + ' '); + } + + if ( typeof console === undefined ){ + console = console || {log:function(){}}; //fix for IE + } + console.log(string.toUpperCase()); + } +}; + +if(typeof module !== 'undefined' && module.exports){ + module.exports = sjcl; +} +if (typeof define === "function") { + define([], function () { + return sjcl; + }); +} +export default sjcl; diff --git a/src/blindrsa/sjcl/tsconfig.json b/src/blindrsa/sjcl/tsconfig.json new file mode 100644 index 0000000..8e2a84d --- /dev/null +++ b/src/blindrsa/sjcl/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "declaration": false, + "declarationMap": false, + "composite": false, + "sourceMap": false, + "allowJs": true + }, + "files": [ + "index.js" + ] +} diff --git a/src/blindrsa/testdata/emsa_pss_vectors.json b/src/blindrsa/testdata/emsa_pss_vectors.json new file mode 100644 index 0000000..97a2cb1 --- /dev/null +++ b/src/blindrsa/testdata/emsa_pss_vectors.json @@ -0,0 +1,5 @@ +{ + "msg": "859eef2fd78aca00308bdc471193bf55bf9d78db8f8a672b484634f3c9c26e6478ae10260fe0dd8c082e53a5293af2173cd50c6d5d354febf78b26021c25c02712e78cd4694c9f469777e451e7f8e9e04cd3739c6bbfedae487fb55644e9ca74ff77a53cb729802f6ed4a5ffa8ba159890fc", + "salt": "e3b5d5d002c1bce50c2b65ef88a188d83bce7e61", + "expected": "66e4672e836ad121ba244bed6576b867d9a447c28a6e66a5b87dee7fbc7e65af5057f86fae8984d9ba7f969ad6fe02a4d75f7445fefdd85b6d3a477c28d24ba1e3756f792dd1dce8ca94440ecb5279ecd3183a311fc896da1cb39311af37ea4a75e24bdbfd5c1da0de7cecdf1a896f9d8bc816d97cd7a2c43bad546fbe8cfebc" +} diff --git a/src/blindrsa/testdata/rsablind_vectors.json b/src/blindrsa/testdata/rsablind_vectors.json new file mode 100644 index 0000000..63ea5d4 --- /dev/null +++ b/src/blindrsa/testdata/rsablind_vectors.json @@ -0,0 +1,30 @@ +[ + { + "p": "e1f4d7a34802e27c7392a3cea32a262a34dc3691bd87f3f310dc75673488930559c120fd0410194fb8a0da55bd0b81227e843fdca6692ae80e5a5d414116d4803fca7d8c30eaaae57e44a1816ebb5c5b0606c536246c7f11985d731684150b63c9a3ad9e41b04c0b5b27cb188a692c84696b742a80d3cd00ab891f2457443dadfeba6d6daf108602be26d7071803c67105a5426838e6889d77e8474b29244cefaf418e381b312048b457d73419213063c60ee7b0d81820165864fef93523c9635c22210956e53a8d96322493ffc58d845368e2416e078e5bcb5d2fd68ae6acfa54f9627c42e84a9d3f2774017e32ebca06308a12ecc290c7cd1156dcccfb2311", + "q": "c601a9caea66dc3835827b539db9df6f6f5ae77244692780cd334a006ab353c806426b60718c05245650821d39445d3ab591ed10a7339f15d83fe13f6a3dfb20b9452c6a9b42eaa62a68c970df3cadb2139f804ad8223d56108dfde30ba7d367e9b0a7a80c4fdba2fd9dde6661fc73fc2947569d2029f2870fc02d8325acf28c9afa19ecf962daa7916e21afad09eb62fe9f1cf91b77dc879b7974b490d3ebd2e95426057f35d0a3c9f45f79ac727ab81a519a8b9285932d9b2e5ccd347e59f3f32ad9ca359115e7da008ab7406707bd0e8e185a5ed8758b5ba266e8828f8d863ae133846304a2936ad7bc7c9803879d2fc4a28e69291d73dbd799f8bc238385", + "n": "aec4d69addc70b990ea66a5e70603b6fee27aafebd08f2d94cbe1250c556e047a928d635c3f45ee9b66d1bc628a03bac9b7c3f416fe20dabea8f3d7b4bbf7f963be335d2328d67e6c13ee4a8f955e05a3283720d3e1f139c38e43e0338ad058a9495c53377fc35be64d208f89b4aa721bf7f7d3fef837be2a80e0f8adf0bcd1eec5bb040443a2b2792fdca522a7472aed74f31a1ebe1eebc1f408660a0543dfe2a850f106a617ec6685573702eaaa21a5640a5dcaf9b74e397fa3af18a2f1b7c03ba91a6336158de420d63188ee143866ee415735d155b7c2d854d795b7bc236cffd71542df34234221a0413e142d8c61355cc44d45bda94204974557ac2704cd8b593f035a5724b1adf442e78c542cd4414fce6f1298182fb6d8e53cef1adfd2e90e1e4deec52999bdc6c29144e8d52a125232c8c6d75c706ea3cc06841c7bda33568c63a6c03817f722b50fcf898237d788a4400869e44d90a3020923dc646388abcc914315215fcd1bae11b1c751fd52443aac8f601087d8d42737c18a3fa11ecd4131ecae017ae0a14acfc4ef85b83c19fed33cfd1cd629da2c4c09e222b398e18d822f77bb378dea3cb360b605e5aa58b20edc29d000a66bd177c682a17e7eb12a63ef7c2e4183e0d898f3d6bf567ba8ae84f84f1d23bf8b8e261c3729e2fa6d07b832e07cddd1d14f55325c6f924267957121902dc19b3b32948bdead5", + "e": "010001", + "d": "0d43242aefe1fb2c13fbc66e20b678c4336d20b1808c558b6e62ad16a287077180b177e1f01b12f9c6cd6c52630257ccef26a45135a990928773f3bd2fc01a313f1dac97a51cec71cb1fd7efc7adffdeb05f1fb04812c924ed7f4a8269925dad88bd7dcfbc4ef01020ebfc60cb3e04c54f981fdbd273e69a8a58b8ceb7c2d83fbcbd6f784d052201b88a9848186f2a45c0d2826870733e6fd9aa46983e0a6e82e35ca20a439c5ee7b502a9062e1066493bdadf8b49eb30d9558ed85abc7afb29b3c9bc644199654a4676681af4babcea4e6f71fe4565c9c1b85d9985b84ec1abf1a820a9bbebee0df1398aae2c85ab580a9f13e7743afd3108eb32100b870648fa6bc17e8abac4d3c99246b1f0ea9f7f93a5dd5458c56d9f3f81ff2216b3c3680a13591673c43194d8e6fc93fc1e37ce2986bd628ac48088bc723d8fbe293861ca7a9f4a73e9fa63b1b6d0074f5dea2a624c5249ff3ad811b6255b299d6bc5451ba7477f19c5a0db690c3e6476398b1483d10314afd38bbaf6e2fbdbcd62c3ca9797a420ca6034ec0a83360a3ee2adf4b9d4ba29731d131b099a38d6a23cc463db754603211260e99d19affc902c915d7854554aabf608e3ac52c19b8aa26ae042249b17b2d29669b5c859103ee53ef9bdc73ba3c6b537d5c34b6d8f034671d7f3a8a6966cc4543df223565343154140fd7391c7e7be03e241f4ecfeb877a051", + "msg": "8f3dc6fb8c4a02f4d6352edf0907822c1210a9b32f9bdda4c45a698c80023aa6b59f8cfec5fdbb36331372ebefedae7d", + "salt": "051722b35f458781397c3a671a7d3bd3096503940e4c4f1aaa269d60300ce449555cd7340100df9d46944c5356825abf", + "inv": "80682c48982407b489d53d1261b19ec8627d02b8cda5336750b8cee332ae260de57b02d72609c1e0e9f28e2040fc65b6f02d56dbd6aa9af8fde656f70495dfb723ba01173d4707a12fddac628ca29f3e32340bd8f7ddb557cf819f6b01e445ad96f874ba235584ee71f6581f62d4f43bf03f910f6510deb85e8ef06c7f09d9794a008be7ff2529f0ebb69decef646387dc767b74939265fec0223aa6d84d2a8a1cc912d5ca25b4e144ab8f6ba054b54910176d5737a2cff011da431bd5f2a0d2d66b9e70b39f4b050e45c0d9c16f02deda9ddf2d00f3e4b01037d7029cd49c2d46a8e1fc2c0c17520af1f4b5e25ba396afc4cd60c494a4c426448b35b49635b337cfb08e7c22a39b256dd032c00adddafb51a627f99a0e1704170ac1f1912e49d9db10ec04c19c58f420212973e0cb329524223a6aa56c7937c5dffdb5d966b6cd4cbc26f3201dd25c80960a1a111b32947bb78973d269fac7f5186530930ed19f68507540eed9e1bab8b00f00d8ca09b3f099aae46180e04e3584bd7ca054df18a1504b89d1d1675d0966c4ae1407be325cdf623cf13ff13e4a28b594d59e3eadbadf6136eee7a59d6a444c9eb4e2198e8a974f27a39eb63af2c9af3870488b8adaad444674f512133ad80b9220e09158521614f1faadfe8505ef57b7df6813048603f0dd04f4280177a11380fbfc861dbcbd7418d62155248dad5fdec0991f", + "encoded_msg": "6e0c464d9c2f9fbc147b43570fc4f238e0d0b38870b3addcf7a4217df912ccef17a7f629aa850f63a063925f312d61d6437be954b45025e8282f9c0b1131bc8ff19a8a928d859b37113db1064f92a27f64761c181c1e1f9b251ae5a2f8a4047573b67a270584e089beadcb13e7c82337797119712e9b849ff56e04385d144d3ca9d8d92bf78adb20b5bbeb3685f17038ec6afade3ef354429c51c687b45a7018ee3a6966b3af15c9ba8f40e6461ba0a17ef5a799672ad882bab02b518f9da7c1a962945c2e9b0f02f29b31b9cdf3e633f9d9d2a22e96e1de28e25241ca7dd04147112f578973403e0f4fd80865965475d22294f065e17a1c4a201de93bd14223e6b1b999fd548f2f759f52db71964528b6f15b9c2d7811f2a0a35d534b8216301c47f4f04f412cae142b48c4cdff78bc54df690fd43142d750c671dd8e2e938e6a440b2f825b6dbb3e19f1d7a3c0150428a47948037c322365b7fe6fe57ac88d8f80889e9ff38177bad8c8d8d98db42908b389cb59692a58ce275aa15acb032ca951b3e0a3404b7f33f655b7c7d83a2f8d1b6bbff49d5fcedf2e030e80881aa436db27a5c0dea13f32e7d460dbf01240c2320c2bb5b3225b17145c72d61d47c8f84d1e19417ebd8ce3638a82d395cc6f7050b6209d9283dc7b93fecc04f3f9e7f566829ac41568ef799480c733c09759aa9734e2013d7640dc6151018ea902bc", + "blinded_msg": "10c166c6a711e81c46f45b18e5873cc4f494f003180dd7f115585d871a28930259654fe28a54dab319cc5011204c8373b50a57b0fdc7a678bd74c523259dfe4fd5ea9f52f170e19dfa332930ad1609fc8a00902d725cfe50685c95e5b2968c9a2828a21207fcf393d15f849769e2af34ac4259d91dfd98c3a707c509e1af55647efaa31290ddf48e0133b798562af5eabd327270ac2fb6c594734ce339a14ea4fe1b9a2f81c0bc230ca523bda17ff42a377266bc2778a274c0ae5ec5a8cbbe364fcf0d2403f7ee178d77ff28b67a20c7ceec009182dbcaa9bc99b51ebbf13b7d542be337172c6474f2cd3561219fe0dfa3fb207cff89632091ab841cf38d8aa88af6891539f263adb8eac6402c41b6ebd72984e43666e537f5f5fe27b2b5aa114957e9a580730308a5f5a9c63a1eb599f093ab401d0c6003a451931b6d124180305705845060ebba6b0036154fcef3e5e9f9e4b87e8f084542fd1dd67e7782a5585150181c01eb6d90cb95883837384a5b91dbb606f266059ecc51b5acbaa280e45cfd2eec8cc1cdb1b7211c8e14805ba683f9b78824b2eb005bc8a7d7179a36c152cb87c8219e5569bba911bb32a1b923ca83de0e03fb10fba75d85c55907dda5a2606bf918b056c3808ba496a4d95532212040a5f44f37e1097f26dc27b98a51837daa78f23e532156296b64352669c94a8a855acf30533d8e0594ace7c442", + "blind_sig": "364f6a40dbfbc3bbb257943337eeff791a0f290898a6791283bba581d9eac90a6376a837241f5f73a78a5c6746e1306ba3adab6067c32ff69115734ce014d354e2f259d4cbfb890244fd451a497fe6ecf9aa90d19a2d441162f7eaa7ce3fc4e89fd4e76b7ae585be2a2c0fd6fb246b8ac8d58bcb585634e30c9168a434786fe5e0b74bfe8187b47ac091aa571ffea0a864cb906d0e28c77a00e8cd8f6aba4317a8cc7bf32ce566bd1ef80c64de041728abe087bee6cadd0b7062bde5ceef308a23bd1ccc154fd0c3a26110df6193464fc0d24ee189aea8979d722170ba945fdcce9b1b4b63349980f3a92dc2e5418c54d38a862916926b3f9ca270a8cf40dfb9772bfbdd9a3e0e0892369c18249211ba857f35963d0e05d8da98f1aa0c6bba58f47487b8f663e395091275f82941830b050b260e4767ce2fa903e75ff8970c98bfb3a08d6db91ab1746c86420ee2e909bf681cac173697135983c3594b2def673736220452fde4ddec867d40ff42dd3da36c84e3e52508b891a00f50b4f62d112edb3b6b6cc3dbd546ba10f36b03f06c0d82aeec3b25e127af545fac28e1613a0517a6095ad18a98ab79f68801e05c175e15bae21f821e80c80ab4fdec6fb34ca315e194502b8f3dcf7892b511aee45060e3994cd15e003861bc7220a2babd7b40eda03382548a34a7110f9b1779bf3ef6011361611e6bc5c0dc851e1509de1a", + "sig": "6fef8bf9bc182cd8cf7ce45c7dcf0e6f3e518ae48f06f3c670c649ac737a8b8119a34d51641785be151a697ed7825fdfece82865123445eab03eb4bb91cecf4d6951738495f8481151b62de869658573df4e50a95c17c31b52e154ae26a04067d5ecdc1592c287550bb982a5bb9c30fd53a768cee6baabb3d483e9f1e2da954c7f4cf492fe3944d2fe456c1ecaf0840369e33fb4010e6b44bb1d721840513524d8e9a3519f40d1b81ae34fb7a31ee6b7ed641cb16c2ac999004c2191de0201457523f5a4700dd649267d9286f5c1d193f1454c9f868a57816bf5ff76c838a2eeb616a3fc9976f65d4371deecfbab29362caebdff69c635fe5a2113da4d4d8c24f0b16a0584fa05e80e607c5d9a2f765f1f069f8d4da21f27c2a3b5c984b4ab24899bef46c6d9323df4862fe51ce300fca40fb539c3bb7fe2dcc9409e425f2d3b95e70e9c49c5feb6ecc9d43442c33d50003ee936845892fb8be475647da9a080f5bc7f8a716590b3745c2209fe05b17992830ce15f32c7b22cde755c8a2fe50bd814a0434130b807dc1b7218d4e85342d70695a5d7f29306f25623ad1e8aa08ef71b54b8ee447b5f64e73d09bdd6c3b7ca224058d7c67cc7551e9241688ada12d859cb7646fbd3ed8b34312f3b49d69802f0eaa11bc4211c2f7a29cd5c01ed01a39001c5856fab36228f5ee2f2e1110811872fe7c865c42ed59029c706195d52" + }, + { + "p": "ca9d82e9059fa3b145da850e0c451ff31093d819644ba29a3409393de2adfa1bcd65e8669a5c5140142c1404204edbc380d4e7a5c866c06bb2427c76b9e3d16bbfc1b1668dec219b8c59fee90b7baf557fc2feb13f2f4b30d8606d20b9928f4f588a3b34baa659b3bd1dd590c83e90e6251b5239fbbb73b12e90534a375e3f71", + "q": "c075694f69db6a07456e19eeace01b430f2d6cc6cd5495d569e242b6f5e8ded7df27e6aeea4db4e307554fb519b68279a58d9e2d25cee4b37668554eec2f2feb79246955a07bd526f02a6afedc7a3aff2b8953287fef2c4a02207ccb9f14e4612e9af3447dd3401728a8957871b759b6bbf22aa0e8271b82f32dd5a2d2550197", + "n": "98530f850dcc894d84ecfce9dec3a475bf30ec3ce4606f677ac4a6ef63f763ff64a162ef1c991d8094b5652d0d78c126b3e97d1d77eba2f833b5be9a124e003065ec2a3ea4fbc31bc283de1c7cd8a971eb57aa7284b082562ccde572b73702068a6143e6dabf886538ff419874c300a85f3d9d50f0731fc6b9c92a121fefb7911f5ea92d25b17a4f3b2883eff34a221b5c28c488e35067a8460d8fab1c405704ebfa1ca165d69cd4e425995a03a447f6cbba5d20d459707ab4a2c537a5dbd02801d7b19a03aaa9aec21d1c363996c6b9fee2cab370d501c9b67e7dc4a20eb0cdc3b24be242093b5a66119b96da0fb0ec0b1b0da0bd0b92236ece47d5c95bdca7", + "e": "010001", + "d": "6b15d18e4f8220709fe75f7226ca517ef9b7320d28dc66d54fa89a5727670f24c7a0f1857a0c6682338946a4a298e6e90788390e137553afbbe2a4297a7edd8128d61b68c8e1b96b7596f0fa0406e9308e2ba64735e344edc237c97b993411b7796721ae54d05bda1574d5af913e59e30479b373e86676cb6566f7ada0480d3ae21d50ac94c0b41c476e566d6bcdef88eeab3042ef1016527558e794b6029cff1120596fe2104fac928a66ad2fb1094d1ae1231abf95206cae7cd4e7aad388199d7ac1fe17e3f917436232cffe70e12056e02cfb9604e73cc34984bb83f7112ed197bf3a4d9f6d0c0e3c4dd8f2d9cbe17185f1e63561b08f7d14bd36112f3ea1", + "msg": "5465737420766563746f7220776974682064657465726d696e69737469632070616464696e67", + "salt": "", + "inv": "6e69972553327ee6240ce0de7146aea2243927cf9f7f52c0103367df79e3bafebfa61c2ffdc41ea397a38523654a1a806f4eebcd5fe9a2592a463f1faa26c3601f83f29141eda488f14f7c0aa82faa025e37adbe77e02e575f72f7b9d095882923476f2328dfaeb23b607d2f706c6c8ef6c2aee50ddb14e6d27e043e7dec8e5dede6844aa80b2206b6019350d37925bb8819653aa7a13bfb9cc3c95b53378f278903b5c06a10c0b3ce0aa028e9600f7b2733f0278565f9b88e9d92e039db78300170d7bbd32ce2b89ad8944167839880e3a2aeba05bf00edc8032a63e6279bf42a131ccc9bb95b8693764b27665274fb673bdfb7d69b7957ee8b64a99efbeed9", + "encoded_msg": "4021ac68705782fb7587bf24ac0528853025aa4a998db7b1a503afb5b266cbd1876710a2b0aa6e37b70fca538d42285beddd61d965c02b2162c86445873bdaf687a29bf6b2ab10fa22013cae53ff1c78969ef6c3eb069bfef339a5df788044d159678e571e50fc3fa40a30fe183348453542f258c663dc9c4b372895120ad12ff8b8ec1d37d766b2604fbf50bf9d84432a59593d21d7f379d6bf9198ea2fa90ee5abadb27eada5d6f40a2ec45aa4bb8710042beab5c6afb4381fc57012e61b3a815800e53e69fe2fdccb3b4ee51968c1ef6281d7e8fe08c4337bad73d99e947df834e5402378a66142bf032dfade7e6e2d43ae90b145055861e06eff189b63bc", + "blinded_msg": "5a631b41e7759a634cef04359436e358143ee2892fbebd072d1e5cc45475ff55b6b492e13c59979f4b968994ddca3cc068084d3b176a6132039c584707acbb9862c009fa5b63cfb7b6f6d577825c1e81ad11059cb87a524083230f906ea0a4d9db3434d49cf9f0ea52b2425db4d319f51540e5de6cfb30b86d5e5d810a284f3478f6259f054407c854303ec23c2e0989dd57aa002e56ab6287594c25154a1646060cb4f6479b07f627991f7089ac0491d5841d6461166b324b3d448b2a8071de68505503feadf7d8182d18d8b0d3b91d77b627a5ffae68f913efbbb2fc082437f845880f94f07d873bc0c0688f60033235bcc1701dcba83dca944b05227884e3", + "blind_sig": "817596a0b568088b60c29482c0178d34e0d54dc34a9375152701e4e6d5ef76c92f4281a377d8b2f438f6af4ef9c26dd38ad2cc932f90fe45d4c0a1ba10e695a1c8e797aa5023f84385904e5f378df5677b8eb7312f835f9e3a097b1b7e55fece0d00ec3f52ba26b39c91322b6404eef4e567d909195bfc0f72690805ea3f71736d7eb51e84556c5241786f5f37bf9d2a0305bf36454d9ab8b5a9f6fe03fd4ab472b5379d7e8ab92e803c7c15bf3d0234653e1f6d80d23c7f127bed7fba3d297b62fee51b8e71b04d402cf291ac87460011fd222cfd27b5669d79d1e0dcc8d911c2dc6d0edcd205a91278cc97019cfc709ce8a50297409e66f27b1299e386a6cd", + "sig": "848fc8a032ea073280a7d9146ae55bb0199cd1941c10a03cce1dc38579c4e77e87f259e250b16a9912ce2c085cb9489846f803fd6ed09bf8605c4aa8b0ebf2c938093e53ad025a48b97f7975255805118c33fa0f73ec204b9723acefacd8031ab3d9f7ebeaf996eee3678c788cea96932dd723b236355c0e6864fad2fc87b00e4eda476e90f000936b0d9fa65bf1112fc296e8aa5bb05ca7cb32dec01407e3d3ed94c1ebb0dc430ea59588ccc0995a6e2f1423dbe06c6f27650b23b12eb343b9e461ba532825e5e26572fbe723b69753c178361e7a834a566ce950df55ff97d314b384b3fa8c0098d560d4c6ba519a9b6040f908adf34f6b2d5d30c265cd0fb1" + } +] diff --git a/src/blindrsa/tsconfig.json b/src/blindrsa/tsconfig.json new file mode 100644 index 0000000..c7a48e7 --- /dev/null +++ b/src/blindrsa/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "resolveJsonModule": true + }, + "include": [ + ".", + "testdata/*.json" + ] +} diff --git a/src/blindrsa/util.test.ts b/src/blindrsa/util.test.ts new file mode 100644 index 0000000..a81df85 --- /dev/null +++ b/src/blindrsa/util.test.ts @@ -0,0 +1,21 @@ +import { emsa_pss_encode } from './util.js'; +import { jest } from '@jest/globals'; +// Test vector in file pss_test.go from: https://cs.opensource.google/go/go/+/refs/tags/go1.18.2:src/crypto/rsa/pss_test.go +// Test vector in file pss-int.txt from: ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip +import vector from './testdata/emsa_pss_vectors.json'; + +function hexToUint8(x: string): Uint8Array { + return new Uint8Array(Buffer.from(x, 'hex')); +} + +test('emsa_pss_encode', async () => { + const hash = 'SHA-1'; + const msg = hexToUint8(vector.msg); + const salt = hexToUint8(vector.salt); + const sLen = salt.length; + + jest.spyOn(crypto, 'getRandomValues').mockReturnValueOnce(salt); + + const encoded = await emsa_pss_encode(msg, 1023, { hash, sLen }); + expect(encoded).toStrictEqual(hexToUint8(vector.expected)); +}); diff --git a/src/blindrsa/util.ts b/src/blindrsa/util.ts new file mode 100644 index 0000000..58a64a9 --- /dev/null +++ b/src/blindrsa/util.ts @@ -0,0 +1,245 @@ +import sjcl from './sjcl'; + +function assertNever(name: string, x: unknown): never { + throw new Error(`unexpected ${name} identifier: ${x}`); +} + +interface HashParams { + name: string; + hLen: number; +} + +function getHashParams(hash: string): HashParams { + switch (hash) { + case 'SHA-1': + return { name: hash, hLen: 20 }; + case 'SHA-256': + return { name: hash, hLen: 32 }; + case 'SHA-384': + return { name: hash, hLen: 48 }; + case 'SHA-512': + return { name: hash, hLen: 64 }; + default: + assertNever('Hash', hash); + } +} + +export function os2ip(bytes: Uint8Array): sjcl.bn { + return sjcl.bn.fromBits(sjcl.codec.bytes.toBits(Array.from(bytes))); +} + +export function i2osp(num: sjcl.bn, byteLength: number): Uint8Array { + const bytes = new Uint8Array(byteLength); + const unpadded = new Uint8Array(sjcl.codec.arrayBuffer.fromBits(num.toBits(undefined), false)); + bytes.set(unpadded, byteLength - unpadded.length); + return bytes; +} + +export function joinAll(a: Uint8Array[]): Uint8Array { + let size = 0; + for (let i = 0; i < a.length; i++) { + size += a[i as number].length; + } + const ret = new Uint8Array(new ArrayBuffer(size)); + for (let i = 0, offset = 0; i < a.length; i++) { + ret.set(a[i as number], offset); + offset += a[i as number].length; + } + return ret; +} + +export function xor(a: Uint8Array, b: Uint8Array): Uint8Array { + if (a.length !== b.length || a.length === 0) { + throw new Error('arrays of different length'); + } + const n = a.length; + const c = new Uint8Array(n); + for (let i = 0; i < n; i++) { + c[i as number] = a[i as number] ^ b[i as number]; + } + return c; +} + +function incCounter(c: Uint8Array) { + c[3]++; + if (c[3] != 0) { + return; + } + c[2]++; + if (c[2] != 0) { + return; + } + c[1]++; + if (c[1] != 0) { + return; + } + c[0]++; +} + +type MGFFn = (h: HashParams, seed: Uint8Array, mLen: number) => Promise; + +// MGF1 (mgfSeed, maskLen) +// +// https://www.rfc-editor.org/rfc/rfc8017#appendix-B.2.1 +// +// Options: +// Hash hash function (hLen denotes the length in octets of +// the hash function output) +// +// Input: +// mgfSeed seed from which mask is generated, an octet string +// maskLen intended length in octets of the mask, at most 2^32 hLen +// +// Output: +// mask mask, an octet string of length maskLen +// +// Error: "mask too long" +async function mgf1(h: HashParams, seed: Uint8Array, mLen: number): Promise { + // 1. If maskLen > 2^32 hLen, output "mask too long" and stop. + const n = Math.ceil(mLen / h.hLen); + if (n > Math.pow(2, 32)) { + throw new Error('mask too long'); + } + + // 2. Let T be the empty octet string. + let T = new Uint8Array(); + + // 3. For counter from 0 to \ceil (maskLen / hLen) - 1, do the + // following: + const counter = new Uint8Array(4); + for (let i = 0; i < n; i++) { + // A. Convert counter to an octet string C of length 4 octets (see + // Section 4.1): + // + // C = I2OSP (counter, 4) . + // B. Concatenate the hash of the seed mgfSeed and C to the octet + // string T: + // + // T = T || Hash(mgfSeed || C) . + const hash = new Uint8Array(await crypto.subtle.digest(h.name, joinAll([seed, counter]))); + T = joinAll([T, hash]); + incCounter(counter); + } + + // 4. Output the leading maskLen octets of T as the octet string mask. + return T.subarray(0, mLen); +} + +// EMSA-PSS-ENCODE (M, emBits) +// +// https://www.rfc-editor.org/rfc/rfc3447.html#section-9.1.1 +// +// Input: +// M message to be encoded, an octet string +// emBits maximal bit length of the integer OS2IP (EM) (see Section +// 4.2), at least 8hLen + 8sLen + 9 +// MGF mask generation function +// +// Output: +// EM encoded message, an octet string of length emLen = \ceil +// (emBits/8) +// +// Errors: "encoding error"; "message too long" +export async function emsa_pss_encode( + msg: Uint8Array, + emBits: number, + opts: { + hash: string; + sLen: number; + }, + mgf: MGFFn = mgf1, +): Promise { + const { hash, sLen } = opts; + const hashParams = getHashParams(hash); + const { hLen } = hashParams; + const emLen = Math.ceil(emBits / 8); + + // 1. If the length of M is greater than the input limitation for the + // hash function (2^61 - 1 octets for SHA-1), output "message too + // long" and stop. + // + // 2. Let mHash = Hash(M), an octet string of length hLen. + const mHash = new Uint8Array(await crypto.subtle.digest(hash, msg)); + // 3. If emLen < hLen + sLen + 2, output "encoding error" and stop. + if (emLen < hLen + sLen + 2) { + throw new Error('encoding error'); + } + // 4. Generate a random octet string salt of length sLen; if sLen = 0, + // then salt is the empty string. + const salt = crypto.getRandomValues(new Uint8Array(sLen)); + // 5. Let + // M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt; + // + // M' is an octet string of length 8 + hLen + sLen with eight + // initial zero octets. + // + const mPrime = joinAll([new Uint8Array(8), mHash, salt]); + // 6. Let H = Hash(M'), an octet string of length hLen. + const h = new Uint8Array(await crypto.subtle.digest(hash, mPrime)); + // 7. Generate an octet string PS consisting of emLen - sLen - hLen - 2 + // zero octets. The length of PS may be 0. + const ps = new Uint8Array(emLen - sLen - hLen - 2); + // 8. Let DB = PS || 0x01 || salt; DB is an octet string of length + // emLen - hLen - 1. + const db = joinAll([ps, Uint8Array.of(0x01), salt]); + // 9. Let dbMask = MGF(H, emLen - hLen - 1). + const dbMask = await mgf(hashParams, h, emLen - hLen - 1); + // 10. Let maskedDB = DB \xor dbMask. + const maskedDB = xor(db, dbMask); + // 11. Set the leftmost 8emLen - emBits bits of the leftmost octet + // in maskedDB to zero. + maskedDB[0] &= 0xff >> (8 * emLen - emBits); + // 12. Let EM = maskedDB || H || 0xbc. + const em = joinAll([maskedDB, h, Uint8Array.of(0xbc)]); + + // 13. Output EM. + return em; +} + +// RSAVP1 +// https://www.rfc-editor.org/rfc/rfc3447.html#section-5.2.2 +export function rsavp1(pkS: { n: sjcl.bn; e: sjcl.bn }, s: sjcl.bn): sjcl.bn { + // 1. If the signature representative s is not between 0 and n - 1, + // output "signature representative out of range" and stop. + if (!s.greaterEquals(new sjcl.bn(0)) || s.greaterEquals(pkS.n) == 1) { + throw new Error('signature representative out of range'); + } + // 2. Let m = s^e mod n. + const m = s.powermod(pkS.e, pkS.n); + // 3. Output m. + return m; +} + +// RSASP1 +// https://www.rfc-editor.org/rfc/rfc3447.html#section-5.2.1 +export function rsasp1(skS: { n: sjcl.bn; d: sjcl.bn }, m: sjcl.bn): sjcl.bn { + // 1. If the message representative m is not between 0 and n - 1, + // output "message representative out of range" and stop. + if (!m.greaterEquals(new sjcl.bn(0)) || m.greaterEquals(skS.n) == 1) { + throw new Error('signature representative out of range'); + } + // 2. The signature representative s is computed as follows. + // + // a. If the first form (n, d) of K is used, let s = m^d mod n. + const s = m.powermod(skS.d, skS.n); + /* TODO: implement the CRT variant. + // b. If the second form (p, q, dP, dQ, qInv) and (r_i, d_i, t_i) + // of K is used, proceed as follows: + // + // i. Let s_1 = m^dP mod p and s_2 = m^dQ mod q. + // + // ii. If u > 2, let s_i = m^(d_i) mod r_i, i = 3, ..., u. + // + // iii. Let h = (s_1 - s_2) * qInv mod p. + // + // iv. Let s = s_2 + q * h. + // + // v. If u > 2, let R = r_1 and for i = 3 to u do + // + // 1. Let R = R * r_(i-1). + // 2. Let h = (s_i - s) * t_i mod r_i. + // 3. Let s = s + R * h. + */ + // 3. Output s. + return s; +} diff --git a/tsconfig.json b/tsconfig.json index 209346b..77e103a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -27,6 +27,12 @@ "files": [], "include": [], "references": [ + { + "path": "./src/blindrsa/sjcl" + }, + { + "path": "./src/blindrsa" + }, { "path": "./src/background" }, diff --git a/webpack.config.js b/webpack.config.js index 56758eb..5009a70 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -48,6 +48,24 @@ const background = { }, }; +const blindrsa = { + ...common, + entry: { + blindrsa: path.resolve('src/blindrsa/index.ts'), + }, + externals: { crypto: 'null' }, + module: { + rules: [tsloader], + }, + resolve: { + extensions: ['.tsx', '.ts', '.js'], + fallback: { + // 'buffer': buffer, + // 'stream': streamBrowserify, + }, + }, +}; + const popup = { ...common, entry: { @@ -86,4 +104,4 @@ const popup = { }; // Mutiple targets for webpack: https://webpack.js.org/concepts/targets/#multiple-targets -export default [background, popup]; +export default [blindrsa, background, popup];