mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-05 05:15:48 +00:00
Compare commits
107 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1305acb849 | ||
|
|
1e1e70d9a6 | ||
|
|
8640176a07 | ||
|
|
e49838437e | ||
|
|
7c5e9bae2a | ||
|
|
08a2d771cd | ||
|
|
c06c74e460 | ||
|
|
78b1e4f570 | ||
|
|
815e2af3cf | ||
|
|
5bc1603f43 | ||
|
|
c48bf4089c | ||
|
|
fd67ea3036 | ||
|
|
006d1fadce | ||
|
|
a1206f6e3f | ||
|
|
be2d647d48 | ||
|
|
9d863c4dfa | ||
|
|
6bb9f9e5e4 | ||
|
|
f69ad8b172 | ||
|
|
6e2170156d | ||
|
|
a8a760fc41 | ||
|
|
8e54231a6c | ||
|
|
78fdd6bae7 | ||
|
|
89a8e6c362 | ||
|
|
03a6583032 | ||
|
|
09e190c822 | ||
|
|
d08e06ad53 | ||
|
|
1f40bb7ea8 | ||
|
|
3e1e62c03a | ||
|
|
6bc2493d8d | ||
|
|
0d00a30d19 | ||
|
|
c70e8dcf01 | ||
|
|
06c3a87929 | ||
|
|
5b11795dc3 | ||
|
|
9a6d4adfbe | ||
|
|
913df130e8 | ||
|
|
1222599c6c | ||
|
|
b51d677145 | ||
|
|
4eb516e072 | ||
|
|
451e6f9b86 | ||
|
|
151a4fa1c0 | ||
|
|
a025c187cb | ||
|
|
9550edab9b | ||
|
|
9ec72ee8c5 | ||
|
|
d93145fc1e | ||
|
|
087f357714 | ||
|
|
0fcce464bb | ||
|
|
44bb8658f0 | ||
|
|
be6bd8cc5d | ||
|
|
3812ac7d53 | ||
|
|
6e36ded34f | ||
|
|
07d33d817b | ||
|
|
28f7b483a8 | ||
|
|
722ff4dc5c | ||
|
|
13b7c9bfbb | ||
|
|
daaac98bef | ||
|
|
84e79abbaa | ||
|
|
2a340d09a4 | ||
|
|
db5c3f1bf2 | ||
|
|
705a9ad087 | ||
|
|
fa1a4a0307 | ||
|
|
ce1338cf20 | ||
|
|
28408bfa24 | ||
|
|
dc290f69ec | ||
|
|
dde93f5e8d | ||
|
|
d862d17770 | ||
|
|
58ca70ee1c | ||
|
|
ed1bc7fb25 | ||
|
|
7cb9787424 | ||
|
|
be78db1563 | ||
|
|
9dd337a16c | ||
|
|
c2b03e9d93 | ||
|
|
75d3a4f827 | ||
|
|
c2ad23996d | ||
|
|
348615671a | ||
|
|
6704120105 | ||
|
|
45a3ac3f66 | ||
|
|
5a1b9d1f90 | ||
|
|
355a2b076b | ||
|
|
82224de494 | ||
|
|
8a1c5a7b66 | ||
|
|
8feaae0e2d | ||
|
|
a0e1c07425 | ||
|
|
514dff0e2c | ||
|
|
10c883e432 | ||
|
|
b0c8d67d27 | ||
|
|
6601edadb2 | ||
|
|
9de7b285f0 | ||
|
|
c8471e5d11 | ||
|
|
8ff5f6022a | ||
|
|
3a4cd93629 | ||
|
|
ba2f290100 | ||
|
|
337bb03a00 | ||
|
|
b651bc80f9 | ||
|
|
b3c96419d4 | ||
|
|
a813b0cc9d | ||
|
|
a22de5e84a | ||
|
|
44d1f1457b | ||
|
|
22a954deed | ||
|
|
bad52779e3 | ||
|
|
8073fc7979 | ||
|
|
c7a464b0e2 | ||
|
|
34d8a77bc0 | ||
|
|
498e7df622 | ||
|
|
60587b59ee | ||
|
|
d1c1ac7fbb | ||
|
|
0622cc9766 | ||
|
|
20032e073f |
10
.gitmodules
vendored
10
.gitmodules
vendored
@@ -1,10 +0,0 @@
|
||||
[submodule "src/js/cryptojs"]
|
||||
path = src/js/cryptojs
|
||||
url = git://github.com/gwjjeff/cryptojs.git
|
||||
[submodule "src/js/sjcl"]
|
||||
path = src/js/sjcl
|
||||
url = git://github.com/bitwiseshiftleft/sjcl.git
|
||||
ignore = dirty
|
||||
[submodule "src/cpp/leveldb"]
|
||||
path = src/cpp/leveldb
|
||||
url = https://code.google.com/p/leveldb/
|
||||
2
.npmignore
Normal file
2
.npmignore
Normal file
@@ -0,0 +1,2 @@
|
||||
build
|
||||
deploy
|
||||
@@ -1,8 +1,11 @@
|
||||
module.exports = function(grunt) {
|
||||
grunt.loadNpmTasks('grunt-webpack');
|
||||
grunt.loadNpmTasks('grunt-dox');
|
||||
grunt.loadNpmTasks('grunt-contrib-concat');
|
||||
grunt.loadNpmTasks('grunt-contrib-watch');
|
||||
|
||||
grunt.initConfig({
|
||||
pkg: '<json:package.json>',
|
||||
pkg: grunt.file.readJSON('package.json'),
|
||||
meta: {
|
||||
banner: '/*! <%= pkg.name %> - v<%= pkg.version %> - ' +
|
||||
'<%= grunt.template.today("yyyy-mm-dd") %>\n' +
|
||||
@@ -43,39 +46,55 @@ module.exports = function(grunt) {
|
||||
}
|
||||
},
|
||||
webpack: {
|
||||
options: {
|
||||
entry: "./src/js/ripple/index.js",
|
||||
output: {
|
||||
library: "ripple"
|
||||
}
|
||||
},
|
||||
lib: {
|
||||
src: "src/js/index.js",
|
||||
dest: "build/ripple-<%= pkg.version %>.js",
|
||||
libary: "ripple", // misspelling fixed in later versions of webpack
|
||||
library: "ripple"
|
||||
output: {
|
||||
filename: "build/ripple-<%= pkg.version %>.js"
|
||||
}
|
||||
},
|
||||
lib_debug: {
|
||||
src: "src/js/index.js",
|
||||
dest: "build/ripple-<%= pkg.version %>-debug.js",
|
||||
libary: "ripple", // misspelling fixed in later versions of webpack
|
||||
library: "ripple",
|
||||
debug: true
|
||||
output: {
|
||||
filename: "build/ripple-<%= pkg.version %>-debug.js"
|
||||
},
|
||||
debug: true,
|
||||
devtool: 'eval'
|
||||
},
|
||||
lib_min: {
|
||||
src: "src/js/index.js",
|
||||
dest: "build/ripple-<%= pkg.version %>-min.js",
|
||||
libary: "ripple", // misspelling fixed in later versions of webpack
|
||||
library: "ripple",
|
||||
minimize: true
|
||||
output: {
|
||||
filename: "build/ripple-<%= pkg.version %>-min.js"
|
||||
},
|
||||
optimize: {
|
||||
minimize: true
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
sjcl: {
|
||||
files: ['<config:concat.sjcl.src>'],
|
||||
files: ['<%= concat.sjcl.src %>'],
|
||||
tasks: 'concat:sjcl'
|
||||
},
|
||||
lib: {
|
||||
files: 'src/js/*.js',
|
||||
tasks: 'webpack'
|
||||
}
|
||||
},
|
||||
dox: {
|
||||
libdocs: {
|
||||
options: {
|
||||
title: "Test"
|
||||
},
|
||||
src: ['src/js/ripple/'],
|
||||
dest: 'build/docs'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Tasks
|
||||
grunt.registerTask('default', 'concat:sjcl webpack');
|
||||
grunt.registerTask('default', ['concat:sjcl', 'webpack']);
|
||||
|
||||
};
|
||||
118
README.md
118
README.md
@@ -3,9 +3,121 @@ Ripple JavaScript Library - ripple-lib
|
||||
|
||||
This library can connect to the Ripple network via the WebSocket protocol and runs in Node.js as well as in the browser.
|
||||
|
||||
Build instructions:
|
||||
* https://ripple.com/wiki/Ripple_JavaScript_library
|
||||
|
||||
For more information:
|
||||
* https://ripple.com
|
||||
* https://ripple.com/wiki
|
||||
|
||||
##Initializing a remote connection
|
||||
|
||||
[ripple-lib.remote](https://github.com/ripple/ripple-lib/blob/develop/src/js/ripple/remote.js) is responsible for managing connections to rippled servers.
|
||||
|
||||
```js
|
||||
var Remote = require('ripple-lib').Remote;
|
||||
|
||||
var remote = new Remote({
|
||||
trusted: false,
|
||||
servers: [
|
||||
{
|
||||
host: ''
|
||||
, port: 1111,
|
||||
, secure: true
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
remote.connect();
|
||||
```
|
||||
|
||||
Once a connection is formed to any of the supplied servers, a `connect` event is emitted, indicating that the remote is ready to begin fulfilling requests. When there are no more connected servers to fulfill requests, a `disconnect` event is emitted. If you send requests before ripple-lib is connected to any servers, requests are deferred until the `connect` event is received.
|
||||
|
||||
```js
|
||||
var remote = new Remote({ /* options */ }).connect();
|
||||
remote.request_server_info(function(err, info) { }); // will defer until connected
|
||||
```
|
||||
|
||||
##Remote functions
|
||||
|
||||
Each remote function returns a `Request` object. is object is an `EventEmitter`. You may listen for success or failure events from each request, or provide a callback. Example:
|
||||
|
||||
```js
|
||||
var request = remote.request_server_info();
|
||||
request.on('success', function(res) {
|
||||
//handle success conditions
|
||||
});
|
||||
request.on('error', function(err) {
|
||||
//handle error conditions
|
||||
});
|
||||
request.request();
|
||||
```
|
||||
|
||||
Or:
|
||||
|
||||
```js
|
||||
remote.request_server_info(function(err, res) {
|
||||
|
||||
});
|
||||
```
|
||||
|
||||
**request_server_info([callback])**
|
||||
|
||||
**request_ledger(ledger, [opts], [callback])**
|
||||
|
||||
**request_ledger_hash([callback])**
|
||||
|
||||
**request_ledger_header([callback])**
|
||||
|
||||
**request_ledger_current([callback])**
|
||||
|
||||
**request_ledger_entry(type, [callback])**
|
||||
|
||||
**request_subscribe(streams, [callback])**
|
||||
|
||||
**request_unsubscribe(streams, [callback])**
|
||||
|
||||
**request_transaction_entry(hash, [callback])**
|
||||
|
||||
**request_tx(hash, [callback])**
|
||||
|
||||
**request_account_info(accountID, [callback])**
|
||||
|
||||
**request_account_lines(accountID, account_index, current, [callback])**
|
||||
|
||||
**request_account_offers(accountID, account_index, current, [callback])**
|
||||
|
||||
**request_account_tx(opts, [callback])**
|
||||
|
||||
**request_book_offers(gets, pays, taker, [callback])**
|
||||
|
||||
**request_wallet_accounts(seed, [callback])**
|
||||
|
||||
+ requires trusted **remote
|
||||
|
||||
**request_sign(secret, tx_json, [callback])**
|
||||
|
||||
+ requires trusted **remote
|
||||
|
||||
**request_submit([callback])**
|
||||
|
||||
**request_account_balance(account, current, [callback])**
|
||||
|
||||
**request_account_flags(account, current, [callback])**
|
||||
|
||||
**request_owner_count(account, current, [callback])**
|
||||
|
||||
**request_ripple_balance(account, issuer, currency, current, [callback])**
|
||||
|
||||
**request_ripple_path_find(src_account, dst_account, dst_amount, src_currencies, [callback])**
|
||||
|
||||
**request_unl_list([callback])**
|
||||
|
||||
**request_unl_add(addr, comment, [callback])**
|
||||
|
||||
**request_unl_delete(node, [callback])**
|
||||
|
||||
**request_peers([callback])**
|
||||
|
||||
**request_connect(ip, port, [callback])**
|
||||
|
||||
**transaction()**
|
||||
|
||||
+ returns a [Transaction](https://github.com/ripple/ripple-lib/blob/develop/src/js/ripple/transaction.js) object
|
||||
|
||||
65
bin/rsign.js
Executable file
65
bin/rsign.js
Executable file
@@ -0,0 +1,65 @@
|
||||
#!/usr/bin/node
|
||||
|
||||
var Transaction = require('../src/js/ripple/transaction').Transaction;
|
||||
|
||||
var cursor = 2;
|
||||
var verbose;
|
||||
var secret;
|
||||
var tx_json;
|
||||
|
||||
var usage = function () {
|
||||
console.log(
|
||||
"Usage: rsign.js <secret> <json>\n"
|
||||
+ " Example: rsign.js ssq55ueDob4yV3kPVnNQLHB6icwpC '{ \"TransactionType\" : \"Payment\", \"Account\" : \"r3P9vH81KBayazSTrQj6S25jW6kDb779Gi\", \"Destination\" : \"r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV\", \"Amount\" : \"200000000\", \"Fee\" : \"10\", \"Sequence\" : \"1\" }'"
|
||||
);
|
||||
};
|
||||
|
||||
if (process.argv.length > cursor && process.argv[cursor] === "-v")
|
||||
{
|
||||
verbose = true;
|
||||
cursor++;
|
||||
}
|
||||
|
||||
if (process.argv.length > cursor)
|
||||
{
|
||||
secret = process.argv[cursor++];
|
||||
}
|
||||
|
||||
if (process.argv.length > cursor)
|
||||
{
|
||||
tx_json = JSON.parse(process.argv[cursor++]);
|
||||
}
|
||||
|
||||
if (process.argv.length !== cursor || !secret || !tx_json)
|
||||
{
|
||||
usage();
|
||||
}
|
||||
else
|
||||
{
|
||||
var tx = new Transaction();
|
||||
|
||||
tx.tx_json = tx_json;
|
||||
tx._secret = secret;
|
||||
tx.complete();
|
||||
|
||||
var unsigned = tx.serialize().to_hex();
|
||||
tx.sign();
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
var sim = {};
|
||||
|
||||
sim.tx_blob = tx.serialize().to_hex();
|
||||
sim.tx_json = tx.tx_json;
|
||||
sim.tx_signing_hash = tx.signing_hash().to_hex();
|
||||
sim.tx_unsigned = unsigned;
|
||||
|
||||
console.log(JSON.stringify(sim, undefined, 2));
|
||||
}
|
||||
else
|
||||
{
|
||||
console.log(tx.serialize().to_hex());
|
||||
}
|
||||
}
|
||||
|
||||
// vim:sw=2:sts=2:ts=8:et
|
||||
40
package.json
40
package.json
@@ -1,38 +1,42 @@
|
||||
{
|
||||
"name": "ripple-lib",
|
||||
"version": "0.7.11",
|
||||
"version": "0.7.19",
|
||||
"description": "Ripple JavaScript client library",
|
||||
|
||||
"files": [
|
||||
"src/js/*.js",
|
||||
"src/js/ripple/*.js",
|
||||
"build/sjcl.js",
|
||||
"bin/rsign.js"
|
||||
],
|
||||
"main": "src/js",
|
||||
"main": "src/js/ripple",
|
||||
"directories": {
|
||||
"test": "test"
|
||||
},
|
||||
|
||||
"dependencies": {
|
||||
"async": "~0.1.22",
|
||||
"ws": "~0.4.22",
|
||||
"extend": "~1.1.1",
|
||||
"simple-jsonrpc": "~0.0.1"
|
||||
"async": "~0.2.9",
|
||||
"ws": "~0.4.27",
|
||||
"extend": "~1.1.3",
|
||||
"simple-jsonrpc": "~0.0.2",
|
||||
"jshint-loader": "~0.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"grunt": "~0.3.17",
|
||||
"buster": "~0.6.2",
|
||||
"grunt-webpack": "~0.4.0"
|
||||
"grunt": "~0.4.1",
|
||||
"grunt-cli": "~0.1.9",
|
||||
"grunt-contrib-concat": "~0.3.0",
|
||||
"grunt-contrib-watch": "~0.4.4",
|
||||
"grunt-webpack": "~0.10.5",
|
||||
"grunt-dox": "~0.5.0",
|
||||
"buster": "~0.6.12"
|
||||
},
|
||||
|
||||
"scripts": {
|
||||
"test": "buster test"
|
||||
"test": "node_modules/buster/bin/buster-test",
|
||||
"build": "node_modules/.bin/grunt"
|
||||
},
|
||||
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/jedmccaleb/NewCoin.git"
|
||||
"url": "git://github.com/rippleFoundation/ripple-lib.git"
|
||||
},
|
||||
|
||||
"readmeFilename": "README.md"
|
||||
"readmeFilename": "README.md",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
}
|
||||
|
||||
126
src/cpp/TransactionErr.cpp
Normal file
126
src/cpp/TransactionErr.cpp
Normal file
@@ -0,0 +1,126 @@
|
||||
#include "TransactionErr.h"
|
||||
#include "utils.h"
|
||||
|
||||
bool transResultInfo(TER terCode, std::string& strToken, std::string& strHuman)
|
||||
{
|
||||
static struct {
|
||||
TER terCode;
|
||||
const char* cpToken;
|
||||
const char* cpHuman;
|
||||
} transResultInfoA[] = {
|
||||
{ tecCLAIM, "tecCLAIM", "Fee claimed. Sequence used. No action." },
|
||||
{ tecDIR_FULL, "tecDIR_FULL", "Can not add entry to full directory." },
|
||||
{ tecFAILED_PROCESSING, "tecFAILED_PROCESSING", "Failed to correctly process transaction." },
|
||||
{ tecINSUF_RESERVE_LINE, "tecINSUF_RESERVE_LINE", "Insufficient reserve to add trust line." },
|
||||
{ tecINSUF_RESERVE_OFFER, "tecINSUF_RESERVE_OFFER", "Insufficient reserve to create offer." },
|
||||
{ tecNO_DST, "tecNO_DST", "Destination does not exist. Send XRP to create it." },
|
||||
{ tecNO_DST_INSUF_XRP, "tecNO_DST_INSUF_XRP", "Destination does not exist. Too little XRP sent to create it." },
|
||||
{ tecNO_LINE_INSUF_RESERVE, "tecNO_LINE_INSUF_RESERVE", "No such line. Too little reserve to create it." },
|
||||
{ tecNO_LINE_REDUNDANT, "tecNO_LINE_REDUNDANT", "Can't set non-existant line to default." },
|
||||
{ tecPATH_DRY, "tecPATH_DRY", "Path could not send partial amount." },
|
||||
{ tecPATH_PARTIAL, "tecPATH_PARTIAL", "Path could not send full amount." },
|
||||
|
||||
{ tecUNFUNDED, "tecUNFUNDED", "One of _ADD, _OFFER, or _SEND. Deprecated." },
|
||||
{ tecUNFUNDED_ADD, "tecUNFUNDED_ADD", "Insufficient XRP balance for WalletAdd." },
|
||||
{ tecUNFUNDED_OFFER, "tecUNFUNDED_OFFER", "Insufficient balance to fund created offer." },
|
||||
{ tecUNFUNDED_PAYMENT, "tecUNFUNDED_PAYMENT", "Insufficient XRP balance to send." },
|
||||
|
||||
{ tefFAILURE, "tefFAILURE", "Failed to apply." },
|
||||
{ tefALREADY, "tefALREADY", "The exact transaction was already in this ledger." },
|
||||
{ tefBAD_ADD_AUTH, "tefBAD_ADD_AUTH", "Not authorized to add account." },
|
||||
{ tefBAD_AUTH, "tefBAD_AUTH", "Transaction's public key is not authorized." },
|
||||
{ tefBAD_CLAIM_ID, "tefBAD_CLAIM_ID", "Malformed: Bad claim id." },
|
||||
{ tefBAD_GEN_AUTH, "tefBAD_GEN_AUTH", "Not authorized to claim generator." },
|
||||
{ tefBAD_LEDGER, "tefBAD_LEDGER", "Ledger in unexpected state." },
|
||||
{ tefCLAIMED, "tefCLAIMED", "Can not claim a previously claimed account." },
|
||||
{ tefCREATED, "tefCREATED", "Can't add an already created account." },
|
||||
{ tefDST_TAG_NEEDED, "tefDST_TAG_NEEDED", "Destination tag required." },
|
||||
{ tefEXCEPTION, "tefEXCEPTION", "Unexpected program state." },
|
||||
{ tefGEN_IN_USE, "tefGEN_IN_USE", "Generator already in use." },
|
||||
{ tefINTERNAL, "tefINTERNAL", "Internal error." },
|
||||
{ tefNO_AUTH_REQUIRED, "tefNO_AUTH_REQUIRED", "Auth is not required." },
|
||||
{ tefPAST_SEQ, "tefPAST_SEQ", "This sequence number has already past." },
|
||||
|
||||
{ telLOCAL_ERROR, "telLOCAL_ERROR", "Local failure." },
|
||||
{ telBAD_DOMAIN, "telBAD_DOMAIN", "Domain too long." },
|
||||
{ telBAD_PATH_COUNT, "telBAD_PATH_COUNT", "Malformed: Too many paths." },
|
||||
{ telBAD_PUBLIC_KEY, "telBAD_PUBLIC_KEY", "Public key too long." },
|
||||
{ telFAILED_PROCESSING, "telFAILED_PROCESSING", "Failed to correctly process transaction." },
|
||||
{ telINSUF_FEE_P, "telINSUF_FEE_P", "Fee insufficient." },
|
||||
{ telNO_DST_PARTIAL, "telNO_DST_PARTIAL", "Partial payment to create account not allowed." },
|
||||
|
||||
{ temMALFORMED, "temMALFORMED", "Malformed transaction." },
|
||||
{ temBAD_AMOUNT, "temBAD_AMOUNT", "Can only send positive amounts." },
|
||||
{ temBAD_AUTH_MASTER, "temBAD_AUTH_MASTER", "Auth for unclaimed account needs correct master key." },
|
||||
{ temBAD_CURRENCY, "temBAD_CURRENCY", "Malformed: Bad currency." },
|
||||
{ temBAD_FEE, "temBAD_FEE", "Invalid fee, negative or not XRP." },
|
||||
{ temBAD_EXPIRATION, "temBAD_EXPIRATION", "Malformed: Bad expiration." },
|
||||
{ temBAD_ISSUER, "temBAD_ISSUER", "Malformed: Bad issuer." },
|
||||
{ temBAD_LIMIT, "temBAD_LIMIT", "Limits must be non-negative." },
|
||||
{ temBAD_OFFER, "temBAD_OFFER", "Malformed: Bad offer." },
|
||||
{ temBAD_PATH, "temBAD_PATH", "Malformed: Bad path." },
|
||||
{ temBAD_PATH_LOOP, "temBAD_PATH_LOOP", "Malformed: Loop in path." },
|
||||
{ temBAD_PUBLISH, "temBAD_PUBLISH", "Malformed: Bad publish." },
|
||||
{ temBAD_SIGNATURE, "temBAD_SIGNATURE", "Malformed: Bad signature." },
|
||||
{ temBAD_SRC_ACCOUNT, "temBAD_SRC_ACCOUNT", "Malformed: Bad source account." },
|
||||
{ temBAD_TRANSFER_RATE, "temBAD_TRANSFER_RATE", "Malformed: Transfer rate must be >= 1.0" },
|
||||
{ temBAD_SEQUENCE, "temBAD_SEQUENCE", "Malformed: Sequence is not in the past." },
|
||||
{ temBAD_SEND_XRP_LIMIT, "temBAD_SEND_XRP_LIMIT", "Malformed: Limit quality is not allowed for XRP to XRP." },
|
||||
{ temBAD_SEND_XRP_MAX, "temBAD_SEND_XRP_MAX", "Malformed: Send max is not allowed for XRP to XRP." },
|
||||
{ temBAD_SEND_XRP_NO_DIRECT, "temBAD_SEND_XRP_NO_DIRECT", "Malformed: No Ripple direct is not allowed for XRP to XRP." },
|
||||
{ temBAD_SEND_XRP_PARTIAL, "temBAD_SEND_XRP_PARTIAL", "Malformed: Partial payment is not allowed for XRP to XRP." },
|
||||
{ temBAD_SEND_XRP_PATHS, "temBAD_SEND_XRP_PATHS", "Malformed: Paths are not allowed for XRP to XRP." },
|
||||
{ temDST_IS_SRC, "temDST_IS_SRC", "Destination may not be source." },
|
||||
{ temDST_NEEDED, "temDST_NEEDED", "Destination not specified." },
|
||||
{ temINVALID, "temINVALID", "The transaction is ill-formed." },
|
||||
{ temINVALID_FLAG, "temINVALID_FLAG", "The transaction has an invalid flag." },
|
||||
{ temREDUNDANT, "temREDUNDANT", "Sends same currency to self." },
|
||||
{ temREDUNDANT_SEND_MAX, "temREDUNDANT_SEND_MAX", "Send max is redundant." },
|
||||
{ temRIPPLE_EMPTY, "temRIPPLE_EMPTY", "PathSet with no paths." },
|
||||
{ temUNCERTAIN, "temUNCERTAIN", "In process of determining result. Never returned." },
|
||||
{ temUNKNOWN, "temUNKNOWN", "The transactions requires logic not implemented yet." },
|
||||
|
||||
{ terRETRY, "terRETRY", "Retry transaction." },
|
||||
{ terFUNDS_SPENT, "terFUNDS_SPENT", "Can't set password, password set funds already spent." },
|
||||
{ terINSUF_FEE_B, "terINSUF_FEE_B", "Account balance can't pay fee." },
|
||||
{ terLAST, "terLAST", "Process last." },
|
||||
{ terNO_ACCOUNT, "terNO_ACCOUNT", "The source account does not exist." },
|
||||
{ terNO_AUTH, "terNO_AUTH", "Not authorized to hold IOUs." },
|
||||
{ terNO_LINE, "terNO_LINE", "No such line." },
|
||||
{ terPRE_SEQ, "terPRE_SEQ", "Missing/inapplicable prior transaction." },
|
||||
{ terOWNERS, "terOWNERS", "Non-zero owner count." },
|
||||
|
||||
{ tesSUCCESS, "tesSUCCESS", "The transaction was applied." },
|
||||
};
|
||||
|
||||
int iIndex = NUMBER(transResultInfoA);
|
||||
|
||||
while (iIndex-- && transResultInfoA[iIndex].terCode != terCode)
|
||||
;
|
||||
|
||||
if (iIndex >= 0)
|
||||
{
|
||||
strToken = transResultInfoA[iIndex].cpToken;
|
||||
strHuman = transResultInfoA[iIndex].cpHuman;
|
||||
}
|
||||
|
||||
return iIndex >= 0;
|
||||
}
|
||||
|
||||
std::string transToken(TER terCode)
|
||||
{
|
||||
std::string strToken;
|
||||
std::string strHuman;
|
||||
|
||||
return transResultInfo(terCode, strToken, strHuman) ? strToken : "-";
|
||||
}
|
||||
|
||||
std::string transHuman(TER terCode)
|
||||
{
|
||||
std::string strToken;
|
||||
std::string strHuman;
|
||||
|
||||
return transResultInfo(terCode, strToken, strHuman) ? strHuman : "-";
|
||||
}
|
||||
|
||||
// vim:ts=4
|
||||
153
src/cpp/TransactionErr.h
Normal file
153
src/cpp/TransactionErr.h
Normal file
@@ -0,0 +1,153 @@
|
||||
#ifndef _TRANSACTION_ERR_
|
||||
#define _TRANSACTION_ERR_
|
||||
|
||||
#include <string>
|
||||
|
||||
enum TER // aka TransactionEngineResult
|
||||
{
|
||||
// Note: Range is stable. Exact numbers are currently unstable. Use tokens.
|
||||
|
||||
// -399 .. -300: L Local error (transaction fee inadequate, exceeds local limit)
|
||||
// Only valid during non-consensus processing.
|
||||
// Implications:
|
||||
// - Not forwarded
|
||||
// - No fee check
|
||||
telLOCAL_ERROR = -399,
|
||||
telBAD_DOMAIN,
|
||||
telBAD_PATH_COUNT,
|
||||
telBAD_PUBLIC_KEY,
|
||||
telFAILED_PROCESSING,
|
||||
telINSUF_FEE_P,
|
||||
telNO_DST_PARTIAL,
|
||||
|
||||
// -299 .. -200: M Malformed (bad signature)
|
||||
// Causes:
|
||||
// - Transaction corrupt.
|
||||
// Implications:
|
||||
// - Not applied
|
||||
// - Not forwarded
|
||||
// - Reject
|
||||
// - Can not succeed in any imagined ledger.
|
||||
temMALFORMED = -299,
|
||||
temBAD_AMOUNT,
|
||||
temBAD_AUTH_MASTER,
|
||||
temBAD_CURRENCY,
|
||||
temBAD_FEE,
|
||||
temBAD_EXPIRATION,
|
||||
temBAD_ISSUER,
|
||||
temBAD_LIMIT,
|
||||
temBAD_OFFER,
|
||||
temBAD_PATH,
|
||||
temBAD_PATH_LOOP,
|
||||
temBAD_PUBLISH,
|
||||
temBAD_TRANSFER_RATE,
|
||||
temBAD_SEND_XRP_LIMIT,
|
||||
temBAD_SEND_XRP_MAX,
|
||||
temBAD_SEND_XRP_NO_DIRECT,
|
||||
temBAD_SEND_XRP_PARTIAL,
|
||||
temBAD_SEND_XRP_PATHS,
|
||||
temBAD_SIGNATURE,
|
||||
temBAD_SRC_ACCOUNT,
|
||||
temBAD_SEQUENCE,
|
||||
temDST_IS_SRC,
|
||||
temDST_NEEDED,
|
||||
temINVALID,
|
||||
temINVALID_FLAG,
|
||||
temREDUNDANT,
|
||||
temREDUNDANT_SEND_MAX,
|
||||
temRIPPLE_EMPTY,
|
||||
temUNCERTAIN, // An intermediate result used internally, should never be returned.
|
||||
temUNKNOWN,
|
||||
|
||||
// -199 .. -100: F Failure (sequence number previously used)
|
||||
// Causes:
|
||||
// - Transaction cannot succeed because of ledger state.
|
||||
// - Unexpected ledger state.
|
||||
// - C++ exception.
|
||||
// Implications:
|
||||
// - Not applied
|
||||
// - Not forwarded
|
||||
// - Could succeed in an imagined ledger.
|
||||
tefFAILURE = -199,
|
||||
tefALREADY,
|
||||
tefBAD_ADD_AUTH,
|
||||
tefBAD_AUTH,
|
||||
tefBAD_CLAIM_ID,
|
||||
tefBAD_GEN_AUTH,
|
||||
tefBAD_LEDGER,
|
||||
tefCLAIMED,
|
||||
tefCREATED,
|
||||
tefDST_TAG_NEEDED,
|
||||
tefEXCEPTION,
|
||||
tefGEN_IN_USE,
|
||||
tefINTERNAL,
|
||||
tefNO_AUTH_REQUIRED, // Can't set auth if auth is not required.
|
||||
tefPAST_SEQ,
|
||||
|
||||
// -99 .. -1: R Retry (sequence too high, no funds for txn fee, originating account non-existent)
|
||||
// Causes:
|
||||
// - Prior application of another, possibly non-existant, another transaction could allow this transaction to succeed.
|
||||
// Implications:
|
||||
// - Not applied
|
||||
// - Not forwarded
|
||||
// - Might succeed later
|
||||
// - Hold
|
||||
// - Makes hole in sequence which jams transactions.
|
||||
terRETRY = -99,
|
||||
terFUNDS_SPENT, // This is a free transaction, therefore don't burden network.
|
||||
terINSUF_FEE_B, // Can't pay fee, therefore don't burden network.
|
||||
terNO_ACCOUNT, // Can't pay fee, therefore don't burden network.
|
||||
terNO_AUTH, // Not authorized to hold IOUs.
|
||||
terNO_LINE, // Internal flag.
|
||||
terOWNERS, // Can't succeed with non-zero owner count.
|
||||
terPRE_SEQ, // Can't pay fee, no point in forwarding, therefore don't burden network.
|
||||
terLAST, // Process after all other transactions
|
||||
|
||||
// 0: S Success (success)
|
||||
// Causes:
|
||||
// - Success.
|
||||
// Implications:
|
||||
// - Applied
|
||||
// - Forwarded
|
||||
tesSUCCESS = 0,
|
||||
|
||||
// 100 .. 129 C Claim fee only (ripple transaction with no good paths, pay to non-existent account, no path)
|
||||
// Causes:
|
||||
// - Success, but does not achieve optimal result.
|
||||
// - Invalid transaction or no effect, but claim fee to use the sequence number.
|
||||
// Implications:
|
||||
// - Applied
|
||||
// - Forwarded
|
||||
// Only allowed as a return code of appliedTransaction when !tapRetry. Otherwise, treated as terRETRY.
|
||||
//
|
||||
// DO NOT CHANGE THESE NUMBERS: They appear in ledger meta data.
|
||||
tecCLAIM = 100,
|
||||
tecPATH_PARTIAL = 101,
|
||||
tecUNFUNDED_ADD = 102,
|
||||
tecUNFUNDED_OFFER = 103,
|
||||
tecUNFUNDED_PAYMENT = 104,
|
||||
tecFAILED_PROCESSING = 105,
|
||||
tecDIR_FULL = 121,
|
||||
tecINSUF_RESERVE_LINE = 122,
|
||||
tecINSUF_RESERVE_OFFER = 123,
|
||||
tecNO_DST = 124,
|
||||
tecNO_DST_INSUF_XRP = 125,
|
||||
tecNO_LINE_INSUF_RESERVE = 126,
|
||||
tecNO_LINE_REDUNDANT = 127,
|
||||
tecPATH_DRY = 128,
|
||||
tecUNFUNDED = 129, // Deprecated, old ambiguous unfunded.
|
||||
};
|
||||
|
||||
#define isTelLocal(x) ((x) >= telLOCAL_ERROR && (x) < temMALFORMED)
|
||||
#define isTemMalformed(x) ((x) >= temMALFORMED && (x) < tefFAILURE)
|
||||
#define isTefFailure(x) ((x) >= tefFAILURE && (x) < terRETRY)
|
||||
#define isTerRetry(x) ((x) >= terRETRY && (x) < tesSUCCESS)
|
||||
#define isTesSuccess(x) ((x) == tesSUCCESS)
|
||||
#define isTecClaim(x) ((x) >= tecCLAIM)
|
||||
|
||||
bool transResultInfo(TER terCode, std::string& strToken, std::string& strHuman);
|
||||
std::string transToken(TER terCode);
|
||||
std::string transHuman(TER terCode);
|
||||
|
||||
#endif
|
||||
// vim:ts=4
|
||||
@@ -1,3 +0,0 @@
|
||||
# Ripple JavaScript library
|
||||
|
||||
This library lets you connect to a ripple server via websockets.
|
||||
Submodule src/js/cryptojs deleted from c3c843c513
@@ -1,87 +0,0 @@
|
||||
|
||||
//
|
||||
// Currency support
|
||||
//
|
||||
|
||||
// XXX Internal form should be UInt160.
|
||||
var Currency = function () {
|
||||
// Internal form: 0 = XRP. 3 letter-code.
|
||||
// XXX Internal should be 0 or hex with three letter annotation when valid.
|
||||
|
||||
// Json form:
|
||||
// '', 'XRP', '0': 0
|
||||
// 3-letter code: ...
|
||||
// XXX Should support hex, C++ doesn't currently allow it.
|
||||
|
||||
this._value = NaN;
|
||||
}
|
||||
|
||||
// Given "USD" return the json.
|
||||
Currency.json_rewrite = function (j) {
|
||||
return Currency.from_json(j).to_json();
|
||||
};
|
||||
|
||||
Currency.from_json = function (j) {
|
||||
if (j instanceof Currency) return j.clone();
|
||||
else if ('string' === typeof j || 'number' === typeof j) return (new Currency()).parse_json(j);
|
||||
else return new Currency(); // NaN
|
||||
};
|
||||
|
||||
Currency.is_valid = function (j) {
|
||||
return Currency.from_json(j).is_valid();
|
||||
};
|
||||
|
||||
Currency.prototype.clone = function() {
|
||||
return this.copyTo(new Currency());
|
||||
};
|
||||
|
||||
// Returns copy.
|
||||
Currency.prototype.copyTo = function (d) {
|
||||
d._value = this._value;
|
||||
|
||||
return d;
|
||||
};
|
||||
|
||||
Currency.prototype.equals = function (d) {
|
||||
return ('string' !== typeof this._value && isNaN(this._value))
|
||||
|| ('string' !== typeof d._value && isNaN(d._value)) ? false : this._value === d._value;
|
||||
};
|
||||
|
||||
// this._value = NaN on error.
|
||||
Currency.prototype.parse_json = function (j) {
|
||||
if ("" === j || "0" === j || "XRP" === j) {
|
||||
this._value = 0;
|
||||
}
|
||||
else if ('number' === typeof j) {
|
||||
// XXX This is a hack
|
||||
this._value = j;
|
||||
}
|
||||
else if ('string' != typeof j || 3 !== j.length) {
|
||||
this._value = NaN;
|
||||
}
|
||||
else {
|
||||
this._value = j;
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Currency.prototype.is_native = function () {
|
||||
return !isNaN(this._value) && !this._value;
|
||||
};
|
||||
|
||||
Currency.prototype.is_valid = function () {
|
||||
return 'string' === typeof this._value || !isNaN(this._value);
|
||||
};
|
||||
|
||||
Currency.prototype.to_json = function () {
|
||||
return this._value ? this._value : "XRP";
|
||||
};
|
||||
|
||||
Currency.prototype.to_human = function () {
|
||||
return this._value ? this._value : "XRP";
|
||||
};
|
||||
|
||||
exports.Currency = Currency;
|
||||
|
||||
// vim:sw=2:sts=2:ts=8:et
|
||||
@@ -127,6 +127,35 @@ Account.prototype.entry = function (callback)
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve this account's Ripple trust lines.
|
||||
*
|
||||
* To keep up-to-date with changes to the AccountRoot entry, subscribe to the
|
||||
* "lines" event. (Not yet implemented.)
|
||||
*
|
||||
* @param {function (err, lines)} callback Called with the result
|
||||
*/
|
||||
Account.prototype.lines = function (callback)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
self._remote.request_account_lines(this._account_id)
|
||||
.on('success', function (e) {
|
||||
self._lines = e.lines;
|
||||
self.emit('lines', self._lines);
|
||||
|
||||
if ("function" === typeof callback) {
|
||||
callback(null, e);
|
||||
}
|
||||
})
|
||||
.on('error', function (e) {
|
||||
callback(e);
|
||||
})
|
||||
.request();
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Notify object of a relevant transaction.
|
||||
*
|
||||
@@ -1,7 +1,7 @@
|
||||
// Represent Ripple amounts and currencies.
|
||||
// - Numbers in hex are big-endian.
|
||||
|
||||
var sjcl = require('../../build/sjcl');
|
||||
var sjcl = require('../../../build/sjcl');
|
||||
var bn = sjcl.bn;
|
||||
var utils = require('./utils');
|
||||
var jsbn = require('./jsbn');
|
||||
@@ -116,7 +116,6 @@ Amount.prototype.add = function (v) {
|
||||
}
|
||||
else if (this.is_zero()) {
|
||||
result = v.clone();
|
||||
result._is_negative = false;
|
||||
result._is_native = this._is_native;
|
||||
result._currency = this._currency;
|
||||
result._issuer = this._issuer;
|
||||
@@ -397,6 +396,11 @@ Amount.prototype.ratio_human = function (denominator) {
|
||||
var numerator = this;
|
||||
denominator = Amount.from_json(denominator);
|
||||
|
||||
// If either operand is NaN, the result is NaN.
|
||||
if (!numerator.is_valid() || !denominator.is_valid()) {
|
||||
return Amount.NaN();
|
||||
}
|
||||
|
||||
// Special case: The denominator is a native (XRP) amount.
|
||||
//
|
||||
// In that case, it's going to be expressed as base units (1 XRP =
|
||||
@@ -442,6 +446,11 @@ Amount.prototype.product_human = function (factor) {
|
||||
factor = Amount.from_json(factor);
|
||||
}
|
||||
|
||||
// If either operand is NaN, the result is NaN.
|
||||
if (!this.is_valid() || !factor.is_valid()) {
|
||||
return Amount.NaN();
|
||||
}
|
||||
|
||||
var product = this.multiply(factor);
|
||||
|
||||
// Special case: The second factor is a native (XRP) amount expressed as base
|
||||
@@ -547,6 +556,21 @@ Amount.prototype.negate = function () {
|
||||
return this.clone('NEGATE');
|
||||
};
|
||||
|
||||
/**
|
||||
* Invert this amount and return the new value.
|
||||
*
|
||||
* Creates a new Amount object as a copy of the current one (including the same
|
||||
* unit (currency & issuer), inverts it (1/x) and returns the result.
|
||||
*/
|
||||
Amount.prototype.invert = function () {
|
||||
var one = this.clone();
|
||||
one._value = BigInteger.ONE;
|
||||
one._offset = 0;
|
||||
one._is_negative = false;
|
||||
one.canonicalize();
|
||||
return one.ratio_human(this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Tries to correctly interpret an amount as entered by a user.
|
||||
*
|
||||
@@ -730,7 +754,7 @@ Amount.prototype.parse_value = function (j) {
|
||||
|
||||
if ('number' === typeof j) {
|
||||
this._is_negative = j < 0;
|
||||
this._value = new BigInteger(this._is_negative ? -j : j);
|
||||
this._value = new BigInteger(Math.abs(j));
|
||||
this._offset = 0;
|
||||
|
||||
this.canonicalize();
|
||||
@@ -786,13 +810,7 @@ Amount.prototype.parse_value = function (j) {
|
||||
};
|
||||
|
||||
Amount.prototype.set_currency = function (c) {
|
||||
if ('string' === typeof c) {
|
||||
this._currency = Currency.from_json(c);
|
||||
}
|
||||
else
|
||||
{
|
||||
this._currency = c;
|
||||
}
|
||||
this._currency = Currency.from_json(c);
|
||||
this._is_native = this._currency.is_native();
|
||||
|
||||
return this;
|
||||
@@ -873,6 +891,8 @@ Amount.prototype.to_text = function (allow_nan) {
|
||||
* @param opts.min_precision {Number} Min. number of digits after dec. point.
|
||||
* @param opts.skip_empty_fraction {Boolean} Don't show fraction if it is zero,
|
||||
* even if min_precision is set.
|
||||
* @param opts.max_sig_digits {Number} Maximum number of significant digits.
|
||||
* Will cut fractional part, but never integer part.
|
||||
* @param opts.group_sep {Boolean|String} Whether to show a separator every n
|
||||
* digits, if a string, that value will be used as the separator. Default: ","
|
||||
* @param opts.group_width {Number} How many numbers will be grouped together,
|
||||
@@ -905,10 +925,38 @@ Amount.prototype.to_human = function (opts)
|
||||
fraction_part = fraction_part.replace(/0*$/, '');
|
||||
|
||||
if (fraction_part.length || !opts.skip_empty_fraction) {
|
||||
// Enforce the maximum number of decimal digits (precision)
|
||||
if ("number" === typeof opts.precision) {
|
||||
fraction_part = fraction_part.slice(0, opts.precision);
|
||||
}
|
||||
|
||||
// Limit the number of significant digits (max_sig_digits)
|
||||
if ("number" === typeof opts.max_sig_digits) {
|
||||
// First, we count the significant digits we have.
|
||||
// A zero in the integer part does not count.
|
||||
var int_is_zero = +int_part === 0;
|
||||
var digits = int_is_zero ? 0 : int_part.length;
|
||||
|
||||
// Don't count leading zeros in the fractional part if the integer part is
|
||||
// zero.
|
||||
var sig_frac = int_is_zero ? fraction_part.replace(/^0*/, '') : fraction_part;
|
||||
digits += sig_frac.length;
|
||||
|
||||
// Now we calculate where we are compared to the maximum
|
||||
var rounding = digits - opts.max_sig_digits;
|
||||
|
||||
// If we're under the maximum we want to cut no (=0) digits
|
||||
rounding = Math.max(rounding, 0);
|
||||
|
||||
// If we're over the maximum we still only want to cut digits from the
|
||||
// fractional part, not from the integer part.
|
||||
rounding = Math.min(rounding, fraction_part.length);
|
||||
|
||||
// Now we cut `rounding` digits off the right.
|
||||
if (rounding > 0) fraction_part = fraction_part.slice(0, -rounding);
|
||||
}
|
||||
|
||||
// Enforce the minimum number of decimal digits (min_precision)
|
||||
if ("number" === typeof opts.min_precision) {
|
||||
while (fraction_part.length < opts.min_precision) {
|
||||
fraction_part += "0";
|
||||
@@ -977,7 +1025,7 @@ Amount.prototype.to_json = function () {
|
||||
Amount.prototype.to_text_full = function (opts) {
|
||||
return this._value instanceof BigInteger
|
||||
? this._is_native
|
||||
? this.to_text() + "/XRP"
|
||||
? this.to_human() + "/XRP"
|
||||
: this.to_text() + "/" + this._currency.to_json() + "/" + this._issuer.to_json(opts)
|
||||
: NaN;
|
||||
};
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
var sjcl = require('../../build/sjcl');
|
||||
var sjcl = require('../../../build/sjcl');
|
||||
var utils = require('./utils');
|
||||
var jsbn = require('./jsbn');
|
||||
var extend = require('extend');
|
||||
@@ -64,6 +64,8 @@ Base.encode = function (input, alpha) {
|
||||
// --> input: String
|
||||
// <-- array of bytes or undefined.
|
||||
Base.decode = function (input, alpha) {
|
||||
if ("string" !== typeof input) return undefined;
|
||||
|
||||
var alphabet = alphabets[alpha || 'ripple'];
|
||||
var bi_base = new BigInteger(String(alphabet.length));
|
||||
var bi_value = nbi();
|
||||
@@ -105,6 +107,17 @@ Base.decode = function (input, alpha) {
|
||||
return [].concat(utils.arraySet(zeros, 0), bytes);
|
||||
};
|
||||
|
||||
Base.verify_checksum = function (bytes) {
|
||||
var computed = sha256hash(bytes.slice(0, -4)).slice(0, 4);
|
||||
var checksum = bytes.slice(-4);
|
||||
|
||||
for (var i = 0; i < 4; i++)
|
||||
if (computed[i] !== checksum[i])
|
||||
return false;
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
// --> input: Array
|
||||
// <-- String
|
||||
Base.encode_check = function (version, input, alphabet) {
|
||||
@@ -119,16 +132,24 @@ Base.encode_check = function (version, input, alphabet) {
|
||||
Base.decode_check = function (version, input, alphabet) {
|
||||
var buffer = Base.decode(input, alphabet);
|
||||
|
||||
if (!buffer || buffer[0] !== version || buffer.length < 5)
|
||||
if (!buffer || buffer.length < 5)
|
||||
return NaN;
|
||||
|
||||
var computed = sha256hash(buffer.slice(0, -4)).slice(0, 4);
|
||||
var checksum = buffer.slice(-4);
|
||||
var i;
|
||||
// Single valid version
|
||||
if ("number" === typeof version && buffer[0] !== version)
|
||||
return NaN;
|
||||
|
||||
for (i = 0; i != 4; i += 1)
|
||||
if (computed[i] !== checksum[i])
|
||||
return NaN;
|
||||
// Multiple allowed versions
|
||||
if ("object" === typeof version && Array.isArray(version)) {
|
||||
var match = false;
|
||||
for (var i = 0, l = version.length; i < l; i++) {
|
||||
match |= version[i] === buffer[0];
|
||||
}
|
||||
if (!match) return NaN;
|
||||
}
|
||||
|
||||
if (!Base.verify_checksum(buffer))
|
||||
return NaN;
|
||||
|
||||
// We'll use the version byte to add a leading zero, this ensures JSBN doesn't
|
||||
// intrepret the value as a negative number
|
||||
130
src/js/ripple/currency.js
Normal file
130
src/js/ripple/currency.js
Normal file
@@ -0,0 +1,130 @@
|
||||
|
||||
//
|
||||
// Currency support
|
||||
//
|
||||
|
||||
// XXX Internal form should be UInt160.
|
||||
var Currency = function () {
|
||||
// Internal form: 0 = XRP. 3 letter-code.
|
||||
// XXX Internal should be 0 or hex with three letter annotation when valid.
|
||||
|
||||
// Json form:
|
||||
// '', 'XRP', '0': 0
|
||||
// 3-letter code: ...
|
||||
// XXX Should support hex, C++ doesn't currently allow it.
|
||||
|
||||
this._value = NaN;
|
||||
}
|
||||
|
||||
// Given "USD" return the json.
|
||||
Currency.json_rewrite = function (j) {
|
||||
return Currency.from_json(j).to_json();
|
||||
};
|
||||
|
||||
Currency.from_json = function (j) {
|
||||
if (j instanceof Currency) {
|
||||
return j.clone();
|
||||
} else {
|
||||
return new Currency().parse_json(j);
|
||||
}
|
||||
};
|
||||
|
||||
Currency.from_bytes = function (j) {
|
||||
if (j instanceof Currency) {
|
||||
return j.clone();
|
||||
} else {
|
||||
return new Currency().parse_bytes(j);
|
||||
}
|
||||
};
|
||||
|
||||
Currency.is_valid = function (j) {
|
||||
return Currency.from_json(j).is_valid();
|
||||
};
|
||||
|
||||
Currency.prototype.clone = function() {
|
||||
return this.copyTo(new Currency());
|
||||
};
|
||||
|
||||
// Returns copy.
|
||||
Currency.prototype.copyTo = function (d) {
|
||||
d._value = this._value;
|
||||
|
||||
return d;
|
||||
};
|
||||
|
||||
Currency.prototype.equals = function (d) {
|
||||
return ('string' !== typeof this._value && isNaN(this._value))
|
||||
|| ('string' !== typeof d._value && isNaN(d._value)) ? false : this._value === d._value;
|
||||
};
|
||||
|
||||
// this._value = NaN on error.
|
||||
Currency.prototype.parse_json = function (j) {
|
||||
if (j instanceof Currency) {
|
||||
this._value = j;
|
||||
} else if ('string' === typeof j) {
|
||||
if (j === "" || j === "0" || j === "XRP") {
|
||||
// XRP is never allowed as a Currency object
|
||||
this._value = 0;
|
||||
} else if (j.length === 3) {
|
||||
this._value = j;
|
||||
} else {
|
||||
this._value = NaN;
|
||||
}
|
||||
} else if ('number' === typeof j) {
|
||||
// XXX This is a hack
|
||||
this._value = j;
|
||||
} else if ('string' != typeof j || 3 !== j.length) {
|
||||
this._value = NaN;
|
||||
} else {
|
||||
this._value = j;
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
Currency.prototype.parse_bytes = function (byte_array) {
|
||||
if (Array.isArray(byte_array) && byte_array.length == 20) {
|
||||
var result;
|
||||
// is it 0 everywhere except 12, 13, 14?
|
||||
var isZeroExceptInStandardPositions = true;
|
||||
for (var i=0; i<20; i++) {
|
||||
isZeroExceptInStandardPositions = isZeroExceptInStandardPositions && (i===12 || i===13 || i===14 || byte_array[0]===0)
|
||||
}
|
||||
if (isZeroExceptInStandardPositions) {
|
||||
var currencyCode = String.fromCharCode(byte_array[12]) + String.fromCharCode(byte_array[13]) + String.fromCharCode(byte_array[14]);
|
||||
if (/^[A-Z]{3}$/.test(currencyCode) && currencyCode !== "XRP" ) {
|
||||
this._value = currencyCode;
|
||||
} else if (currencyCode === "\0\0\0") {
|
||||
this._value = 0;
|
||||
} else {
|
||||
this._value = NaN;
|
||||
}
|
||||
} else {
|
||||
// XXX Should support non-standard currency codes
|
||||
this._value = NaN;
|
||||
}
|
||||
} else {
|
||||
this._value = NaN;
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
Currency.prototype.is_native = function () {
|
||||
return !isNaN(this._value) && !this._value;
|
||||
};
|
||||
|
||||
Currency.prototype.is_valid = function () {
|
||||
return 'string' === typeof this._value || !isNaN(this._value);
|
||||
};
|
||||
|
||||
Currency.prototype.to_json = function () {
|
||||
return this._value ? this._value : "XRP";
|
||||
};
|
||||
|
||||
Currency.prototype.to_human = function () {
|
||||
return this._value ? this._value : "XRP";
|
||||
};
|
||||
|
||||
exports.Currency = Currency;
|
||||
|
||||
// vim:sw=2:sts=2:ts=8:et
|
||||
@@ -1,11 +1,14 @@
|
||||
exports.Remote = require('./remote').Remote;
|
||||
exports.Amount = require('./amount').Amount;
|
||||
exports.Currency = require('./currency').Currency;
|
||||
exports.Base = require('./base').Base;
|
||||
exports.UInt160 = require('./amount').UInt160;
|
||||
exports.Seed = require('./amount').Seed;
|
||||
exports.Transaction = require('./transaction').Transaction;
|
||||
exports.Meta = require('./meta').Meta;
|
||||
exports.SerializedObject = require('./serializedobject').SerializedObject;
|
||||
|
||||
exports.binformat = require('./binformat');
|
||||
exports.utils = require('./utils');
|
||||
|
||||
// Important: We do not guarantee any specific version of SJCL or for any
|
||||
@@ -15,7 +18,7 @@ exports.utils = require('./utils');
|
||||
// However, for programs that are tied to a specific version of ripple.js like
|
||||
// the official client, it makes sense to expose the SJCL instance so we don't
|
||||
// have to include it twice.
|
||||
exports.sjcl = require('../../build/sjcl');
|
||||
exports.sjcl = require('../../../build/sjcl');
|
||||
|
||||
exports.config = require('./config');
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
var sjcl = require('../../build/sjcl');
|
||||
var sjcl = require('../../../build/sjcl');
|
||||
|
||||
var UInt256 = require('./uint256').UInt256;
|
||||
|
||||
@@ -9,35 +9,32 @@
|
||||
// var network = require("./network.js");
|
||||
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var util = require('util');
|
||||
var util = require('util');
|
||||
|
||||
var Amount = require('./amount').Amount;
|
||||
var UInt160 = require('./uint160').UInt160;
|
||||
var Currency = require('./currency').Currency;
|
||||
var Amount = require('./amount').Amount;
|
||||
var UInt160 = require('./uint160').UInt160;
|
||||
var Currency = require('./currency').Currency;
|
||||
|
||||
var extend = require('extend');
|
||||
var extend = require('extend');
|
||||
|
||||
var OrderBook = function (remote,
|
||||
currency_gets, issuer_gets,
|
||||
currency_pays, issuer_pays) {
|
||||
var OrderBook = function (remote, currency_gets, issuer_gets, currency_pays, issuer_pays) {
|
||||
EventEmitter.call(this);
|
||||
|
||||
var self = this;
|
||||
var self = this;
|
||||
|
||||
this._remote = remote;
|
||||
this._remote = remote;
|
||||
this._currency_gets = currency_gets;
|
||||
this._issuer_gets = issuer_gets;
|
||||
this._issuer_gets = issuer_gets;
|
||||
this._currency_pays = currency_pays;
|
||||
this._issuer_pays = issuer_pays;
|
||||
|
||||
this._subs = 0;
|
||||
this._issuer_pays = issuer_pays;
|
||||
this._subs = 0;
|
||||
|
||||
// We consider ourselves synchronized if we have a current copy of the offers,
|
||||
// we are online and subscribed to updates.
|
||||
this._sync = false;
|
||||
this._sync = false;
|
||||
|
||||
// Offers
|
||||
this._offers = [];
|
||||
this._offers = [];
|
||||
|
||||
this.on('newListener', function (type, listener) {
|
||||
if (OrderBook.subscribe_events.indexOf(type) !== -1) {
|
||||
@@ -49,10 +46,9 @@ var OrderBook = function (remote,
|
||||
});
|
||||
|
||||
this.on('removeListener', function (type, listener) {
|
||||
if (OrderBook.subscribe_events.indexOf(type) !== -1) {
|
||||
if (~OrderBook.subscribe_events.indexOf(type)) {
|
||||
self._subs -= 1;
|
||||
|
||||
if (!self._subs && 'open' === self._remote._online_state) {
|
||||
if (!self._subs && self._remote._connected) {
|
||||
self._sync = false;
|
||||
self._remote.request_unsubscribe()
|
||||
.books([self.to_json()])
|
||||
@@ -86,8 +82,7 @@ OrderBook.subscribe_events = ['transaction', 'model', 'trade'];
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
OrderBook.prototype._subscribe = function ()
|
||||
{
|
||||
OrderBook.prototype._subscribe = function () {
|
||||
var self = this;
|
||||
self._remote.request_subscribe()
|
||||
.books([self.to_json()], true)
|
||||
@@ -95,26 +90,28 @@ OrderBook.prototype._subscribe = function ()
|
||||
// XXX What now?
|
||||
})
|
||||
.on('success', function (res) {
|
||||
self._sync = true;
|
||||
self._sync = true;
|
||||
self._offers = res.offers;
|
||||
self.emit('model', self._offers);
|
||||
})
|
||||
.request();
|
||||
};
|
||||
|
||||
OrderBook.prototype.to_json = function ()
|
||||
{
|
||||
OrderBook.prototype.to_json = function () {
|
||||
var json = {
|
||||
"taker_gets": {
|
||||
"currency": this._currency_gets
|
||||
'taker_gets': {
|
||||
'currency': this._currency_gets
|
||||
},
|
||||
"taker_pays": {
|
||||
"currency": this._currency_pays
|
||||
'taker_pays': {
|
||||
'currency': this._currency_pays
|
||||
}
|
||||
};
|
||||
|
||||
if (this._currency_gets !== "XRP") json["taker_gets"]["issuer"] = this._issuer_gets;
|
||||
if (this._currency_pays !== "XRP") json["taker_pays"]["issuer"] = this._issuer_pays;
|
||||
if (this._currency_gets !== 'XRP')
|
||||
json['taker_gets']['issuer'] = this._issuer_gets;
|
||||
|
||||
if (this._currency_pays !== 'XRP')
|
||||
json['taker_pays']['issuer'] = this._issuer_pays;
|
||||
|
||||
return json;
|
||||
};
|
||||
@@ -125,78 +122,88 @@ OrderBook.prototype.to_json = function ()
|
||||
* Note: This only checks whether the parameters (currencies and issuer) are
|
||||
* syntactically valid. It does not check anything against the ledger.
|
||||
*/
|
||||
OrderBook.prototype.is_valid = function ()
|
||||
{
|
||||
OrderBook.prototype.is_valid = function () {
|
||||
// XXX Should check for same currency (non-native) && same issuer
|
||||
return (
|
||||
Currency.is_valid(this._currency_pays) &&
|
||||
(this._currency_pays === "XRP" || UInt160.is_valid(this._issuer_pays)) &&
|
||||
(this._currency_pays === 'XRP' || UInt160.is_valid(this._issuer_pays)) &&
|
||||
Currency.is_valid(this._currency_gets) &&
|
||||
(this._currency_gets === "XRP" || UInt160.is_valid(this._issuer_gets)) &&
|
||||
!(this._currency_pays === "XRP" && this._currency_gets === "XRP")
|
||||
(this._currency_gets === 'XRP' || UInt160.is_valid(this._issuer_gets)) &&
|
||||
!(this._currency_pays === 'XRP' && this._currency_gets === 'XRP')
|
||||
);
|
||||
};
|
||||
|
||||
OrderBook.prototype.trade = function(type) {
|
||||
var tradeStr = '0'
|
||||
+ (this['_currency_' + type] === 'XRP') ? '' : '/'
|
||||
+ this['_currency_' + type ] + '/'
|
||||
+ this['_issuer_' + type];
|
||||
return Amount.from_json(tradeStr);
|
||||
};
|
||||
|
||||
/**
|
||||
* Notify object of a relevant transaction.
|
||||
*
|
||||
* This is only meant to be called by the Remote class. You should never have to
|
||||
* call this yourself.
|
||||
*/
|
||||
OrderBook.prototype.notifyTx = function (message)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
var changed = false;
|
||||
|
||||
var trade_gets = Amount.from_json("0" + ((this._currency_gets === 'XRP') ? "" :
|
||||
"/" + this._currency_gets +
|
||||
"/" + this._issuer_gets));
|
||||
var trade_pays = Amount.from_json("0" + ((this._currency_pays === 'XRP') ? "" :
|
||||
"/" + this._currency_pays +
|
||||
"/" + this._issuer_pays));
|
||||
OrderBook.prototype.notifyTx = function (message) {
|
||||
var self = this;
|
||||
var changed = false;
|
||||
var trade_gets = this.trade('gets');
|
||||
var trade_pays = this.trade('pays');
|
||||
|
||||
message.mmeta.each(function (an) {
|
||||
if (an.entryType !== 'Offer') return;
|
||||
|
||||
var i, l, offer;
|
||||
if (an.diffType === 'DeletedNode' ||
|
||||
an.diffType === 'ModifiedNode') {
|
||||
for (i = 0, l = self._offers.length; i < l; i++) {
|
||||
offer = self._offers[i];
|
||||
if (offer.index === an.ledgerIndex) {
|
||||
if (an.diffType === 'DeletedNode') {
|
||||
self._offers.splice(i, 1);
|
||||
|
||||
switch(an.diffType) {
|
||||
case 'DeletedNode':
|
||||
case 'ModifiedNode':
|
||||
var deletedNode = an.diffType === 'DeletedNode';
|
||||
|
||||
for (i = 0, l = self._offers.length; i < l; i++) {
|
||||
offer = self._offers[i];
|
||||
if (offer.index === an.ledgerIndex) {
|
||||
if (deletedNode) {
|
||||
self._offers.splice(i, 1);
|
||||
} else {
|
||||
extend(offer, an.fieldsFinal);
|
||||
}
|
||||
changed = true;
|
||||
break;
|
||||
}
|
||||
else extend(offer, an.fieldsFinal);
|
||||
changed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// We don't want to count a OfferCancel as a trade
|
||||
if (message.transaction.TransactionType === "OfferCancel") return;
|
||||
// We don't want to count a OfferCancel as a trade
|
||||
if (message.transaction.TransactionType === 'OfferCancel') return;
|
||||
|
||||
trade_gets = trade_gets.add(an.fieldsPrev.TakerGets);
|
||||
trade_pays = trade_pays.add(an.fieldsPrev.TakerPays);
|
||||
if (an.diffType === 'ModifiedNode') {
|
||||
trade_gets = trade_gets.subtract(an.fieldsFinal.TakerGets);
|
||||
trade_pays = trade_pays.subtract(an.fieldsFinal.TakerPays);
|
||||
}
|
||||
} else if (an.diffType === 'CreatedNode') {
|
||||
var price = Amount.from_json(an.fields.TakerPays).ratio_human(an.fields.TakerGets);
|
||||
for (i = 0, l = self._offers.length; i < l; i++) {
|
||||
offer = self._offers[i];
|
||||
var priceItem = Amount.from_json(offer.TakerPays).ratio_human(offer.TakerGets);
|
||||
trade_gets = trade_gets.add(an.fieldsPrev.TakerGets);
|
||||
trade_pays = trade_pays.add(an.fieldsPrev.TakerPays);
|
||||
|
||||
if (price.compareTo(priceItem) <= 0) {
|
||||
var obj = an.fields;
|
||||
obj.index = an.ledgerIndex;
|
||||
self._offers.splice(i, 0, an.fields);
|
||||
changed = true;
|
||||
break;
|
||||
if (!deletedNode) {
|
||||
trade_gets = trade_gets.subtract(an.fieldsFinal.TakerGets);
|
||||
trade_pays = trade_pays.subtract(an.fieldsFinal.TakerPays);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'CreatedNode':
|
||||
var price = Amount.from_json(an.fields.TakerPays).ratio_human(an.fields.TakerGets);
|
||||
|
||||
for (i = 0, l = self._offers.length; i < l; i++) {
|
||||
offer = self._offers[i];
|
||||
var priceItem = Amount.from_json(offer.TakerPays).ratio_human(offer.TakerGets);
|
||||
|
||||
if (price.compareTo(priceItem) <= 0) {
|
||||
var obj = an.fields;
|
||||
obj.index = an.ledgerIndex;
|
||||
self._offers.splice(i, 0, an.fields);
|
||||
changed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -218,17 +225,13 @@ OrderBook.prototype.notifyTx = function (message)
|
||||
*
|
||||
* If the data is available immediately, the callback may be called synchronously.
|
||||
*/
|
||||
OrderBook.prototype.offers = function (callback)
|
||||
{
|
||||
OrderBook.prototype.offers = function (callback) {
|
||||
var self = this;
|
||||
|
||||
if ("function" === typeof callback) {
|
||||
if (typeof callback === 'function') {
|
||||
if (this._sync) {
|
||||
callback(this._offers);
|
||||
} else {
|
||||
this.once('model', function (offers) {
|
||||
callback(offers);
|
||||
});
|
||||
this.once('model', callback);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
@@ -240,11 +243,10 @@ OrderBook.prototype.offers = function (callback)
|
||||
* Usually, this will just be an empty array if the order book hasn't been
|
||||
* loaded yet. But this accessor may be convenient in some circumstances.
|
||||
*/
|
||||
OrderBook.prototype.offersSync = function ()
|
||||
{
|
||||
OrderBook.prototype.offersSync = function () {
|
||||
return this._offers;
|
||||
};
|
||||
|
||||
exports.OrderBook = OrderBook;
|
||||
exports.OrderBook = OrderBook;
|
||||
|
||||
// vim:sw=2:sts=2:ts=8:et
|
||||
88
src/js/ripple/pathfind.js
Normal file
88
src/js/ripple/pathfind.js
Normal file
@@ -0,0 +1,88 @@
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var util = require('util');
|
||||
|
||||
var Amount = require('./amount').Amount;
|
||||
|
||||
var extend = require('extend');
|
||||
|
||||
/**
|
||||
* Represents a persistent path finding request.
|
||||
*
|
||||
* Only one path find request is allowed per connection, so when another path
|
||||
* find request is triggered it will supercede the existing one, making it emit
|
||||
* the 'end' and 'superceded' events.
|
||||
*/
|
||||
var PathFind = function (remote, src_account, dst_account,
|
||||
dst_amount, src_currencies)
|
||||
{
|
||||
EventEmitter.call(this);
|
||||
|
||||
this.remote = remote;
|
||||
|
||||
this.src_account = src_account;
|
||||
this.dst_account = dst_account;
|
||||
this.dst_amount = dst_amount;
|
||||
this.src_currencies = src_currencies;
|
||||
};
|
||||
|
||||
util.inherits(PathFind, EventEmitter);
|
||||
|
||||
/**
|
||||
* Submits a path_find_create request to the network.
|
||||
*
|
||||
* This starts a path find request, superceding all previous path finds.
|
||||
*
|
||||
* This will be called automatically by Remote when this object is instantiated,
|
||||
* so you should only have to call it if the path find was closed or superceded
|
||||
* and you wish to restart it.
|
||||
*/
|
||||
PathFind.prototype.create = function ()
|
||||
{
|
||||
var self = this;
|
||||
|
||||
var req = this.remote.request_path_find_create(this.src_account,
|
||||
this.dst_account,
|
||||
this.dst_amount,
|
||||
this.src_currencies,
|
||||
handleInitialPath);
|
||||
|
||||
function handleInitialPath(err, msg) {
|
||||
if (err) {
|
||||
// XXX Handle error
|
||||
return;
|
||||
}
|
||||
self.notify_update(msg);
|
||||
}
|
||||
|
||||
req.request();
|
||||
};
|
||||
|
||||
PathFind.prototype.close = function ()
|
||||
{
|
||||
this.remote.request_path_find_close().request();
|
||||
this.emit('end');
|
||||
this.emit('close');
|
||||
};
|
||||
|
||||
PathFind.prototype.notify_update = function (message)
|
||||
{
|
||||
var src_account = message.source_account;
|
||||
var dst_account = message.destination_account;
|
||||
var dst_amount = Amount.from_json(message.destination_amount);
|
||||
|
||||
// Only pass the event along if this path find response matches what we were
|
||||
// looking for.
|
||||
if (this.src_account === src_account &&
|
||||
this.dst_account === dst_account &&
|
||||
this.dst_amount.equals(dst_amount)) {
|
||||
this.emit('update', message);
|
||||
}
|
||||
};
|
||||
|
||||
PathFind.prototype.notify_superceded = function ()
|
||||
{
|
||||
this.emit('end');
|
||||
this.emit('superceded');
|
||||
};
|
||||
|
||||
exports.PathFind = PathFind;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@
|
||||
// Seed support
|
||||
//
|
||||
|
||||
var sjcl = require('../../build/sjcl');
|
||||
var sjcl = require('../../../build/sjcl');
|
||||
var utils = require('./utils');
|
||||
var jsbn = require('./jsbn');
|
||||
var extend = require('extend');
|
||||
@@ -1,12 +1,20 @@
|
||||
var binformat = require('./binformat'),
|
||||
sjcl = require('../../build/sjcl'),
|
||||
sjcl = require('../../../build/sjcl'),
|
||||
extend = require('extend'),
|
||||
stypes = require('./serializedtypes');
|
||||
|
||||
var UInt256 = require('./uint256').UInt256;
|
||||
|
||||
var SerializedObject = function () {
|
||||
this.buffer = [];
|
||||
var SerializedObject = function (buf) {
|
||||
if (Array.isArray(buf)) {
|
||||
this.buffer = buf;
|
||||
} else if ("string" === typeof buf) {
|
||||
this.buffer = sjcl.codec.bytes.fromBits(sjcl.codec.hex.toBits(buf));
|
||||
} else if (!buf) {
|
||||
this.buffer = [];
|
||||
} else {
|
||||
throw new Error("Invalid buffer passed.");
|
||||
}
|
||||
this.pointer = 0;
|
||||
};
|
||||
|
||||
@@ -45,6 +53,23 @@ SerializedObject.prototype.append = function (bytes) {
|
||||
this.pointer += bytes.length;
|
||||
};
|
||||
|
||||
SerializedObject.prototype.resetPointer = function () {
|
||||
this.pointer = 0;
|
||||
};
|
||||
|
||||
SerializedObject.prototype.read = function (numberOfBytes) {
|
||||
var start = this.pointer;
|
||||
var end = start+numberOfBytes;
|
||||
if (end > this.buffer.length) {
|
||||
throw new Error("There aren't that many bytes left to read.");
|
||||
} else {
|
||||
var result = this.buffer.slice(start,end);
|
||||
this.pointer = end;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
SerializedObject.prototype.to_bits = function ()
|
||||
{
|
||||
return sjcl.codec.bytes.toBits(this.buffer);
|
||||
@@ -8,10 +8,12 @@
|
||||
|
||||
var extend = require('extend'),
|
||||
utils = require('./utils'),
|
||||
sjcl = require('../../build/sjcl');
|
||||
sjcl = require('../../../build/sjcl');
|
||||
|
||||
var amount = require('./amount'),
|
||||
UInt160 = amount.UInt160,
|
||||
UInt128 = require('./uint128').UInt128,
|
||||
UInt160 = require('./uint160').UInt160,
|
||||
UInt256 = require('./uint256').UInt256,
|
||||
Amount = amount.Amount,
|
||||
Currency= amount.Currency;
|
||||
|
||||
@@ -19,17 +21,32 @@ var amount = require('./amount'),
|
||||
var hex = sjcl.codec.hex,
|
||||
bytes = sjcl.codec.bytes;
|
||||
|
||||
var jsbn = require('./jsbn');
|
||||
var BigInteger = jsbn.BigInteger;
|
||||
|
||||
|
||||
var SerializedType = function (methods) {
|
||||
extend(this, methods);
|
||||
};
|
||||
|
||||
SerializedType.prototype.serialize_hex = function (so, hexData) {
|
||||
function serialize_hex(so, hexData, noLength) {
|
||||
var byteData = bytes.fromBits(hex.toBits(hexData));
|
||||
this.serialize_varint(so, byteData.length);
|
||||
if (!noLength) {
|
||||
SerializedType.serialize_varint(so, byteData.length);
|
||||
}
|
||||
so.append(byteData);
|
||||
};
|
||||
|
||||
SerializedType.prototype.serialize_varint = function (so, val) {
|
||||
|
||||
|
||||
/**
|
||||
* parses bytes as hex
|
||||
*/
|
||||
function convert_bytes_to_hex (byte_array) {
|
||||
return sjcl.codec.hex.fromBits(sjcl.codec.bytes.toBits(byte_array));
|
||||
}
|
||||
|
||||
SerializedType.serialize_varint = function (so, val) {
|
||||
if (val < 0) {
|
||||
throw new Error("Variable integers are unsigned.");
|
||||
}
|
||||
@@ -48,84 +65,174 @@ SerializedType.prototype.serialize_varint = function (so, val) {
|
||||
} else throw new Error("Variable integer overflow.");
|
||||
};
|
||||
|
||||
|
||||
SerializedType.parse_varint = function (so) {
|
||||
var b1 = so.read(1)[0], b2, b3;
|
||||
if (b1 <= 192) {
|
||||
return b1;
|
||||
} else if (b1 <= 240) {
|
||||
b2 = so.read(1)[0];
|
||||
return 193 + (b1-193)*256 + b2;
|
||||
} else if (b1 <= 254) {
|
||||
b2 = so.read(1)[0];
|
||||
b3 = so.read(1)[0];
|
||||
return 12481 + (b1-241)*65536 + b2*256 + b3
|
||||
}
|
||||
else {
|
||||
throw new Error("Invalid varint length indicator");
|
||||
}
|
||||
};
|
||||
|
||||
// In the following, we assume that the inputs are in the proper range. Is this correct?
|
||||
|
||||
// Helper functions for 1-, 2-, and 4-byte integers.
|
||||
|
||||
/**
|
||||
* Convert an integer value into an array of bytes.
|
||||
*
|
||||
* The result is appended to the serialized object ("so").
|
||||
*/
|
||||
function append_byte_array(so, val, bytes) {
|
||||
if ("number" !== typeof val) {
|
||||
throw new Error("Integer is not a number");
|
||||
}
|
||||
if (val < 0 || val >= (Math.pow(256, bytes))) {
|
||||
throw new Error("Integer out of bounds");
|
||||
}
|
||||
var newBytes = [];
|
||||
for (var i=0; i<bytes; i++) {
|
||||
newBytes.unshift(val >>> (i*8) & 0xff);
|
||||
}
|
||||
so.append(newBytes);
|
||||
}
|
||||
|
||||
// Convert a certain number of bytes from the serialized object ("so") into an integer.
|
||||
function readAndSum(so, bytes) {
|
||||
var sum = 0;
|
||||
for (var i = 0; i<bytes; i++) {
|
||||
sum += (so.read(1)[0] << (8*(bytes-1-i)) );
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
|
||||
var STInt8 = exports.Int8 = new SerializedType({
|
||||
serialize: function (so, val) {
|
||||
so.append([val & 0xff]);
|
||||
append_byte_array(so, val, 1);
|
||||
},
|
||||
parse: function (so) {
|
||||
return so.read(1)[0];
|
||||
return readAndSum(so, 1);
|
||||
}
|
||||
});
|
||||
|
||||
var STInt16 = exports.Int16 = new SerializedType({
|
||||
serialize: function (so, val) {
|
||||
so.append([
|
||||
val >>> 8 & 0xff,
|
||||
val & 0xff
|
||||
]);
|
||||
append_byte_array(so, val, 2);
|
||||
/*so.append([
|
||||
val >>> 8 & 0xff,
|
||||
val & 0xff
|
||||
]);*/
|
||||
},
|
||||
parse: function (so) {
|
||||
// XXX
|
||||
throw new Error("Parsing Int16 not implemented");
|
||||
return readAndSum(so, 2);
|
||||
}
|
||||
});
|
||||
|
||||
var STInt32 = exports.Int32 = new SerializedType({
|
||||
serialize: function (so, val) {
|
||||
so.append([
|
||||
val >>> 24 & 0xff,
|
||||
val >>> 16 & 0xff,
|
||||
val >>> 8 & 0xff,
|
||||
val & 0xff
|
||||
]);
|
||||
append_byte_array(so, val, 4)
|
||||
/*so.append([
|
||||
val >>> 24 & 0xff,
|
||||
val >>> 16 & 0xff,
|
||||
val >>> 8 & 0xff,
|
||||
val & 0xff
|
||||
]);*/
|
||||
},
|
||||
parse: function (so) {
|
||||
// XXX
|
||||
throw new Error("Parsing Int32 not implemented");
|
||||
return readAndSum(so, 4);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
var STInt64 = exports.Int64 = new SerializedType({
|
||||
serialize: function (so, val) {
|
||||
// XXX
|
||||
throw new Error("Serializing Int64 not implemented");
|
||||
var bigNumObject;
|
||||
if ("number" === typeof val) {
|
||||
val = Math.floor(val);
|
||||
if (val < 0) {
|
||||
throw new Error("Negative value for unsigned Int64 is invalid.");
|
||||
}
|
||||
bigNumObject = new BigInteger(""+val, 10);
|
||||
} else if ("string" === typeof val) {
|
||||
if (!/^[0-9A-F]{0,16}$/i.test(val)) {
|
||||
throw new Error("Not a valid hex Int64.");
|
||||
}
|
||||
bigNumObject = new BigInteger(val, 16);
|
||||
} else if (val instanceof BigInteger) {
|
||||
if (val.compareTo(BigInteger.ZERO) < 0) {
|
||||
throw new Error("Negative value for unsigned Int64 is invalid.");
|
||||
}
|
||||
bigNumObject = val;
|
||||
} else {
|
||||
throw new Error("Invalid type for Int64");
|
||||
}
|
||||
|
||||
var hex = bigNumObject.toString(16);
|
||||
if (hex.length > 16) {
|
||||
throw new Error("Int64 is too large");
|
||||
}
|
||||
while (hex.length < 16) {
|
||||
hex = "0" + hex;
|
||||
}
|
||||
return serialize_hex(so, hex, true); //noLength = true
|
||||
},
|
||||
parse: function (so) {
|
||||
// XXX
|
||||
throw new Error("Parsing Int64 not implemented");
|
||||
var hi = readAndSum(so, 4);
|
||||
var lo = readAndSum(so, 4);
|
||||
|
||||
var result = new BigInteger(hi);
|
||||
result.shiftLeft(32);
|
||||
result.add(lo);
|
||||
return result;
|
||||
}
|
||||
});
|
||||
|
||||
var STHash128 = exports.Hash128 = new SerializedType({
|
||||
serialize: function (so, val) {
|
||||
// XXX
|
||||
throw new Error("Serializing Hash128 not implemented");
|
||||
var hash = UInt128.from_json(val);
|
||||
if (!hash.is_valid()) {
|
||||
throw new Error("Invalid Hash128");
|
||||
}
|
||||
serialize_hex(so, hash.to_hex(), true); //noLength = true
|
||||
},
|
||||
parse: function (so) {
|
||||
// XXX
|
||||
throw new Error("Parsing Hash128 not implemented");
|
||||
return UInt128.from_bytes(so.read(16));
|
||||
}
|
||||
});
|
||||
|
||||
var STHash256 = exports.Hash256 = new SerializedType({
|
||||
serialize: function (so, val) {
|
||||
// XXX
|
||||
throw new Error("Serializing Hash256 not implemented");
|
||||
var hash = UInt256.from_json(val);
|
||||
if (!hash.is_valid()) {
|
||||
throw new Error("Invalid Hash256");
|
||||
}
|
||||
serialize_hex(so, hash.to_hex(), true); //noLength = true
|
||||
},
|
||||
parse: function (so) {
|
||||
// XXX
|
||||
throw new Error("Parsing Hash256 not implemented");
|
||||
return UInt256.from_bytes(so.read(32));
|
||||
}
|
||||
});
|
||||
|
||||
var STHash160 = exports.Hash160 = new SerializedType({
|
||||
serialize: function (so, val) {
|
||||
// XXX
|
||||
throw new Error("Serializing Hash160 not implemented");
|
||||
var hash = UInt160.from_json(val);
|
||||
if (!hash.is_valid()) {
|
||||
throw new Error("Invalid Hash160");
|
||||
}
|
||||
serialize_hex(so, hash.to_hex(), true); //noLength = true
|
||||
},
|
||||
parse: function (so) {
|
||||
// XXX
|
||||
throw new Error("Parsing Hash160 not implemented");
|
||||
return UInt160.from_bytes(so.read(20));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -133,11 +240,13 @@ var STHash160 = exports.Hash160 = new SerializedType({
|
||||
var STCurrency = new SerializedType({
|
||||
serialize: function (so, val) {
|
||||
var currency = val.to_json();
|
||||
if ("string" === typeof currency && currency.length === 3) {
|
||||
if ("XRP" === currency) {
|
||||
serialize_hex(so, UInt160.HEX_ZERO, true);
|
||||
} else if ("string" === typeof currency && currency.length === 3) {
|
||||
var currencyCode = currency.toUpperCase(),
|
||||
currencyData = utils.arraySet(20, 0);
|
||||
|
||||
if (!/^[A-Z]{3}$/.test(currencyCode)) {
|
||||
if (!/^[A-Z]{3}$/.test(currencyCode) || currencyCode === "XRP" ) {
|
||||
throw new Error('Invalid currency code');
|
||||
}
|
||||
|
||||
@@ -151,8 +260,11 @@ var STCurrency = new SerializedType({
|
||||
}
|
||||
},
|
||||
parse: function (so) {
|
||||
// XXX
|
||||
throw new Error("Parsing Currency not implemented");
|
||||
var currency = Currency.from_bytes(so.read(20));
|
||||
if (!currency.is_valid()) {
|
||||
throw new Error("Invalid currency");
|
||||
}
|
||||
return currency;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -215,30 +327,71 @@ var STAmount = exports.Amount = new SerializedType({
|
||||
}
|
||||
},
|
||||
parse: function (so) {
|
||||
// XXX
|
||||
throw new Error("Parsing Amount not implemented");
|
||||
var amount = new Amount();
|
||||
var value_bytes = so.read(8);
|
||||
var is_zero = !(value_bytes[0] & 0x7f);
|
||||
for (var i=1; i<8; i++) {
|
||||
is_zero = is_zero && !value_bytes[i];
|
||||
}
|
||||
if (value_bytes[0] & 0x80) {
|
||||
//non-native
|
||||
var currency = STCurrency.parse(so);
|
||||
var issuer_bytes = so.read(20);
|
||||
var issuer = UInt160.from_bytes(issuer_bytes);
|
||||
|
||||
var offset = ((value_bytes[0] & 0x3f) << 2) + (value_bytes[1] >>> 6) - 97;
|
||||
var mantissa_bytes = value_bytes.slice(1);
|
||||
mantissa_bytes[0] &= 0x3f;
|
||||
var value = new BigInteger(mantissa_bytes, 256);
|
||||
|
||||
if (value.equals(BigInteger.ZERO) && !is_zero ) {
|
||||
throw new Error("Invalid zero representation");
|
||||
}
|
||||
|
||||
amount._value = value;
|
||||
amount._offset = offset;
|
||||
amount._currency = currency;
|
||||
amount._issuer = issuer;
|
||||
amount._is_native = false;
|
||||
|
||||
} else {
|
||||
//native
|
||||
var integer_bytes = value_bytes.slice();
|
||||
integer_bytes[0] &= 0x3f;
|
||||
amount._value = new BigInteger(integer_bytes, 256);
|
||||
amount._is_native = true;
|
||||
}
|
||||
amount._is_negative = !is_zero && !(value_bytes[0] & 0x40);
|
||||
return amount;
|
||||
}
|
||||
});
|
||||
|
||||
var STVL = exports.VariableLength = new SerializedType({
|
||||
serialize: function (so, val) {
|
||||
if ("string" === typeof val) this.serialize_hex(so, val);
|
||||
if ("string" === typeof val) serialize_hex(so, val);
|
||||
else throw new Error("Unknown datatype.");
|
||||
},
|
||||
parse: function (so) {
|
||||
// XXX
|
||||
throw new Error("Parsing VL not implemented");
|
||||
var len = this.parse_varint(so);
|
||||
return convert_bytes_to_hex(so.read(len));
|
||||
}
|
||||
});
|
||||
|
||||
var STAccount = exports.Account = new SerializedType({
|
||||
serialize: function (so, val) {
|
||||
var account = UInt160.from_json(val);
|
||||
this.serialize_hex(so, account.to_hex());
|
||||
serialize_hex(so, account.to_hex());
|
||||
},
|
||||
parse: function (so) {
|
||||
// XXX
|
||||
throw new Error("Parsing Account not implemented");
|
||||
var len = this.parse_varint(so);
|
||||
if (len !== 20) {
|
||||
throw new Error("Non-standard-length account ID");
|
||||
}
|
||||
var result = UInt160.from_bytes(so.read(len));
|
||||
if (!result.is_valid()) {
|
||||
throw new Error("Invalid Account");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,31 +1,45 @@
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var util = require('util');
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var util = require('util');
|
||||
var utils = require('./utils');
|
||||
|
||||
var utils = require('./utils');
|
||||
/**
|
||||
* @constructor Server
|
||||
* @param remote The Remote object
|
||||
* @param cfg Configuration parameters.
|
||||
*
|
||||
* Keys for cfg:
|
||||
* url
|
||||
*/
|
||||
|
||||
var Server = function (remote, cfg)
|
||||
{
|
||||
var Server = function (remote, opts) {
|
||||
EventEmitter.call(this);
|
||||
|
||||
if ("object" !== typeof cfg || "string" !== typeof cfg.url) {
|
||||
throw new Error("Invalid server configuration.");
|
||||
if (typeof opts !== 'object' || typeof opts.url !== 'string') {
|
||||
throw new Error('Invalid server configuration.');
|
||||
}
|
||||
|
||||
this._remote = remote;
|
||||
this._cfg = cfg;
|
||||
var self = this;
|
||||
|
||||
this._ws = null;
|
||||
this._connected = false;
|
||||
this._remote = remote;
|
||||
this._opts = opts;
|
||||
|
||||
this._ws = void(0);
|
||||
this._connected = false;
|
||||
this._should_connect = false;
|
||||
this._state = null;
|
||||
this._state = void(0);
|
||||
|
||||
this._id = 0;
|
||||
this._retry = 0;
|
||||
this._id = 0;
|
||||
this._retry = 0;
|
||||
|
||||
this._requests = {};
|
||||
this._requests = { };
|
||||
|
||||
this.on('message', this._handle_message.bind(this));
|
||||
this.on('response_subscribe', this._handle_response_subscribe.bind(this));
|
||||
this.on('message', function(message) {
|
||||
self._handle_message(message);
|
||||
});
|
||||
|
||||
this.on('response_subscribe', function(message) {
|
||||
self._handle_response_subscribe(message);
|
||||
});
|
||||
};
|
||||
|
||||
util.inherits(Server, EventEmitter);
|
||||
@@ -37,13 +51,34 @@ util.inherits(Server, EventEmitter);
|
||||
* us of changes.
|
||||
*/
|
||||
Server.online_states = [
|
||||
'proposing',
|
||||
'validating',
|
||||
'full'
|
||||
'syncing'
|
||||
, 'tracking'
|
||||
, 'proposing'
|
||||
, 'validating'
|
||||
, 'full'
|
||||
];
|
||||
|
||||
Server.prototype.connect = function ()
|
||||
{
|
||||
Server.prototype._is_online = function (status) {
|
||||
return Server.online_states.indexOf(status) !== -1;
|
||||
};
|
||||
|
||||
Server.prototype._set_state = function (state) {
|
||||
if (state !== this._state) {
|
||||
this._state = state;
|
||||
|
||||
this.emit('state', state);
|
||||
|
||||
if (state === 'online') {
|
||||
this._connected = true;
|
||||
this.emit('connect');
|
||||
} else if (state === 'offline') {
|
||||
this._connected = false;
|
||||
this.emit('disconnect');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Server.prototype.connect = function () {
|
||||
var self = this;
|
||||
|
||||
// We don't connect if we believe we're already connected. This means we have
|
||||
@@ -52,13 +87,15 @@ Server.prototype.connect = function ()
|
||||
// we will automatically reconnect.
|
||||
if (this._connected === true) return;
|
||||
|
||||
if (this._remote.trace) console.log("server: connect: %s", this._cfg.url);
|
||||
if (this._remote.trace) console.log('server: connect: %s', this._opts.url);
|
||||
|
||||
// Ensure any existing socket is given the command to close first.
|
||||
if (this._ws) this._ws.close();
|
||||
|
||||
// We require this late, because websocket shims may be loaded after
|
||||
// ripple-lib.
|
||||
var WebSocket = require('ws');
|
||||
var ws = this._ws = new WebSocket(this._cfg.url);
|
||||
var ws = this._ws = new WebSocket(this._opts.url);
|
||||
|
||||
this._should_connect = true;
|
||||
|
||||
@@ -79,9 +116,9 @@ Server.prototype.connect = function ()
|
||||
// If we are no longer the active socket, simply ignore any event
|
||||
if (ws !== self._ws) return;
|
||||
|
||||
if (self._remote.trace) console.log("server: onerror: %s", e.data || e);
|
||||
if (self._remote.trace) console.log('server: onerror: %s', e.data || e);
|
||||
|
||||
// Most connection errors for WebSockets are conveyed as "close" events with
|
||||
// Most connection errors for WebSockets are conveyed as 'close' events with
|
||||
// code 1006. This is done for security purposes and therefore unlikely to
|
||||
// ever change.
|
||||
|
||||
@@ -103,13 +140,12 @@ Server.prototype.connect = function ()
|
||||
// If we are no longer the active socket, simply ignore any event
|
||||
if (ws !== self._ws) return;
|
||||
|
||||
if (self._remote.trace) console.log("server: onclose: %s", ws.readyState);
|
||||
if (self._remote.trace) console.log('server: onclose: %s', ws.readyState);
|
||||
|
||||
handleConnectionClose();
|
||||
};
|
||||
|
||||
function handleConnectionClose()
|
||||
{
|
||||
function handleConnectionClose() {
|
||||
self.emit('socket_close');
|
||||
self._set_state('offline');
|
||||
|
||||
@@ -122,7 +158,7 @@ Server.prototype.connect = function ()
|
||||
// Delay and retry.
|
||||
self._retry += 1;
|
||||
self._retry_timer = setTimeout(function () {
|
||||
if (self._remote.trace) console.log("server: retry");
|
||||
if (self._remote.trace) console.log('server: retry');
|
||||
|
||||
if (!self._should_connect) return;
|
||||
self.connect();
|
||||
@@ -140,21 +176,22 @@ Server.prototype.connect = function ()
|
||||
};
|
||||
};
|
||||
|
||||
Server.prototype.disconnect = function ()
|
||||
{
|
||||
Server.prototype.disconnect = function () {
|
||||
this._should_connect = false;
|
||||
this._set_state('offline');
|
||||
|
||||
if (this.ws) {
|
||||
this.ws.close();
|
||||
if (this._ws) {
|
||||
this._ws.close();
|
||||
}
|
||||
};
|
||||
|
||||
Server.prototype.send_message = function (message) {
|
||||
this._ws.send(JSON.stringify(message));
|
||||
};
|
||||
|
||||
/**
|
||||
* Submit a Request object to this server.
|
||||
*/
|
||||
Server.prototype.request = function (request)
|
||||
{
|
||||
Server.prototype.request = function (request) {
|
||||
var self = this;
|
||||
|
||||
// Only bother if we are still connected.
|
||||
@@ -166,38 +203,24 @@ Server.prototype.request = function (request)
|
||||
// Advance message ID
|
||||
self._id++;
|
||||
|
||||
if (self._state === "online" ||
|
||||
(request.message.command === "subscribe" && self._ws.readyState === 1)) {
|
||||
if (self._connected || (request.message.command === 'subscribe' && self._ws.readyState === 1)) {
|
||||
if (self._remote.trace) {
|
||||
utils.logObject("server: request: %s", request.message);
|
||||
utils.logObject('server: request: %s', request.message);
|
||||
}
|
||||
|
||||
self._ws.send(JSON.stringify(request.message));
|
||||
self.send_message(request.message);
|
||||
} else {
|
||||
// XXX There are many ways to make self smarter.
|
||||
self.once('connect', function () {
|
||||
if (self._remote.trace) {
|
||||
utils.logObject("server: request: %s", request.message);
|
||||
utils.logObject('server: request: %s', request.message);
|
||||
}
|
||||
self._ws.send(JSON.stringify(request.message));
|
||||
self.send_message(request.message);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (self._remote.trace) {
|
||||
utils.logObject("server: request: DROPPING: %s", request.message);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Server.prototype._set_state = function (state) {
|
||||
if (state !== this._state) {
|
||||
this._state = state;
|
||||
|
||||
this.emit('state', state);
|
||||
if (state === 'online') {
|
||||
this.emit('connect');
|
||||
} else if (state === 'offline') {
|
||||
this.emit('disconnect');
|
||||
utils.logObject('server: request: DROPPING: %s', request.message);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -205,47 +228,57 @@ Server.prototype._set_state = function (state) {
|
||||
Server.prototype._handle_message = function (json) {
|
||||
var self = this;
|
||||
|
||||
var message = JSON.parse(json);
|
||||
var message;
|
||||
|
||||
try {
|
||||
message = JSON.parse(json);
|
||||
} catch(exception) { return; }
|
||||
|
||||
if (message.type === 'response') {
|
||||
// A response to a request.
|
||||
var request = self._requests[message.id];
|
||||
switch(message.type) {
|
||||
case 'response':
|
||||
// A response to a request.
|
||||
var request = self._requests[message.id];
|
||||
|
||||
delete self._requests[message.id];
|
||||
delete self._requests[message.id];
|
||||
|
||||
if (!request) {
|
||||
if (self._remote.trace) utils.logObject("server: UNEXPECTED: %s", message);
|
||||
} else if ('success' === message.status) {
|
||||
if (self._remote.trace) utils.logObject("server: response: %s", message);
|
||||
if (!request) {
|
||||
if (self._remote.trace) utils.logObject('server: UNEXPECTED: %s', message);
|
||||
} else if ('success' === message.status) {
|
||||
if (self._remote.trace) utils.logObject('server: response: %s', message);
|
||||
|
||||
request.emit('success', message.result);
|
||||
self.emit('response_'+request.message.command, message.result, request, message);
|
||||
self._remote.emit('response_'+request.message.command, message.result, request, message);
|
||||
} else if (message.error) {
|
||||
if (self._remote.trace) utils.logObject("server: error: %s", message);
|
||||
request.emit('success', message.result);
|
||||
|
||||
request.emit('error', {
|
||||
'error' : 'remoteError',
|
||||
'error_message' : 'Remote reported an error.',
|
||||
'remote' : message
|
||||
});
|
||||
}
|
||||
} else if (message.type === 'serverStatus') {
|
||||
// This message is only received when online. As we are connected, it is the definative final state.
|
||||
self._set_state(
|
||||
Server.online_states.indexOf(message.server_status) !== -1
|
||||
? 'online'
|
||||
: 'offline');
|
||||
[ self, self._remote ].forEach(function(emitter) {
|
||||
emitter.emit('response_' + request.message.command, message.result, request, message);
|
||||
});
|
||||
} else if (message.error) {
|
||||
if (self._remote.trace) utils.logObject('server: error: %s', message);
|
||||
|
||||
request.emit('error', {
|
||||
'error' : 'remoteError',
|
||||
'error_message' : 'Remote reported an error.',
|
||||
'remote' : message
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
case 'path_find':
|
||||
if (self._remote.trace) utils.logObject('server: path_find: %s', message);
|
||||
break;
|
||||
|
||||
case 'serverStatus':
|
||||
// This message is only received when online. As we are connected, it is the definative final state.
|
||||
self._set_state(self._is_online(message.server_status) ? 'online' : 'offline');
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
Server.prototype._handle_response_subscribe = function (message)
|
||||
{
|
||||
Server.prototype._handle_response_subscribe = function (message) {
|
||||
var self = this;
|
||||
|
||||
self._server_status = message.server_status;
|
||||
|
||||
if (Server.online_states.indexOf(message.server_status) !== -1) {
|
||||
if (self._is_online(message.server_status)) {
|
||||
self._set_state('online');
|
||||
}
|
||||
};
|
||||
@@ -46,7 +46,7 @@
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var util = require('util');
|
||||
|
||||
var sjcl = require('../../build/sjcl');
|
||||
var sjcl = require('../../../build/sjcl');
|
||||
|
||||
var Amount = require('./amount').Amount;
|
||||
var Currency = require('./amount').Currency;
|
||||
@@ -72,46 +72,56 @@ var Transaction = function (remote) {
|
||||
this.remote = remote;
|
||||
this._secret = undefined;
|
||||
this._build_path = false;
|
||||
this.tx_json = { // Transaction data.
|
||||
'Flags' : 0, // XXX Would be nice if server did not require this.
|
||||
|
||||
// Transaction data.
|
||||
this.tx_json = {
|
||||
'Flags' : 0, // XXX Would be nice if server did not require this.
|
||||
};
|
||||
|
||||
this.hash = undefined;
|
||||
this.submit_index = undefined; // ledger_current_index was this when transaction was submited.
|
||||
this.state = undefined; // Under construction.
|
||||
this.finalized = false;
|
||||
|
||||
this.on('success', function (message) {
|
||||
if (message.engine_result) {
|
||||
self.hash = message.tx_json.hash;
|
||||
if (message.engine_result) {
|
||||
self.hash = message.tx_json.hash;
|
||||
|
||||
self.set_state('client_proposed');
|
||||
self.set_state('client_proposed');
|
||||
|
||||
self.emit('proposed', {
|
||||
'tx_json' : message.tx_json,
|
||||
'result' : message.engine_result,
|
||||
'result_code' : message.engine_result_code,
|
||||
'result_message' : message.engine_result_message,
|
||||
'rejected' : self.isRejected(message.engine_result_code), // If server is honest, don't expect a final if rejected.
|
||||
});
|
||||
}
|
||||
});
|
||||
self.emit('proposed', {
|
||||
'tx_json' : message.tx_json,
|
||||
'result' : message.engine_result,
|
||||
'result_code' : message.engine_result_code,
|
||||
'result_message' : message.engine_result_message,
|
||||
'rejected' : self.isRejected(message.engine_result_code), // If server is honest, don't expect a final if rejected.
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
this.on('error', function (message) {
|
||||
// Might want to give more detailed information.
|
||||
self.set_state('remoteError');
|
||||
});
|
||||
// Might want to give more detailed information.
|
||||
self.set_state('remoteError');
|
||||
});
|
||||
};
|
||||
|
||||
util.inherits(Transaction, EventEmitter);
|
||||
|
||||
// XXX This needs to be determined from the network.
|
||||
Transaction.fees = {
|
||||
'default' : Amount.from_json("10"),
|
||||
'nickname_create' : Amount.from_json("1000"),
|
||||
'offer' : Amount.from_json("10"),
|
||||
Transaction.fee_units = {
|
||||
'default' : 10,
|
||||
};
|
||||
|
||||
Transaction.flags = {
|
||||
'AccountSet' : {
|
||||
'RequireDestTag' : 0x00010000,
|
||||
'OptionalDestTag' : 0x00020000,
|
||||
'RequireAuth' : 0x00040000,
|
||||
'OptionalAuth' : 0x00080000,
|
||||
'DisallowXRP' : 0x00100000,
|
||||
'AllowXRP' : 0x00200000,
|
||||
},
|
||||
|
||||
'OfferCreate' : {
|
||||
'Passive' : 0x00010000,
|
||||
'ImmediateOrCancel' : 0x00020000,
|
||||
@@ -185,15 +195,17 @@ Transaction.prototype.set_state = function (state) {
|
||||
Transaction.prototype.complete = function () {
|
||||
var tx_json = this.tx_json;
|
||||
|
||||
if (undefined === tx_json.Fee && this.remote.local_fee) {
|
||||
tx_json.Fee = Transaction.fees['default'].to_json();
|
||||
if ("undefined" === typeof tx_json.Fee && this.remote.local_fee) {
|
||||
this.tx_json.Fee = this.remote.fee_tx(this.fee_units()).to_json();
|
||||
}
|
||||
|
||||
if (undefined === tx_json.SigningPubKey && (!this.remote || this.remote.local_signing)) {
|
||||
if ("undefined" === typeof tx_json.SigningPubKey && (!this.remote || this.remote.local_signing)) {
|
||||
var seed = Seed.from_json(this._secret);
|
||||
var key = seed.get_key(this.tx_json.Account);
|
||||
tx_json.SigningPubKey = key.to_hex_pub();
|
||||
}
|
||||
|
||||
return this.tx_json;
|
||||
};
|
||||
|
||||
Transaction.prototype.serialize = function () {
|
||||
@@ -202,23 +214,28 @@ Transaction.prototype.serialize = function () {
|
||||
|
||||
Transaction.prototype.signing_hash = function () {
|
||||
var prefix = config.testnet
|
||||
? Transaction.HASH_SIGN_TESTNET
|
||||
: Transaction.HASH_SIGN;
|
||||
? Transaction.HASH_SIGN_TESTNET
|
||||
: Transaction.HASH_SIGN;
|
||||
|
||||
return SerializedObject.from_json(this.tx_json).signing_hash(prefix);
|
||||
};
|
||||
|
||||
Transaction.prototype.sign = function () {
|
||||
var seed = Seed.from_json(this._secret),
|
||||
hash = this.signing_hash();
|
||||
|
||||
var key = seed.get_key(this.tx_json.Account),
|
||||
sig = key.sign(hash, 0),
|
||||
hex = sjcl.codec.hex.fromBits(sig).toUpperCase();
|
||||
var seed = Seed.from_json(this._secret);
|
||||
var hash = this.signing_hash();
|
||||
var key = seed.get_key(this.tx_json.Account);
|
||||
var sig = key.sign(hash, 0);
|
||||
var hex = sjcl.codec.hex.fromBits(sig).toUpperCase();
|
||||
|
||||
this.tx_json.TxnSignature = hex;
|
||||
};
|
||||
|
||||
Transaction.prototype._hasTransactionListeners = function() {
|
||||
return this.listeners('final').length
|
||||
|| this.listeners('lost').length
|
||||
|| this.listeners('pending').length
|
||||
};
|
||||
|
||||
// Submit a transaction to the network.
|
||||
// XXX Don't allow a submit without knowing ledger_index.
|
||||
// XXX Have a network canSubmit(), post events for following.
|
||||
@@ -233,18 +250,25 @@ Transaction.prototype.sign = function () {
|
||||
// case 'tejLost': locally gave up looking
|
||||
// default: some other TER
|
||||
// }
|
||||
|
||||
Transaction.prototype.submit = function (callback) {
|
||||
var self = this;
|
||||
var tx_json = this.tx_json;
|
||||
|
||||
this.callback = callback;
|
||||
this.callback = typeof callback === 'function'
|
||||
? callback
|
||||
: function(){};
|
||||
|
||||
if ('string' !== typeof tx_json.Account)
|
||||
{
|
||||
(this.callback || this.emit)('error', {
|
||||
'error' : 'tejInvalidAccount',
|
||||
'error_message' : 'Bad account.'
|
||||
});
|
||||
function finish(err) {
|
||||
self.emit('error', err);
|
||||
self.callback('error', err);
|
||||
}
|
||||
|
||||
if (typeof tx_json.Account !== 'string') {
|
||||
finish({
|
||||
'error' : 'tejInvalidAccount',
|
||||
'error_message' : 'Bad account.'
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -252,143 +276,142 @@ Transaction.prototype.submit = function (callback) {
|
||||
|
||||
this.complete();
|
||||
|
||||
if (this.callback || this.listeners('final').length || this.listeners('lost').length || this.listeners('pending').length) {
|
||||
// There are listeners for callback, 'final', 'lost', or 'pending' arrange to emit them.
|
||||
//console.log('Callback or has listeners');
|
||||
|
||||
this.submit_index = this.remote._ledger_current_index;
|
||||
// There are listeners for callback, 'final', 'lost', or 'pending' arrange to emit them.
|
||||
|
||||
// When a ledger closes, look for the result.
|
||||
var on_ledger_closed = function (message) {
|
||||
var ledger_hash = message.ledger_hash;
|
||||
var ledger_index = message.ledger_index;
|
||||
var stop = false;
|
||||
this.submit_index = this.remote._ledger_current_index;
|
||||
|
||||
// XXX make sure self.hash is available.
|
||||
self.remote.request_transaction_entry(self.hash)
|
||||
.ledger_hash(ledger_hash)
|
||||
.on('success', function (message) {
|
||||
if (self.finalized) return;
|
||||
// When a ledger closes, look for the result.
|
||||
function on_ledger_closed(message) {
|
||||
if (self.finalized) return;
|
||||
|
||||
self.set_state(message.metadata.TransactionResult);
|
||||
self.remote.removeListener('ledger_closed', on_ledger_closed);
|
||||
self.emit('final', message);
|
||||
self.finalized = true;
|
||||
var ledger_hash = message.ledger_hash;
|
||||
var ledger_index = message.ledger_index;
|
||||
var stop = false;
|
||||
|
||||
if (self.callback)
|
||||
self.callback(message.metadata.TransactionResult, message);
|
||||
})
|
||||
.on('error', function (message) {
|
||||
if (self.finalized) return;
|
||||
// XXX make sure self.hash is available.
|
||||
var transaction_entry = self.remote.request_transaction_entry(self.hash)
|
||||
|
||||
if ('remoteError' === message.error
|
||||
&& 'transactionNotFound' === message.remote.error) {
|
||||
if (self.submit_index + SUBMIT_LOST < ledger_index) {
|
||||
self.set_state('client_lost'); // Gave up.
|
||||
self.emit('lost');
|
||||
transaction_entry.ledger_hash(ledger_hash)
|
||||
|
||||
if (self.callback)
|
||||
self.callback('tejLost', message);
|
||||
transaction_entry.on('success', function (message) {
|
||||
if (self.finalized) return;
|
||||
self.set_state(message.metadata.TransactionResult);
|
||||
self.remote.removeListener('ledger_closed', on_ledger_closed);
|
||||
self.emit('final', message);
|
||||
self.finalized = true;
|
||||
self.callback(message.metadata.TransactionResult, message);
|
||||
});
|
||||
|
||||
self.remote.removeListener('ledger_closed', on_ledger_closed);
|
||||
self.emit('final', message);
|
||||
self.finalized = true;
|
||||
}
|
||||
else if (self.submit_index + SUBMIT_MISSING < ledger_index) {
|
||||
self.set_state('client_missing'); // We don't know what happened to transaction, still might find.
|
||||
self.emit('pending');
|
||||
}
|
||||
else {
|
||||
self.emit('pending');
|
||||
}
|
||||
}
|
||||
// XXX Could log other unexpectedness.
|
||||
})
|
||||
.request();
|
||||
};
|
||||
transaction_entry.on('error', function (message) {
|
||||
if (self.finalized) return;
|
||||
|
||||
this.remote.on('ledger_closed', on_ledger_closed);
|
||||
if (message.error === 'remoteError' && message.remote.error === 'transactionNotFound') {
|
||||
if (self.submit_index + SUBMIT_LOST < ledger_index) {
|
||||
self.set_state('client_lost'); // Gave up.
|
||||
self.emit('lost');
|
||||
self.callback('tejLost', message);
|
||||
self.remote.removeListener('ledger_closed', on_ledger_closed);
|
||||
self.emit('final', message);
|
||||
self.finalized = true;
|
||||
} else if (self.submit_index + SUBMIT_MISSING < ledger_index) {
|
||||
self.set_state('client_missing'); // We don't know what happened to transaction, still might find.
|
||||
self.emit('pending');
|
||||
} else {
|
||||
self.emit('pending');
|
||||
}
|
||||
}
|
||||
// XXX Could log other unexpectedness.
|
||||
});
|
||||
|
||||
if (this.callback) {
|
||||
this.on('error', function (message) {
|
||||
self.callback(message.error, message);
|
||||
});
|
||||
}
|
||||
}
|
||||
transaction_entry.request();
|
||||
};
|
||||
|
||||
this.remote.on('ledger_closed', on_ledger_closed);
|
||||
|
||||
this.once('error', function (message) {
|
||||
self.callback(message.error, message);
|
||||
});
|
||||
|
||||
this.set_state('client_submitted');
|
||||
|
||||
if (self.remote.local_sequence && !self.tx_json.Sequence) {
|
||||
self.tx_json.Sequence = this.remote.account_seq(self.tx_json.Account, 'ADVANCE');
|
||||
|
||||
self.tx_json.Sequence = this.remote.account_seq(self.tx_json.Account, 'ADVANCE');
|
||||
// console.log("Sequence: %s", self.tx_json.Sequence);
|
||||
|
||||
if (!self.tx_json.Sequence) {
|
||||
//console.log('NO SEQUENCE');
|
||||
|
||||
// Look in the last closed ledger.
|
||||
this.remote.account_seq_cache(self.tx_json.Account, false)
|
||||
var account_seq = this.remote.account_seq_cache(self.tx_json.Account, false)
|
||||
|
||||
account_seq.on('success_account_seq_cache', function () {
|
||||
// Try again.
|
||||
self.submit();
|
||||
})
|
||||
|
||||
account_seq.on('error_account_seq_cache', function (message) {
|
||||
// XXX Maybe be smarter about this. Don't want to trust an untrusted server for this seq number.
|
||||
// Look in the current ledger.
|
||||
self.remote.account_seq_cache(self.tx_json.Account, 'CURRENT')
|
||||
.on('success_account_seq_cache', function () {
|
||||
// Try again.
|
||||
self.submit();
|
||||
})
|
||||
.on('error_account_seq_cache', function (message) {
|
||||
// XXX Maybe be smarter about this. Don't want to trust an untrusted server for this seq number.
|
||||
|
||||
// Look in the current ledger.
|
||||
self.remote.account_seq_cache(self.tx_json.Account, 'CURRENT')
|
||||
.on('success_account_seq_cache', function () {
|
||||
// Try again.
|
||||
self.submit();
|
||||
})
|
||||
.on('error_account_seq_cache', function (message) {
|
||||
// Forward errors.
|
||||
self.emit('error', message);
|
||||
})
|
||||
.request();
|
||||
// Forward errors.
|
||||
self.emit('error', message);
|
||||
})
|
||||
.request();
|
||||
})
|
||||
|
||||
account_seq.request();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
// If the transaction fails we want to either undo incrementing the sequence
|
||||
// or submit a noop transaction to consume the sequence remotely.
|
||||
this.on('success', function (res) {
|
||||
if (!res || "string" !== typeof res.engine_result) return;
|
||||
this.once('success', function (res) {
|
||||
if (typeof res.engine_result === 'string') {
|
||||
switch (res.engine_result.slice(0, 3)) {
|
||||
// Synchronous local error
|
||||
case 'tej':
|
||||
self.remote.account_seq(self.tx_json.Account, 'REWIND');
|
||||
break;
|
||||
|
||||
switch (res.engine_result.slice(0, 3)) {
|
||||
// Synchronous local error
|
||||
case 'tej':
|
||||
self.remote.account_seq(self.tx_json.Account, 'REWIND');
|
||||
break;
|
||||
// XXX: What do we do in case of ter?
|
||||
case 'tel':
|
||||
case 'tem':
|
||||
case 'tef':
|
||||
// XXX Once we have a transaction submission manager class, we can
|
||||
// check if there are any other transactions pending. If there are,
|
||||
// we should submit a dummy transaction to ensure those
|
||||
// transactions are still valid.
|
||||
//var noop = self.remote.transaction().account_set(self.tx_json.Account);
|
||||
//noop.submit();
|
||||
case 'ter':
|
||||
// XXX: What do we do in case of ter?
|
||||
break;
|
||||
|
||||
// XXX Hotfix. This only works if no other transactions are pending.
|
||||
self.remote.account_seq(self.tx_json.Account, 'REWIND');
|
||||
break;
|
||||
case 'tel':
|
||||
case 'tem':
|
||||
case 'tef':
|
||||
// XXX Once we have a transaction submission manager class, we can
|
||||
// check if there are any other transactions pending. If there are,
|
||||
// we should submit a dummy transaction to ensure those
|
||||
// transactions are still valid.
|
||||
//var noop = self.remote.transaction().account_set(self.tx_json.Account);
|
||||
//noop.submit();
|
||||
|
||||
// XXX Hotfix. This only works if no other transactions are pending.
|
||||
self.remote.account_seq(self.tx_json.Account, 'REWIND');
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Prepare request
|
||||
|
||||
var request = this.remote.request_submit();
|
||||
|
||||
// Forward successes and errors.
|
||||
request.on('success', function (message) {
|
||||
self.emit('success', message);
|
||||
});
|
||||
request.on('error', function (message) {
|
||||
self.emit('error', message);
|
||||
});
|
||||
// Forward events
|
||||
request.emit = this.emit.bind(this);
|
||||
|
||||
if (!this._secret && !this.tx_json.Signature) {
|
||||
this.emit('error', {
|
||||
finish({
|
||||
'result' : 'tejSecretUnknown',
|
||||
'result_message' : "Could not sign transactions because we."
|
||||
});
|
||||
@@ -398,11 +421,10 @@ Transaction.prototype.submit = function (callback) {
|
||||
request.tx_blob(this.serialize().to_hex());
|
||||
} else {
|
||||
if (!this.remote.trusted) {
|
||||
this.emit('error', {
|
||||
finish({
|
||||
'result' : 'tejServerUntrusted',
|
||||
'result_message' : "Attempt to give a secret to an untrusted server."
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
request.secret(this._secret);
|
||||
@@ -431,8 +453,9 @@ Transaction.prototype.build_path = function (build) {
|
||||
// tag should be undefined or a 32 bit integer.
|
||||
// YYY Add range checking for tag.
|
||||
Transaction.prototype.destination_tag = function (tag) {
|
||||
if (undefined !== tag)
|
||||
this.tx_json.DestinationTag = tag;
|
||||
if (tag !== undefined) {
|
||||
this.tx_json.DestinationTag = tag;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
@@ -482,8 +505,9 @@ Transaction.prototype.secret = function (secret) {
|
||||
}
|
||||
|
||||
Transaction.prototype.send_max = function (send_max) {
|
||||
if (send_max)
|
||||
this.tx_json.SendMax = Amount.json_rewrite(send_max);
|
||||
if (send_max) {
|
||||
this.tx_json.SendMax = Amount.json_rewrite(send_max);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
@@ -491,8 +515,9 @@ Transaction.prototype.send_max = function (send_max) {
|
||||
// tag should be undefined or a 32 bit integer.
|
||||
// YYY Add range checking for tag.
|
||||
Transaction.prototype.source_tag = function (tag) {
|
||||
if (undefined !== tag)
|
||||
this.tx_json.SourceTag = tag;
|
||||
if (tag) {
|
||||
this.tx_json.SourceTag = tag;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
@@ -501,8 +526,9 @@ Transaction.prototype.source_tag = function (tag) {
|
||||
Transaction.prototype.transfer_rate = function (rate) {
|
||||
this.tx_json.TransferRate = Number(rate);
|
||||
|
||||
if (this.tx_json.TransferRate < 1e9)
|
||||
throw 'invalidTransferRate';
|
||||
if (this.tx_json.TransferRate < 1e9) {
|
||||
throw new Error('invalidTransferRate');
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
@@ -511,24 +537,26 @@ Transaction.prototype.transfer_rate = function (rate) {
|
||||
// --> flags: undefined, _flag_, or [ _flags_ ]
|
||||
Transaction.prototype.set_flags = function (flags) {
|
||||
if (flags) {
|
||||
var transaction_flags = Transaction.flags[this.tx_json.TransactionType];
|
||||
var transaction_flags = Transaction.flags[this.tx_json.TransactionType];
|
||||
|
||||
if (undefined == this.tx_json.Flags) // We plan to not define this field on new Transaction.
|
||||
this.tx_json.Flags = 0;
|
||||
// We plan to not define this field on new Transaction.
|
||||
if (this.tx_json.Flags === undefined) {
|
||||
this.tx_json.Flags = 0;
|
||||
}
|
||||
|
||||
var flag_set = 'object' === typeof flags ? flags : [ flags ];
|
||||
var flag_set = Array.isArray(flags) ? flags : [ flags ];
|
||||
|
||||
for (var index in flag_set) {
|
||||
if (!flag_set.hasOwnProperty(index)) continue;
|
||||
for (var index in flag_set) {
|
||||
if (!flag_set.hasOwnProperty(index)) continue;
|
||||
|
||||
var flag = flag_set[index];
|
||||
var flag = flag_set[index];
|
||||
|
||||
if (flag in transaction_flags) {
|
||||
this.tx_json.Flags += transaction_flags[flag];
|
||||
} else {
|
||||
// XXX Immediately report an error or mark it.
|
||||
}
|
||||
if (flag in transaction_flags) {
|
||||
this.tx_json.Flags += transaction_flags[flag];
|
||||
} else {
|
||||
// XXX Immediately report an error or mark it.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
@@ -545,6 +573,7 @@ Transaction.prototype._account_secret = function (account) {
|
||||
|
||||
// Options:
|
||||
// .domain() NYI
|
||||
// .flags()
|
||||
// .message_key() NYI
|
||||
// .transfer_rate()
|
||||
// .wallet_locator() NYI
|
||||
@@ -578,22 +607,24 @@ Transaction.prototype.offer_cancel = function (src, sequence) {
|
||||
|
||||
// Options:
|
||||
// .set_flags()
|
||||
// --> expiration : Date or Number
|
||||
Transaction.prototype.offer_create = function (src, taker_pays, taker_gets, expiration) {
|
||||
// --> expiration : if not undefined, Date or Number
|
||||
// --> cancel_sequence : if not undefined, Sequence
|
||||
Transaction.prototype.offer_create = function (src, taker_pays, taker_gets, expiration, cancel_sequence) {
|
||||
this._secret = this._account_secret(src);
|
||||
this.tx_json.TransactionType = 'OfferCreate';
|
||||
this.tx_json.Account = UInt160.json_rewrite(src);
|
||||
this.tx_json.TakerPays = Amount.json_rewrite(taker_pays);
|
||||
this.tx_json.TakerGets = Amount.json_rewrite(taker_gets);
|
||||
|
||||
if (this.remote.local_fee) {
|
||||
this.tx_json.Fee = Transaction.fees.offer.to_json();
|
||||
if (expiration) {
|
||||
this.tx_json.Expiration = expiration instanceof Date
|
||||
? expiration.getTime()
|
||||
: Number(expiration);
|
||||
}
|
||||
|
||||
if (expiration)
|
||||
this.tx_json.Expiration = Date === expiration.constructor
|
||||
? expiration.getTime()
|
||||
: Number(expiration);
|
||||
if (cancel_sequence) {
|
||||
this.tx_json.OfferSequence = Number(cancel_sequence);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
@@ -650,7 +681,7 @@ Transaction.prototype.ripple_line_set = function (src, limit, quality_in, qualit
|
||||
this.tx_json.Account = UInt160.json_rewrite(src);
|
||||
|
||||
// Allow limit of 0 through.
|
||||
if (undefined !== limit)
|
||||
if (limit !== undefined)
|
||||
this.tx_json.LimitAmount = Amount.json_rewrite(limit);
|
||||
|
||||
if (quality_in)
|
||||
@@ -675,6 +706,22 @@ Transaction.prototype.wallet_add = function (src, amount, authorized_key, public
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the number of fee units this transaction will cost.
|
||||
*
|
||||
* Each Ripple transaction based on its type and makeup costs a certain number
|
||||
* of fee units. The fee units are calculated on a per-server basis based on the
|
||||
* current load on both the network and the server.
|
||||
*
|
||||
* @see https://ripple.com/wiki/Transaction_Fee
|
||||
*
|
||||
* @return {Number} Number of fee units for this transaction.
|
||||
*/
|
||||
Transaction.prototype.fee_units = function ()
|
||||
{
|
||||
return Transaction.fee_units["default"];
|
||||
};
|
||||
|
||||
exports.Transaction = Transaction;
|
||||
|
||||
// vim:sw=2:sts=2:ts=8:et
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
var sjcl = require('../../build/sjcl');
|
||||
var sjcl = require('../../../build/sjcl');
|
||||
var utils = require('./utils');
|
||||
var config = require('./config');
|
||||
var jsbn = require('./jsbn');
|
||||
@@ -60,6 +60,15 @@ UInt.from_bits = function (j) {
|
||||
}
|
||||
};
|
||||
|
||||
// Return a new UInt from j.
|
||||
UInt.from_bytes = function (j) {
|
||||
if (j instanceof this) {
|
||||
return j.clone();
|
||||
} else {
|
||||
return (new this()).parse_bytes(j);
|
||||
}
|
||||
};
|
||||
|
||||
// Return a new UInt from j.
|
||||
UInt.from_bn = function (j) {
|
||||
if (j instanceof this) {
|
||||
@@ -157,7 +166,17 @@ UInt.prototype.parse_bits = function (j) {
|
||||
this._value = NaN;
|
||||
} else {
|
||||
var bytes = sjcl.codec.bytes.fromBits(j);
|
||||
this._value = new BigInteger(bytes, 256);
|
||||
this.parse_bytes(bytes);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
UInt.prototype.parse_bytes = function (j) {
|
||||
if (!Array.isArray(j) || j.length !== this.constructor.width) {
|
||||
this._value = NaN;
|
||||
} else {
|
||||
this._value = new BigInteger(j, 256);
|
||||
}
|
||||
|
||||
return this;
|
||||
32
src/js/ripple/uint128.js
Normal file
32
src/js/ripple/uint128.js
Normal file
@@ -0,0 +1,32 @@
|
||||
|
||||
var sjcl = require('../../../build/sjcl');
|
||||
var utils = require('./utils');
|
||||
var config = require('./config');
|
||||
var jsbn = require('./jsbn');
|
||||
var extend = require('extend');
|
||||
|
||||
var BigInteger = jsbn.BigInteger;
|
||||
var nbi = jsbn.nbi;
|
||||
|
||||
var UInt = require('./uint').UInt,
|
||||
Base = require('./base').Base;
|
||||
|
||||
//
|
||||
// UInt128 support
|
||||
//
|
||||
|
||||
var UInt128 = extend(function () {
|
||||
// Internal form: NaN or BigInteger
|
||||
this._value = NaN;
|
||||
}, UInt);
|
||||
|
||||
UInt128.width = 16;
|
||||
UInt128.prototype = extend({}, UInt.prototype);
|
||||
UInt128.prototype.constructor = UInt128;
|
||||
|
||||
var HEX_ZERO = UInt128.HEX_ZERO = "00000000000000000000000000000000";
|
||||
var HEX_ONE = UInt128.HEX_ONE = "00000000000000000000000000000000";
|
||||
var STR_ZERO = UInt128.STR_ZERO = utils.hexToString(HEX_ZERO);
|
||||
var STR_ONE = UInt128.STR_ONE = utils.hexToString(HEX_ONE);
|
||||
|
||||
exports.UInt128 = UInt128;
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
var sjcl = require('../../build/sjcl');
|
||||
var sjcl = require('../../../build/sjcl');
|
||||
var utils = require('./utils');
|
||||
var config = require('./config');
|
||||
var jsbn = require('./jsbn');
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
var sjcl = require('../../build/sjcl');
|
||||
var sjcl = require('../../../build/sjcl');
|
||||
var utils = require('./utils');
|
||||
var config = require('./config');
|
||||
var jsbn = require('./jsbn');
|
||||
Submodule src/js/sjcl deleted from dbdef434e7
96
src/js/sjcl/Makefile
Normal file
96
src/js/sjcl/Makefile
Normal file
@@ -0,0 +1,96 @@
|
||||
JSDOCSTYLE= codeview
|
||||
JSDOCDIR= jsdoc_toolkit-2.3.3-beta
|
||||
JSDOC= $(JSDOCDIR)/jsrun.sh
|
||||
JSTEMPLATEDIR= $(JSDOCDIR)/templates/$(JSDOCSTYLE)/
|
||||
|
||||
YUICOMPRESSOR= yuicompressor-2.4.2.jar
|
||||
|
||||
include config.mk
|
||||
|
||||
.PHONY: all test test_yui test_closure test_uncompressed lint compression_stats
|
||||
|
||||
all: sjcl.js
|
||||
|
||||
sjcl.js: $(COMPRESS)
|
||||
cp $^ $@
|
||||
|
||||
core.js: $(SOURCES) config.mk
|
||||
cat $(SOURCES) > $@
|
||||
|
||||
# compressed targets
|
||||
core_closure.js: core.js compress/compress_with_closure.sh compress/*.pl
|
||||
compress/compress_with_closure.sh $< > $@
|
||||
|
||||
core_yui.js: core.js compress/compress_with_yui.sh compress/*.pl
|
||||
compress/compress_with_yui.sh $< > $@
|
||||
|
||||
compression_stats: core.js core_closure.js core_yui.js
|
||||
gzip -c core.js > core.js.gz
|
||||
gzip -c core_yui.js > core_yui.js.gz
|
||||
gzip -c core_closure.js > core_closure.js.gz
|
||||
|
||||
@echo
|
||||
@echo
|
||||
@echo Compression stats:
|
||||
@echo
|
||||
@wc -c core.js core_closure.js core_yui.js | head -n -1
|
||||
@echo
|
||||
@wc -c core*.js.gz | head -n -1
|
||||
@echo
|
||||
@echo
|
||||
|
||||
rm -f core*.js.gz
|
||||
|
||||
doc: $(SOURCES)
|
||||
rm -fr $@
|
||||
JSDOCDIR=$(JSDOCDIR) $(JSDOC) -t=$(JSTEMPLATEDIR) $(SOURCES) -d=$@
|
||||
|
||||
doc_private: $(SOURCES)
|
||||
rm -fr $@
|
||||
JSDOCDIR=$(JSDOCDIR) $(JSDOC) -t=$(JSTEMPLATEDIR) $(SOURCES) --private -d=$@
|
||||
|
||||
lint: core.js core/*.js test/*.js browserTest/*.js lint/coding_guidelines.pl
|
||||
rhino lint/jslint_rhino.js core.js
|
||||
lint/coding_guidelines.pl core/*.js test/*.js browserTest/*.js
|
||||
|
||||
|
||||
TEST_COMMON= browserTest/rhinoUtil.js test/test.js
|
||||
|
||||
TEST_SCRIPTS= $(TEST_COMMON) \
|
||||
test/aes_vectors.js test/aes_test.js \
|
||||
test/ocb2_vectors.js test/ocb2_test.js \
|
||||
test/ccm_vectors.js test/ccm_test.js \
|
||||
test/cbc_vectors.js test/cbc_test.js \
|
||||
test/gcm_vectors.js test/gcm_test.js \
|
||||
test/sha256_vectors.js test/sha256_test.js \
|
||||
test/sha256_test_brute_force.js \
|
||||
test/sha512_vectors.js test/sha512_test.js \
|
||||
test/sha512_test_brute_force.js \
|
||||
test/sha1_vectors.js test/sha1_test.js \
|
||||
test/hmac_vectors.js test/hmac_test.js \
|
||||
test/pbkdf2_test.js \
|
||||
test/bn_vectors.js test/bn_test.js \
|
||||
test/ecdsa_test.js test/ecdsa_vectors.js test/ecdh_test.js
|
||||
|
||||
TEST_SCRIPTS_OPT= $(TEST_COMMON) \
|
||||
test/srp_vectors.js test/srp_test.js
|
||||
|
||||
# Rhino fails at -O 0. Probably because the big files full of test vectors blow the
|
||||
# bytecode limit. So, run most tests with -O -1. But modular exponentiation is
|
||||
# currently very slow (on Rhino), so run the SRP test with optimizations on.
|
||||
|
||||
test: sjcl.js $(TEST_SCRIPTS) test/run_tests_rhino.js
|
||||
@rhino -O -1 -w test/run_tests_rhino.js $< $(TEST_SCRIPTS)
|
||||
@rhino -O 9 -w test/run_tests_rhino.js $< $(TEST_SCRIPTS_OPT)
|
||||
|
||||
tidy:
|
||||
find . -name '*~' -delete
|
||||
rm -f core.js core_*.js
|
||||
|
||||
clean: tidy
|
||||
rm -fr sjcl.js doc doc_private
|
||||
|
||||
distclean: clean
|
||||
./configure
|
||||
make sjcl.js tidy
|
||||
|
||||
32
src/js/sjcl/README/COPYRIGHT
Normal file
32
src/js/sjcl/README/COPYRIGHT
Normal file
@@ -0,0 +1,32 @@
|
||||
SJCL used to be in the public domain. Now it's:
|
||||
|
||||
Copyright 2009-2010 Emily Stark, Mike Hamburg, Dan Boneh, Stanford University.
|
||||
|
||||
This is for liability reasons. (Speaking of which, SJCL comes with NO
|
||||
WARRANTY WHATSOEVER, express or implied, to the limit of applicable
|
||||
law.)
|
||||
|
||||
SJCL is dual-licensed under the GNU GPL version 2.0 or higher, and a
|
||||
2-clause BSD license. You may use SJCL under the terms of either of
|
||||
these licenses. For your convenience, the GPL versions 2.0 and 3.0
|
||||
and the 2-clause BSD license are included here. Additionally, you may
|
||||
serve "crunched" copies of sjcl (i.e. those with comments removed,
|
||||
and other transformations to reduce code size) without any copyright
|
||||
notice.
|
||||
|
||||
SJCL includes JsDoc toolkit, YUI compressor, Closure compressor,
|
||||
JSLint and the CodeView template in its build system. These programs'
|
||||
copyrights are owned by other people. They are distributed here under
|
||||
the MPL, MIT, BSD, Apache and JSLint licenses. Codeview is "free for
|
||||
download" but has no license attached; it is Copyright 2010 Wouter Bos.
|
||||
|
||||
The BSD license is (almost?) strictly more permissive, but the
|
||||
additionally licensing under the GPL allows us to use OCB 2.0 code
|
||||
royalty-free (at least, if OCB 2.0's creator Phil Rogaway has anything
|
||||
to say about it). Note that if you redistribute SJCL under a license
|
||||
other than the GPL, you or your users may need to pay patent licensing
|
||||
fees for OCB 2.0.
|
||||
|
||||
There may be patents which apply to SJCL other than Phil Rogaway's OCB
|
||||
patents. We suggest that you consult legal counsel before using SJCL
|
||||
in a commercial project.
|
||||
36
src/js/sjcl/README/INSTALL
Normal file
36
src/js/sjcl/README/INSTALL
Normal file
@@ -0,0 +1,36 @@
|
||||
SJCL comes with a file sjcl.js pre-built. This default build includes
|
||||
all the modules except for sjcl.codec.bytes (because the demo site doesn't
|
||||
use it). All you need to do to install is copy this file to your web
|
||||
server and start using it.
|
||||
|
||||
SJCL is divided into modules implementing various cryptographic and
|
||||
convenience functions. If you don't need them all for your application,
|
||||
you can reconfigure SJCL for a smaller code size. To do this, you can
|
||||
run
|
||||
|
||||
./configure --without-all --with-aes --with-sha256 ...
|
||||
|
||||
Then type
|
||||
|
||||
make
|
||||
|
||||
to rebuild sjcl.js. This will also create a few intermediate files
|
||||
core*.js; you can delete these automatically by typing
|
||||
|
||||
make sjcl.js tidy
|
||||
|
||||
instead. You will need make, perl, bash and java to rebuild SJCL.
|
||||
|
||||
Some of the modules depend on other modules; configure should handle this
|
||||
automatically unless you tell it --without-FOO --with-BAR, where BAR
|
||||
depends on FOO. If you do this, configure will yell at you.
|
||||
|
||||
SJCL is compressed by stripping comments, shortening variable names, etc.
|
||||
You can also pass a --compress argument to configure to change the
|
||||
compressor. By default SJCL uses some perl/sh scripts and Google's
|
||||
Closure compressor.
|
||||
|
||||
If you reconfigure SJCL, it is recommended that you run the included test
|
||||
suite by typing "make test". If this prints "FAIL" or segfaults, SJCL
|
||||
doesn't work; please file a bug.
|
||||
|
||||
30
src/js/sjcl/README/bsd.txt
Normal file
30
src/js/sjcl/README/bsd.txt
Normal file
@@ -0,0 +1,30 @@
|
||||
Copyright 2009-2010 Emily Stark, Mike Hamburg, Dan Boneh.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation
|
||||
are those of the authors and should not be interpreted as representing
|
||||
official policies, either expressed or implied, of the authors.
|
||||
339
src/js/sjcl/README/gpl-2.0.txt
Normal file
339
src/js/sjcl/README/gpl-2.0.txt
Normal file
@@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
674
src/js/sjcl/README/gpl-3.0.txt
Normal file
674
src/js/sjcl/README/gpl-3.0.txt
Normal file
@@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
16
src/js/sjcl/browserTest/browserTest.html
Normal file
16
src/js/sjcl/browserTest/browserTest.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>SJCL browser test</title>
|
||||
<link rel="stylesheet" type="text/css" href="test.css"/>
|
||||
<script type="text/javascript" src="browserUtil.js"></script>
|
||||
<script type="text/javascript" src="../test/run_tests_browser.js"></script>
|
||||
</head>
|
||||
<body onload="testCores(['sjcl.js'])">
|
||||
<h1>SJCL browser test</h1>
|
||||
<div id="status">Waiting for tests to begin...</div>
|
||||
<div id="print"></div>
|
||||
</body>
|
||||
</html>
|
||||
133
src/js/sjcl/browserTest/browserUtil.js
Normal file
133
src/js/sjcl/browserTest/browserUtil.js
Normal file
@@ -0,0 +1,133 @@
|
||||
browserUtil = {};
|
||||
|
||||
browserUtil.isRhino = (typeof(window) === 'undefined');
|
||||
|
||||
/**
|
||||
* Pause (for the graphics to update and the script timer to clear), then run the
|
||||
* specified action.
|
||||
*/
|
||||
browserUtil.pauseAndThen = function (cb) {
|
||||
cb && window.setTimeout(cb, 1);
|
||||
};
|
||||
|
||||
/**
|
||||
* Iterate using continuation-passing style.
|
||||
*/
|
||||
browserUtil.cpsIterate = function (f, start, end, pause, callback) {
|
||||
var pat = pause ? browserUtil.pauseAndThen : function (cb) { cb && cb(); };
|
||||
function go() {
|
||||
var called = false;
|
||||
if (start >= end) {
|
||||
pat(callback);
|
||||
} else {
|
||||
pat(function () { f(start, function () {
|
||||
if (!called) { called = true; start++; go(); }
|
||||
}); });
|
||||
}
|
||||
}
|
||||
go (start);
|
||||
};
|
||||
|
||||
/**
|
||||
* Map a function over an array using continuation-passing style.
|
||||
*/
|
||||
browserUtil.cpsMap = function (map, list, pause, callback) {
|
||||
browserUtil.cpsIterate(function (i, cb) { map(list[i], i, list.length, cb); },
|
||||
0, list.length, pause, callback);
|
||||
}
|
||||
|
||||
/** Cache for remotely loaded scripts. */
|
||||
browserUtil.scriptCache = {}
|
||||
|
||||
/** Load several scripts, then call back */
|
||||
browserUtil.loadScripts = function(scriptNames, cbSuccess, cbError) {
|
||||
var head = document.getElementsByTagName('head')[0];
|
||||
browserUtil.cpsMap(function (script, i, n, cb) {
|
||||
var scriptE = document.createElement('script'), xhr, loaded = false;
|
||||
|
||||
browserUtil.status("Loading script " + script);
|
||||
|
||||
if (window.location.protocol === "file:") {
|
||||
/* Can't make an AJAX request for files.
|
||||
* But, we know the load time will be short, so timeout-based error
|
||||
* detection is fine.
|
||||
*/
|
||||
scriptE.onload = function () {
|
||||
loaded = true;
|
||||
cb();
|
||||
};
|
||||
scriptE.onerror = function(err) {
|
||||
cbError && cbError(script, err, cb);
|
||||
};
|
||||
script.onreadystatechange = function() {
|
||||
if (this.readyState == 'complete' || this.readyState == 'loaded') {
|
||||
loaded = true;
|
||||
cb();
|
||||
}
|
||||
};
|
||||
scriptE.type = 'text/javascript';
|
||||
scriptE.src = script+"?"+(new Date().valueOf());
|
||||
window.setTimeout(function () {
|
||||
loaded || cbError && cbError(script, "timeout expired", cb);
|
||||
}, 100);
|
||||
head.appendChild(scriptE);
|
||||
} else if (browserUtil.scriptCache[script] !== undefined) {
|
||||
try {
|
||||
scriptE.appendChild(document.createTextNode(browserUtil.scriptCache[script]));
|
||||
} catch (e) {
|
||||
scriptE.text = browserUtil.scriptCache[script];
|
||||
}
|
||||
head.appendChild(scriptE);
|
||||
cb();
|
||||
} else {
|
||||
var xhr;
|
||||
if (window.XMLHttpRequest) {
|
||||
xhr = new XMLHttpRequest;
|
||||
} else if (window.ActiveXObject) {
|
||||
xhr = new ActiveXObject("Microsoft.XMLHTTP");
|
||||
}
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState == 4) {
|
||||
if (xhr.status == 200) {
|
||||
browserUtil.scriptCache[script] = xhr.responseText;
|
||||
try {
|
||||
scriptE.appendChild(document.createTextNode(xhr.responseText));
|
||||
} catch (e) {
|
||||
scriptE.text = xhr.responseText;
|
||||
}
|
||||
head.appendChild(scriptE);
|
||||
cb();
|
||||
} else {
|
||||
cbError && cbError(script, xhr.status, cb);
|
||||
}
|
||||
}
|
||||
}
|
||||
xhr.open("GET", script+"?"+(new Date().valueOf()), true);
|
||||
xhr.send();
|
||||
}
|
||||
}, scriptNames, false, cbSuccess);
|
||||
};
|
||||
|
||||
/** Write a message to the console */
|
||||
browserUtil.write = function(type, message) {
|
||||
var d1 = document.getElementById("print"), d2 = document.createElement("div"), d3 = document.createElement("div");
|
||||
d3.className = type;
|
||||
d3.appendChild(document.createTextNode(message));
|
||||
d2.appendChild(d3);
|
||||
d1.appendChild(d2);
|
||||
return { update: function (type2, message2) {
|
||||
var d4 = document.createElement("div");
|
||||
d4.className = type2 + " also";
|
||||
d4.appendChild(document.createTextNode(message2));
|
||||
d2.insertBefore(d4, d3);
|
||||
}};
|
||||
};
|
||||
|
||||
/** Write a newline. Does nothing in the browser. */
|
||||
browserUtil.writeNewline = function () { };
|
||||
|
||||
/** Write a message to the status line */
|
||||
browserUtil.status = function(message) {
|
||||
var d1 = document.getElementById("status");
|
||||
d1.replaceChild(document.createTextNode(message), d1.firstChild);
|
||||
};
|
||||
44
src/js/sjcl/browserTest/rhinoUtil.js
Normal file
44
src/js/sjcl/browserTest/rhinoUtil.js
Normal file
@@ -0,0 +1,44 @@
|
||||
browserUtil = {
|
||||
isRhino: true,
|
||||
|
||||
pauseAndThen: function (cb) { cb(); },
|
||||
|
||||
cpsIterate: function (f, start, end, pause, callback) {
|
||||
function go() {
|
||||
var called = false;
|
||||
if (start >= end) {
|
||||
callback && callback();
|
||||
} else {
|
||||
f(start, function () {
|
||||
if (!called) { called = true; start++; go(); }
|
||||
});
|
||||
}
|
||||
}
|
||||
go (start);
|
||||
},
|
||||
|
||||
cpsMap: function (map, list, pause, callback) {
|
||||
browserUtil.cpsIterate(function (i, cb) { map(list[i], i, list.length, cb); },
|
||||
0, list.length, pause, callback);
|
||||
},
|
||||
|
||||
loadScripts: function(scriptNames, callback) {
|
||||
for (i=0; i<scriptNames.length; i++) {
|
||||
load(scriptNames[i]);
|
||||
callback && callback();
|
||||
}
|
||||
},
|
||||
|
||||
write: function(type, message) {
|
||||
print(message);
|
||||
return { update: function (type2, message2) {
|
||||
if (type2 === 'pass') { print(" + " + message2); }
|
||||
else if (type2 === 'unimplemented') { print(" ? " + message2); }
|
||||
else { print(" - " + message2); }
|
||||
}};
|
||||
},
|
||||
|
||||
writeNewline: function () { print(""); },
|
||||
|
||||
status: function(message) {}
|
||||
};
|
||||
59
src/js/sjcl/browserTest/test.css
Normal file
59
src/js/sjcl/browserTest/test.css
Normal file
@@ -0,0 +1,59 @@
|
||||
* {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
font-family: Arial, Helvetica, FreeSans, sans;
|
||||
}
|
||||
|
||||
#print {
|
||||
position: relative;
|
||||
width: 40em;
|
||||
margin: 0px auto;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
#print div {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.pass { color: #0A0; }
|
||||
.fail { color: #A00; }
|
||||
.unimplemented { color: #F80; }
|
||||
|
||||
.begin {
|
||||
text-align: center;
|
||||
padding-bottom: 2px;
|
||||
border-bottom: 1px solid #aaa;
|
||||
margin: 0px auto 2px auto;
|
||||
}
|
||||
|
||||
.all {
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
*+* > .begin, *+* > .all {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.also {
|
||||
float: right;
|
||||
width: 17em;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
background: #8A0000;
|
||||
padding: 5px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
#status {
|
||||
padding: 3px 10px 3px 5px;
|
||||
background: #d5c490;
|
||||
color: #444;
|
||||
font-size: 0.8em;
|
||||
margin-bottom: 1em;
|
||||
height: 1.3em;
|
||||
vertical-align: middle;
|
||||
}
|
||||
5
src/js/sjcl/component.json
Normal file
5
src/js/sjcl/component.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "sjcl",
|
||||
"version": "1.0.0",
|
||||
"main": ["./sjcl.js"]
|
||||
}
|
||||
BIN
src/js/sjcl/compress/compiler.jar
Normal file
BIN
src/js/sjcl/compress/compiler.jar
Normal file
Binary file not shown.
15
src/js/sjcl/compress/compress_with_closure.sh
Executable file
15
src/js/sjcl/compress/compress_with_closure.sh
Executable file
@@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
|
||||
DIR=`dirname $0`
|
||||
|
||||
$DIR/remove_constants.pl $1 | $DIR/opacify.pl > ._tmpRC.js
|
||||
|
||||
echo -n '"use strict";'
|
||||
java -jar $DIR/compiler.jar --compilation_level ADVANCED_OPTIMIZATIONS \
|
||||
--js ._tmpRC.js \
|
||||
| $DIR/digitize.pl \
|
||||
| $DIR/dewindowize.pl
|
||||
|
||||
|
||||
rm -f ._tmpRC.js
|
||||
|
||||
13
src/js/sjcl/compress/compress_with_yui.sh
Executable file
13
src/js/sjcl/compress/compress_with_yui.sh
Executable file
@@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Compress $1 with YUI Compressor 2.4.2, returning the compressed script on stdout
|
||||
|
||||
DIR=`dirname $0`
|
||||
|
||||
$DIR/remove_constants.pl $1 > ._tmpRC.js
|
||||
|
||||
java -jar $DIR/yuicompressor-2.4.2.jar ._tmpRC.js \
|
||||
| $DIR/digitize.pl
|
||||
|
||||
rm -f ._tmpRC.js
|
||||
|
||||
8
src/js/sjcl/compress/dewindowize.pl
Executable file
8
src/js/sjcl/compress/dewindowize.pl
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
while (<>) {
|
||||
s/window\.sjcl\s*=/var sjcl=/g;
|
||||
s/window\.sjcl/sjcl/g;
|
||||
print;
|
||||
}
|
||||
|
||||
22
src/js/sjcl/compress/digitize.pl
Executable file
22
src/js/sjcl/compress/digitize.pl
Executable file
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
# Convert numbers to hex, when doing so is likely to increase compressibility.
|
||||
# This actually makes the script slightly longer, but generally makes it compress
|
||||
# to something shorter.
|
||||
#
|
||||
# Here we're targeting constants like 0xFF, 0xFFFF0000, 0x10101, 0x100000000, etc.
|
||||
|
||||
sub digitize {
|
||||
my $number = shift;
|
||||
if ($number >= 256) {
|
||||
my $nn = `printf "%x" $number`;
|
||||
if ($nn =~ /^[01f]+$/i) { return "0x$nn"; }
|
||||
}
|
||||
return $number;
|
||||
}
|
||||
|
||||
while (<>) {
|
||||
s/([^a-zA-Z0-9_])(\d+)/$1 . digitize $2/eg;
|
||||
print;
|
||||
}
|
||||
|
||||
39
src/js/sjcl/compress/opacify.pl
Executable file
39
src/js/sjcl/compress/opacify.pl
Executable file
@@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
# This script is a hack.
|
||||
#
|
||||
# Opacify all non-private names by turning them into strings.
|
||||
# That way, the Google compressor won't rename them.
|
||||
#
|
||||
# The script ignores properties whose names begin with _, because they
|
||||
# are believed to be private.
|
||||
#
|
||||
# XXX TODO FIXME: this messes with strings, so it screws up exceptions.
|
||||
|
||||
my $script = join '', <>;
|
||||
|
||||
# remove comments
|
||||
#$script =~ s=/\*([^\*]|\*+[^\/])*\*/==g;
|
||||
#$script =~ s=//.*==g;
|
||||
|
||||
# stringify property names
|
||||
$script =~ s=\.([a-zA-Z][_a-zA-Z0-9]*)=['$1']=g;
|
||||
|
||||
# destringify 'prototype'
|
||||
$script =~ s=\['prototype'\]=.prototype=g;
|
||||
|
||||
# stringify sjcl
|
||||
$script =~ s=(?:var\s+)?sjcl(\.|\s*\=)=window['sjcl']$1=g;
|
||||
|
||||
# stringify object notation
|
||||
$script =~ s=([\{,]
|
||||
\s*
|
||||
(?:/\*(?:[^\*]|\*+[^\/])*\*/\s* # preserve C-style comments
|
||||
|//[^\n]*\n\s*)*)
|
||||
([a-zA-Z0-9][_a-zA-Z0-9]*):=$1'$2':=xg;
|
||||
|
||||
# Export sjcl. This is a bit of a hack, and might get replaced later.
|
||||
print $script;
|
||||
|
||||
# not necessary with windowization.
|
||||
# print "window\['sjcl'\] = sjcl;\n";
|
||||
69
src/js/sjcl/compress/remove_constants.pl
Executable file
69
src/js/sjcl/compress/remove_constants.pl
Executable file
@@ -0,0 +1,69 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
# This script is a hack. It identifies things which it believes to be
|
||||
# constant, then replaces them throughout the code.
|
||||
#
|
||||
# Constants are identified as properties declared in object notation
|
||||
# with values consisting only of capital letters and underscores. If
|
||||
# the first character is an underscore, the constant is private, and
|
||||
# can be removed entirely.
|
||||
#
|
||||
# The script dies if any two constants have the same property name but
|
||||
# different values.
|
||||
my $script = join '', <>;
|
||||
|
||||
# remove comments
|
||||
#$script =~ s=/\*([^\*]|\*+[^\/])*\*/==g;
|
||||
#$script =~ s=//.*==g;
|
||||
|
||||
sub preserve {
|
||||
my $stuff = shift;
|
||||
$stuff =~ s/,//;
|
||||
return $stuff;
|
||||
}
|
||||
|
||||
my %constants = ();
|
||||
|
||||
sub add_constant {
|
||||
my ($name, $value) = @_;
|
||||
if (defined $constants{$name} && $constants{$name} ne $value) {
|
||||
print STDERR "variant constant $name = $value";
|
||||
die;
|
||||
} else {
|
||||
$constants{$name} = $value;
|
||||
#print STDERR "constant: $name = $value\n";
|
||||
}
|
||||
}
|
||||
|
||||
# find private constants
|
||||
while ($script =~
|
||||
s/([,\{]) \s* # indicator that this is part of an object
|
||||
(_[A-Z0-9_]+) \s* : \s* # all-caps variable name beginning with _
|
||||
(\d+|0x[0-9A-Fa-f]+) \s* # numeric value
|
||||
([,\}]) # next part of object
|
||||
/preserve "$1$4"/ex) {
|
||||
add_constant $2, $3;
|
||||
}
|
||||
|
||||
my $script2 = '';
|
||||
|
||||
# find public constants
|
||||
while ($script =~
|
||||
s/^(.*?) # beginning of script
|
||||
([,\{]) \s* # indicator that this is part of an object
|
||||
([A-Z0-9_]+) \s* : \s* # all-caps variable name
|
||||
(\d+|0x[0-9A-Fa-f]+) \s* # numeric value
|
||||
([,\}]) # next part of object([,\{]) \s*
|
||||
/$5/esx) {
|
||||
$script2 .= "$1$2$3:$4";
|
||||
add_constant $3, $4;
|
||||
}
|
||||
|
||||
$script = "$script2$script";
|
||||
|
||||
foreach (keys %constants) {
|
||||
my $value = $constants{$_};
|
||||
$script =~ s/(?:[a-zA-Z0-9_]+\.)+$_(?=[^a-zA-Z0-9_])/$value/g;
|
||||
}
|
||||
|
||||
print $script;
|
||||
BIN
src/js/sjcl/compress/yuicompressor-2.4.2.jar
Normal file
BIN
src/js/sjcl/compress/yuicompressor-2.4.2.jar
Normal file
Binary file not shown.
2
src/js/sjcl/config.mk
Normal file
2
src/js/sjcl/config.mk
Normal file
@@ -0,0 +1,2 @@
|
||||
SOURCES= core/sjcl.js core/aes.js core/bitArray.js core/codecString.js core/codecHex.js core/codecBase64.js core/sha256.js core/ccm.js core/ocb2.js core/gcm.js core/hmac.js core/pbkdf2.js core/random.js core/convenience.js
|
||||
COMPRESS= core_closure.js
|
||||
143
src/js/sjcl/configure
vendored
Executable file
143
src/js/sjcl/configure
vendored
Executable file
@@ -0,0 +1,143 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
use strict;
|
||||
|
||||
my ($arg, $i, $j, $targ);
|
||||
|
||||
my @targets = qw/sjcl aes bitArray codecString codecHex codecBase64 codecBytes sha256 sha512 sha1 ccm cbc ocb2 gcm hmac pbkdf2 random convenience bn ecc srp/;
|
||||
my %deps = ('aes'=>'sjcl',
|
||||
'bitArray'=>'sjcl',
|
||||
'codecString'=>'bitArray',
|
||||
'codecHex'=>'bitArray',
|
||||
'codecBase64'=>'bitArray',
|
||||
'codecBytes'=>'bitArray',
|
||||
'sha256'=>'codecString',
|
||||
'sha512'=>'codecString',
|
||||
'sha1'=>'codecString',
|
||||
'ccm'=>'bitArray,aes',
|
||||
'ocb2'=>'bitArray,aes',
|
||||
'gcm'=>'bitArray,aes',
|
||||
'hmac'=>'sha256',
|
||||
'pbkdf2'=>'hmac',
|
||||
'srp'=>'sha1,bn,bitArray',
|
||||
'bn'=>'bitArray,random',
|
||||
'ecc'=>'bn',
|
||||
'cbc'=>'bitArray,aes',
|
||||
'random'=>'sha256,aes',
|
||||
'convenience'=>'ccm,pbkdf2,random,codecBase64');
|
||||
|
||||
my $compress = "closure";
|
||||
|
||||
my %enabled = ();
|
||||
$enabled{$_} = 0 foreach (@targets);
|
||||
|
||||
# by default, all but codecBytes, srp, bn
|
||||
$enabled{$_} = 1 foreach (qw/aes bitArray codecString codecHex codecBase64 sha256 ccm ocb2 gcm hmac pbkdf2 random convenience/);
|
||||
|
||||
# argument parsing
|
||||
while ($arg = shift @ARGV) {
|
||||
if ($arg =~ /^--?with-all$/) {
|
||||
foreach (@targets) {
|
||||
if ($enabled{$_} == 0) {
|
||||
$enabled{$_} = 1;
|
||||
}
|
||||
}
|
||||
} elsif ($arg =~ /^--?without-all$/) {
|
||||
foreach (@targets) {
|
||||
if ($enabled{$_} == 1) {
|
||||
$enabled{$_} = 0;
|
||||
}
|
||||
}
|
||||
} elsif ($arg =~ /^--?with-(.*)$/) {
|
||||
$targ = $1;
|
||||
$targ =~ s/-(.)/uc $1/ge;
|
||||
if (!defined $deps{$targ}) {
|
||||
print STDERR "No such target $targ\n";
|
||||
exit 1;
|
||||
}
|
||||
$enabled{$targ} = 2;
|
||||
} elsif ($arg =~ /^--?without-(.*)$/) {
|
||||
$targ = $1;
|
||||
$targ =~ s/-(.)/uc $1/ge;
|
||||
if (!defined $deps{$targ}) {
|
||||
print STDERR "No such target $targ\n";
|
||||
exit 1;
|
||||
}
|
||||
$enabled{$targ} = -1;
|
||||
} elsif ($arg =~ /^--?compress(?:or|ion)?=(none|closure|yui)$/) {
|
||||
$compress = $1;
|
||||
} else {
|
||||
my $targets = join " ", @targets;
|
||||
$targets =~ s/sjcl //;
|
||||
$targets =~ s/(.{50})\s+/$1\n /g;
|
||||
print STDERR <<EOT;
|
||||
Usage: $0 arguments...
|
||||
|
||||
Valid arguments are:
|
||||
--with-all: by default, include all targets
|
||||
--without-all: by default, include no targets
|
||||
|
||||
--compress=none|closure|yui
|
||||
|
||||
--with-TARGET: require TARGET
|
||||
--without-TARGET: forbid TARGET
|
||||
|
||||
--help: show this message
|
||||
|
||||
Valid targets are:
|
||||
$targets
|
||||
|
||||
EOT
|
||||
exit 1 unless $arg =~ /^--?help$/;
|
||||
exit 0;
|
||||
}
|
||||
}
|
||||
|
||||
my $config = '';
|
||||
my $pconfig;
|
||||
|
||||
# dependency analysis: forbidden
|
||||
foreach $i (@targets) {
|
||||
if ($enabled{$i} > 0) {
|
||||
foreach $j (split /,/, $deps{$i}) {
|
||||
if ($enabled{$j} == -1) {
|
||||
if ($enabled{$i} == 2) {
|
||||
print STDERR "Conflicting options: $i depends on $j\n";
|
||||
exit 1;
|
||||
} else {
|
||||
$enabled{$i} = -1;
|
||||
last;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# reverse
|
||||
foreach $i (reverse @targets) {
|
||||
if ($enabled{$i} > 0) {
|
||||
foreach $j (split /,/, $deps{$i}) {
|
||||
if ($enabled{$j} < $enabled{$i}) {
|
||||
$enabled{$j} = $enabled{$i};
|
||||
}
|
||||
}
|
||||
$config = "$i $config";
|
||||
}
|
||||
}
|
||||
|
||||
open CONFIG, "> config.mk" or die "$!";
|
||||
|
||||
|
||||
($pconfig = $config) =~ s/^sjcl //;
|
||||
$pconfig =~ s/ /\n /g;
|
||||
print "Enabled components:\n $pconfig\n";
|
||||
print "Compression: $compress\n";
|
||||
|
||||
$config =~ s=\S+=core/$&.js=g;
|
||||
print CONFIG "SOURCES= $config\n";
|
||||
|
||||
$compress = "core_$compress.js";
|
||||
$compress = 'core.js' if ($compress eq 'core_none.js');
|
||||
|
||||
print CONFIG "COMPRESS= $compress\n";
|
||||
|
||||
208
src/js/sjcl/core/aes.js
Normal file
208
src/js/sjcl/core/aes.js
Normal file
@@ -0,0 +1,208 @@
|
||||
/** @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.
|
||||
*
|
||||
* @class Advanced Encryption Standard (low-level interface)
|
||||
*/
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
187
src/js/sjcl/core/bitArray.js
Normal file
187
src/js/sjcl/core/bitArray.js
Normal file
@@ -0,0 +1,187 @@
|
||||
/** @fileOverview Arrays of bits, encoded as arrays of Numbers.
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
|
||||
/** @namespace Arrays of bits, encoded as arrays of Numbers.
|
||||
*
|
||||
* @description
|
||||
* <p>
|
||||
* These objects are the currency accepted by SJCL's crypto functions.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* 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.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Because bitwise ops clear this out-of-band data, these arrays can be passed
|
||||
* to ciphers like AES which want arrays of words.
|
||||
* </p>
|
||||
*/
|
||||
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} length 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<<blength) - 1);
|
||||
},
|
||||
|
||||
/**
|
||||
* Concatenate two bit arrays.
|
||||
* @param {bitArray} a1 The first array.
|
||||
* @param {bitArray} a2 The second array.
|
||||
* @return {bitArray} The concatenation of a1 and a2.
|
||||
*/
|
||||
concat: function (a1, a2) {
|
||||
if (a1.length === 0 || a2.length === 0) {
|
||||
return a1.concat(a2);
|
||||
}
|
||||
|
||||
var out, i, last = a1[a1.length-1], shift = sjcl.bitArray.getPartial(last);
|
||||
if (shift === 32) {
|
||||
return a1.concat(a2);
|
||||
} else {
|
||||
return sjcl.bitArray._shiftRight(a2, shift, last|0, a1.slice(0,a1.length-1));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Find the length of an array of bits.
|
||||
* @param {bitArray} a The array.
|
||||
* @return {Number} The length of a, in bits.
|
||||
*/
|
||||
bitLength: function (a) {
|
||||
var l = a.length, x;
|
||||
if (l === 0) { return 0; }
|
||||
x = a[l - 1];
|
||||
return (l-1) * 32 + sjcl.bitArray.getPartial(x);
|
||||
},
|
||||
|
||||
/**
|
||||
* Truncate an array.
|
||||
* @param {bitArray} a The array.
|
||||
* @param {Number} len The length to truncate to, in bits.
|
||||
* @return {bitArray} A new array, truncated to len bits.
|
||||
*/
|
||||
clamp: function (a, len) {
|
||||
if (a.length * 32 < len) { return a; }
|
||||
a = a.slice(0, Math.ceil(len / 32));
|
||||
var l = a.length;
|
||||
len = len & 31;
|
||||
if (l > 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} [0] _end 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<a.length; i++) {
|
||||
x |= a[i]^b[i];
|
||||
}
|
||||
return (x === 0);
|
||||
},
|
||||
|
||||
/** Shift an array right.
|
||||
* @param {bitArray} a The array to shift.
|
||||
* @param {Number} shift The number of bits to shift.
|
||||
* @param {Number} [carry=0] A byte to carry in
|
||||
* @param {bitArray} [out=[]] An array to prepend to the output.
|
||||
* @private
|
||||
*/
|
||||
_shiftRight: function (a, shift, carry, out) {
|
||||
var i, last2=0, shift2;
|
||||
if (out === undefined) { out = []; }
|
||||
|
||||
for (; shift >= 32; shift -= 32) {
|
||||
out.push(carry);
|
||||
carry = 0;
|
||||
}
|
||||
if (shift === 0) {
|
||||
return out.concat(a);
|
||||
}
|
||||
|
||||
for (i=0; i<a.length; i++) {
|
||||
out.push(carry | a[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]];
|
||||
}
|
||||
};
|
||||
552
src/js/sjcl/core/bn.js
Normal file
552
src/js/sjcl/core/bn.js
Normal file
@@ -0,0 +1,552 @@
|
||||
/**
|
||||
* @constructor
|
||||
* Constructs a new bignum from another bignum, a number or a hex string.
|
||||
*/
|
||||
sjcl.bn = function(it) {
|
||||
this.initWith(it);
|
||||
};
|
||||
|
||||
sjcl.bn.prototype = {
|
||||
radix: 24,
|
||||
maxMul: 8,
|
||||
_class: sjcl.bn,
|
||||
|
||||
copy: function() {
|
||||
return new this._class(this);
|
||||
},
|
||||
|
||||
/**
|
||||
* Initializes this with it, either as a bn, a number, or a hex string.
|
||||
*/
|
||||
initWith: function(it) {
|
||||
var i=0, k, n, l;
|
||||
switch(typeof it) {
|
||||
case "object":
|
||||
this.limbs = it.limbs.slice(0);
|
||||
break;
|
||||
|
||||
case "number":
|
||||
this.limbs = [it];
|
||||
this.normalize();
|
||||
break;
|
||||
|
||||
case "string":
|
||||
it = it.replace(/^0x/, '');
|
||||
this.limbs = [];
|
||||
// hack
|
||||
k = this.radix / 4;
|
||||
for (i=0; i < it.length; i+=k) {
|
||||
this.limbs.push(parseInt(it.substring(Math.max(it.length - i - k, 0), it.length - i),16));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
this.limbs = [0];
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if "this" and "that" are equal. Calls fullReduce().
|
||||
* Equality test is in constant time.
|
||||
*/
|
||||
equals: function(that) {
|
||||
if (typeof that === "number") { that = new this._class(that); }
|
||||
var difference = 0, i;
|
||||
this.fullReduce();
|
||||
that.fullReduce();
|
||||
for (i = 0; i < this.limbs.length || i < that.limbs.length; i++) {
|
||||
difference |= this.getLimb(i) ^ that.getLimb(i);
|
||||
}
|
||||
return (difference === 0);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the i'th limb of this, zero if i is too large.
|
||||
*/
|
||||
getLimb: function(i) {
|
||||
return (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<ll.length; i++) {
|
||||
l[i] = 0;
|
||||
}
|
||||
for (i=0; i<ll.length; i++) {
|
||||
l[i] += ll[i];
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
/** this *= 2. Requires normalized; ends up normalized. */
|
||||
doubleM: function() {
|
||||
var i, carry=0, tmp, r=this.radix, m=this.radixMask, l=this.limbs;
|
||||
for (i=0; i<l.length; i++) {
|
||||
tmp = l[i];
|
||||
tmp = tmp+tmp+carry;
|
||||
l[i] = tmp & m;
|
||||
carry = tmp >> 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<ll.length; i++) {
|
||||
l[i] = 0;
|
||||
}
|
||||
for (i=0; i<ll.length; i++) {
|
||||
l[i] -= ll[i];
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
mod: function(that) {
|
||||
var neg = !this.greaterEquals(new sjcl.bn(0));
|
||||
|
||||
that = new sjcl.bn(that).normalize(); // copy before we begin
|
||||
var out = new sjcl.bn(this).normalize(), ci=0;
|
||||
|
||||
if (neg) out = (new sjcl.bn(0)).subM(out).normalize();
|
||||
|
||||
for (; out.greaterEquals(that); ci++) {
|
||||
that.doubleM();
|
||||
}
|
||||
|
||||
if (neg) out = that.sub(out).normalize();
|
||||
|
||||
for (; ci > 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<x.limbs.length; i++) {
|
||||
nz |= x.limbs[i];
|
||||
}
|
||||
} while(nz);
|
||||
|
||||
if (!y.equals(1)) {
|
||||
throw (new sjcl.exception.invalid("inverseMod: p and x must be relatively prime"));
|
||||
}
|
||||
|
||||
return b;
|
||||
},
|
||||
|
||||
/** this + that. Does not normalize. */
|
||||
add: function(that) {
|
||||
return this.copy().addM(that);
|
||||
},
|
||||
|
||||
/** this - that. Does not normalize. */
|
||||
sub: function(that) {
|
||||
return this.copy().subM(that);
|
||||
},
|
||||
|
||||
/** this * that. Normalizes and reduces. */
|
||||
mul: function(that) {
|
||||
if (typeof(that) === "number") { that = new this._class(that); }
|
||||
var i, j, a = this.limbs, b = that.limbs, al = a.length, bl = b.length, out = new this._class(), c = out.limbs, ai, ii=this.maxMul;
|
||||
|
||||
for (i=0; i < this.limbs.length + that.limbs.length + 1; i++) {
|
||||
c[i] = 0;
|
||||
}
|
||||
for (i=0; i<al; i++) {
|
||||
ai = a[i];
|
||||
for (j=0; j<bl; j++) {
|
||||
c[i+j] += ai * b[j];
|
||||
}
|
||||
|
||||
if (!--ii) {
|
||||
ii = this.maxMul;
|
||||
out.cnormalize();
|
||||
}
|
||||
}
|
||||
return out.cnormalize().reduce();
|
||||
},
|
||||
|
||||
/** this ^ 2. Normalizes and reduces. */
|
||||
square: function() {
|
||||
return this.mul(this);
|
||||
},
|
||||
|
||||
/** this ^ n. Uses square-and-multiply. Normalizes and reduces. */
|
||||
power: function(l) {
|
||||
if (typeof(l) === "number") {
|
||||
l = [l];
|
||||
} else if (l.limbs !== undefined) {
|
||||
l = l.normalize().limbs;
|
||||
}
|
||||
var i, j, out = new this._class(1), pow = this;
|
||||
|
||||
for (i=0; i<l.length; i++) {
|
||||
for (j=0; j<this.radix; j++) {
|
||||
if (l[i] & (1<<j)) {
|
||||
out = out.mul(pow);
|
||||
}
|
||||
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) {
|
||||
var result = new sjcl.bn(1), a = new sjcl.bn(this), k = new sjcl.bn(x);
|
||||
while (true) {
|
||||
if (k.limbs[0] & 1) { result = result.mulmod(a, N); }
|
||||
k.halveM();
|
||||
if (k.equals(0)) { break; }
|
||||
a = a.mulmod(a, N);
|
||||
}
|
||||
return result.normalize().reduce();
|
||||
},
|
||||
|
||||
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] -= this.placeVal;
|
||||
}
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
/** @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 */
|
||||
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<coeff.length; i++) {
|
||||
ppr.offset[i] = Math.floor(coeff[i][0] / ppr.radix - tmp);
|
||||
ppr.fullOffset[i] = Math.ceil(coeff[i][0] / ppr.radix - tmp);
|
||||
ppr.factor[i] = coeff[i][1] * Math.pow(1/2, exponent - coeff[i][0] + ppr.offset[i] * ppr.radix);
|
||||
ppr.fullFactor[i] = coeff[i][1] * Math.pow(1/2, exponent - coeff[i][0] + ppr.fullOffset[i] * ppr.radix);
|
||||
ppr.modulus.addM(new sjcl.bn(Math.pow(2,coeff[i][0])*coeff[i][1]));
|
||||
ppr.minOffset = Math.min(ppr.minOffset, -ppr.offset[i]); // conservative
|
||||
}
|
||||
ppr._class = p;
|
||||
ppr.modulus.cnormalize();
|
||||
|
||||
/** Approximate reduction mod p. May leave a number which is negative or slightly larger than p.
|
||||
* @this {sjcl.bn}
|
||||
*/
|
||||
ppr.reduce = function() {
|
||||
var i, k, l, mo = this.modOffset, limbs = this.limbs, aff, off = this.offset, ol = this.offset.length, fac = this.factor, ll;
|
||||
|
||||
i = this.minOffset;
|
||||
while (limbs.length > mo) {
|
||||
l = limbs.pop();
|
||||
ll = limbs.length;
|
||||
for (k=0; k<ol; k++) {
|
||||
limbs[ll+off[k]] -= fac[k] * l;
|
||||
}
|
||||
|
||||
i--;
|
||||
if (!i) {
|
||||
limbs.push(0);
|
||||
this.cnormalize();
|
||||
i = this.minOffset;
|
||||
}
|
||||
}
|
||||
this.cnormalize();
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/** @this {sjcl.bn} */
|
||||
ppr._strongReduce = (ppr.fullMask === -1) ? ppr.reduce : function() {
|
||||
var limbs = this.limbs, i = limbs.length - 1, k, l;
|
||||
this.reduce();
|
||||
if (i === this.modOffset - 1) {
|
||||
l = limbs[i] & this.fullMask;
|
||||
limbs[i] -= l;
|
||||
for (k=0; k<this.fullOffset.length; k++) {
|
||||
limbs[i+this.fullOffset[k]] -= this.fullFactor[k] * l;
|
||||
}
|
||||
this.normalize();
|
||||
}
|
||||
};
|
||||
|
||||
/** mostly constant-time, very expensive full reduction.
|
||||
* @this {sjcl.bn}
|
||||
*/
|
||||
ppr.fullReduce = function() {
|
||||
var greater, i;
|
||||
// massively above the modulus, may be negative
|
||||
|
||||
this._strongReduce();
|
||||
// less than twice the modulus, may be negative
|
||||
|
||||
this.addM(this.modulus);
|
||||
this.addM(this.modulus);
|
||||
this.normalize();
|
||||
// probably 2-3x the modulus
|
||||
|
||||
this._strongReduce();
|
||||
// less than the power of 2. still may be more than
|
||||
// the modulus
|
||||
|
||||
// HACK: pad out to this length
|
||||
for (i=this.limbs.length; i<this.modOffset; i++) {
|
||||
this.limbs[i] = 0;
|
||||
}
|
||||
|
||||
// constant-time subtract modulus
|
||||
greater = this.greaterEquals(this.modulus);
|
||||
for (i=0; i<this.limbs.length; i++) {
|
||||
this.limbs[i] -= this.modulus.limbs[i] * greater;
|
||||
}
|
||||
this.cnormalize();
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/** @this {sjcl.bn} */
|
||||
ppr.inverse = function() {
|
||||
return (this.power(this.modulus.sub(2)));
|
||||
};
|
||||
|
||||
p.fromBits = sjcl.bn.fromBits;
|
||||
|
||||
return p;
|
||||
};
|
||||
|
||||
// a small Mersenne prime
|
||||
sjcl.bn.prime = {
|
||||
p127: sjcl.bn.pseudoMersennePrime(127, [[0,-1]]),
|
||||
|
||||
// Bernstein's prime for Curve25519
|
||||
p25519: sjcl.bn.pseudoMersennePrime(255, [[0,-19]]),
|
||||
|
||||
// NIST primes
|
||||
p192: sjcl.bn.pseudoMersennePrime(192, [[0,-1],[64,-1]]),
|
||||
p224: sjcl.bn.pseudoMersennePrime(224, [[0,1],[96,-1]]),
|
||||
p256: sjcl.bn.pseudoMersennePrime(256, [[0,-1],[96,1],[192,1],[224,-1]]),
|
||||
p384: sjcl.bn.pseudoMersennePrime(384, [[0,-1],[32,1],[96,-1],[128,-1]]),
|
||||
p521: sjcl.bn.pseudoMersennePrime(521, [[0,-1]])
|
||||
};
|
||||
|
||||
sjcl.bn.random = function(modulus, paranoia) {
|
||||
if (typeof modulus !== "object") { modulus = new sjcl.bn(modulus); }
|
||||
var words, i, l = modulus.limbs.length, m = modulus.limbs[l-1]+1, out = new sjcl.bn();
|
||||
while (true) {
|
||||
// get a sequence whose first digits make sense
|
||||
do {
|
||||
words = sjcl.random.randomWords(l, paranoia);
|
||||
if (words[l-1] < 0) { words[l-1] += 0x100000000; }
|
||||
} while (Math.floor(words[l-1] / m) === Math.floor(0x100000000 / m));
|
||||
words[l-1] %= m;
|
||||
|
||||
// mask off all the limbs
|
||||
for (i=0; i<l-1; i++) {
|
||||
words[i] &= modulus.radixMask;
|
||||
}
|
||||
|
||||
// check the rest of the digitssj
|
||||
out.limbs = words;
|
||||
if (!out.greaterEquals(modulus)) {
|
||||
return out;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
115
src/js/sjcl/core/cbc.js
Normal file
115
src/js/sjcl/core/cbc.js
Normal file
@@ -0,0 +1,115 @@
|
||||
/** @fileOverview CBC mode implementation
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
|
||||
/** @namespace
|
||||
* Dangerous: CBC mode with PKCS#5 padding.
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
if (sjcl.beware === undefined) {
|
||||
sjcl.beware = {};
|
||||
}
|
||||
sjcl.beware["CBC mode is dangerous because it doesn't protect message integrity."
|
||||
] = function() {
|
||||
sjcl.mode.cbc = {
|
||||
/** The name of the mode.
|
||||
* @constant
|
||||
*/
|
||||
name: "cbc",
|
||||
|
||||
/** Encrypt in CBC mode with PKCS#5 padding.
|
||||
* @param {Object} prp The block cipher. 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. Must be empty.
|
||||
* @return The encrypted data, an array of bytes.
|
||||
* @throws {sjcl.exception.invalid} if the IV isn't exactly 128 bits, or if any adata is specified.
|
||||
*/
|
||||
encrypt: function(prp, plaintext, iv, adata) {
|
||||
if (adata && adata.length) {
|
||||
throw new sjcl.exception.invalid("cbc can't authenticate data");
|
||||
}
|
||||
if (sjcl.bitArray.bitLength(iv) !== 128) {
|
||||
throw new sjcl.exception.invalid("cbc iv must be 128 bits");
|
||||
}
|
||||
var i,
|
||||
w = sjcl.bitArray,
|
||||
xor = w._xor4,
|
||||
bl = w.bitLength(plaintext),
|
||||
bp = 0,
|
||||
output = [];
|
||||
|
||||
if (bl&7) {
|
||||
throw new sjcl.exception.invalid("pkcs#5 padding only works for multiples of a byte");
|
||||
}
|
||||
|
||||
for (i=0; bp+128 <= bl; i+=4, bp+=128) {
|
||||
/* Encrypt a non-final block */
|
||||
iv = prp.encrypt(xor(iv, plaintext.slice(i,i+4)));
|
||||
output.splice(i,0,iv[0],iv[1],iv[2],iv[3]);
|
||||
}
|
||||
|
||||
/* Construct the pad. */
|
||||
bl = (16 - ((bl >> 3) & 15)) * 0x1010101;
|
||||
|
||||
/* Pad and encrypt. */
|
||||
iv = prp.encrypt(xor(iv,w.concat(plaintext,[bl,bl,bl,bl]).slice(i,i+4)));
|
||||
output.splice(i,0,iv[0],iv[1],iv[2],iv[3]);
|
||||
return output;
|
||||
},
|
||||
|
||||
/** Decrypt in CBC mode.
|
||||
* @param {Object} prp The block cipher. It must have a block size of 16 bytes.
|
||||
* @param {bitArray} ciphertext The ciphertext data.
|
||||
* @param {bitArray} iv The initialization value.
|
||||
* @param {bitArray} [adata=[]] The authenticated data. It must be empty.
|
||||
* @return The decrypted data, an array of bytes.
|
||||
* @throws {sjcl.exception.invalid} if the IV isn't exactly 128 bits, or if any adata is specified.
|
||||
* @throws {sjcl.exception.corrupt} if if the message is corrupt.
|
||||
*/
|
||||
decrypt: function(prp, ciphertext, iv, adata) {
|
||||
if (adata && adata.length) {
|
||||
throw new sjcl.exception.invalid("cbc can't authenticate data");
|
||||
}
|
||||
if (sjcl.bitArray.bitLength(iv) !== 128) {
|
||||
throw new sjcl.exception.invalid("cbc iv must be 128 bits");
|
||||
}
|
||||
if ((sjcl.bitArray.bitLength(ciphertext) & 127) || !ciphertext.length) {
|
||||
throw new sjcl.exception.corrupt("cbc ciphertext must be a positive multiple of the block size");
|
||||
}
|
||||
var i,
|
||||
w = sjcl.bitArray,
|
||||
xor = w._xor4,
|
||||
bi, bo,
|
||||
output = [];
|
||||
|
||||
adata = adata || [];
|
||||
|
||||
for (i=0; i<ciphertext.length; i+=4) {
|
||||
bi = ciphertext.slice(i,i+4);
|
||||
bo = xor(iv,prp.decrypt(bi));
|
||||
output.splice(i,0,bo[0],bo[1],bo[2],bo[3]);
|
||||
iv = bi;
|
||||
}
|
||||
|
||||
/* check and remove the pad */
|
||||
bi = output[i-1] & 255;
|
||||
if (bi == 0 || bi > 16) {
|
||||
throw new sjcl.exception.corrupt("pkcs#5 padding corrupt");
|
||||
}
|
||||
bo = bi * 0x1010101;
|
||||
if (!w.equal(w.bitSlice([bo,bo,bo,bo], 0, bi*8),
|
||||
w.bitSlice(output, output.length*32 - bi*8, output.length*32))) {
|
||||
throw new sjcl.exception.corrupt("pkcs#5 padding corrupt");
|
||||
}
|
||||
|
||||
return w.bitSlice(output, 0, output.length*32 - bi*8);
|
||||
}
|
||||
};
|
||||
};
|
||||
185
src/js/sjcl/core/ccm.js
Normal file
185
src/js/sjcl/core/ccm.js
Normal file
@@ -0,0 +1,185 @@
|
||||
/** @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
|
||||
*/
|
||||
|
||||
/** @namespace CTR mode with CBC MAC. */
|
||||
sjcl.mode.ccm = {
|
||||
/** The name of the mode.
|
||||
* @constant
|
||||
*/
|
||||
name: "ccm",
|
||||
|
||||
/** 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, i, 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 The authenticated data.
|
||||
* @param {Number} [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, i,
|
||||
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;
|
||||
},
|
||||
|
||||
/* Compute the (unencrypted) authentication tag, according to the CCM specification
|
||||
* @param {Object} prf The pseudorandom function.
|
||||
* @param {bitArray} plaintext The plaintext data.
|
||||
* @param {bitArray} iv The initialization value.
|
||||
* @param {bitArray} adata The authenticated data.
|
||||
* @param {Number} tlen the desired tag length, in bits.
|
||||
* @return {bitArray} The tag, but not yet encrypted.
|
||||
* @private
|
||||
*/
|
||||
_computeTag: function(prf, plaintext, iv, adata, tlen, L) {
|
||||
// compute B[0]
|
||||
var q, mac, field = 0, offset = 24, tmp, i, macData = [], w=sjcl.bitArray, xor = w._xor4;
|
||||
|
||||
tlen /= 8;
|
||||
|
||||
// check tag length and message length
|
||||
if (tlen % 2 || tlen < 4 || tlen > 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 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] |= w.bitLength(plaintext)/8;
|
||||
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<macData.length; i += 4) {
|
||||
mac = prf.encrypt(xor(mac, macData.slice(i,i+4).concat([0,0,0])));
|
||||
}
|
||||
}
|
||||
|
||||
// mac the plaintext
|
||||
for (i=0; i<plaintext.length; i+=4) {
|
||||
mac = prf.encrypt(xor(mac, plaintext.slice(i,i+4).concat([0,0,0])));
|
||||
}
|
||||
|
||||
return w.clamp(mac, tlen * 8);
|
||||
},
|
||||
|
||||
/** CCM CTR mode.
|
||||
* Encrypt or decrypt data and tag with the prf in CCM-style CTR mode.
|
||||
* May mutate its arguments.
|
||||
* @param {Object} prf The PRF.
|
||||
* @param {bitArray} data The data to be encrypted or decrypted.
|
||||
* @param {bitArray} iv The initialization vector.
|
||||
* @param {bitArray} tag The authentication tag.
|
||||
* @param {Number} tlen The length of th etag, in bits.
|
||||
* @param {Number} L The CCM L value.
|
||||
* @return {Object} An object with data and tag, the en/decryption of data and tag values.
|
||||
* @private
|
||||
*/
|
||||
_ctrMode: function(prf, data, iv, tag, tlen, L) {
|
||||
var enc, i, w=sjcl.bitArray, xor = w._xor4, ctr, b, l = data.length, bl=w.bitLength(data);
|
||||
|
||||
// start the ctr
|
||||
ctr = w.concat([w.partial(8,L-1)],iv).concat([0,0,0]).slice(0,4);
|
||||
|
||||
// en/decrypt the tag
|
||||
tag = w.bitSlice(xor(tag,prf.encrypt(ctr)), 0, tlen);
|
||||
|
||||
// en/decrypt the data
|
||||
if (!l) { return {tag:tag, data:[]}; }
|
||||
|
||||
for (i=0; i<l; i+=4) {
|
||||
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) };
|
||||
}
|
||||
};
|
||||
63
src/js/sjcl/core/codecBase64.js
Normal file
63
src/js/sjcl/core/codecBase64.js
Normal file
@@ -0,0 +1,63 @@
|
||||
/** @fileOverview Bit array codec implementations.
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
|
||||
/** @namespace Base64 encoding/decoding */
|
||||
sjcl.codec.base64 = {
|
||||
/** The base64 alphabet.
|
||||
* @private
|
||||
*/
|
||||
_chars: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
|
||||
|
||||
/** Convert from a bitArray to a base64 string. */
|
||||
fromBits: function (arr, _noEquals, _url) {
|
||||
var out = "", i, bits=0, c = sjcl.codec.base64._chars, ta=0, bl = sjcl.bitArray.bitLength(arr);
|
||||
if (_url) c = c.substr(0,62) + '-_';
|
||||
for (i=0; out.length * 6 < bl; ) {
|
||||
out += c.charAt((ta ^ arr[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<str.length; i++) {
|
||||
x = c.indexOf(str.charAt(i));
|
||||
if (x < 0) {
|
||||
throw new sjcl.exception.invalid("this isn't base64!");
|
||||
}
|
||||
if (bits > 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); }
|
||||
};
|
||||
37
src/js/sjcl/core/codecBytes.js
Normal file
37
src/js/sjcl/core/codecBytes.js
Normal file
@@ -0,0 +1,37 @@
|
||||
/** @fileOverview Bit array codec implementations.
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
|
||||
/** @namespace Arrays of bytes */
|
||||
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<bl/8; i++) {
|
||||
if ((i&3) === 0) {
|
||||
tmp = arr[i/4];
|
||||
}
|
||||
out.push(tmp >>> 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<bytes.length; i++) {
|
||||
tmp = tmp << 8 | bytes[i];
|
||||
if ((i&3) === 3) {
|
||||
out.push(tmp);
|
||||
tmp = 0;
|
||||
}
|
||||
}
|
||||
if (i&3) {
|
||||
out.push(sjcl.bitArray.partial(8*(i&3), tmp));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
};
|
||||
30
src/js/sjcl/core/codecHex.js
Normal file
30
src/js/sjcl/core/codecHex.js
Normal file
@@ -0,0 +1,30 @@
|
||||
/** @fileOverview Bit array codec implementations.
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
|
||||
/** @namespace Hexadecimal */
|
||||
sjcl.codec.hex = {
|
||||
/** Convert from a bitArray to a hex string. */
|
||||
fromBits: function (arr) {
|
||||
var out = "", i, x;
|
||||
for (i=0; i<arr.length; i++) {
|
||||
out += ((arr[i]|0)+0xF00000000000).toString(16).substr(4);
|
||||
}
|
||||
return out.substr(0, sjcl.bitArray.bitLength(arr)/4);//.replace(/(.{8})/g, "$1 ");
|
||||
},
|
||||
/** Convert from a hex string to a bitArray. */
|
||||
toBits: function (str) {
|
||||
var i, out=[], len;
|
||||
str = str.replace(/\s|0x/g, "");
|
||||
len = str.length;
|
||||
str = str + "00000000";
|
||||
for (i=0; i<str.length; i+=8) {
|
||||
out.push(parseInt(str.substr(i,8),16)^0);
|
||||
}
|
||||
return sjcl.bitArray.clamp(out, len*4);
|
||||
}
|
||||
};
|
||||
|
||||
39
src/js/sjcl/core/codecString.js
Normal file
39
src/js/sjcl/core/codecString.js
Normal file
@@ -0,0 +1,39 @@
|
||||
/** @fileOverview Bit array codec implementations.
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
|
||||
/** @namespace UTF-8 strings */
|
||||
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<bl/8; i++) {
|
||||
if ((i&3) === 0) {
|
||||
tmp = arr[i/4];
|
||||
}
|
||||
out += String.fromCharCode(tmp >>> 24);
|
||||
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<str.length; i++) {
|
||||
tmp = tmp << 8 | str.charCodeAt(i);
|
||||
if ((i&3) === 3) {
|
||||
out.push(tmp);
|
||||
tmp = 0;
|
||||
}
|
||||
}
|
||||
if (i&3) {
|
||||
out.push(sjcl.bitArray.partial(8*(i&3), tmp));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
};
|
||||
285
src/js/sjcl/core/convenience.js
Normal file
285
src/js/sjcl/core/convenience.js
Normal file
@@ -0,0 +1,285 @@
|
||||
/** @fileOverview Convenince functions centered around JSON encapsulation.
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
|
||||
/** @namespace JSON encapsulation */
|
||||
sjcl.json = {
|
||||
/** Default values for encryption */
|
||||
defaults: { v:1, iter:1000, ks:128, ts:64, mode:"ccm", adata:"", cipher:"aes" },
|
||||
|
||||
/** 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.
|
||||
* @throws {sjcl.exception.invalid} if a parameter is invalid.
|
||||
*/
|
||||
encrypt: function (password, plaintext, params, rp) {
|
||||
params = params || {};
|
||||
rp = rp || {};
|
||||
|
||||
var j = sjcl.json, p = j._add({ iv: sjcl.random.randomWords(4,0) },
|
||||
j.defaults), tmp, prp, adata;
|
||||
j._add(p, params);
|
||||
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.length < 2 || p.iv.length > 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") {
|
||||
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 */
|
||||
p.ct = sjcl.mode[p.mode].encrypt(prp, plaintext, p.iv, adata, p.ts);
|
||||
|
||||
//return j.encode(j._subtract(p, j.defaults));
|
||||
return j.encode(p);
|
||||
},
|
||||
|
||||
/** 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) {
|
||||
params = params || {};
|
||||
rp = rp || {};
|
||||
|
||||
var j = sjcl.json, p = j._add(j._add(j._add({},j.defaults),j.decode(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 */
|
||||
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;
|
||||
|
||||
return sjcl.codec.utf8String.fromBits(ct);
|
||||
},
|
||||
|
||||
/** 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<a.length; i++) {
|
||||
if (!(m=a[i].match(/^(?:(["']?)([a-z][a-z0-9]*)\1):(?:(\d+)|"([a-z0-9+\/%*_.@=\-]*)")$/i))) {
|
||||
throw new sjcl.exception.invalid("json decode: this isn't json!");
|
||||
}
|
||||
if (m[3]) {
|
||||
out[m[2]] = parseInt(m[3],10);
|
||||
} else {
|
||||
out[m[2]] = m[2].match(/^(ct|salt|iv)$/) ? sjcl.codec.base64.toBits(m[4]) : unescape(m[4]);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
},
|
||||
|
||||
/** Insert all elements of src into target, modifying and returning target.
|
||||
* @param {Object} target The object to be modified.
|
||||
* @param {Object} src The object to pull data from.
|
||||
* @param {boolean} [requireSame=false] If true, throw an exception if any field of target differs from corresponding field of src.
|
||||
* @return {Object} target.
|
||||
* @private
|
||||
*/
|
||||
_add: function (target, src, requireSame) {
|
||||
if (target === undefined) { target = {}; }
|
||||
if (src === undefined) { return target; }
|
||||
var i;
|
||||
for (i in src) {
|
||||
if (src.hasOwnProperty(i)) {
|
||||
if (requireSame && target[i] !== undefined && target[i] !== src[i]) {
|
||||
throw new sjcl.exception.invalid("required parameter overridden");
|
||||
}
|
||||
target[i] = src[i];
|
||||
}
|
||||
}
|
||||
return target;
|
||||
},
|
||||
|
||||
/** Remove all elements of minus from plus. Does not modify plus.
|
||||
* @private
|
||||
*/
|
||||
_subtract: function (plus, minus) {
|
||||
var out = {}, i;
|
||||
|
||||
for (i in plus) {
|
||||
if (plus.hasOwnProperty(i) && plus[i] !== minus[i]) {
|
||||
out[i] = plus[i];
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
},
|
||||
|
||||
/** Return only the specified elements of src.
|
||||
* @private
|
||||
*/
|
||||
_filter: function (src, filter) {
|
||||
var out = {}, i;
|
||||
for (i=0; i<filter.length; i++) {
|
||||
if (src[filter[i]] !== undefined) {
|
||||
out[filter[i]] = src[filter[i]];
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
/** Simple encryption function; convenient shorthand for sjcl.json.encrypt.
|
||||
* @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.
|
||||
*/
|
||||
sjcl.encrypt = sjcl.json.encrypt;
|
||||
|
||||
/** Simple decryption function; convenient shorthand for sjcl.json.decrypt.
|
||||
* @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.
|
||||
*/
|
||||
sjcl.decrypt = sjcl.json.decrypt;
|
||||
|
||||
/** The cache for cachedPbkdf2.
|
||||
* @private
|
||||
*/
|
||||
sjcl.misc._pbkdf2Cache = {};
|
||||
|
||||
/** Cached PBKDF2 key derivation.
|
||||
* @param {String} password The password.
|
||||
* @param {Object} [params] The derivation params (iteration count and optional salt).
|
||||
* @return {Object} The derived data in key, the salt in salt.
|
||||
*/
|
||||
sjcl.misc.cachedPbkdf2 = function (password, obj) {
|
||||
var cache = sjcl.misc._pbkdf2Cache, c, cp, str, salt, iter;
|
||||
|
||||
obj = obj || {};
|
||||
iter = obj.iter || 1000;
|
||||
|
||||
/* open the cache for this password and iteration count */
|
||||
cp = cache[password] = cache[password] || {};
|
||||
c = cp[iter] = cp[iter] || { firstSalt: (obj.salt && obj.salt.length) ?
|
||||
obj.salt.slice(0) : sjcl.random.randomWords(2,0) };
|
||||
|
||||
salt = (obj.salt === undefined) ? c.firstSalt : obj.salt;
|
||||
|
||||
c[salt] = c[salt] || sjcl.misc.pbkdf2(password, salt, obj.iter);
|
||||
return { key: c[salt].slice(0), salt:salt.slice(0) };
|
||||
};
|
||||
|
||||
|
||||
412
src/js/sjcl/core/ecc.js
Normal file
412
src/js/sjcl/core/ecc.js
Normal file
@@ -0,0 +1,412 @@
|
||||
sjcl.ecc = {};
|
||||
|
||||
/**
|
||||
* Represents a point on a curve in affine coordinates.
|
||||
* @constructor
|
||||
* @param {sjcl.ecc.curve} curve The curve that this point lies on.
|
||||
* @param {bigInt} x The x coordinate.
|
||||
* @param {bigInt} y The y coordinate.
|
||||
*/
|
||||
sjcl.ecc.point = function(curve,x,y) {
|
||||
if (x === undefined) {
|
||||
this.isIdentity = true;
|
||||
} else {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.isIdentity = false;
|
||||
}
|
||||
this.curve = curve;
|
||||
};
|
||||
|
||||
|
||||
|
||||
sjcl.ecc.point.prototype = {
|
||||
toJac: function() {
|
||||
return new sjcl.ecc.pointJac(this.curve, this.x, this.y, new this.curve.field(1));
|
||||
},
|
||||
|
||||
mult: function(k) {
|
||||
return this.toJac().mult(k, this).toAffine();
|
||||
},
|
||||
|
||||
/**
|
||||
* 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 {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(k, k2, affine2) {
|
||||
return this.toJac().mult2(k, this, k2, affine2).toAffine();
|
||||
},
|
||||
|
||||
multiples: function() {
|
||||
var m, i, j;
|
||||
if (this._multiples === undefined) {
|
||||
j = this.toJac().doubl();
|
||||
m = this._multiples = [new sjcl.ecc.point(this.curve), this, j.toAffine()];
|
||||
for (i=3; i<16; i++) {
|
||||
j = j.add(this);
|
||||
m.push(j.toAffine());
|
||||
}
|
||||
}
|
||||
return this._multiples;
|
||||
},
|
||||
|
||||
isValid: function() {
|
||||
return this.y.square().equals(this.curve.b.add(this.x.mul(this.curve.a.add(this.x.square()))));
|
||||
},
|
||||
|
||||
toBits: function() {
|
||||
return sjcl.bitArray.concat(this.x.toBits(), this.y.toBits());
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a point on a curve in Jacobian coordinates. Coordinates can be specified as bigInts or strings (which
|
||||
* will be converted to bigInts).
|
||||
*
|
||||
* @constructor
|
||||
* @param {bigInt/string} x The x coordinate.
|
||||
* @param {bigInt/string} y The y coordinate.
|
||||
* @param {bigInt/string} z The z coordinate.
|
||||
* @param {sjcl.ecc.curve} curve The curve that this point lies on.
|
||||
*/
|
||||
sjcl.ecc.pointJac = function(curve, x, y, z) {
|
||||
if (x === undefined) {
|
||||
this.isIdentity = true;
|
||||
} else {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.isIdentity = false;
|
||||
}
|
||||
this.curve = curve;
|
||||
};
|
||||
|
||||
sjcl.ecc.pointJac.prototype = {
|
||||
/**
|
||||
* Adds S and T and returns the result in Jacobian coordinates. Note that S must be in Jacobian coordinates and T must be in affine coordinates.
|
||||
* @param {sjcl.ecc.pointJac} S One of the points to add, in Jacobian coordinates.
|
||||
* @param {sjcl.ecc.point} T The other point to add, in affine coordinates.
|
||||
* @return {sjcl.ecc.pointJac} The sum of the two points, in Jacobian coordinates.
|
||||
*/
|
||||
add: function(T) {
|
||||
var S = this, sz2, c, d, c2, x1, x2, x, y1, y2, y, z;
|
||||
if (S.curve !== T.curve) {
|
||||
throw("sjcl.ecc.add(): Points must be on the same curve to add them!");
|
||||
}
|
||||
|
||||
if (S.isIdentity) {
|
||||
return T.toJac();
|
||||
} else if (T.isIdentity) {
|
||||
return S;
|
||||
}
|
||||
|
||||
sz2 = S.z.square();
|
||||
c = T.x.mul(sz2).subM(S.x);
|
||||
|
||||
if (c.equals(0)) {
|
||||
if (S.y.equals(T.y.mul(sz2.mul(S.z)))) {
|
||||
// same point
|
||||
return S.doubl();
|
||||
} else {
|
||||
// inverses
|
||||
return new sjcl.ecc.pointJac(S.curve);
|
||||
}
|
||||
}
|
||||
|
||||
d = T.y.mul(sz2.mul(S.z)).subM(S.y);
|
||||
c2 = c.square();
|
||||
|
||||
x1 = d.square();
|
||||
x2 = c.square().mul(c).addM( S.x.add(S.x).mul(c2) );
|
||||
x = x1.subM(x2);
|
||||
|
||||
y1 = S.x.mul(c2).subM(x).mul(d);
|
||||
y2 = S.y.mul(c.square().mul(c));
|
||||
y = y1.subM(y2);
|
||||
|
||||
z = S.z.mul(c);
|
||||
|
||||
return new sjcl.ecc.pointJac(this.curve,x,y,z);
|
||||
},
|
||||
|
||||
/**
|
||||
* doubles this point.
|
||||
* @return {sjcl.ecc.pointJac} The doubled point.
|
||||
*/
|
||||
doubl: function() {
|
||||
if (this.isIdentity) { return this; }
|
||||
|
||||
var
|
||||
y2 = this.y.square(),
|
||||
a = y2.mul(this.x.mul(4)),
|
||||
b = y2.square().mul(8),
|
||||
z2 = this.z.square(),
|
||||
c = this.x.sub(z2).mul(3).mul(this.x.add(z2)),
|
||||
x = c.square().subM(a).subM(a),
|
||||
y = a.sub(x).mul(c).subM(b),
|
||||
z = this.y.add(this.y).mul(this.z);
|
||||
return new sjcl.ecc.pointJac(this.curve, x, y, z);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a copy of this point converted to affine coordinates.
|
||||
* @return {sjcl.ecc.point} The converted point.
|
||||
*/
|
||||
toAffine: function() {
|
||||
if (this.isIdentity || this.z.equals(0)) {
|
||||
return new sjcl.ecc.point(this.curve);
|
||||
}
|
||||
var zi = this.z.inverse(), zi2 = zi.square();
|
||||
return new sjcl.ecc.point(this.curve, this.x.mul(zi2).fullReduce(), this.y.mul(zi2.mul(zi)).fullReduce());
|
||||
},
|
||||
|
||||
/**
|
||||
* Multiply this point by k and return the answer in Jacobian coordinates.
|
||||
* @param {bigInt} k The coefficient to multiply by.
|
||||
* @param {sjcl.ecc.point} affine This point in affine coordinates.
|
||||
* @return {sjcl.ecc.pointJac} The result of the multiplication, in Jacobian coordinates.
|
||||
*/
|
||||
mult: function(k, affine) {
|
||||
if (typeof(k) === "number") {
|
||||
k = [k];
|
||||
} else if (k.limbs !== undefined) {
|
||||
k = k.normalize().limbs;
|
||||
}
|
||||
|
||||
var i, j, out = new sjcl.ecc.point(this.curve).toJac(), multiples = affine.multiples();
|
||||
|
||||
for (i=k.length-1; i>=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;
|
||||
},
|
||||
|
||||
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 = Field.prototype.modulus.sub(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,
|
||||
"0x662107c8eb94364e4b2dd7ce",
|
||||
-3,
|
||||
"0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1",
|
||||
"0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012",
|
||||
"0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811"),
|
||||
|
||||
c224: new sjcl.ecc.curve(
|
||||
sjcl.bn.prime.p224,
|
||||
"0xe95c1f470fc1ec22d6baa3a3d5c4",
|
||||
-3,
|
||||
"0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4",
|
||||
"0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21",
|
||||
"0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34"),
|
||||
|
||||
c256: new sjcl.ecc.curve(
|
||||
sjcl.bn.prime.p256,
|
||||
"0x4319055358e8617b0c46353d039cdaae",
|
||||
-3,
|
||||
"0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b",
|
||||
"0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
|
||||
"0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5"),
|
||||
|
||||
c384: new sjcl.ecc.curve(
|
||||
sjcl.bn.prime.p384,
|
||||
"0x389cb27e0bc8d21fa7e5f24cb74f58851313e696333ad68c",
|
||||
-3,
|
||||
"0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef",
|
||||
"0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7",
|
||||
"0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f")
|
||||
};
|
||||
|
||||
|
||||
/* Diffie-Hellman-like public-key system */
|
||||
sjcl.ecc._dh = function(cn) {
|
||||
sjcl.ecc[cn] = {
|
||||
/** @constructor */
|
||||
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.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 };
|
||||
}
|
||||
},
|
||||
|
||||
/** @constructor */
|
||||
secretKey: function(curve, exponent) {
|
||||
this._curve = curve;
|
||||
this._curveBitLength = curve.r.bitLength();
|
||||
this._exponent = exponent;
|
||||
|
||||
this.get = function() {
|
||||
return this._exponent.toBits();
|
||||
}
|
||||
},
|
||||
|
||||
/** @constructor */
|
||||
generateKeys: function(curve, paranoia, sec) {
|
||||
if (curve === undefined) {
|
||||
curve = 256;
|
||||
}
|
||||
if (typeof curve === "number") {
|
||||
curve = sjcl.ecc.curves['c'+curve];
|
||||
if (curve === undefined) {
|
||||
throw new sjcl.exception.invalid("no such curve");
|
||||
}
|
||||
}
|
||||
if (sec === undefined) {
|
||||
var 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) };
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
sjcl.ecc._dh("elGamal");
|
||||
|
||||
sjcl.ecc.elGamal.publicKey.prototype = {
|
||||
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 };
|
||||
}
|
||||
};
|
||||
|
||||
sjcl.ecc.elGamal.secretKey.prototype = {
|
||||
unkem: function(tag) {
|
||||
return sjcl.hash.sha256.hash(this._curve.fromBits(tag).mult(this._exponent).toBits());
|
||||
},
|
||||
|
||||
dh: function(pk) {
|
||||
return sjcl.hash.sha256.hash(pk._point.mult(this._exponent).toBits());
|
||||
}
|
||||
};
|
||||
|
||||
sjcl.ecc._dh("ecdsa");
|
||||
|
||||
sjcl.ecc.ecdsa.secretKey.prototype = {
|
||||
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));
|
||||
}
|
||||
};
|
||||
|
||||
sjcl.ecc.ecdsa.publicKey.prototype = {
|
||||
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;
|
||||
}
|
||||
};
|
||||
183
src/js/sjcl/core/gcm.js
Normal file
183
src/js/sjcl/core/gcm.js
Normal file
@@ -0,0 +1,183 @@
|
||||
/** @fileOverview GCM mode implementation.
|
||||
*
|
||||
* @author Juho Vähä-Herttua
|
||||
*/
|
||||
|
||||
/** @namespace Galois/Counter mode. */
|
||||
sjcl.mode.gcm = {
|
||||
/** The name of the mode.
|
||||
* @constant
|
||||
*/
|
||||
name: "gcm",
|
||||
|
||||
/** Encrypt in GCM 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=128] The desired tag length, in bits.
|
||||
* @return {bitArray} The encrypted data, an array of bytes.
|
||||
*/
|
||||
encrypt: function (prf, plaintext, iv, adata, tlen) {
|
||||
var out, data = plaintext.slice(0), w=sjcl.bitArray;
|
||||
tlen = tlen || 128;
|
||||
adata = adata || [];
|
||||
|
||||
// encrypt and tag
|
||||
out = sjcl.mode.gcm._ctrMode(true, prf, data, adata, iv, tlen);
|
||||
|
||||
return w.concat(out.data, out.tag);
|
||||
},
|
||||
|
||||
/** Decrypt in GCM 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=[]] The authenticated data.
|
||||
* @param {Number} [tlen=128] The desired tag length, in bits.
|
||||
* @return {bitArray} The decrypted data.
|
||||
*/
|
||||
decrypt: function (prf, ciphertext, iv, adata, tlen) {
|
||||
var out, data = ciphertext.slice(0), tag, w=sjcl.bitArray, l=w.bitLength(data);
|
||||
tlen = tlen || 128;
|
||||
adata = adata || [];
|
||||
|
||||
// Slice tag out of data
|
||||
if (tlen <= l) {
|
||||
tag = w.bitSlice(data, l-tlen);
|
||||
data = w.bitSlice(data, 0, l-tlen);
|
||||
} else {
|
||||
tag = data;
|
||||
data = [];
|
||||
}
|
||||
|
||||
// decrypt and tag
|
||||
out = sjcl.mode.gcm._ctrMode(false, prf, data, adata, iv, tlen);
|
||||
|
||||
if (!w.equal(out.tag, tag)) {
|
||||
throw new sjcl.exception.corrupt("gcm: tag doesn't match");
|
||||
}
|
||||
return out.data;
|
||||
},
|
||||
|
||||
/* Compute the galois multiplication of X and Y
|
||||
* @private
|
||||
*/
|
||||
_galoisMultiply: function (x, y) {
|
||||
var i, j, xi, Zi, Vi, lsb_Vi, w=sjcl.bitArray, xor=w._xor4;
|
||||
|
||||
Zi = [0,0,0,0];
|
||||
Vi = y.slice(0);
|
||||
|
||||
// Block size is 128 bits, run 128 times to get Z_128
|
||||
for (i=0; i<128; i++) {
|
||||
xi = (x[Math.floor(i/32)] & (1 << (31-i%32))) !== 0;
|
||||
if (xi) {
|
||||
// Z_i+1 = Z_i ^ V_i
|
||||
Zi = xor(Zi, Vi);
|
||||
}
|
||||
|
||||
// Store the value of LSB(V_i)
|
||||
lsb_Vi = (Vi[3] & 1) !== 0;
|
||||
|
||||
// V_i+1 = V_i >> 1
|
||||
for (j=3; j>0; j--) {
|
||||
Vi[j] = (Vi[j] >>> 1) | ((Vi[j-1]&1) << 31);
|
||||
}
|
||||
Vi[0] = Vi[0] >>> 1;
|
||||
|
||||
// If LSB(V_i) is 1, V_i+1 = (V_i >> 1) ^ R
|
||||
if (lsb_Vi) {
|
||||
Vi[0] = Vi[0] ^ (0xe1 << 24);
|
||||
}
|
||||
}
|
||||
return Zi;
|
||||
},
|
||||
|
||||
_ghash: function(H, Y0, data) {
|
||||
var Yi, i, l = data.length;
|
||||
|
||||
Yi = Y0.slice(0);
|
||||
for (i=0; i<l; i+=4) {
|
||||
Yi[0] ^= 0xffffffff&data[i];
|
||||
Yi[1] ^= 0xffffffff&data[i+1];
|
||||
Yi[2] ^= 0xffffffff&data[i+2];
|
||||
Yi[3] ^= 0xffffffff&data[i+3];
|
||||
Yi = sjcl.mode.gcm._galoisMultiply(Yi, H);
|
||||
}
|
||||
return Yi;
|
||||
},
|
||||
|
||||
/** GCM CTR mode.
|
||||
* Encrypt or decrypt data and tag with the prf in GCM-style CTR mode.
|
||||
* @param {Boolean} encrypt True if encrypt, false if decrypt.
|
||||
* @param {Object} prf The PRF.
|
||||
* @param {bitArray} data The data to be encrypted or decrypted.
|
||||
* @param {bitArray} iv The initialization vector.
|
||||
* @param {bitArray} adata The associated data to be tagged.
|
||||
* @param {Number} tlen The length of the tag, in bits.
|
||||
*/
|
||||
_ctrMode: function(encrypt, prf, data, adata, iv, tlen) {
|
||||
var H, J0, S0, enc, i, ctr, tag, last, l, bl, abl, ivbl, w=sjcl.bitArray, xor=w._xor4;
|
||||
|
||||
// Calculate data lengths
|
||||
l = data.length;
|
||||
bl = w.bitLength(data);
|
||||
abl = w.bitLength(adata);
|
||||
ivbl = w.bitLength(iv);
|
||||
|
||||
// Calculate the parameters
|
||||
H = prf.encrypt([0,0,0,0]);
|
||||
if (ivbl === 96) {
|
||||
J0 = iv.slice(0);
|
||||
J0 = w.concat(J0, [1]);
|
||||
} else {
|
||||
J0 = sjcl.mode.gcm._ghash(H, [0,0,0,0], iv);
|
||||
J0 = sjcl.mode.gcm._ghash(H, J0, [0,0,Math.floor(ivbl/0x100000000),ivbl&0xffffffff]);
|
||||
}
|
||||
S0 = sjcl.mode.gcm._ghash(H, [0,0,0,0], adata);
|
||||
|
||||
// Initialize ctr and tag
|
||||
ctr = J0.slice(0);
|
||||
tag = S0.slice(0);
|
||||
|
||||
// If decrypting, calculate hash
|
||||
if (!encrypt) {
|
||||
tag = sjcl.mode.gcm._ghash(H, S0, data);
|
||||
}
|
||||
|
||||
// Encrypt all the data
|
||||
for (i=0; i<l; i+=4) {
|
||||
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];
|
||||
}
|
||||
data = w.clamp(data, bl);
|
||||
|
||||
// If encrypting, calculate hash
|
||||
if (encrypt) {
|
||||
tag = sjcl.mode.gcm._ghash(H, S0, data);
|
||||
}
|
||||
|
||||
// Calculate last block from bit lengths, ugly because bitwise operations are 32-bit
|
||||
last = [
|
||||
Math.floor(abl/0x100000000), abl&0xffffffff,
|
||||
Math.floor(bl/0x100000000), bl&0xffffffff
|
||||
];
|
||||
|
||||
// Calculate the final tag block
|
||||
tag = sjcl.mode.gcm._ghash(H, tag, last);
|
||||
enc = prf.encrypt(J0);
|
||||
tag[0] ^= enc[0];
|
||||
tag[1] ^= enc[1];
|
||||
tag[2] ^= enc[2];
|
||||
tag[3] ^= enc[3];
|
||||
|
||||
return { tag:w.bitSlice(tag, 0, tlen), data:data };
|
||||
}
|
||||
};
|
||||
39
src/js/sjcl/core/hmac.js
Normal file
39
src/js/sjcl/core/hmac.js
Normal file
@@ -0,0 +1,39 @@
|
||||
/** @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; i<bs; i++) {
|
||||
exKey[0][i] = key[i]^0x36363636;
|
||||
exKey[1][i] = key[i]^0x5C5C5C5C;
|
||||
}
|
||||
|
||||
this._baseHash[0].update(exKey[0]);
|
||||
this._baseHash[1].update(exKey[1]);
|
||||
};
|
||||
|
||||
/** HMAC with the specified hash function. Also called encrypt since it's a prf.
|
||||
* @param {bitArray|String} data The data to mac.
|
||||
*/
|
||||
sjcl.misc.hmac.prototype.encrypt = sjcl.misc.hmac.prototype.mac = function (data) {
|
||||
var w = new (this._hash)(this._baseHash[0]).update(data).finalize();
|
||||
return new (this._hash)(this._baseHash[1]).update(w).finalize();
|
||||
};
|
||||
|
||||
171
src/js/sjcl/core/ocb2.js
Normal file
171
src/js/sjcl/core/ocb2.js
Normal file
@@ -0,0 +1,171 @@
|
||||
/** @fileOverview OCB 2.0 implementation
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
|
||||
/** @namespace
|
||||
* Phil Rogaway's Offset CodeBook mode, version 2.0.
|
||||
* May be covered by US and international patents.
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
sjcl.mode.ocb2 = {
|
||||
/** The name of the mode.
|
||||
* @constant
|
||||
*/
|
||||
name: "ocb2",
|
||||
|
||||
/** Encrypt in OCB mode, version 2.0.
|
||||
* @param {Object} prp The block cipher. 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.
|
||||
* @param [false] premac 1 if the authentication data is pre-macced with PMAC.
|
||||
* @return The encrypted data, an array of bytes.
|
||||
* @throws {sjcl.exception.invalid} if the IV isn't exactly 128 bits.
|
||||
*/
|
||||
encrypt: function(prp, plaintext, iv, adata, tlen, premac) {
|
||||
if (sjcl.bitArray.bitLength(iv) !== 128) {
|
||||
throw new sjcl.exception.invalid("ocb iv must be 128 bits");
|
||||
}
|
||||
var i,
|
||||
times2 = sjcl.mode.ocb2._times2,
|
||||
w = sjcl.bitArray,
|
||||
xor = w._xor4,
|
||||
checksum = [0,0,0,0],
|
||||
delta = times2(prp.encrypt(iv)),
|
||||
bi, bl,
|
||||
output = [],
|
||||
pad;
|
||||
|
||||
adata = adata || [];
|
||||
tlen = tlen || 64;
|
||||
|
||||
for (i=0; i+4 < plaintext.length; i+=4) {
|
||||
/* Encrypt a non-final block */
|
||||
bi = plaintext.slice(i,i+4);
|
||||
checksum = xor(checksum, bi);
|
||||
output = output.concat(xor(delta,prp.encrypt(xor(delta, bi))));
|
||||
delta = times2(delta);
|
||||
}
|
||||
|
||||
/* Chop out the final block */
|
||||
bi = plaintext.slice(i);
|
||||
bl = w.bitLength(bi);
|
||||
pad = prp.encrypt(xor(delta,[0,0,0,bl]));
|
||||
bi = w.clamp(xor(bi.concat([0,0,0]),pad), bl);
|
||||
|
||||
/* Checksum the final block, and finalize the checksum */
|
||||
checksum = xor(checksum,xor(bi.concat([0,0,0]),pad));
|
||||
checksum = prp.encrypt(xor(checksum,xor(delta,times2(delta))));
|
||||
|
||||
/* MAC the header */
|
||||
if (adata.length) {
|
||||
checksum = xor(checksum, premac ? adata : sjcl.mode.ocb2.pmac(prp, adata));
|
||||
}
|
||||
|
||||
return output.concat(w.concat(bi, w.clamp(checksum, tlen)));
|
||||
},
|
||||
|
||||
/** Decrypt in OCB mode.
|
||||
* @param {Object} prp The block cipher. It must have a block size of 16 bytes.
|
||||
* @param {bitArray} ciphertext The ciphertext data.
|
||||
* @param {bitArray} iv The initialization value.
|
||||
* @param {bitArray} [adata=[]] The authenticated data.
|
||||
* @param {Number} [tlen=64] the desired tag length, in bits.
|
||||
* @param {boolean} [premac=false] true if the authentication data is pre-macced with PMAC.
|
||||
* @return The decrypted data, an array of bytes.
|
||||
* @throws {sjcl.exception.invalid} if the IV isn't exactly 128 bits.
|
||||
* @throws {sjcl.exception.corrupt} if if the message is corrupt.
|
||||
*/
|
||||
decrypt: function(prp, ciphertext, iv, adata, tlen, premac) {
|
||||
if (sjcl.bitArray.bitLength(iv) !== 128) {
|
||||
throw new sjcl.exception.invalid("ocb iv must be 128 bits");
|
||||
}
|
||||
tlen = tlen || 64;
|
||||
var i,
|
||||
times2 = sjcl.mode.ocb2._times2,
|
||||
w = sjcl.bitArray,
|
||||
xor = w._xor4,
|
||||
checksum = [0,0,0,0],
|
||||
delta = times2(prp.encrypt(iv)),
|
||||
bi, bl,
|
||||
len = sjcl.bitArray.bitLength(ciphertext) - tlen,
|
||||
output = [],
|
||||
pad;
|
||||
|
||||
adata = adata || [];
|
||||
|
||||
for (i=0; i+4 < len/32; i+=4) {
|
||||
/* Decrypt a non-final block */
|
||||
bi = xor(delta, prp.decrypt(xor(delta, ciphertext.slice(i,i+4))));
|
||||
checksum = xor(checksum, bi);
|
||||
output = output.concat(bi);
|
||||
delta = times2(delta);
|
||||
}
|
||||
|
||||
/* Chop out and decrypt the final block */
|
||||
bl = len-i*32;
|
||||
pad = prp.encrypt(xor(delta,[0,0,0,bl]));
|
||||
bi = xor(pad, w.clamp(ciphertext.slice(i),bl).concat([0,0,0]));
|
||||
|
||||
/* Checksum the final block, and finalize the checksum */
|
||||
checksum = xor(checksum, bi);
|
||||
checksum = prp.encrypt(xor(checksum, xor(delta, times2(delta))));
|
||||
|
||||
/* MAC the header */
|
||||
if (adata.length) {
|
||||
checksum = xor(checksum, premac ? adata : sjcl.mode.ocb2.pmac(prp, adata));
|
||||
}
|
||||
|
||||
if (!w.equal(w.clamp(checksum, tlen), w.bitSlice(ciphertext, len))) {
|
||||
throw new sjcl.exception.corrupt("ocb: tag doesn't match");
|
||||
}
|
||||
|
||||
return output.concat(w.clamp(bi,bl));
|
||||
},
|
||||
|
||||
/** PMAC authentication for OCB associated data.
|
||||
* @param {Object} prp The block cipher. It must have a block size of 16 bytes.
|
||||
* @param {bitArray} adata The authenticated data.
|
||||
*/
|
||||
pmac: function(prp, adata) {
|
||||
var i,
|
||||
times2 = sjcl.mode.ocb2._times2,
|
||||
w = sjcl.bitArray,
|
||||
xor = w._xor4,
|
||||
checksum = [0,0,0,0],
|
||||
delta = prp.encrypt([0,0,0,0]),
|
||||
bi;
|
||||
|
||||
delta = xor(delta,times2(times2(delta)));
|
||||
|
||||
for (i=0; i+4<adata.length; i+=4) {
|
||||
delta = times2(delta);
|
||||
checksum = xor(checksum, prp.encrypt(xor(delta, adata.slice(i,i+4))));
|
||||
}
|
||||
|
||||
bi = adata.slice(i);
|
||||
if (w.bitLength(bi) < 128) {
|
||||
delta = xor(delta,times2(delta));
|
||||
bi = w.concat(bi,[0x80000000|0,0,0,0]);
|
||||
}
|
||||
checksum = xor(checksum, bi);
|
||||
return prp.encrypt(xor(times2(xor(delta,times2(delta))), checksum));
|
||||
},
|
||||
|
||||
/** Double a block of words, OCB style.
|
||||
* @private
|
||||
*/
|
||||
_times2: function(x) {
|
||||
return [x[0]<<1 ^ x[1]>>>31,
|
||||
x[1]<<1 ^ x[2]>>>31,
|
||||
x[2]<<1 ^ x[3]>>>31,
|
||||
x[3]<<1 ^ (x[0]>>>31)*0x87];
|
||||
}
|
||||
};
|
||||
54
src/js/sjcl/core/pbkdf2.js
Normal file
54
src/js/sjcl/core/pbkdf2.js
Normal file
@@ -0,0 +1,54 @@
|
||||
/** @fileOverview Password-based key-derivation function, version 2.0.
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
|
||||
/** Password-Based Key-Derivation Function, version 2.0.
|
||||
*
|
||||
* Generate keys from passwords using PBKDF2-HMAC-SHA256.
|
||||
*
|
||||
* This is the method specified by RSA's PKCS #5 standard.
|
||||
*
|
||||
* @param {bitArray|String} password The password.
|
||||
* @param {bitArray} salt The salt. Should have lots of entropy.
|
||||
* @param {Number} [count=1000] The number of iterations. Higher numbers make the function slower but more secure.
|
||||
* @param {Number} [length] The length of the derived key. Defaults to the
|
||||
output size of the hash function.
|
||||
* @param {Object} [Prff=sjcl.misc.hmac] The pseudorandom function family.
|
||||
* @return {bitArray} the derived key.
|
||||
*/
|
||||
sjcl.misc.pbkdf2 = function (password, salt, count, length, Prff) {
|
||||
count = count || 1000;
|
||||
|
||||
if (length < 0 || count < 0) {
|
||||
throw sjcl.exception.invalid("invalid params to pbkdf2");
|
||||
}
|
||||
|
||||
if (typeof password === "string") {
|
||||
password = sjcl.codec.utf8String.toBits(password);
|
||||
}
|
||||
|
||||
Prff = Prff || sjcl.misc.hmac;
|
||||
|
||||
var prf = new Prff(password),
|
||||
u, ui, i, j, k, out = [], b = sjcl.bitArray;
|
||||
|
||||
for (k = 1; 32 * out.length < (length || 1); k++) {
|
||||
u = ui = prf.encrypt(b.concat(salt,[k]));
|
||||
|
||||
for (i=1; i<count; i++) {
|
||||
ui = prf.encrypt(ui);
|
||||
for (j=0; j<ui.length; j++) {
|
||||
u[j] ^= ui[j];
|
||||
}
|
||||
}
|
||||
|
||||
out = out.concat(u);
|
||||
}
|
||||
|
||||
if (length) { out = b.clamp(out, length); }
|
||||
|
||||
return out;
|
||||
};
|
||||
406
src/js/sjcl/core/random.js
Normal file
406
src/js/sjcl/core/random.js
Normal file
@@ -0,0 +1,406 @@
|
||||
/** @fileOverview Random number generator.
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
|
||||
/** @constructor
|
||||
* @class Random number generator
|
||||
*
|
||||
* @description
|
||||
* <p>
|
||||
* 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.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* 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.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* 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.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* 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.
|
||||
* </p>
|
||||
*/
|
||||
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
|
||||
* @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; i<nwords; i+= 4) {
|
||||
if ((i+1) % this._MAX_WORDS_PER_BURST === 0) {
|
||||
this._gate();
|
||||
}
|
||||
|
||||
g = this._gen4words();
|
||||
out.push(g[0],g[1],g[2],g[3]);
|
||||
}
|
||||
this._gate();
|
||||
|
||||
return out.slice(0,nwords);
|
||||
},
|
||||
|
||||
setDefaultParanoia: function (paranoia) {
|
||||
this._defaultParanoia = paranoia;
|
||||
},
|
||||
|
||||
/**
|
||||
* Add entropy to the pools.
|
||||
* @param data The entropic value. Should be a 32-bit integer, array of 32-bit integers, or string
|
||||
* @param {Number} estimatedEntropy The estimated entropy of data, in bits
|
||||
* @param {String} source The source of the entropy, eg "mouse"
|
||||
*/
|
||||
addEntropy: function (data, estimatedEntropy, source) {
|
||||
source = source || "user";
|
||||
|
||||
var id,
|
||||
i, tmp,
|
||||
t = (new Date()).valueOf(),
|
||||
robin = this._robins[source],
|
||||
oldReady = this.isReady(), err = 0;
|
||||
|
||||
id = this._collectorIds[source];
|
||||
if (id === undefined) { id = this._collectorIds[source] = this._collectorIdNext ++; }
|
||||
|
||||
if (robin === undefined) { robin = this._robins[source] = 0; }
|
||||
this._robins[source] = ( this._robins[source] + 1 ) % this._pools.length;
|
||||
|
||||
switch(typeof(data)) {
|
||||
|
||||
case "number":
|
||||
if (estimatedEntropy === undefined) {
|
||||
estimatedEntropy = 1;
|
||||
}
|
||||
this._pools[robin].update([id,this._eventId++,1,estimatedEntropy,t,1,data|0]);
|
||||
break;
|
||||
|
||||
case "object":
|
||||
var objName = Object.prototype.toString.call(data);
|
||||
if (objName === "[object Uint32Array]") {
|
||||
tmp = [];
|
||||
for (i = 0; i < data.length; i++) {
|
||||
tmp.push(data[i]);
|
||||
}
|
||||
data = tmp;
|
||||
} else {
|
||||
if (objName !== "[object Array]") {
|
||||
err = 1;
|
||||
}
|
||||
for (i=0; i<data.length && !err; i++) {
|
||||
if (typeof(data[i]) != "number") {
|
||||
err = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!err) {
|
||||
if (estimatedEntropy === undefined) {
|
||||
/* horrible entropy estimator */
|
||||
estimatedEntropy = 0;
|
||||
for (i=0; i<data.length; i++) {
|
||||
tmp= data[i];
|
||||
while (tmp>0) {
|
||||
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; }
|
||||
|
||||
if (window.addEventListener) {
|
||||
window.addEventListener("load", this._loadTimeCollector, false);
|
||||
window.addEventListener("mousemove", this._mouseCollector, false);
|
||||
} else if (document.attachEvent) {
|
||||
document.attachEvent("onload", this._loadTimeCollector);
|
||||
document.attachEvent("onmousemove", this._mouseCollector);
|
||||
}
|
||||
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._loadTimeCollector, false);
|
||||
window.removeEventListener("mousemove", this._mouseCollector, false);
|
||||
} else if (window.detachEvent) {
|
||||
window.detachEvent("onload", this._loadTimeCollector);
|
||||
window.detachEvent("onmousemove", this._mouseCollector);
|
||||
}
|
||||
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<jsTemp.length; i++) {
|
||||
j = jsTemp[i];
|
||||
delete cbs[j];
|
||||
}
|
||||
},
|
||||
|
||||
/** Generate 4 random words, no reseed, no gate.
|
||||
* @private
|
||||
*/
|
||||
_gen4words: function () {
|
||||
for (var i=0; i<4; i++) {
|
||||
this._counter[i] = this._counter[i]+1 | 0;
|
||||
if (this._counter[i]) { break; }
|
||||
}
|
||||
return this._cipher.encrypt(this._counter);
|
||||
},
|
||||
|
||||
/* Rekey the AES instance with itself after a request, or every _MAX_WORDS_PER_BURST words.
|
||||
* @private
|
||||
*/
|
||||
_gate: function () {
|
||||
this._key = this._gen4words().concat(this._gen4words());
|
||||
this._cipher = new sjcl.cipher.aes(this._key);
|
||||
},
|
||||
|
||||
/** Reseed the generator with the given words
|
||||
* @private
|
||||
*/
|
||||
_reseed: function (seedWords) {
|
||||
this._key = sjcl.hash.sha256.hash(this._key.concat(seedWords));
|
||||
this._cipher = new sjcl.cipher.aes(this._key);
|
||||
for (var i=0; i<4; i++) {
|
||||
this._counter[i] = this._counter[i]+1 | 0;
|
||||
if (this._counter[i]) { break; }
|
||||
}
|
||||
},
|
||||
|
||||
/** reseed the data from the entropy pools
|
||||
* @param full If set, use all the entropy pools in the reseed.
|
||||
*/
|
||||
_reseedFromPools: function (full) {
|
||||
var reseedData = [], strength = 0, i;
|
||||
|
||||
this._nextReseed = reseedData[0] =
|
||||
(new Date()).valueOf() + this._MILLISECONDS_PER_RESEED;
|
||||
|
||||
for (i=0; i<16; i++) {
|
||||
/* On some browsers, this is cryptographically random. So we might
|
||||
* as well toss it in the pot and stir...
|
||||
*/
|
||||
reseedData.push(Math.random()*0x100000000|0);
|
||||
}
|
||||
|
||||
for (i=0; i<this._pools.length; i++) {
|
||||
reseedData = reseedData.concat(this._pools[i].finalize());
|
||||
strength += this._poolEntropy[i];
|
||||
this._poolEntropy[i] = 0;
|
||||
|
||||
if (!full && (this._reseedCount & (1<<i))) { break; }
|
||||
}
|
||||
|
||||
/* if we used the last pool, push a new one onto the stack */
|
||||
if (this._reseedCount >= 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);
|
||||
},
|
||||
|
||||
_mouseCollector: function (ev) {
|
||||
var x = ev.x || ev.clientX || ev.offsetX || 0, y = ev.y || ev.clientY || ev.offsetY || 0;
|
||||
sjcl.random.addEntropy([x,y], 2, "mouse");
|
||||
},
|
||||
|
||||
_loadTimeCollector: function (ev) {
|
||||
sjcl.random.addEntropy((new Date()).valueOf(), 2, "loadtime");
|
||||
},
|
||||
|
||||
_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<cbsTemp.length; j++) {
|
||||
cbsTemp[j](arg);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
sjcl.random = new sjcl.prng(6);
|
||||
|
||||
(function(){
|
||||
try {
|
||||
// get cryptographically strong entropy in Webkit
|
||||
var ab = new Uint32Array(32);
|
||||
crypto.getRandomValues(ab);
|
||||
sjcl.random.addEntropy(ab, 1024, "crypto.getRandomValues");
|
||||
} catch (e) {
|
||||
// no getRandomValues :-(
|
||||
}
|
||||
})();
|
||||
165
src/js/sjcl/core/sha1.js
Normal file
165
src/js/sjcl/core/sha1.js
Normal file
@@ -0,0 +1,165 @@
|
||||
/** @fileOverview Javascript SHA-1 implementation.
|
||||
*
|
||||
* Based on the implementation in RFC 3174, method 1, and on the SJCL
|
||||
* SHA-256 implementation.
|
||||
*
|
||||
* @author Quinn Slack
|
||||
*/
|
||||
|
||||
/**
|
||||
* Context for a SHA-1 operation in progress.
|
||||
* @constructor
|
||||
* @class Secure Hash Algorithm, 160 bits.
|
||||
*/
|
||||
sjcl.hash.sha1 = function (hash) {
|
||||
if (hash) {
|
||||
this._h = hash._h.slice(0);
|
||||
this._buffer = hash._buffer.slice(0);
|
||||
this._length = hash._length;
|
||||
} else {
|
||||
this.reset();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Hash a string or an array of words.
|
||||
* @static
|
||||
* @param {bitArray|String} data the data to hash.
|
||||
* @return {bitArray} The hash value, an array of 5 big-endian words.
|
||||
*/
|
||||
sjcl.hash.sha1.hash = function (data) {
|
||||
return (new sjcl.hash.sha1()).update(data).finalize();
|
||||
};
|
||||
|
||||
sjcl.hash.sha1.prototype = {
|
||||
/**
|
||||
* The hash's block size, in bits.
|
||||
* @constant
|
||||
*/
|
||||
blockSize: 512,
|
||||
|
||||
/**
|
||||
* Reset the hash state.
|
||||
* @return this
|
||||
*/
|
||||
reset:function () {
|
||||
this._h = this._init.slice(0);
|
||||
this._buffer = [];
|
||||
this._length = 0;
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Input several words to the hash.
|
||||
* @param {bitArray|String} data the data to hash.
|
||||
* @return this
|
||||
*/
|
||||
update: function (data) {
|
||||
if (typeof data === "string") {
|
||||
data = sjcl.codec.utf8String.toBits(data);
|
||||
}
|
||||
var i, b = this._buffer = sjcl.bitArray.concat(this._buffer, data),
|
||||
ol = this._length,
|
||||
nl = this._length = ol + sjcl.bitArray.bitLength(data);
|
||||
for (i = this.blockSize+ol & -this.blockSize; i <= nl;
|
||||
i+= this.blockSize) {
|
||||
this._block(b.splice(0,16));
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Complete hashing and output the hash value.
|
||||
* @return {bitArray} The hash value, an array of 5 big-endian words. TODO
|
||||
*/
|
||||
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-1 initialization vector.
|
||||
* @private
|
||||
*/
|
||||
_init:[0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0],
|
||||
|
||||
/**
|
||||
* The SHA-1 hash key.
|
||||
* @private
|
||||
*/
|
||||
_key:[0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6],
|
||||
|
||||
/**
|
||||
* The SHA-1 logical functions f(0), f(1), ..., f(79).
|
||||
* @private
|
||||
*/
|
||||
_f:function(t, b, c, d) {
|
||||
if (t <= 19) {
|
||||
return (b & c) | (~b & d);
|
||||
} else if (t <= 39) {
|
||||
return b ^ c ^ d;
|
||||
} else if (t <= 59) {
|
||||
return (b & c) | (b & d) | (c & d);
|
||||
} else if (t <= 79) {
|
||||
return b ^ c ^ d;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Circular left-shift operator.
|
||||
* @private
|
||||
*/
|
||||
_S:function(n, x) {
|
||||
return (x << n) | (x >>> 32-n);
|
||||
},
|
||||
|
||||
/**
|
||||
* Perform one cycle of SHA-1.
|
||||
* @param {bitArray} words one block of words.
|
||||
* @private
|
||||
*/
|
||||
_block:function (words) {
|
||||
var t, tmp, a, b, c, d, e,
|
||||
w = words.slice(0),
|
||||
h = this._h,
|
||||
k = this._key;
|
||||
|
||||
a = h[0]; b = h[1]; c = h[2]; d = h[3]; e = h[4];
|
||||
|
||||
for (t=0; t<=79; t++) {
|
||||
if (t >= 16) {
|
||||
w[t] = this._S(1, w[t-3] ^ w[t-8] ^ w[t-14] ^ w[t-16]);
|
||||
}
|
||||
tmp = (this._S(5, a) + this._f(t, b, c, d) + e + w[t] +
|
||||
this._key[Math.floor(t/20)]) | 0;
|
||||
e = d;
|
||||
d = c;
|
||||
c = this._S(30, b);
|
||||
b = a;
|
||||
a = tmp;
|
||||
}
|
||||
|
||||
h[0] = (h[0]+a) |0;
|
||||
h[1] = (h[1]+b) |0;
|
||||
h[2] = (h[2]+c) |0;
|
||||
h[3] = (h[3]+d) |0;
|
||||
h[4] = (h[4]+e) |0;
|
||||
}
|
||||
};
|
||||
216
src/js/sjcl/core/sha256.js
Normal file
216
src/js/sjcl/core/sha256.js
Normal file
@@ -0,0 +1,216 @@
|
||||
/** @fileOverview Javascript SHA-256 implementation.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Special thanks to Aldo Cortesi for pointing out several bugs in
|
||||
* this code.
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
*/
|
||||
|
||||
/**
|
||||
* Context for a SHA-256 operation in progress.
|
||||
* @constructor
|
||||
* @class Secure Hash Algorithm, 256 bits.
|
||||
*/
|
||||
sjcl.hash.sha256 = function (hash) {
|
||||
if (!this._key[0]) { this._precompute(); }
|
||||
if (hash) {
|
||||
this._h = hash._h.slice(0);
|
||||
this._buffer = hash._buffer.slice(0);
|
||||
this._length = hash._length;
|
||||
} else {
|
||||
this.reset();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Hash a string or an array of words.
|
||||
* @static
|
||||
* @param {bitArray|String} data the data to hash.
|
||||
* @return {bitArray} The hash value, an array of 16 big-endian words.
|
||||
*/
|
||||
sjcl.hash.sha256.hash = function (data) {
|
||||
return (new sjcl.hash.sha256()).update(data).finalize();
|
||||
};
|
||||
|
||||
sjcl.hash.sha256.prototype = {
|
||||
/**
|
||||
* The hash's block size, in bits.
|
||||
* @constant
|
||||
*/
|
||||
blockSize: 512,
|
||||
|
||||
/**
|
||||
* Reset the hash state.
|
||||
* @return this
|
||||
*/
|
||||
reset:function () {
|
||||
this._h = this._init.slice(0);
|
||||
this._buffer = [];
|
||||
this._length = 0;
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Input several words to the hash.
|
||||
* @param {bitArray|String} data the data to hash.
|
||||
* @return this
|
||||
*/
|
||||
update: function (data) {
|
||||
if (typeof data === "string") {
|
||||
data = sjcl.codec.utf8String.toBits(data);
|
||||
}
|
||||
var i, b = this._buffer = sjcl.bitArray.concat(this._buffer, data),
|
||||
ol = this._length,
|
||||
nl = this._length = ol + sjcl.bitArray.bitLength(data);
|
||||
for (i = 512+ol & -512; 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;
|
||||
|
||||
function frac(x) { return (x-Math.floor(x)) * 0x100000000 | 0; }
|
||||
|
||||
outer: for (; i<64; prime++) {
|
||||
for (factor=2; factor*factor <= prime; factor++) {
|
||||
if (prime % factor === 0) {
|
||||
// not a prime
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
|
||||
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 {bitArray} words one block of words.
|
||||
* @private
|
||||
*/
|
||||
_block:function (words) {
|
||||
var i, tmp, a, b,
|
||||
w = words.slice(0),
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
348
src/js/sjcl/core/sha512.js
Normal file
348
src/js/sjcl/core/sha512.js
Normal file
@@ -0,0 +1,348 @@
|
||||
/** @fileOverview Javascript SHA-512 implementation.
|
||||
*
|
||||
* This implementation was written for CryptoJS by Jeff Mott and adapted for
|
||||
* SJCL by Stefan Thomas.
|
||||
*
|
||||
* CryptoJS (c) 2009–2012 by Jeff Mott. All rights reserved.
|
||||
* Released with New BSD License
|
||||
*
|
||||
* @author Emily Stark
|
||||
* @author Mike Hamburg
|
||||
* @author Dan Boneh
|
||||
* @author Jeff Mott
|
||||
* @author Stefan Thomas
|
||||
*/
|
||||
|
||||
/**
|
||||
* Context for a SHA-512 operation in progress.
|
||||
* @constructor
|
||||
* @class Secure Hash Algorithm, 512 bits.
|
||||
*/
|
||||
sjcl.hash.sha512 = function (hash) {
|
||||
if (!this._key[0]) { this._precompute(); }
|
||||
if (hash) {
|
||||
this._h = hash._h.slice(0);
|
||||
this._buffer = hash._buffer.slice(0);
|
||||
this._length = hash._length;
|
||||
} else {
|
||||
this.reset();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Hash a string or an array of words.
|
||||
* @static
|
||||
* @param {bitArray|String} data the data to hash.
|
||||
* @return {bitArray} The hash value, an array of 16 big-endian words.
|
||||
*/
|
||||
sjcl.hash.sha512.hash = function (data) {
|
||||
return (new sjcl.hash.sha512()).update(data).finalize();
|
||||
};
|
||||
|
||||
sjcl.hash.sha512.prototype = {
|
||||
/**
|
||||
* The hash's block size, in bits.
|
||||
* @constant
|
||||
*/
|
||||
blockSize: 1024,
|
||||
|
||||
/**
|
||||
* Reset the hash state.
|
||||
* @return this
|
||||
*/
|
||||
reset:function () {
|
||||
this._h = this._init.slice(0);
|
||||
this._buffer = [];
|
||||
this._length = 0;
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Input several words to the hash.
|
||||
* @param {bitArray|String} data the data to hash.
|
||||
* @return this
|
||||
*/
|
||||
update: function (data) {
|
||||
if (typeof data === "string") {
|
||||
data = sjcl.codec.utf8String.toBits(data);
|
||||
}
|
||||
var i, b = this._buffer = sjcl.bitArray.concat(this._buffer, data),
|
||||
ol = this._length,
|
||||
nl = this._length = ol + sjcl.bitArray.bitLength(data);
|
||||
for (i = 1024+ol & -1024; i <= nl; i+= 1024) {
|
||||
this._block(b.splice(0,32));
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Complete hashing and output the hash value.
|
||||
* @return {bitArray} The hash value, an array of 16 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 32 words, less the 4 length words.
|
||||
for (i = b.length + 4; i & 31; i++) {
|
||||
b.push(0);
|
||||
}
|
||||
|
||||
// append the length
|
||||
b.push(0);
|
||||
b.push(0);
|
||||
b.push(Math.floor(this._length / 0x100000000));
|
||||
b.push(this._length | 0);
|
||||
|
||||
while (b.length) {
|
||||
this._block(b.splice(0,32));
|
||||
}
|
||||
|
||||
this.reset();
|
||||
return h;
|
||||
},
|
||||
|
||||
/**
|
||||
* The SHA-512 initialization vector, to be precomputed.
|
||||
* @private
|
||||
*/
|
||||
_init:[],
|
||||
|
||||
/**
|
||||
* Least significant 24 bits of SHA512 initialization values.
|
||||
*
|
||||
* Javascript only has 53 bits of precision, so we compute the 40 most
|
||||
* significant bits and add the remaining 24 bits as constants.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_initr: [ 0xbcc908, 0xcaa73b, 0x94f82b, 0x1d36f1, 0xe682d1, 0x3e6c1f, 0x41bd6b, 0x7e2179 ],
|
||||
|
||||
/*
|
||||
_init:
|
||||
[0x6a09e667, 0xf3bcc908, 0xbb67ae85, 0x84caa73b, 0x3c6ef372, 0xfe94f82b, 0xa54ff53a, 0x5f1d36f1,
|
||||
0x510e527f, 0xade682d1, 0x9b05688c, 0x2b3e6c1f, 0x1f83d9ab, 0xfb41bd6b, 0x5be0cd19, 0x137e2179],
|
||||
*/
|
||||
|
||||
/**
|
||||
* The SHA-512 hash key, to be precomputed.
|
||||
* @private
|
||||
*/
|
||||
_key:[],
|
||||
|
||||
/**
|
||||
* Least significant 24 bits of SHA512 key values.
|
||||
* @private
|
||||
*/
|
||||
_keyr:
|
||||
[0x28ae22, 0xef65cd, 0x4d3b2f, 0x89dbbc, 0x48b538, 0x05d019, 0x194f9b, 0x6d8118,
|
||||
0x030242, 0x706fbe, 0xe4b28c, 0xffb4e2, 0x7b896f, 0x1696b1, 0xc71235, 0x692694,
|
||||
0xf14ad2, 0x4f25e3, 0x8cd5b5, 0xac9c65, 0x2b0275, 0xa6e483, 0x41fbd4, 0x1153b5,
|
||||
0x66dfab, 0xb43210, 0xfb213f, 0xef0ee4, 0xa88fc2, 0x0aa725, 0x03826f, 0x0e6e70,
|
||||
0xd22ffc, 0x26c926, 0xc42aed, 0x95b3df, 0xaf63de, 0x77b2a8, 0xedaee6, 0x82353b,
|
||||
0xf10364, 0x423001, 0xf89791, 0x54be30, 0xef5218, 0x65a910, 0x71202a, 0xbbd1b8,
|
||||
0xd2d0c8, 0x41ab53, 0x8eeb99, 0x9b48a8, 0xc95a63, 0x418acb, 0x63e373, 0xb2b8a3,
|
||||
0xefb2fc, 0x172f60, 0xf0ab72, 0x6439ec, 0x631e28, 0x82bde9, 0xc67915, 0x72532b,
|
||||
0x26619c, 0xc0c207, 0xe0eb1e, 0x6ed178, 0x176fba, 0xc898a6, 0xf90dae, 0x1c471b,
|
||||
0x047d84, 0xc72493, 0xc9bebc, 0x100d4c, 0x3e42b6, 0x657e2a, 0xd6faec, 0x475817],
|
||||
|
||||
/*
|
||||
_key:
|
||||
[0x428a2f98, 0xd728ae22, 0x71374491, 0x23ef65cd, 0xb5c0fbcf, 0xec4d3b2f, 0xe9b5dba5, 0x8189dbbc,
|
||||
0x3956c25b, 0xf348b538, 0x59f111f1, 0xb605d019, 0x923f82a4, 0xaf194f9b, 0xab1c5ed5, 0xda6d8118,
|
||||
0xd807aa98, 0xa3030242, 0x12835b01, 0x45706fbe, 0x243185be, 0x4ee4b28c, 0x550c7dc3, 0xd5ffb4e2,
|
||||
0x72be5d74, 0xf27b896f, 0x80deb1fe, 0x3b1696b1, 0x9bdc06a7, 0x25c71235, 0xc19bf174, 0xcf692694,
|
||||
0xe49b69c1, 0x9ef14ad2, 0xefbe4786, 0x384f25e3, 0x0fc19dc6, 0x8b8cd5b5, 0x240ca1cc, 0x77ac9c65,
|
||||
0x2de92c6f, 0x592b0275, 0x4a7484aa, 0x6ea6e483, 0x5cb0a9dc, 0xbd41fbd4, 0x76f988da, 0x831153b5,
|
||||
0x983e5152, 0xee66dfab, 0xa831c66d, 0x2db43210, 0xb00327c8, 0x98fb213f, 0xbf597fc7, 0xbeef0ee4,
|
||||
0xc6e00bf3, 0x3da88fc2, 0xd5a79147, 0x930aa725, 0x06ca6351, 0xe003826f, 0x14292967, 0x0a0e6e70,
|
||||
0x27b70a85, 0x46d22ffc, 0x2e1b2138, 0x5c26c926, 0x4d2c6dfc, 0x5ac42aed, 0x53380d13, 0x9d95b3df,
|
||||
0x650a7354, 0x8baf63de, 0x766a0abb, 0x3c77b2a8, 0x81c2c92e, 0x47edaee6, 0x92722c85, 0x1482353b,
|
||||
0xa2bfe8a1, 0x4cf10364, 0xa81a664b, 0xbc423001, 0xc24b8b70, 0xd0f89791, 0xc76c51a3, 0x0654be30,
|
||||
0xd192e819, 0xd6ef5218, 0xd6990624, 0x5565a910, 0xf40e3585, 0x5771202a, 0x106aa070, 0x32bbd1b8,
|
||||
0x19a4c116, 0xb8d2d0c8, 0x1e376c08, 0x5141ab53, 0x2748774c, 0xdf8eeb99, 0x34b0bcb5, 0xe19b48a8,
|
||||
0x391c0cb3, 0xc5c95a63, 0x4ed8aa4a, 0xe3418acb, 0x5b9cca4f, 0x7763e373, 0x682e6ff3, 0xd6b2b8a3,
|
||||
0x748f82ee, 0x5defb2fc, 0x78a5636f, 0x43172f60, 0x84c87814, 0xa1f0ab72, 0x8cc70208, 0x1a6439ec,
|
||||
0x90befffa, 0x23631e28, 0xa4506ceb, 0xde82bde9, 0xbef9a3f7, 0xb2c67915, 0xc67178f2, 0xe372532b,
|
||||
0xca273ece, 0xea26619c, 0xd186b8c7, 0x21c0c207, 0xeada7dd6, 0xcde0eb1e, 0xf57d4f7f, 0xee6ed178,
|
||||
0x06f067aa, 0x72176fba, 0x0a637dc5, 0xa2c898a6, 0x113f9804, 0xbef90dae, 0x1b710b35, 0x131c471b,
|
||||
0x28db77f5, 0x23047d84, 0x32caab7b, 0x40c72493, 0x3c9ebe0a, 0x15c9bebc, 0x431d67c4, 0x9c100d4c,
|
||||
0x4cc5d4be, 0xcb3e42b6, 0x597f299c, 0xfc657e2a, 0x5fcb6fab, 0x3ad6faec, 0x6c44198c, 0x4a475817],
|
||||
*/
|
||||
|
||||
/**
|
||||
* Function to precompute _init and _key.
|
||||
* @private
|
||||
*/
|
||||
_precompute: function () {
|
||||
// XXX: This code is for precomputing the SHA256 constants, change for
|
||||
// SHA512 and re-enable.
|
||||
var i = 0, prime = 2, factor;
|
||||
|
||||
function frac(x) { return (x-Math.floor(x)) * 0x100000000 | 0; }
|
||||
function frac2(x) { return (x-Math.floor(x)) * 0x10000000000 & 0xff; }
|
||||
|
||||
outer: for (; i<80; prime++) {
|
||||
for (factor=2; factor*factor <= prime; factor++) {
|
||||
if (prime % factor === 0) {
|
||||
// not a prime
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
|
||||
if (i<8) {
|
||||
this._init[i*2] = frac(Math.pow(prime, 1/2));
|
||||
this._init[i*2+1] = (frac2(Math.pow(prime, 1/2)) << 24) | this._initr[i];
|
||||
}
|
||||
this._key[i*2] = frac(Math.pow(prime, 1/3));
|
||||
this._key[i*2+1] = (frac2(Math.pow(prime, 1/3)) << 24) | this._keyr[i];
|
||||
i++;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Perform one cycle of SHA-512.
|
||||
* @param {bitArray} words one block of words.
|
||||
* @private
|
||||
*/
|
||||
_block:function (words) {
|
||||
var i, wrh, wrl,
|
||||
w = words.slice(0),
|
||||
h = this._h,
|
||||
k = this._key,
|
||||
h0h = h[ 0], h0l = h[ 1], h1h = h[ 2], h1l = h[ 3],
|
||||
h2h = h[ 4], h2l = h[ 5], h3h = h[ 6], h3l = h[ 7],
|
||||
h4h = h[ 8], h4l = h[ 9], h5h = h[10], h5l = h[11],
|
||||
h6h = h[12], h6l = h[13], h7h = h[14], h7l = h[15];
|
||||
|
||||
// Working variables
|
||||
var ah = h0h, al = h0l, bh = h1h, bl = h1l,
|
||||
ch = h2h, cl = h2l, dh = h3h, dl = h3l,
|
||||
eh = h4h, el = h4l, fh = h5h, fl = h5l,
|
||||
gh = h6h, gl = h6l, hh = h7h, hl = h7l;
|
||||
|
||||
for (i=0; i<80; i++) {
|
||||
// load up the input word for this round
|
||||
if (i<16) {
|
||||
wrh = w[i * 2];
|
||||
wrl = w[i * 2 + 1];
|
||||
} else {
|
||||
// Gamma0
|
||||
var gamma0xh = w[(i-15) * 2];
|
||||
var gamma0xl = w[(i-15) * 2 + 1];
|
||||
var gamma0h =
|
||||
((gamma0xl << 31) | (gamma0xh >>> 1)) ^
|
||||
((gamma0xl << 24) | (gamma0xh >>> 8)) ^
|
||||
(gamma0xh >>> 7);
|
||||
var gamma0l =
|
||||
((gamma0xh << 31) | (gamma0xl >>> 1)) ^
|
||||
((gamma0xh << 24) | (gamma0xl >>> 8)) ^
|
||||
((gamma0xh << 25) | (gamma0xl >>> 7));
|
||||
|
||||
// Gamma1
|
||||
var gamma1xh = w[(i-2) * 2];
|
||||
var gamma1xl = w[(i-2) * 2 + 1];
|
||||
var gamma1h =
|
||||
((gamma1xl << 13) | (gamma1xh >>> 19)) ^
|
||||
((gamma1xh << 3) | (gamma1xl >>> 29)) ^
|
||||
(gamma1xh >>> 6);
|
||||
var gamma1l =
|
||||
((gamma1xh << 13) | (gamma1xl >>> 19)) ^
|
||||
((gamma1xl << 3) | (gamma1xh >>> 29)) ^
|
||||
((gamma1xh << 26) | (gamma1xl >>> 6));
|
||||
|
||||
// Shortcuts
|
||||
var wr7h = w[(i-7) * 2];
|
||||
var wr7l = w[(i-7) * 2 + 1];
|
||||
|
||||
var wr16h = w[(i-16) * 2];
|
||||
var wr16l = w[(i-16) * 2 + 1];
|
||||
|
||||
// W(round) = gamma0 + W(round - 7) + gamma1 + W(round - 16)
|
||||
wrl = gamma0l + wr7l;
|
||||
wrh = gamma0h + wr7h + ((wrl >>> 0) < (gamma0l >>> 0) ? 1 : 0);
|
||||
wrl += gamma1l;
|
||||
wrh += gamma1h + ((wrl >>> 0) < (gamma1l >>> 0) ? 1 : 0);
|
||||
wrl += wr16l;
|
||||
wrh += wr16h + ((wrl >>> 0) < (wr16l >>> 0) ? 1 : 0);
|
||||
}
|
||||
|
||||
w[i*2] = wrh |= 0;
|
||||
w[i*2 + 1] = wrl |= 0;
|
||||
|
||||
// Ch
|
||||
var chh = (eh & fh) ^ (~eh & gh);
|
||||
var chl = (el & fl) ^ (~el & gl);
|
||||
|
||||
// Maj
|
||||
var majh = (ah & bh) ^ (ah & ch) ^ (bh & ch);
|
||||
var majl = (al & bl) ^ (al & cl) ^ (bl & cl);
|
||||
|
||||
// Sigma0
|
||||
var sigma0h = ((al << 4) | (ah >>> 28)) ^ ((ah << 30) | (al >>> 2)) ^ ((ah << 25) | (al >>> 7));
|
||||
var sigma0l = ((ah << 4) | (al >>> 28)) ^ ((al << 30) | (ah >>> 2)) ^ ((al << 25) | (ah >>> 7));
|
||||
|
||||
// Sigma1
|
||||
var sigma1h = ((el << 18) | (eh >>> 14)) ^ ((el << 14) | (eh >>> 18)) ^ ((eh << 23) | (el >>> 9));
|
||||
var sigma1l = ((eh << 18) | (el >>> 14)) ^ ((eh << 14) | (el >>> 18)) ^ ((el << 23) | (eh >>> 9));
|
||||
|
||||
// K(round)
|
||||
var krh = k[i*2];
|
||||
var krl = k[i*2+1];
|
||||
|
||||
// t1 = h + sigma1 + ch + K(round) + W(round)
|
||||
var t1l = hl + sigma1l;
|
||||
var t1h = hh + sigma1h + ((t1l >>> 0) < (hl >>> 0) ? 1 : 0);
|
||||
t1l += chl;
|
||||
t1h += chh + ((t1l >>> 0) < (chl >>> 0) ? 1 : 0);
|
||||
t1l += krl;
|
||||
t1h += krh + ((t1l >>> 0) < (krl >>> 0) ? 1 : 0);
|
||||
t1l += wrl;
|
||||
t1h += wrh + ((t1l >>> 0) < (wrl >>> 0) ? 1 : 0);
|
||||
|
||||
// t2 = sigma0 + maj
|
||||
var t2l = sigma0l + majl;
|
||||
var t2h = sigma0h + majh + ((t2l >>> 0) < (sigma0l >>> 0) ? 1 : 0);
|
||||
|
||||
// Update working variables
|
||||
hh = gh;
|
||||
hl = gl;
|
||||
gh = fh;
|
||||
gl = fl;
|
||||
fh = eh;
|
||||
fl = el;
|
||||
el = (dl + t1l) | 0;
|
||||
eh = (dh + t1h + ((el >>> 0) < (dl >>> 0) ? 1 : 0)) | 0;
|
||||
dh = ch;
|
||||
dl = cl;
|
||||
ch = bh;
|
||||
cl = bl;
|
||||
bh = ah;
|
||||
bl = al;
|
||||
al = (t1l + t2l) | 0;
|
||||
ah = (t1h + t2h + ((al >>> 0) < (t1l >>> 0) ? 1 : 0)) | 0;
|
||||
}
|
||||
|
||||
// Intermediate hash
|
||||
h0l = h[1] = (h0l + al) | 0;
|
||||
h[0] = (h0h + ah + ((h0l >>> 0) < (al >>> 0) ? 1 : 0)) | 0;
|
||||
h1l = h[3] = (h1l + bl) | 0;
|
||||
h[2] = (h1h + bh + ((h1l >>> 0) < (bl >>> 0) ? 1 : 0)) | 0;
|
||||
h2l = h[5] = (h2l + cl) | 0;
|
||||
h[4] = (h2h + ch + ((h2l >>> 0) < (cl >>> 0) ? 1 : 0)) | 0;
|
||||
h3l = h[7] = (h3l + dl) | 0;
|
||||
h[6] = (h3h + dh + ((h3l >>> 0) < (dl >>> 0) ? 1 : 0)) | 0;
|
||||
h4l = h[9] = (h4l + el) | 0;
|
||||
h[8] = (h4h + eh + ((h4l >>> 0) < (el >>> 0) ? 1 : 0)) | 0;
|
||||
h5l = h[11] = (h5l + fl) | 0;
|
||||
h[10] = (h5h + fh + ((h5l >>> 0) < (fl >>> 0) ? 1 : 0)) | 0;
|
||||
h6l = h[13] = (h6l + gl) | 0;
|
||||
h[12] = (h6h + gh + ((h6l >>> 0) < (gl >>> 0) ? 1 : 0)) | 0;
|
||||
h7l = h[15] = (h7l + hl) | 0;
|
||||
h[14] = (h7h + hh + ((h7l >>> 0) < (hl >>> 0) ? 1 : 0)) | 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
73
src/js/sjcl/core/sjcl.js
Normal file
73
src/js/sjcl/core/sjcl.js
Normal file
@@ -0,0 +1,73 @@
|
||||
/** @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 */
|
||||
|
||||
/** @namespace The Stanford Javascript Crypto Library, top-level namespace. */
|
||||
var sjcl = {
|
||||
/** @namespace Symmetric ciphers. */
|
||||
cipher: {},
|
||||
|
||||
/** @namespace Hash functions. Right now only SHA256 is implemented. */
|
||||
hash: {},
|
||||
|
||||
/** @namespace Key exchange functions. Right now only SRP is implemented. */
|
||||
keyexchange: {},
|
||||
|
||||
/** @namespace Block cipher modes of operation. */
|
||||
mode: {},
|
||||
|
||||
/** @namespace Miscellaneous. HMAC and PBKDF2. */
|
||||
misc: {},
|
||||
|
||||
/**
|
||||
* @namespace Bit array encoders and decoders.
|
||||
*
|
||||
* @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: {},
|
||||
|
||||
/** @namespace Exceptions. */
|
||||
exception: {
|
||||
/** @constructor Ciphertext is corrupt. */
|
||||
corrupt: function(message) {
|
||||
this.toString = function() { return "CORRUPT: "+this.message; };
|
||||
this.message = message;
|
||||
},
|
||||
|
||||
/** @constructor Invalid parameter. */
|
||||
invalid: function(message) {
|
||||
this.toString = function() { return "INVALID: "+this.message; };
|
||||
this.message = message;
|
||||
},
|
||||
|
||||
/** @constructor Bug or missing feature in SJCL. @constructor */
|
||||
bug: function(message) {
|
||||
this.toString = function() { return "BUG: "+this.message; };
|
||||
this.message = message;
|
||||
},
|
||||
|
||||
/** @constructor Something isn't ready. */
|
||||
notReady: function(message) {
|
||||
this.toString = function() { return "NOT READY: "+this.message; };
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if(typeof module != 'undefined' && module.exports){
|
||||
module.exports = sjcl;
|
||||
}
|
||||
113
src/js/sjcl/core/srp.js
Normal file
113
src/js/sjcl/core/srp.js
Normal file
@@ -0,0 +1,113 @@
|
||||
/** @fileOverview Javascript SRP implementation.
|
||||
*
|
||||
* This file contains a partial implementation of the SRP (Secure Remote
|
||||
* Password) password-authenticated key exchange protocol. Given a user
|
||||
* identity, salt, and SRP group, it generates the SRP verifier that may
|
||||
* be sent to a remote server to establish and SRP account.
|
||||
*
|
||||
* For more information, see http://srp.stanford.edu/.
|
||||
*
|
||||
* @author Quinn Slack
|
||||
*/
|
||||
|
||||
/**
|
||||
* Compute the SRP verifier from the username, password, salt, and group.
|
||||
* @class SRP
|
||||
*/
|
||||
sjcl.keyexchange.srp = {
|
||||
/**
|
||||
* Calculates SRP v, the verifier.
|
||||
* v = g^x mod N [RFC 5054]
|
||||
* @param {String} I The username.
|
||||
* @param {String} P The password.
|
||||
* @param {Object} s A bitArray of the salt.
|
||||
* @param {Object} group The SRP group. Use sjcl.keyexchange.srp.knownGroup
|
||||
to obtain this object.
|
||||
* @return {Object} A bitArray of SRP v.
|
||||
*/
|
||||
makeVerifier: function(I, P, s, group) {
|
||||
var x;
|
||||
x = sjcl.keyexchange.srp.makeX(I, P, s);
|
||||
x = sjcl.bn.fromBits(x);
|
||||
return group.g.powermod(x, group.N);
|
||||
},
|
||||
|
||||
/**
|
||||
* Calculates SRP x.
|
||||
* x = SHA1(<salt> | SHA(<username> | ":" | <raw password>)) [RFC 2945]
|
||||
* @param {String} I The username.
|
||||
* @param {String} P The password.
|
||||
* @param {Object} s A bitArray of the salt.
|
||||
* @return {Object} A bitArray of SRP x.
|
||||
*/
|
||||
makeX: function(I, P, s) {
|
||||
var inner = sjcl.hash.sha1.hash(I + ':' + P);
|
||||
return sjcl.hash.sha1.hash(sjcl.bitArray.concat(s, inner));
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the known SRP group with the given size (in bits).
|
||||
* @param {String} i The size of the known SRP group.
|
||||
* @return {Object} An object with "N" and "g" properties.
|
||||
*/
|
||||
knownGroup:function(i) {
|
||||
if (typeof i !== "string") { i = i.toString(); }
|
||||
if (!sjcl.keyexchange.srp._didInitKnownGroups) { sjcl.keyexchange.srp._initKnownGroups(); }
|
||||
return sjcl.keyexchange.srp._knownGroups[i];
|
||||
},
|
||||
|
||||
/**
|
||||
* Initializes bignum objects for known group parameters.
|
||||
* @private
|
||||
*/
|
||||
_didInitKnownGroups: false,
|
||||
_initKnownGroups:function() {
|
||||
var i, size, group;
|
||||
for (i=0; i < sjcl.keyexchange.srp._knownGroupSizes.length; i++) {
|
||||
size = sjcl.keyexchange.srp._knownGroupSizes[i].toString();
|
||||
group = sjcl.keyexchange.srp._knownGroups[size];
|
||||
group.N = new sjcl.bn(group.N);
|
||||
group.g = new sjcl.bn(group.g);
|
||||
}
|
||||
sjcl.keyexchange.srp._didInitKnownGroups = true;
|
||||
},
|
||||
|
||||
_knownGroupSizes: [1024, 1536, 2048],
|
||||
_knownGroups: {
|
||||
1024: {
|
||||
N: "EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C" +
|
||||
"9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE4" +
|
||||
"8E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B29" +
|
||||
"7BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9A" +
|
||||
"FD5138FE8376435B9FC61D2FC0EB06E3",
|
||||
g:2
|
||||
},
|
||||
|
||||
1536: {
|
||||
N: "9DEF3CAFB939277AB1F12A8617A47BBBDBA51DF499AC4C80BEEEA961" +
|
||||
"4B19CC4D5F4F5F556E27CBDE51C6A94BE4607A291558903BA0D0F843" +
|
||||
"80B655BB9A22E8DCDF028A7CEC67F0D08134B1C8B97989149B609E0B" +
|
||||
"E3BAB63D47548381DBC5B1FC764E3F4B53DD9DA1158BFD3E2B9C8CF5" +
|
||||
"6EDF019539349627DB2FD53D24B7C48665772E437D6C7F8CE442734A" +
|
||||
"F7CCB7AE837C264AE3A9BEB87F8A2FE9B8B5292E5A021FFF5E91479E" +
|
||||
"8CE7A28C2442C6F315180F93499A234DCF76E3FED135F9BB",
|
||||
g: 2
|
||||
},
|
||||
|
||||
2048: {
|
||||
N: "AC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC319294" +
|
||||
"3DB56050A37329CBB4A099ED8193E0757767A13DD52312AB4B03310D" +
|
||||
"CD7F48A9DA04FD50E8083969EDB767B0CF6095179A163AB3661A05FB" +
|
||||
"D5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF74" +
|
||||
"7359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A" +
|
||||
"436C6481F1D2B9078717461A5B9D32E688F87748544523B524B0D57D" +
|
||||
"5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6AF874E73" +
|
||||
"03CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB6" +
|
||||
"94B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F" +
|
||||
"9E4AFF73",
|
||||
g: 2
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
BIN
src/js/sjcl/demo/alpha-arrow.png
Normal file
BIN
src/js/sjcl/demo/alpha-arrow.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 669 B |
179
src/js/sjcl/demo/example.css
Normal file
179
src/js/sjcl/demo/example.css
Normal file
@@ -0,0 +1,179 @@
|
||||
* {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
font-family: Arial, Helvetica, FreeSans, sans;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
background: #eee;
|
||||
padding: 5px;
|
||||
margin-bottom: 0.6em;
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
.header {
|
||||
width: 650px;
|
||||
margin: 0px auto 1em;
|
||||
}
|
||||
|
||||
p+p {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.explanation {
|
||||
color: #555;
|
||||
margin-top: 0.3em;
|
||||
}
|
||||
|
||||
.section+.section, .explanation+.section {
|
||||
margin-top: 1.5em;
|
||||
}
|
||||
|
||||
.hex {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.hex, .base64, #ciphertext {
|
||||
font-family: 'Courier', mono;
|
||||
}
|
||||
|
||||
.wide, textarea {
|
||||
width: 100%;
|
||||
margin: 0px -4px;
|
||||
font-size: inherit;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
textarea+*, .wide+* {
|
||||
margin-top: 0.3em;
|
||||
}
|
||||
|
||||
/* bulk object placement */
|
||||
#theForm {
|
||||
position: relative;
|
||||
width: 940px;
|
||||
margin: 0px auto;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
.column {
|
||||
top: 0px;
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
.box {
|
||||
border: 2px solid #999;
|
||||
padding: 7px;
|
||||
margin-bottom: 20px;
|
||||
-moz-border-radius: 7px;
|
||||
-webkit-border-radius: 7px;
|
||||
}
|
||||
|
||||
#cmode { position: absolute; left: 640px; }
|
||||
#ctexts { position: absolute; left: 320px; }
|
||||
|
||||
.floatright {
|
||||
float: right;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
a {
|
||||
cursor: pointer;
|
||||
color: #282;
|
||||
}
|
||||
|
||||
a.random, #buttons a { text-decoration: none; }
|
||||
a.random:hover, a.random:focus { text-decoration: underline; }
|
||||
|
||||
h2 {
|
||||
margin: -7px -7px 3px -7px;
|
||||
text-align: center;
|
||||
font-size: 1.2em;
|
||||
color: white;
|
||||
background: #999;
|
||||
}
|
||||
|
||||
#pplaintext { border-color: #f65; }
|
||||
#pplaintext h2 { background: #f65; }
|
||||
|
||||
#ppassword { border-color: #4a4; }
|
||||
#ppassword h2 { background: #4a4; }
|
||||
|
||||
#pciphertext { border-color: #78f; }
|
||||
#pciphertext h2 { background: #78f; }
|
||||
|
||||
#buttons { text-align: center; margin-top: -20px; }
|
||||
|
||||
a#doPbkdf2, a#encrypt, a#decrypt {
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
height: 43px;
|
||||
padding-top: 20px;
|
||||
width: 50px;
|
||||
background: url('alpha-arrow.png') no-repeat bottom center;
|
||||
vertical-align: middle;
|
||||
border: none;
|
||||
color: white;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.turnDown {
|
||||
display: inline-block;
|
||||
padding-bottom: 3px;
|
||||
-moz-transform: rotate(90deg);
|
||||
-webkit-transform: rotate(90deg);
|
||||
transform: rotate(90deg);
|
||||
background-color: inherit;
|
||||
}
|
||||
|
||||
.turnUp {
|
||||
display: inline-block;
|
||||
padding-bottom: 3px;
|
||||
-moz-transform: rotate(-90deg);
|
||||
-webkit-transform: rotate(-90deg);
|
||||
transform: rotate(-90deg);
|
||||
background-color: inherit;
|
||||
}
|
||||
|
||||
.buttons a.disabled {
|
||||
background-color: #ccc ! important;
|
||||
cursor: inherit ! important;
|
||||
}
|
||||
|
||||
a#encrypt { background-color: #f65; margin-bottom: 2px; }
|
||||
a#encrypt:hover, a#encrypt:focus { background-color: #f76; }
|
||||
a#encrypt:active { background-color: #f87; }
|
||||
|
||||
a#decrypt {
|
||||
height: 36px;
|
||||
padding-top: 27px;
|
||||
background: url('alpha-arrow.png') no-repeat top center;
|
||||
background-color: #78f;
|
||||
margin-top: 2px;
|
||||
}
|
||||
a#decrypt:hover { background-color: #89f; }
|
||||
a#decrypt:focus { background-color: #89f; }
|
||||
a#decrypt:active { background-color: #9af; }
|
||||
|
||||
#ppassword, #pkey, #pmode, #pplaintext, #pciphertext {
|
||||
-moz-border-radius: 7px;
|
||||
-webkit-border-radius: 7px;
|
||||
}
|
||||
input[type='text'], input[type='password'], textarea {
|
||||
-moz-border-radius: 3px;
|
||||
-webkit-border-radius: 3px;
|
||||
font-size: inherit;
|
||||
border: 1px solid #444;
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
input[type='text']:focus, input[type='password']:focus, textarea:focus {
|
||||
border-color: red;
|
||||
}
|
||||
|
||||
input[type="radio"], input[type="checkbox"] {
|
||||
position: relative;
|
||||
top: 0.15em;
|
||||
margin-right: -0.15em;
|
||||
}
|
||||
153
src/js/sjcl/demo/example.js
Normal file
153
src/js/sjcl/demo/example.js
Normal file
@@ -0,0 +1,153 @@
|
||||
/* keep track of which salts have been used. */
|
||||
var form, usedIvs = {'':1}, usedSalts = {'':1};
|
||||
|
||||
/* enter actions */
|
||||
var enterActions = {
|
||||
password: doPbkdf2,
|
||||
salt: doPbkdf2,
|
||||
iter: doPbkdf2
|
||||
};
|
||||
|
||||
function loaded() {
|
||||
form = new formHandler('theForm', enterActions);
|
||||
form._extendedKey = [];
|
||||
sjcl.random.startCollectors();
|
||||
document.getElementById("password").focus();
|
||||
}
|
||||
|
||||
/* there's probaby a better way to tell the user something, but oh well */
|
||||
function error(x) {
|
||||
alert(x);
|
||||
}
|
||||
|
||||
/* compute PBKDF2 on the password. */
|
||||
function doPbkdf2(decrypting) {
|
||||
var v = form.get(), salt=v.salt, key, hex = sjcl.codec.hex.fromBits, p={},
|
||||
password = v.password;
|
||||
|
||||
p.iter = v.iter;
|
||||
|
||||
if (password.length == 0) {
|
||||
if (decrypting) { error("Can't decrypt: need a password!"); }
|
||||
return;
|
||||
}
|
||||
|
||||
if (salt.length === 0 && decrypting) {
|
||||
error("Can't decrypt: need a salt for PBKDF2!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (decrypting || !v.freshsalt || !usedSalts[v.salt]) {
|
||||
p.salt = v.salt;
|
||||
}
|
||||
|
||||
p = sjcl.misc.cachedPbkdf2(password, p);
|
||||
form._extendedKey = p.key;
|
||||
v.key = p.key.slice(0, v.keysize/32);
|
||||
v.salt = p.salt;
|
||||
|
||||
form.set(v);
|
||||
form.plaintext.el.select();
|
||||
}
|
||||
/* Encrypt a message */
|
||||
function doEncrypt() {
|
||||
var v = form.get(), iv = v.iv, password = v.password, key = v.key, adata = v.adata, aes, plaintext=v.plaintext, rp = {}, ct, p;
|
||||
|
||||
if (plaintext === '' && v.ciphertext.length) { return; }
|
||||
if (key.length == 0 && password.length == 0) {
|
||||
error("need a password or key!");
|
||||
return;
|
||||
}
|
||||
|
||||
p = { adata:v.adata,
|
||||
iter:v.iter,
|
||||
mode:v.mode,
|
||||
ts:parseInt(v.tag),
|
||||
ks:parseInt(v.keysize) };
|
||||
if (!v.freshiv || !usedIvs[v.iv]) { p.iv = v.iv; }
|
||||
if (!v.freshsalt || !usedSalts[v.salt]) { p.salt = v.salt; }
|
||||
ct = sjcl.encrypt(password || key, plaintext, p, rp).replace(/,/g,",\n");
|
||||
|
||||
v.iv = rp.iv;
|
||||
usedIvs[rp.iv] = 1;
|
||||
if (rp.salt) {
|
||||
v.salt = rp.salt;
|
||||
usedSalts[rp.salt] = 1;
|
||||
}
|
||||
v.key = rp.key;
|
||||
|
||||
if (v.json) {
|
||||
v.ciphertext = ct;
|
||||
v.adata = '';
|
||||
} else {
|
||||
v.ciphertext = ct.match(/"ct":"([^"]*)"/)[1]; //"
|
||||
}
|
||||
|
||||
v.plaintext = '';
|
||||
|
||||
form.set(v);
|
||||
form.ciphertext.el.select();
|
||||
}
|
||||
|
||||
/* Decrypt a message */
|
||||
function doDecrypt() {
|
||||
var v = form.get(), iv = v.iv, key = v.key, adata = v.adata, aes, ciphertext=v.ciphertext, rp = {};
|
||||
|
||||
if (ciphertext.length === 0) { return; }
|
||||
if (!v.password && !v.key.length) {
|
||||
error("Can't decrypt: need a password or key!"); return;
|
||||
}
|
||||
|
||||
if (ciphertext.match("{")) {
|
||||
/* it's jsonized */
|
||||
try {
|
||||
v.plaintext = sjcl.decrypt(v.password || v.key, ciphertext, {}, rp);
|
||||
} catch(e) {
|
||||
error("Can't decrypt: "+e);
|
||||
return;
|
||||
}
|
||||
v.mode = rp.mode;
|
||||
v.iv = rp.iv;
|
||||
v.adata = rp.adata;
|
||||
if (v.password) {
|
||||
v.salt = rp.salt;
|
||||
v.iter = rp.iter;
|
||||
v.keysize = rp.ks;
|
||||
v.tag = rp.ts;
|
||||
}
|
||||
v.key = rp.key;
|
||||
v.ciphertext = "";
|
||||
document.getElementById('plaintext').select();
|
||||
} else {
|
||||
/* it's raw */
|
||||
ciphertext = sjcl.codec.base64.toBits(ciphertext);
|
||||
if (iv.length === 0) {
|
||||
error("Can't decrypt: need an IV!"); return;
|
||||
}
|
||||
if (key.length === 0) {
|
||||
if (v.password.length) {
|
||||
doPbkdf2(true);
|
||||
key = v.key;
|
||||
}
|
||||
}
|
||||
aes = new sjcl.cipher.aes(key);
|
||||
|
||||
try {
|
||||
v.plaintext = sjcl.codec.utf8String.fromBits(sjcl.mode[v.mode].decrypt(aes, ciphertext, iv, v.adata, v.tag));
|
||||
v.ciphertext = "";
|
||||
document.getElementById('plaintext').select();
|
||||
} catch (e) {
|
||||
error("Can't decrypt: " + e);
|
||||
}
|
||||
}
|
||||
form.set(v);
|
||||
}
|
||||
|
||||
function extendKey(size) {
|
||||
form.key.set(form._extendedKey.slice(0,size));
|
||||
}
|
||||
|
||||
function randomize(field, words, paranoia) {
|
||||
form[field].set(sjcl.random.randomWords(words, paranoia));
|
||||
if (field == 'salt') { form.key.set([]); }
|
||||
}
|
||||
137
src/js/sjcl/demo/form.js
Normal file
137
src/js/sjcl/demo/form.js
Normal file
@@ -0,0 +1,137 @@
|
||||
/* Hackish form handling system. */
|
||||
function hasClass(e, cl) {
|
||||
return (" "+e.className+" ").match(" "+cl+" ");
|
||||
}
|
||||
|
||||
function stopPropagation(e) {
|
||||
e.preventDefault && e.preventDefault();
|
||||
e.cancelBubble = true;
|
||||
}
|
||||
|
||||
/* proxy for a form object, with appropriate encoder/decoder */
|
||||
function formElement(el) {
|
||||
this.el = el;
|
||||
}
|
||||
formElement.prototype = {
|
||||
get: function() {
|
||||
var el = this.el;
|
||||
if (el.type == "checkbox") {
|
||||
return el.checked;
|
||||
} else if (hasClass(el, "numeric")) {
|
||||
return parseInt(el.value);
|
||||
} else if (hasClass(el, "hex")) {
|
||||
return sjcl.codec.hex.toBits(el.value);
|
||||
} else if (hasClass(el, "base64")) {
|
||||
return sjcl.codec.base64.toBits(el.value);
|
||||
} else {
|
||||
return el.value;
|
||||
}
|
||||
},
|
||||
|
||||
set: function(x) {
|
||||
var el = this.el;
|
||||
if (el.type == "checkbox") {
|
||||
el.checked = x; return;
|
||||
} else if (hasClass(el, "hex")) {
|
||||
if (typeof x !== 'string') {
|
||||
x = sjcl.codec.hex.fromBits(x);
|
||||
}
|
||||
x = x.toUpperCase().replace(/ /g,'').replace(/(.{8})/g, "$1 ").replace(/ $/, '');
|
||||
} else if (hasClass(el, "base64")) {
|
||||
if (typeof x !== 'string') {
|
||||
x = sjcl.codec.base64.fromBits(x);
|
||||
}
|
||||
x = x.replace(/\s/g,'').replace(/(.{32})/g, "$1\n").replace(/\n$/, '');
|
||||
}
|
||||
el.value = x;
|
||||
}
|
||||
}
|
||||
|
||||
function radioGroup(name) {
|
||||
this.name = name;
|
||||
}
|
||||
radioGroup.prototype = {
|
||||
get: function() {
|
||||
var els = document.getElementsByName(this.name), i;
|
||||
for (i=0; i<els.length; i++) {
|
||||
if (els[i].checked) {
|
||||
return els[i].value;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
set: function(x) {
|
||||
var els = document.getElementsByName(this.name), i;
|
||||
for (i=0; i<els.length; i++) {
|
||||
els[i].checked = (els[i].value == x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function formHandler(formName, enterActions) {
|
||||
var i, els = [], tmp, name;
|
||||
this._elNames = [];
|
||||
|
||||
tmp = document.getElementById(formName).getElementsByTagName('input');
|
||||
for (i=0; i<tmp.length; i++) { els.push(tmp[i]); }
|
||||
|
||||
tmp = document.getElementById(formName).getElementsByTagName('textarea');
|
||||
for (i=0; i<tmp.length; i++) { els.push(tmp[i]); }
|
||||
|
||||
for (i=0; i<els.length; i++) {
|
||||
name = els[i].name || els[i].id;
|
||||
|
||||
/* enforce numeric properties of element */
|
||||
els[i].onkeypress = (function(e) {
|
||||
return function(ev) {
|
||||
ev = ev || window.event;
|
||||
var key = ev.keyCode || ev.which,
|
||||
keyst = String.fromCharCode(ev.charCode || ev.keyCode),
|
||||
ente = enterActions[e.name||e.id];
|
||||
|
||||
if (ev.ctrlKey || ev.metaKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
(key == 13) && ente && ente();
|
||||
|
||||
if (hasClass(e, 'numeric') && ev.charCode && !keyst.match(/[0-9]/)) {
|
||||
stopPropagation(ev); return false;
|
||||
} else if (hasClass(e, 'hex') && ev.charCode && !keyst.match(/[0-9a-fA-F ]/)) {
|
||||
stopPropagation(ev); return false;
|
||||
}
|
||||
}
|
||||
})(els[i]);
|
||||
|
||||
if (els[i].type == 'radio') {
|
||||
if (this[name] === undefined) {
|
||||
this[name] = new radioGroup(name);
|
||||
this._elNames.push(name);
|
||||
}
|
||||
} else {
|
||||
/* code to get the value of an element */
|
||||
this[name] = new formElement(els[i]);
|
||||
this._elNames.push(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
formHandler.prototype = {
|
||||
get:function() {
|
||||
var i, out = {}, en = this._elNames;
|
||||
for (i=0; i<en.length; i++) {
|
||||
out[en[i]] = this[en[i]].get();
|
||||
}
|
||||
return out;
|
||||
},
|
||||
|
||||
set:function(o) {
|
||||
var i;
|
||||
for (i in o) {
|
||||
if (o.hasOwnProperty(i) && this.hasOwnProperty(i)) {
|
||||
this[i].set(o[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
208
src/js/sjcl/demo/index.html
Normal file
208
src/js/sjcl/demo/index.html
Normal file
@@ -0,0 +1,208 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>SJCL demo</title>
|
||||
<link rel="stylesheet" type="text/css" href="example.css"/>
|
||||
<script type="text/javascript" src="../sjcl.js"></script>
|
||||
<script type="text/javascript" src="form.js"></script>
|
||||
<script type="text/javascript" src="example.js"></script>
|
||||
</head>
|
||||
<body onload="loaded()">
|
||||
<h1>SJCL demo</h1>
|
||||
|
||||
<div class="header">
|
||||
<p>This page is a demo of the Stanford Javascript Crypto Library. To get started, just type in a password in the left pane and a secret message in the middle pane, then click "encrypt". Encryption takes place in your browser and we never see the plaintext.</p>
|
||||
|
||||
<p>SJCL has lots of other options, many of which are shown in the grey boxes.</p>
|
||||
</div>
|
||||
|
||||
<form id="theForm" onsubmit="return false;">
|
||||
<div class="column" id="ckey">
|
||||
<!-- Password and pbkdf2 parameters -->
|
||||
<div class="box" id="ppassword">
|
||||
<h2>Password</h2>
|
||||
<div class="section">
|
||||
<label for="password">Password:</label>
|
||||
<input type="password" class="wide" name="password" id="password" autocomplete="off" tabindex="1"/>
|
||||
<p class="explanation">
|
||||
Choose a strong, random password.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="box" id="pkey">
|
||||
<h2>Key Derivation</h2>
|
||||
<div class="section">
|
||||
<div>
|
||||
<label for="salt"">Salt:</label>
|
||||
<a class="random floatright" href="javascript:randomize('salt',2,0)">random</a>
|
||||
</div>
|
||||
<input type="text" id="salt" class="wide hex" autocomplete="off" size="17" maxlength="35"/>
|
||||
<input type="checkbox" name="freshsalt" id="freshsalt" autocomplete="off" checked="checked"/>
|
||||
<label for="freshsalt">Use fresh random salt for each new password</label>
|
||||
<p class="explanation">
|
||||
Salt adds more variability to your key, and prevents attackers
|
||||
from using <a href="http://en.wikipedia.org/wiki/Rainbow_table">rainbow tables</a> to attack it.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<label for="iter">Strengthen by a factor of:</label>
|
||||
<input type="text" name="iter" id="iter" value="1000" class="numeric" size="5" maxlength="5" autocomplete="off"/>
|
||||
<p class="explanation">
|
||||
Strengthening makes it slower to compute the key corresponding to your
|
||||
password. This makes it take much longer for an attacker to guess it.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
Key size:
|
||||
<input type="radio" name="keysize" value="128" id="key128" checked="checked" autocomplete="off" onclick="extendKey(4)"/>
|
||||
<label for="key128">128</label>
|
||||
<input type="radio" name="keysize" value="192" id="key192" autocomplete="off" onclick="extendKey(6)"/>
|
||||
<label for="key192">192</label>
|
||||
<input type="radio" name="keysize" value="256" id="key256" autocomplete="off" onclick="extendKey(8)"/>
|
||||
<label for="key256">256</label>
|
||||
<p class="explanation">
|
||||
128 bits should be secure enough, but you can generate a longer
|
||||
key if you wish.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- cipher key -->
|
||||
<div class="section">
|
||||
<div>
|
||||
<label for="key">Key:</label>
|
||||
<!--
|
||||
<a class="random floatright" href="javascript:randomizeKey()">random</a>
|
||||
-->
|
||||
</div>
|
||||
<textarea id="key" name="key" class="hex" rows="2" autocomplete="off"></textarea>
|
||||
<p class="explanation">
|
||||
This key is computed from your password, salt and strengthening factor. It
|
||||
will be used internally by the cipher. Instead of using a password, you can
|
||||
enter a key here directly. If you do, it should be 32, 48 or 64 hexadecimal
|
||||
digits (128, 192 or 256 bits).
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- mode controls -->
|
||||
<div class="column" id="cmode">
|
||||
<div class="box">
|
||||
<h2>Cipher Parameters</h2>
|
||||
<p class="explanation">
|
||||
SJCL encrypts your data with the <a href="http://en.wikipedia.org/wiki/Advanced_Encryption_Standard"><acronym title="Advanced Encryption Standard">AES</acronym></a> block cipher.
|
||||
</p>
|
||||
<div class="section">
|
||||
Cipher mode:
|
||||
<input type="radio" name="mode" value="ccm" id="ccm" checked="checked" autocomplete="off"/>
|
||||
<label for="ccm"><acronym title="Counter mode with Cipher block chaining Message authentication code">CCM</acronym></label>
|
||||
<input type="radio" name="mode" value="ocb2" id="ocb2" autocomplete="off"/>
|
||||
<label for="ocb2"><acronym title="Offset CodeBook mode, version 2.0">OCB2</acronym></label>
|
||||
<p class="explanation">
|
||||
The cipher mode is a standard for how to use AES and other
|
||||
algorithms to encrypt and authenticate your message.
|
||||
<a href="http://en.wikipedia.org/wiki/OCB_mode">OCB2 mode</a>
|
||||
is slightly faster and has more features, but
|
||||
<a href="http://en.wikipedia.org/wiki/CCM_mode">CCM mode</a> has wider
|
||||
support because it is not patented.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<div>
|
||||
<label for="iv">Initialization vector:</label>
|
||||
<a class="random floatright" href="javascript:randomize('iv',4,0)">random</a>
|
||||
</div>
|
||||
<input type="text" name="iv" id="iv" class="wide hex" size="32" maxlength="35" autocomplete="off"/>
|
||||
<input type="checkbox" id="freshiv" autocomplete="off" checked="checked"/>
|
||||
<label for="freshiv">Choose a new random IV for every message.</label>
|
||||
<p class="explanation">
|
||||
The IV needs to be different for every message you send. It adds
|
||||
randomness to your message, so that the same message will look
|
||||
different each time you send it.
|
||||
</p>
|
||||
<p class="explanation">
|
||||
Be careful: CCM mode doesn't use
|
||||
the whole IV, so changing just part of it isn't enough.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
Authentication strength:
|
||||
<input type="radio" name="tag" value="64" id="tag64" autocomplete="off" checked="checked"/>
|
||||
<label for="tag64">64</label>
|
||||
<input type="radio" name="tag" value="96" id="tag96" autocomplete="off"/>
|
||||
<label for="tag96">96</label>
|
||||
<input type="radio" name="tag" value="128" id="tag128" autocomplete="off"/>
|
||||
<label for="tag128">128</label>
|
||||
<p class="explanation">
|
||||
SJCL adds a an authentication tag to your message to make sure
|
||||
nobody changes it. The longer the authentication tag, the harder it is
|
||||
for somebody to change your encrypted message without you noticing. 64
|
||||
bits is probably enough.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<input type="checkbox" name="json" id="json" autocomplete="off" checked="checked"/>
|
||||
<label for="json">Send the parameters and authenticated data along
|
||||
with the message.</label>
|
||||
<p class="explanation">
|
||||
These parameters are required to decrypt your message later. If the
|
||||
person you're sending the message to knows them, you don't need to send
|
||||
them so your message will be shorter.
|
||||
</p>
|
||||
<p class="explanation">
|
||||
Default parameters won't be sent. Your password won't be sent, either.
|
||||
The salt and iv will be encoded in base64 instead of hex, so they'll
|
||||
look different from what's in the box.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="column" id="ctexts">
|
||||
<div id="pplaintext" class="box">
|
||||
<h2>Plaintext</h2>
|
||||
<div class="section">
|
||||
<label for="plaintext">Secret message:</label>
|
||||
<textarea id="plaintext" autocomplete="off" rows="5" tabindex="2"></textarea>
|
||||
<div class="explanation">
|
||||
This message will be encrypted, so that nobody can read it or change it
|
||||
without your password.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<label for="adata">Authenticated data:</label>
|
||||
<textarea id="adata" autocomplete="off" tabindex="3"></textarea>
|
||||
<div class="explanation">
|
||||
This auxilliary message isn't secret, but its integrity will be checked
|
||||
along with the integrity of the message.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="buttons">
|
||||
<a href="javascript:doEncrypt()" id="encrypt" tabindex="4"><span class="turnDown">encrypt</span></a>
|
||||
<a href="javascript:doDecrypt()" id="decrypt" tabindex="6"><span class="turnUp">decrypt</span></a>
|
||||
</div>
|
||||
|
||||
<div id="pciphertext" class="box">
|
||||
<h2>Ciphertext</h2>
|
||||
<label for="ciphertext">Ciphertext:</label>
|
||||
<textarea id="ciphertext" autocomplete="off" rows="7" tabindex="5"></textarea>
|
||||
<div class="explanation">
|
||||
Your message, encrypted and authenticated so that nobody can read it
|
||||
or change it without your password.
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
183
src/js/sjcl/jsdoc_toolkit-2.3.3-beta/README.txt
Normal file
183
src/js/sjcl/jsdoc_toolkit-2.3.3-beta/README.txt
Normal file
@@ -0,0 +1,183 @@
|
||||
======================================================================
|
||||
|
||||
DESCRIPTION:
|
||||
|
||||
This is the source code for JsDoc Toolkit, an automatic documentation
|
||||
generation tool for JavaScript. It is written in JavaScript and is run
|
||||
from a command line (or terminal) using Java and Mozilla's Rhino
|
||||
JavaScript runtime engine.
|
||||
|
||||
Using this tool you can automatically turn JavaDoc-like comments in
|
||||
your JavaScript source code into published output files, such as HTML
|
||||
or XML.
|
||||
|
||||
For more information, to report a bug, or to browse the technical
|
||||
documentation for this tool please visit the official JsDoc Toolkit
|
||||
project homepage at http://code.google.com/p/jsdoc-toolkit/
|
||||
|
||||
For the most up-to-date documentation on JsDoc Toolkit see the
|
||||
official wiki at http://code.google.com/p/jsdoc-toolkit/w/list
|
||||
|
||||
======================================================================
|
||||
|
||||
REQUIREMENTS:
|
||||
|
||||
JsDoc Toolkit is known to work with:
|
||||
java version "1.6.0_03"
|
||||
Java(TM) SE Runtime Environment (build 1.6.0_03-b05)
|
||||
on Windows XP,
|
||||
and java version "1.5.0_19"
|
||||
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_19-b02-304)
|
||||
on Mac OS X 10.5.
|
||||
|
||||
Other versions of java may or may not work with JsDoc Toolkit.
|
||||
|
||||
======================================================================
|
||||
|
||||
USAGE:
|
||||
|
||||
Running JsDoc Toolkit requires you to have Java installed on your
|
||||
computer. For more information see http://www.java.com/getjava/
|
||||
|
||||
Before running the JsDoc Toolkit app you should change your current
|
||||
working directory to the jsdoc-toolkit folder. Then follow the
|
||||
examples below, or as shown on the project wiki.
|
||||
|
||||
On a computer running Windows a valid command line to run JsDoc
|
||||
Toolkit might look like this:
|
||||
|
||||
> java -jar jsrun.jar app\run.js -a -t=templates\jsdoc mycode.js
|
||||
|
||||
On Mac OS X or Linux the same command would look like this:
|
||||
|
||||
$ java -jar jsrun.jar app/run.js -a -t=templates/jsdoc mycode.js
|
||||
|
||||
The above assumes your current working directory contains jsrun.jar,
|
||||
the "app" and "templates" subdirectories from the standard JsDoc
|
||||
Toolkit distribution and that the relative path to the code you wish
|
||||
to document is "mycode.js".
|
||||
|
||||
The output documentation files will be saved to a new directory named
|
||||
"out" (by default) in the current directory, or if you specify a
|
||||
-d=somewhere_else option, to the somewhere_else directory.
|
||||
|
||||
For help (usage notes) enter this on the command line:
|
||||
|
||||
$ java -jar jsrun.jar app/run.js --help
|
||||
|
||||
More information about the various command line options used by JsDoc
|
||||
Toolkit are available on the project wiki.
|
||||
|
||||
======================================================================
|
||||
|
||||
RUNNING VIA SHELL SCRIPT
|
||||
|
||||
Avi Deitcher has contributed the file jsrun.sh with the following usage notes:
|
||||
|
||||
A script to simplify running jsdoc from the command-line, especially when
|
||||
running from within a development or build environment such as ant.
|
||||
|
||||
Normally, to run jsdoc, you need a command-line as the following:
|
||||
java -Djsdoc.dir=/some/long/dir/path/to/jsdoc -jar
|
||||
/some/long/dir/path/to/jsdoc/jsrun.jar /some/long/dir/path/to/jsdoc/app/run.js
|
||||
-t=template -r=4 /some/long/dir/path/to/my/src/code
|
||||
|
||||
This can get tedious to redo time and again, and difficult to use from within a build environment.
|
||||
|
||||
To simplify the process, jsrun.sh will automatically run this path, as well as passing through any arguments.
|
||||
|
||||
Usage: jsrun.sh <run.js arguments>
|
||||
|
||||
All <run.js arguments> will be passed through.
|
||||
Additionally, jsrun.sh will take the following actions:
|
||||
1) If the environment variable JSDOCDIR is set, it will add
|
||||
"-Djsdoc.dir=$JSDOCDIR" to the command-line
|
||||
2) If the environment variable JSDOCTEMPLATEDIR is set, it will add
|
||||
"-Djsdoc.template.dir=$JSDOCTEMPLATEDIR" to the command-line
|
||||
3) java with the appropriate path to jsrun.jar and run.js will be instantiated
|
||||
|
||||
If not variables are set, it is assumed that the path to jsrun.jar and app/ is in the current working directory.
|
||||
|
||||
Example:
|
||||
# jsrun.sh ./src/
|
||||
Assuming JSDOCDIR=/some/path/to/my/jsdoc will cause the following command to
|
||||
execute:
|
||||
java -Djsdoc.dir=/some/path/to/my/jsdoc -jar /some/path/to/my/jsdoc/jsrun.jar
|
||||
/some/path/to/my/jsdoc/app/run.js ./src/
|
||||
|
||||
======================================================================
|
||||
|
||||
TESTING:
|
||||
|
||||
To run the suite of unit tests included with JsDoc Toolkit enter this
|
||||
on the command line:
|
||||
|
||||
$ java -jar jsrun.jar app/run.js -T
|
||||
|
||||
To see a dump of the internal data structure that JsDoc Toolkit has
|
||||
built from your source files use this command:
|
||||
|
||||
$ java -jar jsrun.jar app/run.js mycode.js -Z
|
||||
|
||||
======================================================================
|
||||
|
||||
LICENSE:
|
||||
|
||||
JSDoc.pm
|
||||
|
||||
This project is based on the JSDoc.pm tool, created by Michael
|
||||
Mathews and Gabriel Reid. More information on JsDoc.pm can
|
||||
be found on the JSDoc.pm homepage: http://jsdoc.sourceforge.net/
|
||||
|
||||
Complete documentation on JsDoc Toolkit can be found on the project
|
||||
wiki at http://code.google.com/p/jsdoc-toolkit/w/list
|
||||
|
||||
Rhino
|
||||
|
||||
Rhino (JavaScript in Java) is open source and licensed by Mozilla
|
||||
under the MPL 1.1 or later/GPL 2.0 or later licenses, the text of
|
||||
which is available at http://www.mozilla.org/MPL/
|
||||
|
||||
You can obtain the source code for Rhino from the Mozilla web site at
|
||||
http://www.mozilla.org/rhino/download.html
|
||||
|
||||
JsDoc Toolkit is a larger work that uses the Rhino JavaScript engine
|
||||
but is not derived from it in any way. The Rhino library is used
|
||||
without modification and without any claims whatsoever.
|
||||
|
||||
The Rhino Debugger
|
||||
|
||||
You can obtain more information about the Rhino Debugger from the
|
||||
Mozilla web site at http://www.mozilla.org/rhino/debugger.html
|
||||
|
||||
JsDoc Toolkit is a larger work that uses the Rhino Debugger but
|
||||
is not derived from it in any way. The Rhino Debugger is used
|
||||
without modification and without any claims whatsoever.
|
||||
|
||||
JsDoc Toolkit
|
||||
|
||||
All code specific to JsDoc Toolkit are free, open source and licensed
|
||||
for use under the X11/MIT License.
|
||||
|
||||
JsDoc Toolkit is Copyright (c)2009 Michael Mathews <micmath@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms below.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions: The above copyright notice and this
|
||||
permission notice must be included in all copies or substantial
|
||||
portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
33
src/js/sjcl/jsdoc_toolkit-2.3.3-beta/app/frame.js
Normal file
33
src/js/sjcl/jsdoc_toolkit-2.3.3-beta/app/frame.js
Normal file
@@ -0,0 +1,33 @@
|
||||
IO.include("frame/Opt.js");
|
||||
IO.include("frame/Chain.js");
|
||||
IO.include("frame/Link.js");
|
||||
IO.include("frame/String.js");
|
||||
IO.include("frame/Hash.js");
|
||||
IO.include("frame/Namespace.js");
|
||||
//IO.include("frame/Reflection.js");
|
||||
|
||||
/** A few helper functions to make life a little easier. */
|
||||
|
||||
function defined(o) {
|
||||
return (o !== undefined);
|
||||
}
|
||||
|
||||
function copy(o) { // todo check for circular refs
|
||||
if (o == null || typeof(o) != 'object') return o;
|
||||
var c = new o.constructor();
|
||||
for(var p in o) c[p] = copy(o[p]);
|
||||
return c;
|
||||
}
|
||||
|
||||
function isUnique(arr) {
|
||||
var l = arr.length;
|
||||
for(var i = 0; i < l; i++ ) {
|
||||
if (arr.lastIndexOf(arr[i]) > i) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Returns the given string with all regex meta characters backslashed. */
|
||||
RegExp.escapeMeta = function(str) {
|
||||
return str.replace(/([$^\\\/()|?+*\[\]{}.-])/g, "\\$1");
|
||||
}
|
||||
102
src/js/sjcl/jsdoc_toolkit-2.3.3-beta/app/frame/Chain.js
Normal file
102
src/js/sjcl/jsdoc_toolkit-2.3.3-beta/app/frame/Chain.js
Normal file
@@ -0,0 +1,102 @@
|
||||
/**@constructor*/
|
||||
function ChainNode(object, link) {
|
||||
this.value = object;
|
||||
this.link = link; // describes this node's relationship to the previous node
|
||||
}
|
||||
|
||||
/**@constructor*/
|
||||
function Chain(valueLinks) {
|
||||
this.nodes = [];
|
||||
this.cursor = -1;
|
||||
|
||||
if (valueLinks && valueLinks.length > 0) {
|
||||
this.push(valueLinks[0], "//");
|
||||
for (var i = 1, l = valueLinks.length; i < l; i+=2) {
|
||||
this.push(valueLinks[i+1], valueLinks[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Chain.prototype.push = function(o, link) {
|
||||
if (this.nodes.length > 0 && link) this.nodes.push(new ChainNode(o, link));
|
||||
else this.nodes.push(new ChainNode(o));
|
||||
}
|
||||
|
||||
Chain.prototype.unshift = function(o, link) {
|
||||
if (this.nodes.length > 0 && link) this.nodes[0].link = link;
|
||||
this.nodes.unshift(new ChainNode(o));
|
||||
this.cursor++;
|
||||
}
|
||||
|
||||
Chain.prototype.get = function() {
|
||||
if (this.cursor < 0 || this.cursor > this.nodes.length-1) return null;
|
||||
return this.nodes[this.cursor];
|
||||
}
|
||||
|
||||
Chain.prototype.first = function() {
|
||||
this.cursor = 0;
|
||||
return this.get();
|
||||
}
|
||||
|
||||
Chain.prototype.last = function() {
|
||||
this.cursor = this.nodes.length-1;
|
||||
return this.get();
|
||||
}
|
||||
|
||||
Chain.prototype.next = function() {
|
||||
this.cursor++;
|
||||
return this.get();
|
||||
}
|
||||
|
||||
Chain.prototype.prev = function() {
|
||||
this.cursor--;
|
||||
return this.get();
|
||||
}
|
||||
|
||||
Chain.prototype.toString = function() {
|
||||
var string = "";
|
||||
for (var i = 0, l = this.nodes.length; i < l; i++) {
|
||||
if (this.nodes[i].link) string += " -("+this.nodes[i].link+")-> ";
|
||||
string += this.nodes[i].value.toString();
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
Chain.prototype.joinLeft = function() {
|
||||
var result = "";
|
||||
for (var i = 0, l = this.cursor; i < l; i++) {
|
||||
if (result && this.nodes[i].link) result += this.nodes[i].link;
|
||||
result += this.nodes[i].value.toString();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* USAGE:
|
||||
|
||||
var path = "one/two/three.four/five-six";
|
||||
var pathChain = new Chain(path.split(/([\/.-])/));
|
||||
print(pathChain);
|
||||
|
||||
var lineage = new Chain();
|
||||
lineage.push("Port");
|
||||
lineage.push("Les", "son");
|
||||
lineage.push("Dawn", "daughter");
|
||||
lineage.unshift("Purdie", "son");
|
||||
|
||||
print(lineage);
|
||||
|
||||
// walk left
|
||||
for (var node = lineage.last(); node !== null; node = lineage.prev()) {
|
||||
print("< "+node.value);
|
||||
}
|
||||
|
||||
// walk right
|
||||
var node = lineage.first()
|
||||
while (node !== null) {
|
||||
print(node.value);
|
||||
node = lineage.next();
|
||||
if (node && node.link) print("had a "+node.link+" named");
|
||||
}
|
||||
|
||||
*/
|
||||
144
src/js/sjcl/jsdoc_toolkit-2.3.3-beta/app/frame/Dumper.js
Normal file
144
src/js/sjcl/jsdoc_toolkit-2.3.3-beta/app/frame/Dumper.js
Normal file
@@ -0,0 +1,144 @@
|
||||
/**
|
||||
* @class
|
||||
<pre>
|
||||
This is a lightly modified version of Kevin Jones' JavaScript
|
||||
library Data.Dump. To download the original visit:
|
||||
<a href="http://openjsan.org/doc/k/ke/kevinj/Data/Dump/">http://openjsan.org/doc/k/ke/kevinj/Data/Dump/</a>
|
||||
|
||||
AUTHORS
|
||||
|
||||
The Data.Dump JavaScript module is written by Kevin Jones
|
||||
(kevinj@cpan.org), based on Data::Dump by Gisle Aas (gisle@aas.no),
|
||||
based on Data::Dumper by Gurusamy Sarathy (gsar@umich.edu).
|
||||
|
||||
COPYRIGHT
|
||||
|
||||
Copyright 2007 Kevin Jones. Copyright 1998-2000,2003-2004 Gisle Aas.
|
||||
Copyright 1996-1998 Gurusamy Sarathy.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the Perl Artistic License
|
||||
|
||||
See http://www.perl.com/perl/misc/Artistic.html
|
||||
</pre>
|
||||
* @static
|
||||
*/
|
||||
Dumper = {
|
||||
/** @param [...] The objects to dump. */
|
||||
dump: function () {
|
||||
if (arguments.length > 1)
|
||||
return this._dump(arguments);
|
||||
else if (arguments.length == 1)
|
||||
return this._dump(arguments[0]);
|
||||
else
|
||||
return "()";
|
||||
},
|
||||
|
||||
_dump: function (obj) {
|
||||
if (typeof obj == 'undefined') return 'undefined';
|
||||
var out;
|
||||
if (obj.serialize) { return obj.serialize(); }
|
||||
var type = this._typeof(obj);
|
||||
if (obj.circularReference) obj.circularReference++;
|
||||
switch (type) {
|
||||
case 'circular':
|
||||
out = "{ //circularReference\n}";
|
||||
break;
|
||||
case 'object':
|
||||
var pairs = new Array;
|
||||
|
||||
for (var prop in obj) {
|
||||
if (prop != "circularReference" && obj.hasOwnProperty(prop)) { //hide inherited properties
|
||||
pairs.push(prop + ': ' + this._dump(obj[prop]));
|
||||
}
|
||||
}
|
||||
|
||||
out = '{' + this._format_list(pairs) + '}';
|
||||
break;
|
||||
|
||||
case 'string':
|
||||
for (var prop in Dumper.ESC) {
|
||||
if (Dumper.ESC.hasOwnProperty(prop)) {
|
||||
obj = obj.replace(prop, Dumper.ESC[prop]);
|
||||
}
|
||||
}
|
||||
|
||||
// Escape UTF-8 Strings
|
||||
if (obj.match(/^[\x00-\x7f]*$/)) {
|
||||
out = '"' + obj.replace(/\"/g, "\\\"").replace(/([\n\r]+)/g, "\\$1") + '"';
|
||||
}
|
||||
else {
|
||||
out = "unescape('"+escape(obj)+"')";
|
||||
}
|
||||
break;
|
||||
|
||||
case 'array':
|
||||
var elems = new Array;
|
||||
|
||||
for (var i=0; i<obj.length; i++) {
|
||||
elems.push( this._dump(obj[i]) );
|
||||
}
|
||||
|
||||
out = '[' + this._format_list(elems) + ']';
|
||||
break;
|
||||
|
||||
case 'date':
|
||||
// firefox returns GMT strings from toUTCString()...
|
||||
var utc_string = obj.toUTCString().replace(/GMT/,'UTC');
|
||||
out = 'new Date("' + utc_string + '")';
|
||||
break;
|
||||
|
||||
case 'element':
|
||||
// DOM element
|
||||
out = this._dump_dom(obj);
|
||||
break;
|
||||
|
||||
default:
|
||||
out = obj;
|
||||
}
|
||||
|
||||
out = String(out).replace(/\n/g, '\n ');
|
||||
out = out.replace(/\n (.*)$/,"\n$1");
|
||||
|
||||
return out;
|
||||
},
|
||||
|
||||
_format_list: function (list) {
|
||||
if (!list.length) return '';
|
||||
var nl = list.toString().length > 60 ? '\n' : ' ';
|
||||
return nl + list.join(',' + nl) + nl;
|
||||
},
|
||||
|
||||
_typeof: function (obj) {
|
||||
if (obj && obj.circularReference && obj.circularReference > 1) return 'circular';
|
||||
if (Array.prototype.isPrototypeOf(obj)) return 'array';
|
||||
if (Date.prototype.isPrototypeOf(obj)) return 'date';
|
||||
if (typeof obj.nodeType != 'undefined') return 'element';
|
||||
return typeof(obj);
|
||||
},
|
||||
|
||||
_dump_dom: function (obj) {
|
||||
return '"' + Dumper.nodeTypes[obj.nodeType] + '"';
|
||||
}
|
||||
};
|
||||
|
||||
Dumper.ESC = {
|
||||
"\t": "\\t",
|
||||
"\n": "\\n",
|
||||
"\f": "\\f"
|
||||
};
|
||||
|
||||
Dumper.nodeTypes = {
|
||||
1: "ELEMENT_NODE",
|
||||
2: "ATTRIBUTE_NODE",
|
||||
3: "TEXT_NODE",
|
||||
4: "CDATA_SECTION_NODE",
|
||||
5: "ENTITY_REFERENCE_NODE",
|
||||
6: "ENTITY_NODE",
|
||||
7: "PROCESSING_INSTRUCTION_NODE",
|
||||
8: "COMMENT_NODE",
|
||||
9: "DOCUMENT_NODE",
|
||||
10: "DOCUMENT_TYPE_NODE",
|
||||
11: "DOCUMENT_FRAGMENT_NODE",
|
||||
12: "NOTATION_NODE"
|
||||
};
|
||||
84
src/js/sjcl/jsdoc_toolkit-2.3.3-beta/app/frame/Hash.js
Normal file
84
src/js/sjcl/jsdoc_toolkit-2.3.3-beta/app/frame/Hash.js
Normal file
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
@constructor
|
||||
@example
|
||||
var _index = new Hash();
|
||||
_index.set("a", "apple");
|
||||
_index.set("b", "blue");
|
||||
_index.set("c", "coffee");
|
||||
|
||||
for (var p = _index.first(); p; p = _index.next()) {
|
||||
print(p.key+" is for "+p.value);
|
||||
}
|
||||
|
||||
*/
|
||||
var Hash = function() {
|
||||
this._map = {};
|
||||
this._keys = [];
|
||||
this._vals = [];
|
||||
this.reset();
|
||||
}
|
||||
|
||||
Hash.prototype.set = function(k, v) {
|
||||
if (k != "") {
|
||||
this._keys.push(k);
|
||||
this._map["="+k] = this._vals.length;
|
||||
this._vals.push(v);
|
||||
}
|
||||
}
|
||||
|
||||
Hash.prototype.replace = function(k, k2, v) {
|
||||
if (k == k2) return;
|
||||
|
||||
var offset = this._map["="+k];
|
||||
this._keys[offset] = k2;
|
||||
if (typeof v != "undefined") this._vals[offset] = v;
|
||||
this._map["="+k2] = offset;
|
||||
delete(this._map["="+k]);
|
||||
}
|
||||
|
||||
Hash.prototype.drop = function(k) {
|
||||
if (k != "") {
|
||||
var offset = this._map["="+k];
|
||||
this._keys.splice(offset, 1);
|
||||
this._vals.splice(offset, 1);
|
||||
delete(this._map["="+k]);
|
||||
for (var p in this._map) {
|
||||
if (this._map[p] >= offset) this._map[p]--;
|
||||
}
|
||||
if (this._cursor >= offset && this._cursor > 0) this._cursor--;
|
||||
}
|
||||
}
|
||||
|
||||
Hash.prototype.get = function(k) {
|
||||
if (k != "") {
|
||||
return this._vals[this._map["="+k]];
|
||||
}
|
||||
}
|
||||
|
||||
Hash.prototype.keys = function() {
|
||||
return this._keys;
|
||||
}
|
||||
|
||||
Hash.prototype.hasKey = function(k) {
|
||||
if (k != "") {
|
||||
return (typeof this._map["="+k] != "undefined");
|
||||
}
|
||||
}
|
||||
|
||||
Hash.prototype.values = function() {
|
||||
return this._vals;
|
||||
}
|
||||
|
||||
Hash.prototype.reset = function() {
|
||||
this._cursor = 0;
|
||||
}
|
||||
|
||||
Hash.prototype.first = function() {
|
||||
this.reset();
|
||||
return this.next();
|
||||
}
|
||||
|
||||
Hash.prototype.next = function() {
|
||||
if (this._cursor++ < this._keys.length)
|
||||
return {key: this._keys[this._cursor-1], value: this._vals[this._cursor-1]};
|
||||
}
|
||||
171
src/js/sjcl/jsdoc_toolkit-2.3.3-beta/app/frame/Link.js
Normal file
171
src/js/sjcl/jsdoc_toolkit-2.3.3-beta/app/frame/Link.js
Normal file
@@ -0,0 +1,171 @@
|
||||
/** Handle the creation of HTML links to documented symbols.
|
||||
@constructor
|
||||
*/
|
||||
function Link() {
|
||||
this.alias = "";
|
||||
this.src = "";
|
||||
this.file = "";
|
||||
this.text = "";
|
||||
this.innerName = "";
|
||||
this.classLink = false;
|
||||
this.targetName = "";
|
||||
|
||||
this.target = function(targetName) {
|
||||
if (defined(targetName)) this.targetName = targetName;
|
||||
return this;
|
||||
}
|
||||
this.inner = function(inner) {
|
||||
if (defined(inner)) this.innerName = inner;
|
||||
return this;
|
||||
}
|
||||
this.withText = function(text) {
|
||||
if (defined(text)) this.text = text;
|
||||
return this;
|
||||
}
|
||||
this.toSrc = function(filename) {
|
||||
if (defined(filename)) this.src = filename;
|
||||
return this;
|
||||
}
|
||||
this.toSymbol = function(alias) {
|
||||
if (defined(alias)) this.alias = new String(alias);
|
||||
return this;
|
||||
}
|
||||
this.toClass = function(alias) {
|
||||
this.classLink = true;
|
||||
return this.toSymbol(alias);
|
||||
}
|
||||
this.toFile = function(file) {
|
||||
if (defined(file)) this.file = file;
|
||||
return this;
|
||||
}
|
||||
|
||||
this.toString = function() {
|
||||
var linkString;
|
||||
var thisLink = this;
|
||||
|
||||
if (this.alias) {
|
||||
linkString = this.alias.replace(/(^|[^a-z$0-9_#.:^-])([|a-z$0-9_#.:^-]+)($|[^a-z$0-9_#.:^-])/i,
|
||||
function(match, prematch, symbolName, postmatch) {
|
||||
var symbolNames = symbolName.split("|");
|
||||
var links = [];
|
||||
for (var i = 0, l = symbolNames.length; i < l; i++) {
|
||||
thisLink.alias = symbolNames[i];
|
||||
links.push(thisLink._makeSymbolLink(symbolNames[i]));
|
||||
}
|
||||
return prematch+links.join("|")+postmatch;
|
||||
}
|
||||
);
|
||||
}
|
||||
else if (this.src) {
|
||||
linkString = thisLink._makeSrcLink(this.src);
|
||||
}
|
||||
else if (this.file) {
|
||||
linkString = thisLink._makeFileLink(this.file);
|
||||
}
|
||||
|
||||
return linkString;
|
||||
}
|
||||
}
|
||||
|
||||
/** prefixed for hashes */
|
||||
Link.hashPrefix = "";
|
||||
|
||||
/** Appended to the front of relative link paths. */
|
||||
Link.base = "";
|
||||
|
||||
Link.symbolNameToLinkName = function(symbol) {
|
||||
var linker = "";
|
||||
if (symbol.isStatic) linker = ".";
|
||||
else if (symbol.isInner) linker = "-";
|
||||
|
||||
return Link.hashPrefix+linker+symbol.name;
|
||||
}
|
||||
|
||||
Link.getSymbol= function(alias) {
|
||||
var symbol= Link.symbolSet.getSymbol(alias);
|
||||
|
||||
if (symbol)
|
||||
return symbol;
|
||||
|
||||
if ('#'!==alias.charAt(0) || !Link.currentSymbol)
|
||||
return null;
|
||||
|
||||
// resolve relative name
|
||||
var container= Link.currentSymbol;
|
||||
|
||||
while (container)
|
||||
{
|
||||
symbol= Link.symbolSet.getSymbol(container.alias + alias);
|
||||
if (symbol)
|
||||
return symbol;
|
||||
|
||||
// No superclass
|
||||
if (!container.augments.length)
|
||||
return null;
|
||||
|
||||
container= Link.symbolSet.getSymbol(container.augments[0].desc);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Create a link to another symbol. */
|
||||
Link.prototype._makeSymbolLink = function(alias) {
|
||||
var linkBase = Link.base+publish.conf.symbolsDir;
|
||||
var linkTo = Link.getSymbol(alias);
|
||||
var linkPath;
|
||||
var target = (this.targetName)? " target=\""+this.targetName+"\"" : "";
|
||||
|
||||
// if there is no symbol by that name just return the name unaltered
|
||||
if (!linkTo)
|
||||
return this.text || alias;
|
||||
|
||||
// it's a symbol in another file
|
||||
else {
|
||||
if (!linkTo.is("CONSTRUCTOR") && !linkTo.isNamespace) { // it's a method or property
|
||||
linkPath= (Link.filemap) ? Link.filemap[linkTo.memberOf] :
|
||||
escape(linkTo.memberOf) || "_global_";
|
||||
if (linkTo.isEvent)
|
||||
linkPath += publish.conf.ext + "#event:" + Link.symbolNameToLinkName(linkTo);
|
||||
else
|
||||
linkPath += publish.conf.ext + "#" + Link.symbolNameToLinkName(linkTo);
|
||||
}
|
||||
else {
|
||||
linkPath = (Link.filemap)? Link.filemap[linkTo.alias] : escape(linkTo.alias);
|
||||
linkPath += publish.conf.ext;// + (this.classLink? "":"#" + Link.hashPrefix + "constructor");
|
||||
}
|
||||
linkPath = linkBase + linkPath
|
||||
}
|
||||
|
||||
var linkText= this.text || alias;
|
||||
|
||||
var link = {linkPath: linkPath, linkText: linkText, linkInner: (this.innerName? "#"+this.innerName : "")};
|
||||
|
||||
if (typeof JSDOC.PluginManager != "undefined") {
|
||||
JSDOC.PluginManager.run("onSymbolLink", link);
|
||||
}
|
||||
|
||||
return "<a href=\""+link.linkPath+link.linkInner+"\""+target+">"+link.linkText+"</a>";
|
||||
}
|
||||
|
||||
/** Create a link to a source file. */
|
||||
Link.prototype._makeSrcLink = function(srcFilePath) {
|
||||
var target = (this.targetName)? " target=\""+this.targetName+"\"" : "";
|
||||
|
||||
// transform filepath into a filename
|
||||
var srcFile = srcFilePath.replace(/\.\.?[\\\/]/g, "").replace(/[:\\\/]/g, "_");
|
||||
var outFilePath = Link.base + publish.conf.srcDir + srcFile + publish.conf.ext;
|
||||
|
||||
if (!this.text) this.text = FilePath.fileName(srcFilePath);
|
||||
return "<a href=\""+outFilePath+"\""+target+">"+this.text+"</a>";
|
||||
}
|
||||
|
||||
/** Create a link to a source file. */
|
||||
Link.prototype._makeFileLink = function(filePath) {
|
||||
var target = (this.targetName)? " target=\""+this.targetName+"\"" : "";
|
||||
|
||||
var outFilePath = Link.base + filePath;
|
||||
|
||||
if (!this.text) this.text = filePath;
|
||||
return "<a href=\""+outFilePath+"\""+target+">"+this.text+"</a>";
|
||||
}
|
||||
10
src/js/sjcl/jsdoc_toolkit-2.3.3-beta/app/frame/Namespace.js
Normal file
10
src/js/sjcl/jsdoc_toolkit-2.3.3-beta/app/frame/Namespace.js
Normal file
@@ -0,0 +1,10 @@
|
||||
_global_ = this;
|
||||
|
||||
function Namespace(name, f) {
|
||||
var n = name.split(".");
|
||||
for (var o = _global_, i = 0, l = n.length; i < l; i++) {
|
||||
o = o[n[i]] = o[n[i]] || {};
|
||||
}
|
||||
|
||||
if (f) f();
|
||||
}
|
||||
134
src/js/sjcl/jsdoc_toolkit-2.3.3-beta/app/frame/Opt.js
Normal file
134
src/js/sjcl/jsdoc_toolkit-2.3.3-beta/app/frame/Opt.js
Normal file
@@ -0,0 +1,134 @@
|
||||
/** @namespace */
|
||||
Opt = {
|
||||
/**
|
||||
* Get commandline option values.
|
||||
* @param {Array} args Commandline arguments. Like ["-a=xml", "-b", "--class=new", "--debug"]
|
||||
* @param {object} optNames Map short names to long names. Like {a:"accept", b:"backtrace", c:"class", d:"debug"}.
|
||||
* @return {object} Short names and values. Like {a:"xml", b:true, c:"new", d:true}
|
||||
*/
|
||||
get: function(args, optNames) {
|
||||
var opt = {"_": []}; // the unnamed option allows multiple values
|
||||
for (var i = 0; i < args.length; i++) {
|
||||
var arg = new String(args[i]);
|
||||
var name;
|
||||
var value;
|
||||
if (arg.charAt(0) == "-") {
|
||||
if (arg.charAt(1) == "-") { // it's a longname like --foo
|
||||
arg = arg.substring(2);
|
||||
var m = arg.split("=");
|
||||
name = m.shift();
|
||||
value = m.shift();
|
||||
if (typeof value == "undefined") value = true;
|
||||
|
||||
for (var n in optNames) { // convert it to a shortname
|
||||
if (name == optNames[n]) {
|
||||
name = n;
|
||||
}
|
||||
}
|
||||
}
|
||||
else { // it's a shortname like -f
|
||||
arg = arg.substring(1);
|
||||
var m = arg.split("=");
|
||||
name = m.shift();
|
||||
value = m.shift();
|
||||
if (typeof value == "undefined") value = true;
|
||||
|
||||
for (var n in optNames) { // find the matching key
|
||||
if (name == n || name+'[]' == n) {
|
||||
name = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (name.match(/(.+)\[\]$/)) { // it's an array type like n[]
|
||||
name = RegExp.$1;
|
||||
if (!opt[name]) opt[name] = [];
|
||||
}
|
||||
|
||||
if (opt[name] && opt[name].push) {
|
||||
opt[name].push(value);
|
||||
}
|
||||
else {
|
||||
opt[name] = value;
|
||||
}
|
||||
}
|
||||
else { // not associated with any optname
|
||||
opt._.push(args[i]);
|
||||
}
|
||||
}
|
||||
return opt;
|
||||
}
|
||||
}
|
||||
|
||||
/*t:
|
||||
plan(11, "Testing Opt.");
|
||||
|
||||
is(
|
||||
typeof Opt,
|
||||
"object",
|
||||
"Opt is an object."
|
||||
);
|
||||
|
||||
is(
|
||||
typeof Opt.get,
|
||||
"function",
|
||||
"Opt.get is a function."
|
||||
);
|
||||
|
||||
var optNames = {a:"accept", b:"backtrace", c:"class", d:"debug", "e[]":"exceptions"};
|
||||
var t_options = Opt.get(["-a=xml", "-b", "--class=new", "--debug", "-e=one", "-e=two", "foo", "bar"], optNames);
|
||||
|
||||
is(
|
||||
t_options.a,
|
||||
"xml",
|
||||
"an option defined with a short name can be accessed by its short name."
|
||||
);
|
||||
|
||||
is(
|
||||
t_options.b,
|
||||
true,
|
||||
"an option defined with a short name and no value are true."
|
||||
);
|
||||
|
||||
is(
|
||||
t_options.c,
|
||||
"new",
|
||||
"an option defined with a long name can be accessed by its short name."
|
||||
);
|
||||
|
||||
is(
|
||||
t_options.d,
|
||||
true,
|
||||
"an option defined with a long name and no value are true."
|
||||
);
|
||||
|
||||
is(
|
||||
typeof t_options.e,
|
||||
"object",
|
||||
"an option that can accept multiple values is defined."
|
||||
);
|
||||
|
||||
is(
|
||||
t_options.e.length,
|
||||
2,
|
||||
"an option that can accept multiple values can have more than one value."
|
||||
);
|
||||
|
||||
is(
|
||||
t_options.e[1],
|
||||
"two",
|
||||
"an option that can accept multiple values can be accessed as an array."
|
||||
);
|
||||
|
||||
is(
|
||||
typeof t_options._,
|
||||
"object",
|
||||
"the property '_' is defined for unnamed options."
|
||||
);
|
||||
|
||||
is(
|
||||
t_options._[0],
|
||||
"foo",
|
||||
"the property '_' can be accessed as an array."
|
||||
);
|
||||
*/
|
||||
26
src/js/sjcl/jsdoc_toolkit-2.3.3-beta/app/frame/Reflection.js
Normal file
26
src/js/sjcl/jsdoc_toolkit-2.3.3-beta/app/frame/Reflection.js
Normal file
@@ -0,0 +1,26 @@
|
||||
/**@constructor*/
|
||||
function Reflection(obj) {
|
||||
this.obj = obj;
|
||||
}
|
||||
|
||||
Reflection.prototype.getConstructorName = function() {
|
||||
if (this.obj.constructor.name) return this.obj.constructor.name;
|
||||
var src = this.obj.constructor.toSource();
|
||||
var name = src.substring(name.indexOf("function")+8, src.indexOf('(')).replace(/ /g,'');
|
||||
return name;
|
||||
}
|
||||
|
||||
Reflection.prototype.getMethod = function(name) {
|
||||
for (var p in this.obj) {
|
||||
if (p == name && typeof(this.obj[p]) == "function") return this.obj[p];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Reflection.prototype.getParameterNames = function() {
|
||||
var src = this.obj.toSource();
|
||||
src = src.substring(
|
||||
src.indexOf("(", 8)+1, src.indexOf(")")
|
||||
);
|
||||
return src.split(/, ?/);
|
||||
}
|
||||
93
src/js/sjcl/jsdoc_toolkit-2.3.3-beta/app/frame/String.js
Normal file
93
src/js/sjcl/jsdoc_toolkit-2.3.3-beta/app/frame/String.js
Normal file
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
@name String
|
||||
@class Additions to the core string object.
|
||||
*/
|
||||
|
||||
/** @author Steven Levithan, released as public domain. */
|
||||
String.prototype.trim = function() {
|
||||
var str = this.replace(/^\s+/, '');
|
||||
for (var i = str.length - 1; i >= 0; i--) {
|
||||
if (/\S/.test(str.charAt(i))) {
|
||||
str = str.substring(0, i + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
/*t:
|
||||
plan(6, "Testing String.prototype.trim.");
|
||||
|
||||
var s = " a bc ".trim();
|
||||
is(s, "a bc", "multiple spaces front and back are trimmed.");
|
||||
|
||||
s = "a bc\n\n".trim();
|
||||
is(s, "a bc", "newlines only in back are trimmed.");
|
||||
|
||||
s = "\ta bc".trim();
|
||||
is(s, "a bc", "tabs only in front are trimmed.");
|
||||
|
||||
s = "\n \t".trim();
|
||||
is(s, "", "an all-space string is trimmed to empty.");
|
||||
|
||||
s = "a b\nc".trim();
|
||||
is(s, "a b\nc", "a string with no spaces in front or back is trimmed to itself.");
|
||||
|
||||
s = "".trim();
|
||||
is(s, "", "an empty string is trimmed to empty.");
|
||||
|
||||
*/
|
||||
|
||||
String.prototype.balance = function(open, close) {
|
||||
var i = 0;
|
||||
while (this.charAt(i) != open) {
|
||||
if (i == this.length) return [-1, -1];
|
||||
i++;
|
||||
}
|
||||
|
||||
var j = i+1;
|
||||
var balance = 1;
|
||||
while (j < this.length) {
|
||||
if (this.charAt(j) == open) balance++;
|
||||
if (this.charAt(j) == close) balance--;
|
||||
if (balance == 0) break;
|
||||
j++;
|
||||
if (j == this.length) return [-1, -1];
|
||||
}
|
||||
|
||||
return [i, j];
|
||||
}
|
||||
/*t:
|
||||
plan(16, "Testing String.prototype.balance.");
|
||||
|
||||
var s = "{abc}".balance("{","}");
|
||||
is(s[0], 0, "opener in first is found.");
|
||||
is(s[1], 4, "closer in last is found.");
|
||||
|
||||
s = "ab{c}de".balance("{","}");
|
||||
is(s[0], 2, "opener in middle is found.");
|
||||
is(s[1], 4, "closer in middle is found.");
|
||||
|
||||
s = "a{b{c}de}f".balance("{","}");
|
||||
is(s[0], 1, "nested opener is found.");
|
||||
is(s[1], 8, "nested closer is found.");
|
||||
|
||||
s = "{}".balance("{","}");
|
||||
is(s[0], 0, "opener with no content is found.");
|
||||
is(s[1], 1, "closer with no content is found.");
|
||||
|
||||
s = "".balance("{","}");
|
||||
is(s[0], -1, "empty string opener is -1.");
|
||||
is(s[1], -1, "empty string closer is -1.");
|
||||
|
||||
s = "{abc".balance("{","}");
|
||||
is(s[0], -1, "opener with no closer returns -1.");
|
||||
is(s[1], -1, "no closer returns -1.");
|
||||
|
||||
s = "abc".balance("{","}");
|
||||
is(s[0], -1, "no opener or closer returns -1 for opener.");
|
||||
is(s[1], -1, "no opener or closer returns -1 for closer.");
|
||||
|
||||
s = "a<bc}de".balance("<","}");
|
||||
is(s[0], 1, "unmatching opener is found.");
|
||||
is(s[1], 4, "unmatching closer is found.");
|
||||
*/
|
||||
129
src/js/sjcl/jsdoc_toolkit-2.3.3-beta/app/frame/Testrun.js
Normal file
129
src/js/sjcl/jsdoc_toolkit-2.3.3-beta/app/frame/Testrun.js
Normal file
@@ -0,0 +1,129 @@
|
||||
/**
|
||||
* @fileOverview
|
||||
* @name JsTestrun
|
||||
* @author Michael Mathews micmath@gmail.com
|
||||
* @url $HeadURL: http://jsdoc-toolkit.googlecode.com/svn/trunk/jsdoc-toolkit/app/frame/Testrun.js $
|
||||
* @revision $Id: Testrun.js 418 2008-01-15 21:40:33Z micmath $
|
||||
* @license <a href="http://en.wikipedia.org/wiki/MIT_License">X11/MIT License</a>
|
||||
* (See the accompanying README file for full details.)
|
||||
*/
|
||||
|
||||
/**
|
||||
Yet another unit testing tool for JavaScript.
|
||||
@author Michael Mathews <a href="mailto:micmath@gmail.com">micmath@gmail.com</a>
|
||||
@param {object} testCases Properties are testcase names, values are functions to execute as tests.
|
||||
*/
|
||||
function testrun(testCases) {
|
||||
var ran = 0;
|
||||
for (t in testCases) {
|
||||
var result = testCases[t]();
|
||||
ran++;
|
||||
}
|
||||
|
||||
return testrun.reportOut+"-------------------------------\n"+((testrun.fails>0)? ":( Failed "+testrun.fails+"/" : ":) Passed all ")+testrun.count+" test"+((testrun.count == 1)? "":"s")+".\n";
|
||||
}
|
||||
|
||||
|
||||
testrun.count = 0;
|
||||
testrun.current = null;
|
||||
testrun.passes = 0;
|
||||
testrun.fails = 0;
|
||||
testrun.reportOut = "";
|
||||
|
||||
/** @private */
|
||||
testrun.report = function(text) {
|
||||
testrun.reportOut += text+"\n";
|
||||
}
|
||||
|
||||
/**
|
||||
Check if test evaluates to true.
|
||||
@param {string} test To be evaluated.
|
||||
@param {string} message Optional. To be displayed in the report.
|
||||
@return {boolean} True if the string test evaluates to true.
|
||||
*/
|
||||
ok = function(test, message) {
|
||||
testrun.count++;
|
||||
|
||||
var result;
|
||||
try {
|
||||
result = eval(test);
|
||||
|
||||
if (result) {
|
||||
testrun.passes++;
|
||||
testrun.report(" OK "+testrun.count+" - "+((message != null)? message : ""));
|
||||
}
|
||||
else {
|
||||
testrun.fails++;
|
||||
testrun.report("NOT OK "+testrun.count+" - "+((message != null)? message : ""));
|
||||
}
|
||||
}
|
||||
catch(e) {
|
||||
testrun.fails++
|
||||
testrun.report("NOT OK "+testrun.count+" - "+((message != null)? message : ""));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Check if test is same as expected.
|
||||
@param {string} test To be evaluated.
|
||||
@param {string} expected
|
||||
@param {string} message Optional. To be displayed in the report.
|
||||
@return {boolean} True if (test == expected). Note that the comparison is not a strict equality check.
|
||||
*/
|
||||
is = function(test, expected, message) {
|
||||
testrun.count++;
|
||||
|
||||
var result;
|
||||
try {
|
||||
result = eval(test);
|
||||
|
||||
if (result == expected) {
|
||||
testrun.passes++
|
||||
testrun.report(" OK "+testrun.count+" - "+((message != null)? message : ""));
|
||||
}
|
||||
else {
|
||||
testrun.fails++
|
||||
testrun.report("NOT OK "+testrun.count+" - "+((message != null)? message : ""));
|
||||
testrun.report("expected: "+expected);
|
||||
testrun.report(" got: "+result);
|
||||
}
|
||||
}
|
||||
catch(e) {
|
||||
testrun.fails++
|
||||
testrun.report("NOT OK "+testrun.count+" - "+((message != null)? message : ""));
|
||||
testrun.report("expected: "+expected);
|
||||
testrun.report(" got: "+result);}
|
||||
}
|
||||
|
||||
/**
|
||||
Check if test matches pattern.
|
||||
@param {string} test To be evaluated.
|
||||
@param {string} pattern Used to create a RegExp.
|
||||
@param {string} message Optional. To be displayed in the report.
|
||||
@return {boolean} True if test matches pattern.
|
||||
*/
|
||||
like = function(test, pattern, message) {
|
||||
testrun.count++;
|
||||
|
||||
var result;
|
||||
try {
|
||||
result = eval(test);
|
||||
var rgx = new RegExp(pattern);
|
||||
|
||||
if (rgx.test(result)) {
|
||||
testrun.passes++
|
||||
testrun.report(" OK "+testrun.count+" - "+((message != null)? message : ""));
|
||||
}
|
||||
else {
|
||||
testrun.fails++
|
||||
testrun.report("NOT OK "+testrun.count+" - "+((message != null)? message : ""));
|
||||
testrun.report(" this: "+result);
|
||||
testrun.report("is not like: "+pattern);
|
||||
}
|
||||
}
|
||||
catch(e) {
|
||||
testrun.fails++
|
||||
testrun.report("NOT OK "+testrun.count+" - "+((message != null)? message : ""));
|
||||
}
|
||||
}
|
||||
26
src/js/sjcl/jsdoc_toolkit-2.3.3-beta/app/handlers/FOODOC.js
Normal file
26
src/js/sjcl/jsdoc_toolkit-2.3.3-beta/app/handlers/FOODOC.js
Normal file
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
This is the main container for the FOODOC handler.
|
||||
@namespace
|
||||
*/
|
||||
FOODOC = {
|
||||
};
|
||||
|
||||
/** The current version string of this application. */
|
||||
FOODOC.VERSION = "1.0";
|
||||
|
||||
FOODOC.handle = function(srcFile, src) {
|
||||
LOG.inform("Handling file '" + srcFile + "'");
|
||||
|
||||
return [
|
||||
new JSDOC.Symbol(
|
||||
"foo",
|
||||
[],
|
||||
"VIRTUAL",
|
||||
new JSDOC.DocComment("/** This is a foo. */")
|
||||
)
|
||||
];
|
||||
};
|
||||
|
||||
FOODOC.publish = function(symbolgroup) {
|
||||
LOG.inform("Publishing symbolgroup.");
|
||||
};
|
||||
26
src/js/sjcl/jsdoc_toolkit-2.3.3-beta/app/handlers/XMLDOC.js
Executable file
26
src/js/sjcl/jsdoc_toolkit-2.3.3-beta/app/handlers/XMLDOC.js
Executable file
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* This is the main container for the XMLDOC handler.
|
||||
* @namespace
|
||||
* @author Brett Fattori (bfattori@fry.com)
|
||||
* @version $Revision: 498 $
|
||||
*/
|
||||
XMLDOC = {
|
||||
|
||||
};
|
||||
|
||||
/** The current version string of this application. */
|
||||
XMLDOC.VERSION = "1.0";
|
||||
|
||||
/** Include the library necessary to handle XML files */
|
||||
IO.includeDir("handlers/XMLDOC/");
|
||||
|
||||
/**
|
||||
* @type Symbol[]
|
||||
*/
|
||||
XMLDOC.handle = function(srcFile, src) {
|
||||
|
||||
};
|
||||
|
||||
XMLDOC.publish = function(symbolgroup) {
|
||||
|
||||
}
|
||||
159
src/js/sjcl/jsdoc_toolkit-2.3.3-beta/app/handlers/XMLDOC/DomReader.js
Executable file
159
src/js/sjcl/jsdoc_toolkit-2.3.3-beta/app/handlers/XMLDOC/DomReader.js
Executable file
@@ -0,0 +1,159 @@
|
||||
LOG.inform("XMLDOC.DomReader loaded");
|
||||
|
||||
XMLDOC.DomReader = function(root) {
|
||||
|
||||
this.dom = root;
|
||||
|
||||
/**
|
||||
* The current node the reader is on
|
||||
*/
|
||||
this.node = root;
|
||||
|
||||
/**
|
||||
* Get the current node the reader is on
|
||||
* @type XMLDOC.Parser.node
|
||||
*/
|
||||
XMLDOC.DomReader.prototype.getNode = function() {
|
||||
return this.node;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the node the reader should be positioned on.
|
||||
* @param node {XMLDOC.Parser.node}
|
||||
*/
|
||||
XMLDOC.DomReader.prototype.setNode = function(node) {
|
||||
this.node = node;
|
||||
};
|
||||
|
||||
/**
|
||||
* A helper method to make sure the current node will
|
||||
* never return null, unless null is passed as the root.
|
||||
* @param step {String} An expression to evaluate - should return a node or null
|
||||
*/
|
||||
XMLDOC.DomReader.prototype.navigate = function(step) {
|
||||
var n;
|
||||
if ((n = step) != null)
|
||||
{
|
||||
this.node = n;
|
||||
return this.node;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the root node of the current node's document.
|
||||
*/
|
||||
XMLDOC.DomReader.prototype.root = function() {
|
||||
this.navigate(this.dom);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the parent of the current node.
|
||||
*/
|
||||
XMLDOC.DomReader.prototype.parent = function() {
|
||||
return this.navigate(this.node.parentNode());
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the first child of the current node.
|
||||
*/
|
||||
XMLDOC.DomReader.prototype.firstChild = function() {
|
||||
return this.navigate(this.node.firstChild());
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the last child of the current node.
|
||||
*/
|
||||
XMLDOC.DomReader.prototype.lastChild = function() {
|
||||
return this.navigate(this.node.lastChild());
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the next sibling of the current node.
|
||||
*/
|
||||
XMLDOC.DomReader.prototype.nextSibling = function() {
|
||||
return this.navigate(this.node.nextSibling());
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the previous sibling of the current node.
|
||||
*/
|
||||
XMLDOC.DomReader.prototype.prevSibling = function() {
|
||||
return this.navigate(this.node.prevSibling());
|
||||
};
|
||||
|
||||
//===============================================================================================
|
||||
// Support methods
|
||||
|
||||
/**
|
||||
* Walk the tree starting with the current node, calling the plug-in for
|
||||
* each node visited. Each time the plug-in is called, the DomReader
|
||||
* is passed as the only parameter. Use the {@link XMLDOC.DomReader#getNode} method
|
||||
* to access the current node. <i>This method uses a depth first traversal pattern.</i>
|
||||
*
|
||||
* @param srcFile {String} The source file being evaluated
|
||||
*/
|
||||
XMLDOC.DomReader.prototype.getSymbols = function(srcFile)
|
||||
{
|
||||
XMLDOC.DomReader.symbols = [];
|
||||
XMLDOC.DomReader.currentFile = srcFile;
|
||||
JSDOC.Symbol.srcFile = (srcFile || "");
|
||||
|
||||
if (defined(JSDOC.PluginManager)) {
|
||||
JSDOC.PluginManager.run("onDomGetSymbols", this);
|
||||
}
|
||||
|
||||
return XMLDOC.DomReader.symbols;
|
||||
};
|
||||
|
||||
/**
|
||||
* Find the node with the given name using a depth first traversal.
|
||||
* Does not modify the DomReader's current node.
|
||||
*
|
||||
* @param name {String} The name of the node to find
|
||||
* @return the node that was found, or null if not found
|
||||
*/
|
||||
XMLDOC.DomReader.prototype.findNode = function(name)
|
||||
{
|
||||
var findNode = null;
|
||||
|
||||
// Start at the current node and move into the subtree,
|
||||
// looking for the node with the given name
|
||||
function deeper(node, find)
|
||||
{
|
||||
var look = null;
|
||||
|
||||
if (node) {
|
||||
if (node.name == find)
|
||||
{
|
||||
return node;
|
||||
}
|
||||
|
||||
if (node.firstChild())
|
||||
{
|
||||
look = deeper(node.firstChild(), find);
|
||||
}
|
||||
|
||||
if (!look && node.nextSibling())
|
||||
{
|
||||
look = deeper(node.nextSibling(), find);
|
||||
}
|
||||
}
|
||||
|
||||
return look;
|
||||
}
|
||||
|
||||
return deeper(this.getNode().firstChild(), name);
|
||||
};
|
||||
|
||||
/**
|
||||
* Find the next node with the given name using a depth first traversal.
|
||||
*
|
||||
* @param name {String} The name of the node to find
|
||||
*/
|
||||
XMLDOC.DomReader.prototype.findPreviousNode = function(name)
|
||||
{
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
16
src/js/sjcl/jsdoc_toolkit-2.3.3-beta/app/handlers/XMLDOC/XMLDoc.js
Executable file
16
src/js/sjcl/jsdoc_toolkit-2.3.3-beta/app/handlers/XMLDOC/XMLDoc.js
Executable file
@@ -0,0 +1,16 @@
|
||||
LOG.inform("XMLDOC.symbolize loaded");
|
||||
|
||||
/**
|
||||
* Convert the source file to a set of symbols
|
||||
*/
|
||||
XMLDOC.symbolize = function(srcFile, src) {
|
||||
|
||||
LOG.inform("Symbolizing file '" + srcFile + "'");
|
||||
|
||||
// XML files already have a defined structure, so we don't need to
|
||||
// do anything but parse them. The DOM reader can create a symbol
|
||||
// table from the parsed XML.
|
||||
var dr = new XMLDOC.DomReader(XMLDOC.Parser.parse(src));
|
||||
return dr.getSymbols(srcFile);
|
||||
|
||||
};
|
||||
292
src/js/sjcl/jsdoc_toolkit-2.3.3-beta/app/handlers/XMLDOC/XMLParse.js
Executable file
292
src/js/sjcl/jsdoc_toolkit-2.3.3-beta/app/handlers/XMLDOC/XMLParse.js
Executable file
@@ -0,0 +1,292 @@
|
||||
LOG.inform("XMLDOC.Parser loaded");
|
||||
|
||||
/**
|
||||
* XML Parser object. Returns an {@link #XMLDOC.Parser.node} which is
|
||||
* the root element of the parsed document.
|
||||
* <p/>
|
||||
* By default, this parser will only handle well formed XML. To
|
||||
* allow the parser to handle HTML, set the <tt>XMLDOC.Parser.strictMode</tt>
|
||||
* variable to <tt>false</tt> before calling <tt>XMLDOC.Parser.parse()</tt>.
|
||||
* <p/>
|
||||
* <i>Note: If you pass poorly formed XML, it will cause the parser to throw
|
||||
* an exception.</i>
|
||||
*
|
||||
* @author Brett Fattori (bfattori@fry.com)
|
||||
* @author $Author: micmath $
|
||||
* @version $Revision: 497 $
|
||||
*/
|
||||
XMLDOC.Parser = {};
|
||||
|
||||
/**
|
||||
* Strict mode setting. Setting this to false allows HTML-style source to
|
||||
* be parsed. Normally, well formed XML has defined end tags, or empty tags
|
||||
* are properly formed. Default: <tt>true</tt>
|
||||
* @type Boolean
|
||||
*/
|
||||
XMLDOC.Parser.strictMode = true;
|
||||
|
||||
/**
|
||||
* A node in an XML Document. Node types are ROOT, ELEMENT, COMMENT, PI, and TEXT.
|
||||
* @param parent {XMLDOC.Parser.node} The parent node
|
||||
* @param name {String} The node name
|
||||
* @param type {String} One of the types
|
||||
*/
|
||||
XMLDOC.Parser.node = function(parent, name, type)
|
||||
{
|
||||
this.name = name;
|
||||
this.type = type || "ELEMENT";
|
||||
this.parent = parent;
|
||||
this.charData = "";
|
||||
this.attrs = {};
|
||||
this.nodes = [];
|
||||
this.cPtr = 0;
|
||||
|
||||
XMLDOC.Parser.node.prototype.getAttributeNames = function() {
|
||||
var a = [];
|
||||
for (var o in this.attrs)
|
||||
{
|
||||
a.push(o);
|
||||
}
|
||||
|
||||
return a;
|
||||
};
|
||||
|
||||
XMLDOC.Parser.node.prototype.getAttribute = function(attr) {
|
||||
return this.attrs[attr];
|
||||
};
|
||||
|
||||
XMLDOC.Parser.node.prototype.setAttribute = function(attr, val) {
|
||||
this.attrs[attr] = val;
|
||||
};
|
||||
|
||||
XMLDOC.Parser.node.prototype.getChild = function(idx) {
|
||||
return this.nodes[idx];
|
||||
};
|
||||
|
||||
XMLDOC.Parser.node.prototype.parentNode = function() {
|
||||
return this.parent;
|
||||
};
|
||||
|
||||
XMLDOC.Parser.node.prototype.firstChild = function() {
|
||||
return this.nodes[0];
|
||||
};
|
||||
|
||||
XMLDOC.Parser.node.prototype.lastChild = function() {
|
||||
return this.nodes[this.nodes.length - 1];
|
||||
};
|
||||
|
||||
XMLDOC.Parser.node.prototype.nextSibling = function() {
|
||||
var p = this.parent;
|
||||
if (p && (p.nodes.indexOf(this) + 1 != p.nodes.length))
|
||||
{
|
||||
return p.getChild(p.nodes.indexOf(this) + 1);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
XMLDOC.Parser.node.prototype.prevSibling = function() {
|
||||
var p = this.parent;
|
||||
if (p && (p.nodes.indexOf(this) - 1 >= 0))
|
||||
{
|
||||
return p.getChild(p.nodes.indexOf(this) - 1);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse an XML Document from the specified source. The XML should be
|
||||
* well formed, unless strict mode is disabled, then the parser will
|
||||
* handle HTML-style XML documents.
|
||||
* @param src {String} The source to parse
|
||||
*/
|
||||
XMLDOC.Parser.parse = function(src)
|
||||
{
|
||||
var A = [];
|
||||
|
||||
// Normailize whitespace
|
||||
A = src.split("\r\n");
|
||||
src = A.join("\n");
|
||||
A = src.split("\r");
|
||||
src = A.join("\n");
|
||||
|
||||
// Remove XML and DOCTYPE specifier
|
||||
src.replace(/<\?XML .*\?>/i, "");
|
||||
src.replace(/<!DOCTYPE .*\>/i, "");
|
||||
|
||||
// The document is the root node and cannot be modified or removed
|
||||
var doc = new XMLDOC.Parser.node(null, "ROOT", "DOCUMENT");
|
||||
|
||||
// Let's break it down
|
||||
XMLDOC.Parser.eat(doc, src);
|
||||
|
||||
return doc;
|
||||
};
|
||||
|
||||
/**
|
||||
* The XML fragment processing routine. This method is private and should not be called
|
||||
* directly.
|
||||
* @param parentNode {XMLDOC.Parser.node} The node which is the parent of this fragment
|
||||
* @param src {String} The source within the fragment to process
|
||||
* @private
|
||||
*/
|
||||
XMLDOC.Parser.eat = function(parentNode, src)
|
||||
{
|
||||
// A simple tag def
|
||||
var reTag = new RegExp("<(!|)(\\?|--|)((.|\\s)*?)\\2>","g");
|
||||
|
||||
// Special tag types
|
||||
var reCommentTag = /<!--((.|\s)*?)-->/;
|
||||
var rePITag = /<\?((.|\s)*?)\?>/;
|
||||
|
||||
// A start tag (with potential empty marker)
|
||||
var reStartTag = /<(.*?)( +([\w_\-]*)=(\"|')(.*)\4)*(\/)?>/;
|
||||
|
||||
// An empty HTML style tag (not proper XML, but we'll accept it so we can process HTML)
|
||||
var reHTMLEmptyTag = /<(.*?)( +([\w_\-]*)=(\"|')(.*)\4)*>/;
|
||||
|
||||
// Fully enclosing tag with nested tags
|
||||
var reEnclosingTag = /<(.*?)( +([\w_\-]*)=(\"|')(.*?)\4)*>((.|\s)*?)<\/\1>/;
|
||||
|
||||
// Breaks down attributes
|
||||
var reAttributes = new RegExp(" +([\\w_\\-]*)=(\"|')(.*?)\\2","g");
|
||||
|
||||
// Find us a tag
|
||||
var tag;
|
||||
while ((tag = reTag.exec(src)) != null)
|
||||
{
|
||||
if (tag.index > 0)
|
||||
{
|
||||
// The next tag has some text before it
|
||||
var text = src.substring(0, tag.index).replace(/^[ \t\n]+((.|\n)*?)[ \t\n]+$/, "$1");
|
||||
|
||||
if (text.length > 0 && (text != "\n"))
|
||||
{
|
||||
var txtnode = new XMLDOC.Parser.node(parentNode, "", "TEXT");
|
||||
txtnode.charData = text;
|
||||
|
||||
// Append the new text node
|
||||
parentNode.nodes.push(txtnode);
|
||||
}
|
||||
|
||||
// Reset the lastIndex of reTag
|
||||
reTag.lastIndex -= src.substring(0, tag.index).length;
|
||||
|
||||
// Eat the text
|
||||
src = src.substring(tag.index);
|
||||
}
|
||||
|
||||
if (reCommentTag.test(tag[0]))
|
||||
{
|
||||
// Is this a comment?
|
||||
var comment = new XMLDOC.Parser.node(parentNode, "", "COMMENT");
|
||||
comment.charData = reCommentTag.exec(tag[0])[1];
|
||||
|
||||
// Append the comment
|
||||
parentNode.nodes.push(comment);
|
||||
|
||||
// Move the lastIndex of reTag
|
||||
reTag.lastIndex -= tag[0].length;
|
||||
|
||||
// Eat the tag
|
||||
src = src.replace(reCommentTag, "");
|
||||
}
|
||||
else if (rePITag.test(tag[0]))
|
||||
{
|
||||
// Is this a processing instruction?
|
||||
var pi = new XMLDOC.Parser.node(parentNode, "", "PI");
|
||||
pi.charData = rePITag.exec(tag[0])[1];
|
||||
|
||||
// Append the processing instruction
|
||||
parentNode.nodes.push(pi);
|
||||
|
||||
// Move the lastIndex of reTag
|
||||
reTag.lastIndex -= tag[0].length;
|
||||
|
||||
// Eat the tag
|
||||
src = src.replace(rePITag, "");
|
||||
}
|
||||
else if (reStartTag.test(tag[0]))
|
||||
{
|
||||
// Break it down
|
||||
var e = reStartTag.exec(tag[0]);
|
||||
var elem = new XMLDOC.Parser.node(parentNode, e[1], "ELEMENT");
|
||||
|
||||
// Get attributes from the tag
|
||||
var a;
|
||||
while ((a = reAttributes.exec(e[2])) != null )
|
||||
{
|
||||
elem.attrs[a[1]] = a[3];
|
||||
}
|
||||
|
||||
// Is this an empty XML-style tag?
|
||||
if (e[6] == "/")
|
||||
{
|
||||
// Append the empty element
|
||||
parentNode.nodes.push(elem);
|
||||
|
||||
// Move the lastIndex of reTag (include the start tag length)
|
||||
reTag.lastIndex -= e[0].length;
|
||||
|
||||
// Eat the tag
|
||||
src = src.replace(reStartTag, "");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check for malformed XML tags
|
||||
var htmlParsed = false;
|
||||
var htmlStartTag = reHTMLEmptyTag.exec(src);
|
||||
|
||||
// See if there isn't an end tag within this block
|
||||
var reHTMLEndTag = new RegExp("</" + htmlStartTag[1] + ">");
|
||||
var htmlEndTag = reHTMLEndTag.exec(src);
|
||||
|
||||
if (XMLDOC.Parser.strictMode && htmlEndTag == null)
|
||||
{
|
||||
// Poorly formed XML fails in strict mode
|
||||
var err = new Error("Malformed XML passed to XMLDOC.Parser... Error contains malformed 'src'");
|
||||
err.src = src;
|
||||
throw err;
|
||||
}
|
||||
else if (htmlEndTag == null)
|
||||
{
|
||||
// This is an HTML-style empty tag, store the element for it in non-strict mode
|
||||
parentNode.nodes.push(elem);
|
||||
|
||||
// Eat the tag
|
||||
src = src.replace(reHTMLEmptyTag, "");
|
||||
htmlParsed = true;
|
||||
}
|
||||
|
||||
// If we didn't parse HTML-style, it must be an enclosing tag
|
||||
if (!htmlParsed)
|
||||
{
|
||||
var enc = reEnclosingTag.exec(src);
|
||||
|
||||
// Go deeper into the document
|
||||
XMLDOC.Parser.eat(elem, enc[6]);
|
||||
|
||||
// Append the new element node
|
||||
parentNode.nodes.push(elem);
|
||||
|
||||
// Eat the tag
|
||||
src = src.replace(reEnclosingTag, "");
|
||||
}
|
||||
}
|
||||
|
||||
// Reset the lastIndex of reTag
|
||||
reTag.lastIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// No tag was found... append the text if there is any
|
||||
src = src.replace(/^[ \t\n]+((.|\n)*?)[ \t\n]+$/, "$1");
|
||||
if (src.length > 0 && (src != "\n"))
|
||||
{
|
||||
var txtNode = new XMLDOC.Parser.node(parentNode, "", "TEXT");
|
||||
txtNode.charData = src;
|
||||
|
||||
// Append the new text node
|
||||
parentNode.nodes.push(txtNode);
|
||||
}
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user