CyberChef/src/core/vendor/gost/gostSign.mjs

2024 lines
59 KiB
JavaScript
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @file GOST 34.10-2012 signature function with 1024/512 bits digest
* @version 1.76
* @copyright 2014-2016, Rudolf Nickolaev. All rights reserved.
*/
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Used library JSBN http://www-cs-students.stanford.edu/~tjw/jsbn/
* Copyright (c) 2003-2005 Tom Wu (tjw@cs.Stanford.EDU)
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE 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.
*
*/
import GostRandom from './gostRandom.mjs';
import GostDigest from './gostDigest.mjs';
import crypto from 'crypto';
/*
* Predefined curves and params collection
*
* http://tools.ietf.org/html/rfc5832
* http://tools.ietf.org/html/rfc7091
* http://tools.ietf.org/html/rfc4357
*
*/ // <editor-fold defaultstate="collapsed">
var root = {};
var rootCrypto = crypto;
var CryptoOperationData = ArrayBuffer;
var OperationError = Error,
DataError = Error,
NotSupportedError = Error;
// Predefined named curve collection
var ECGostParams = {
'S-256-TEST': {
a: 7,
b: '0x5FBFF498AA938CE739B8E022FBAFEF40563F6E6A3472FC2A514C0CE9DAE23B7E',
p: '0x8000000000000000000000000000000000000000000000000000000000000431',
q: '0x8000000000000000000000000000000150FE8A1892976154C59CFC193ACCF5B3',
x: 2,
y: '0x8E2A8A0E65147D4BD6316030E16D19C85C97F0A9CA267122B96ABBCEA7E8FC8'
},
'S-256-A': {
a: '0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD94',
b: 166,
p: '0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD97',
q: '0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C611070995AD10045841B09B761B893',
x: 1,
y: '0x8D91E471E0989CDA27DF505A453F2B7635294F2DDF23E3B122ACC99C9E9F1E14'
},
'S-256-B': {
a: '0x8000000000000000000000000000000000000000000000000000000000000C96',
b: '0x3E1AF419A269A5F866A7D3C25C3DF80AE979259373FF2B182F49D4CE7E1BBC8B',
p: '0x8000000000000000000000000000000000000000000000000000000000000C99',
q: '0x800000000000000000000000000000015F700CFFF1A624E5E497161BCC8A198F',
x: 1,
y: '0x3FA8124359F96680B83D1C3EB2C070E5C545C9858D03ECFB744BF8D717717EFC'
},
'S-256-C': {
a: '0x9B9F605F5A858107AB1EC85E6B41C8AACF846E86789051D37998F7B9022D7598',
b: 32858,
p: '0x9B9F605F5A858107AB1EC85E6B41C8AACF846E86789051D37998F7B9022D759B',
q: '0x9B9F605F5A858107AB1EC85E6B41C8AA582CA3511EDDFB74F02F3A6598980BB9',
x: 0,
y: '0x41ECE55743711A8C3CBF3783CD08C0EE4D4DC440D4641A8F366E550DFDB3BB67'
},
'P-256': {
p: '0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF',
a: '0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC',
b: '0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B',
x: '0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296',
y: '0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5',
q: '0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551'
},
'T-512-TEST': {
a: 7,
b: '0x1CFF0806A31116DA29D8CFA54E57EB748BC5F377E49400FDD788B649ECA1AC4361834013B2AD7322480A89CA58E0CF74BC9E540C2ADD6897FAD0A3084F302ADC',
p: '0x4531ACD1FE0023C7550D267B6B2FEE80922B14B2FFB90F04D4EB7C09B5D2D15DF1D852741AF4704A0458047E80E4546D35B8336FAC224DD81664BBF528BE6373',
q: '0x4531ACD1FE0023C7550D267B6B2FEE80922B14B2FFB90F04D4EB7C09B5D2D15DA82F2D7ECB1DBAC719905C5EECC423F1D86E25EDBE23C595D644AAF187E6E6DF',
x: '0x24D19CC64572EE30F396BF6EBBFD7A6C5213B3B3D7057CC825F91093A68CD762FD60611262CD838DC6B60AA7EEE804E28BC849977FAC33B4B530F1B120248A9A',
y: '0x2BB312A43BD2CE6E0D020613C857ACDDCFBF061E91E5F2C3F32447C259F39B2C83AB156D77F1496BF7EB3351E1EE4E43DC1A18B91B24640B6DBB92CB1ADD371E'
},
'T-512-A': {
p: '0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC7',
a: '0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC4',
b: '0xE8C2505DEDFC86DDC1BD0B2B6667F1DA34B82574761CB0E879BD081CFD0B6265EE3CB090F30D27614CB4574010DA90DD862EF9D4EBEE4761503190785A71C760',
q: '0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF27E69532F48D89116FF22B8D4E0560609B4B38ABFAD2B85DCACDB1411F10B275',
x: 3,
y: '0x7503CFE87A836AE3A61B8816E25450E6CE5E1C93ACF1ABC1778064FDCBEFA921DF1626BE4FD036E93D75E6A50E3A41E98028FE5FC235F5B889A589CB5215F2A4'
},
'T-512-B': {
p: '0x8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006F',
a: '0x8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006C',
b: '0x687D1B459DC841457E3E06CF6F5E2517B97C7D614AF138BCBF85DC806C4B289F3E965D2DB1416D217F8B276FAD1AB69C50F78BEE1FA3106EFB8CCBC7C5140116',
q: '0x800000000000000000000000000000000000000000000000000000000000000149A1EC142565A545ACFDB77BD9D40CFA8B996712101BEA0EC6346C54374F25BD',
x: 2,
y: '0x1A8F7EDA389B094C2C071E3647A8940F3C123B697578C213BE6DD9E6C8EC7335DCB228FD1EDF4A39152CBCAAF8C0398828041055F94CEEEC7E21340780FE41BD'
}
};
ECGostParams['X-256-A'] = ECGostParams['S-256-A'];
ECGostParams['X-256-B'] = ECGostParams['S-256-C'];
ECGostParams['T-256-TEST'] = ECGostParams['S-256-TEST'];
ECGostParams['T-256-A'] = ECGostParams['S-256-A'];
ECGostParams['T-256-B'] = ECGostParams['S-256-B'];
ECGostParams['T-256-C'] = ECGostParams['S-256-C'];
var GostParams = {
'S-TEST': {
modulusLength: 512, // bit length of p (512 or 1024 bits)
p: '0xEE8172AE8996608FB69359B89EB82A69854510E2977A4D63BC97322CE5DC3386EA0A12B343E9190F23177539845839786BB0C345D165976EF2195EC9B1C379E3',
q: '0x98915E7EC8265EDFCDA31E88F24809DDB064BDC7285DD50D7289F0AC6F49DD2D',
a: '0x9e96031500c8774a869582d4afde2127afad2538b4b6270a6f7c8837b50d50f206755984a49e509304d648be2ab5aab18ebe2cd46ac3d8495b142aa6ce23e21c'
},
'S-A': {
modulusLength: 1024,
p: '0xB4E25EFB018E3C8B87505E2A67553C5EDC56C2914B7E4F89D23F03F03377E70A2903489DD60E78418D3D851EDB5317C4871E40B04228C3B7902963C4B7D85D52B9AA88F2AFDBEB28DA8869D6DF846A1D98924E925561BD69300B9DDD05D247B5922D967CBB02671881C57D10E5EF72D3E6DAD4223DC82AA1F7D0294651A480DF',
q: '0x972432A437178B30BD96195B773789AB2FFF15594B176DD175B63256EE5AF2CF',
a: '0x8FD36731237654BBE41F5F1F8453E71CA414FFC22C25D915309E5D2E62A2A26C7111F3FC79568DAFA028042FE1A52A0489805C0DE9A1A469C844C7CABBEE625C3078888C1D85EEA883F1AD5BC4E6776E8E1A0750912DF64F79956499F1E182475B0B60E2632ADCD8CF94E9C54FD1F3B109D81F00BF2AB8CB862ADF7D40B9369A'
},
'S-B': {
modulusLength: 1024,
p: '0xC6971FC57524B30C9018C5E621DE15499736854F56A6F8AEE65A7A404632B1BCF0349FFCAFCB0A103177971FC1612ADCDB8C8CC938C70225C8FD12AFF01B1D064E0AD6FDE6AB9159166CB9F2FC171D92F0CC7B6A6B2CD7FA342ACBE2C9315A42D576B1ECCE77A963157F3D0BD96A8EB0B0F3502AD238101B05116334F1E5B7AB',
q: '0xB09D634C10899CD7D4C3A7657403E05810B07C61A688BAB2C37F475E308B0607',
a: '0x3D26B467D94A3FFC9D71BF8DB8934084137264F3C2E9EB16DCA214B8BC7C872485336744934FD2EF5943F9ED0B745B90AA3EC8D70CDC91682478B664A2E1F8FB56CEF2972FEE7EDB084AF746419B854FAD02CC3E3646FF2E1A18DD4BEB3C44F7F2745588029649674546CC9187C207FB8F2CECE8E2293F68395C4704AF04BAB5'
},
'S-C': {
modulusLength: 1024,
p: '0x9D88E6D7FE3313BD2E745C7CDD2AB9EE4AF3C8899E847DE74A33783EA68BC30588BA1F738C6AAF8AB350531F1854C3837CC3C860FFD7E2E106C3F63B3D8A4C034CE73942A6C3D585B599CF695ED7A3C4A93B2B947B7157BB1A1C043AB41EC8566C6145E938A611906DE0D32E562494569D7E999A0DDA5C879BDD91FE124DF1E9',
q: '0xFADD197ABD19A1B4653EECF7ECA4D6A22B1F7F893B641F901641FBB555354FAF',
a: '0x7447ED7156310599070B12609947A5C8C8A8625CF1CF252B407B331F93D639DDD1BA392656DECA992DD035354329A1E95A6E32D6F47882D960B8F10ACAFF796D13CD9611F853DAB6D2623483E46788708493937A1A29442598AEC2E0742022563440FE9C18740ECE6765AC05FAF024A64B026E7E408840819E962E7E5F401AE3'
},
'S-D': {
modulusLength: 1024,
p: '0x80F102D32B0FD167D069C27A307ADAD2C466091904DBAA55D5B8CC7026F2F7A1919B890CB652C40E054E1E9306735B43D7B279EDDF9102001CD9E1A831FE8A163EED89AB07CF2ABE8242AC9DEDDDBF98D62CDDD1EA4F5F15D3A42A6677BDD293B24260C0F27C0F1D15948614D567B66FA902BAA11A69AE3BCEADBB83E399C9B5',
q: '0xF0F544C418AAC234F683F033511B65C21651A6078BDA2D69BB9F732867502149',
a: '0x6BCC0B4FADB3889C1E06ADD23CC09B8AB6ECDEDF73F04632595EE4250005D6AF5F5ADE44CB1E26E6263C672347CFA26F9E9393681E6B759733784CDE5DBD9A14A39369DFD99FA85CC0D10241C4010343F34A91393A706CF12677CBFA1F578D6B6CFBE8A1242CFCC94B3B653A476E145E3862C18CC3FED8257CFEF74CDB205BF1'
},
'X-A': {
modulusLength: 1024,
p: '0xCA3B3F2EEE9FD46317D49595A9E7518E6C63D8F4EB4D22D10D28AF0B8839F079F8289E603B03530784B9BB5A1E76859E4850C670C7B71C0DF84CA3E0D6C177FE9F78A9D8433230A883CD82A2B2B5C7A3306980278570CDB79BF01074A69C9623348824B0C53791D53C6A78CAB69E1CFB28368611A397F50F541E16DB348DBE5F',
q: '0xCAE4D85F80C147704B0CA48E85FB00A9057AA4ACC44668E17F1996D7152690D9',
a: '0xBE27D652F2F1E339DA734211B85B06AE4DE236AA8FBEEB3F1ADCC52CD43853777E834A6A518138678A8ADBD3A55C70A7EAB1BA7A0719548677AAF4E609FFB47F6B9D7E45B0D06D83D7ADC53310ABD85783E7317F7EC73268B6A9C08D260B85D8485696CA39C17B17F044D1E050489036ABD381C5E6BF82BA352A1AFF136601AF'
},
'X-B': {
modulusLength: 1024,
p: '0x9286DBDA91ECCFC3060AA5598318E2A639F5BA90A4CA656157B2673FB191CD0589EE05F4CEF1BD13508408271458C30851CE7A4EF534742BFB11F4743C8F787B11193BA304C0E6BCA25701BF88AF1CB9B8FD4711D89F88E32B37D95316541BF1E5DBB4989B3DF13659B88C0F97A3C1087B9F2D5317D557DCD4AFC6D0A754E279',
q: '0xC966E9B3B8B7CDD82FF0F83AF87036C38F42238EC50A876CD390E43D67B6013F',
a: '0x7E9C3096676F51E3B2F9884CF0AC2156779496F410E049CED7E53D8B7B5B366B1A6008E5196605A55E89C3190DABF80B9F1163C979FCD18328DAE5E9048811B370107BB7715F82091BB9DE0E33EE2FED6255474F8769FCE5EAFAEEF1CB5A32E0D5C6C2F0FC0B3447072947F5B4C387666993A333FC06568E534AD56D2338D729'
},
'X-C': {
modulusLength: 1024,
p: '0xB194036ACE14139D36D64295AE6C50FC4B7D65D8B340711366CA93F383653908EE637BE428051D86612670AD7B402C09B820FA77D9DA29C8111A8496DA6C261A53ED252E4D8A69A20376E6ADDB3BDCD331749A491A184B8FDA6D84C31CF05F9119B5ED35246EA4562D85928BA1136A8D0E5A7E5C764BA8902029A1336C631A1D',
q: '0x96120477DF0F3896628E6F4A88D83C93204C210FF262BCCB7DAE450355125259',
a: '0x3F1817052BAA7598FE3E4F4FC5C5F616E122CFF9EBD89EF81DC7CE8BF56CC64B43586C80F1C4F56DD5718FDD76300BE336784259CA25AADE5A483F64C02A20CF4A10F9C189C433DEFE31D263E6C9764660A731ECCAECB74C8279303731E8CF69205BC73E5A70BDF93E5BB681DAB4EEB9C733CAAB2F673C475E0ECA921D29782E'
}
}; // </editor-fold>
/*
* BigInteger arithmetic tools
* optimized release of http://www-cs-students.stanford.edu/~tjw/jsbn/jsbn.js
*
*/ // <editor-fold defaultstate="collapsed">
// Bits per one element
var DB = 28, DM = (1 << DB) - 1, DV = 1 << DB,
FV = Math.pow(2, 52), F1 = 52 - DB, F2 = 2 * DB - 52;
function am(y, i, x, w, j, c, n) {
var xl = x & 0x3fff, xh = x >> 14;
while (--n >= 0) {
var l = y[i] & 0x3fff;
var h = y[i++] >> 14;
var m = xh * l + h * xl;
l = xl * l + ((m & 0x3fff) << 14) + w[j] + c;
c = (l >> 28) + (m >> 14) + xh * h;
w[j++] = l & 0xfffffff;
}
return c;
}
function nbi(words) {
var r = new Array(Math.ceil(words));
r.s = 0;
r.t = 0;
return r;
}
function copyTo(x, r) {
for (var i = x.t - 1; i >= 0; --i)
r[i] = x[i];
r.t = x.t;
r.s = x.s;
return r;
}
function copy(x) {
return copyTo(x, nbi(x.t));
}
function setInt(x, i) {
x.t = 1;
x.s = (i < 0) ? -1 : 0;
if (i > 0)
x[0] = i;
else if (i < -1)
x[0] = i + DV;
else
x.t = 0;
return x;
}
function nbv(i) {
var r = nbi(1);
setInt(r, i);
return r;
}
var ZERO = nbv(0), ONE = nbv(1), THREE = nbv(3);
function clamp(x) {
var c = x.s & DM;
while (x.t > 0 && x[x.t - 1] === c)
--x.t;
return x;
}
function subTo(x, a, r) {
var i = 0, c = 0, m = Math.min(a.t, x.t);
while (i < m) {
c += x[i] - a[i];
r[i++] = c & DM;
c >>= DB;
}
if (a.t < x.t) {
c -= a.s;
while (i < x.t) {
c += x[i];
r[i++] = c & DM;
c >>= DB;
}
c += x.s;
}
else {
c += x.s;
while (i < a.t) {
c -= a[i];
r[i++] = c & DM;
c >>= DB;
}
c -= a.s;
}
r.s = (c < 0) ? -1 : 0;
if (c < -1)
r[i++] = DV + c;
else if (c > 0)
r[i++] = c;
r.t = i;
return clamp(r);
}
function sub(x, y) {
return subTo(x, y, nbi(x.t));
}
function addTo(x, a, r) {
var i = 0, c = 0, m = Math.min(a.t, x.t);
while (i < m) {
c += x[i] + a[i];
r[i++] = c & DM;
c >>= DB;
}
if (a.t < x.t) {
c += a.s;
while (i < x.t) {
c += x[i];
r[i++] = c & DM;
c >>= DB;
}
c += x.s;
}
else {
c += x.s;
while (i < a.t) {
c += a[i];
r[i++] = c & DM;
c = c >> DB;
}
c += a.s;
}
r.s = (c < 0) ? -1 : 0;
if (c > 0)
r[i++] = c;
else if (c < -1)
r[i++] = DV + c;
r.t = i;
return clamp(r);
}
function add(x, y) {
return addTo(x, y, nbi(x.t));
}
function negTo(x, r) {
return subTo(ZERO, x, r);
}
function neg(x) {
return negTo(x, nbi(x.t));
}
function absTo(x, r) {
return (x.s < 0) ? negTo(r) : copyTo(r);
}
function abs(x) {
return (x.s < 0) ? neg(x) : x;
}
function compare(x, a) {
var r = x.s - a.s;
if (r !== 0)
return r;
var i = x.t;
r = i - a.t;
if (r !== 0)
return (x.s < 0) ? -r : r;
while (--i >= 0)
if ((r = x[i] - a[i]) !== 0)
return r;
return 0;
}
function equals(x, y) {
return(compare(x, y) === 0);
}
function min(x, y) {
return(compare(x, y) < 0) ? x : y;
}
function max(x, y) {
return(compare(x, y) > 0) ? x : y;
}
function nbits(x) {
var r = 1, t;
if ((t = x >>> 16) !== 0) {
x = t;
r += 16;
}
if ((t = x >> 8) !== 0) {
x = t;
r += 8;
}
if ((t = x >> 4) !== 0) {
x = t;
r += 4;
}
if ((t = x >> 2) !== 0) {
x = t;
r += 2;
}
if ((t = x >> 1) !== 0) {
x = t;
r += 1;
}
return r;
}
function dshlTo(x, n, r) {
var i;
for (i = x.t - 1; i >= 0; --i)
r[i + n] = x[i];
for (i = n - 1; i >= 0; --i)
r[i] = 0;
r.t = x.t + n;
r.s = x.s;
return r;
}
function dshrTo(x, n, r) {
for (var i = n; i < x.t; ++i)
r[i - n] = x[i];
r.t = Math.max(x.t - n, 0);
r.s = x.s;
return r;
}
function shlTo(x, n, r) {
var bs = n % DB;
var cbs = DB - bs;
var bm = (1 << cbs) - 1;
var ds = Math.floor(n / DB), c = (x.s << bs) & DM, i;
for (i = x.t - 1; i >= 0; --i) {
r[i + ds + 1] = (x[i] >> cbs) | c;
c = (x[i] & bm) << bs;
}
for (i = ds - 1; i >= 0; --i)
r[i] = 0;
r[ds] = c;
r.t = x.t + ds + 1;
r.s = x.s;
return clamp(r);
}
function shrTo(x, n, r) {
r.s = x.s;
var ds = Math.floor(n / DB);
if (ds >= x.t) {
r.t = 0;
return;
}
var bs = n % DB;
var cbs = DB - bs;
var bm = (1 << bs) - 1;
r[0] = x[ds] >> bs;
for (var i = ds + 1; i < x.t; ++i) {
r[i - ds - 1] |= (x[i] & bm) << cbs;
r[i - ds] = x[i] >> bs;
}
if (bs > 0)
r[x.t - ds - 1] |= (x.s & bm) << cbs;
r.t = x.t - ds;
return clamp(r);
}
function shl(x, n) {
var r = nbi(x.t);
if (n < 0)
shrTo(x, -n, r);
else
shlTo(x, n, r);
return r;
}
function shr(x, n) {
var r = nbi(x.t);
if (n < 0)
shlTo(x, -n, r);
else
shrTo(x, n, r);
return r;
}
function bitLength(x) {
if (x.t <= 0)
return 0;
return DB * (x.t - 1) + nbits(x[x.t - 1] ^ (x.s & DM));
}
function mulTo(b, a, r) {
var x = abs(b), y = abs(a);
var i = x.t;
r.t = i + y.t;
while (--i >= 0)
r[i] = 0;
for (i = 0; i < y.t; ++i)
r[i + x.t] = am(x, 0, y[i], r, i, 0, x.t);
r.s = 0;
if (b.s !== a.s)
subTo(ZERO, r, r);
return clamp(r);
}
function mul(x, y) {
return mulTo(x, y, nbi(x.t + y.t));
}
function sqrTo(a, r) {
var x = abs(a);
var i = r.t = 2 * x.t;
while (--i >= 0)
r[i] = 0;
for (i = 0; i < x.t - 1; ++i) {
var c = am(x, i, x[i], r, 2 * i, 0, 1);
if ((r[i + x.t] += am(x, i + 1, 2 * x[i], r, 2 * i + 1, c, x.t - i - 1)) >= x.DV) {
r[i + x.t] -= x.DV;
r[i + x.t + 1] = 1;
}
}
if (r.t > 0)
r[r.t - 1] += am(x, i, x[i], r, 2 * i, 0, 1);
r.s = 0;
return clamp(r);
}
function sqr(a) {
return sqrTo(a, nbi(a.t * 2));
}
function divRemTo(n, m, q, r) {
var pm = abs(m);
if (pm.t <= 0)
throw new OperationError('Division by zero');
var pt = abs(n);
if (pt.t < pm.t) {
if (q)
setInt(q, 0);
if (r)
copyTo(n, r);
return q;
}
if (!r)
r = nbi(m.t);
var y = nbi(m.t), ts = n.s, ms = m.s;
var nsh = DB - nbits(pm[pm.t - 1]);
if (nsh > 0) {
shlTo(pm, nsh, y);
shlTo(pt, nsh, r);
}
else {
copyTo(pm, y);
copyTo(pt, r);
}
var ys = y.t;
var y0 = y[ys - 1];
if (y0 === 0)
return q;
var yt = y0 * (1 << F1) + ((ys > 1) ? y[ys - 2] >> F2 : 0);
var d1 = FV / yt, d2 = (1 << F1) / yt, e = 1 << F2;
var i = r.t, j = i - ys, t = !q ? nbi(Math.max(n.t - m.t, 1)) : q;
dshlTo(y, j, t);
if (compare(r, t) >= 0) {
r[r.t++] = 1;
subTo(r, t, r);
}
dshlTo(ONE, ys, t);
subTo(t, y, y);
while (y.t < ys)
y[y.t++] = 0;
while (--j >= 0) {
var qd = (r[--i] === y0) ? DM : Math.floor(r[i] * d1 + (r[i - 1] + e) * d2);
if ((r[i] += am(y, 0, qd, r, j, 0, ys)) < qd) {
dshlTo(y, j, t);
subTo(r, t, r);
while (r[i] < --qd)
subTo(r, t, r);
}
}
if (q) {
dshrTo(r, ys, q);
if (ts !== ms)
subTo(ZERO, q, q);
}
r.t = ys;
clamp(r);
if (nsh > 0)
shrTo(r, nsh, r);
if (ts < 0)
subTo(ZERO, r, r);
return q;
}
function modTo(b, a, r) {
divRemTo(abs(b), a, null, r);
if (b.s < 0 && compare(r, ZERO) > 0)
subTo(a, r, r);
return r;
}
function mod(b, a) {
return modTo(b, a, nbi(a.t));
}
function div(b, a) {
return divRemTo(b, a, nbi(Math.max(b.t - a.t, 1)), null);
}
function isEven(x) {
return ((x.t > 0) ? (x[0] & 1) : x.s) === 0;
}
function isZero(x) {
return equals(x, ZERO);
}
function sig(x) {
if (x.s < 0)
return -1;
else if (x.t <= 0 || (x.t === 1 && x[0] <= 0))
return 0;
else
return 1;
}
function invMod(x, m) {
var ac = isEven(m);
if ((isEven(x) && ac) || sig(m) === 0)
return ZERO;
var u = copy(m), v = copy(x);
var a = nbv(1), b = nbv(0), c = nbv(0), d = nbv(1);
while (sig(u) !== 0) {
while (isEven(u)) {
shrTo(u, 1, u);
if (ac) {
if (!isEven(a) || !isEven(b)) {
addTo(a, x, a);
subTo(b, m, b);
}
shrTo(a, 1, a);
}
else if (!isEven(b))
subTo(b, m, b);
shrTo(b, 1, b);
}
while (isEven(v)) {
shrTo(v, 1, v);
if (ac) {
if (!isEven(c) || !isEven(d)) {
addTo(c, x, c);
subTo(d, m, d);
}
shrTo(c, 1, c);
}
else if (!isEven(d))
subTo(d, m, d);
shrTo(d, 1, d);
}
if (compare(u, v) >= 0) {
subTo(u, v, u);
if (ac)
subTo(a, c, a);
subTo(b, d, b);
}
else {
subTo(v, u, v);
if (ac)
subTo(c, a, c);
subTo(d, b, d);
}
}
if (compare(v, ONE) !== 0)
return ZERO;
if (compare(d, m) >= 0)
return subtract(d, m);
if (sig(d) < 0)
addTo(d, m, d);
else
return d;
if (sig(d) < 0)
return add(d, m);
else
return d;
}
function testBit(x, n) {
var j = Math.floor(n / DB);
if (j >= x.t)
return (x.s !== 0);
return ((x[j] & (1 << (n % DB))) !== 0);
}
function nothing(x) {
return x;
}
function extend(c, o) {
for (var i in o)
c.prototype[i] = o[i];
} // </editor-fold>
/*
* Classic, Barret, Mongomery reductions, optimized ExpMod algorithms
* optimized release of http://www-cs-students.stanford.edu/~tjw/jsbn/jsbn2.js
*
*/ // <editor-fold defaultstate="collapsed">
// Classic reduction
var Classic = function (m) {
this.m = m;
};
extend(Classic, {
convert: function (x) {
if (x.s < 0 || compare(x, this.m) >= 0)
return mod(x, this.m);
else
return x;
},
revert: nothing,
reduce: function (x) {
modTo(x, this.m, x);
},
sqrTo: function (x, r) {
sqrTo(x, r);
this.reduce(r);
},
mulTo: function (x, y, r) {
mulTo(x, y, r);
this.reduce(r);
}
});
function invDig(a) {
if (a.t < 1)
return 0;
var x = a[0];
if ((x & 1) === 0)
return 0;
var y = x & 3;
y = (y * (2 - (x & 0xf) * y)) & 0xf;
y = (y * (2 - (x & 0xff) * y)) & 0xff;
y = (y * (2 - (((x & 0xffff) * y) & 0xffff))) & 0xffff;
y = (y * (2 - x * y % DV)) % DV;
return (y > 0) ? DV - y : -y;
}
// Montgomery reduction
var Montgomery = function (m) {
this.m = m;
this.mp = invDig(m);
this.mpl = this.mp & 0x7fff;
this.mph = this.mp >> 15;
this.um = (1 << (DB - 15)) - 1;
this.mt2 = 2 * m.t;
};
extend(Montgomery, {
// xR mod m
convert: function (x) {
var r = nbi(x.t);
dshlTo(abs(x), this.m.t, r);
divRemTo(r, this.m, null, r);
if (x.s < 0 && compare(r, ZERO) > 0)
subTo(this.m, r, r);
return r;
},
// x/R mod m
revert: function (x) {
var r = nbi(x.t);
copyTo(x, r);
this.reduce(r);
return r;
},
// x = x/R mod m (HAC 14.32)
reduce: function (x) {
while (x.t <= this.mt2)
x[x.t++] = 0;
for (var i = 0; i < this.m.t; ++i) {
var j = x[i] & 0x7fff;
var u0 = (j * this.mpl + (((j * this.mph + (x[i] >> 15) * this.mpl) & this.um) << 15)) & DM;
j = i + this.m.t;
x[j] += am(this.m, 0, u0, x, i, 0, this.m.t);
while (x[j] >= DV) {
x[j] -= DV;
x[++j]++;
}
}
clamp(x);
dshrTo(x, this.m.t, x);
if (compare(x, this.m) >= 0)
subTo(x, this.m, x);
},
// r = "x^2/R mod m"; x != r
sqrTo: function (x, r) {
sqrTo(x, r);
this.reduce(r);
},
// r = "xy/R mod m"; x,y != r
mulTo: function (x, y, r) {
mulTo(x, y, r);
this.reduce(r);
}
});
function dAddOffset(x, n, w) {
if (n === 0)
return;
while (x.t <= w)
x[x.t++] = 0;
x[w] += n;
while (x[w] >= DV) {
x[w] -= DV;
if (++w >= x.t)
x[x.t++] = 0;
++x[w];
}
}
function mulLowerTo(x, a, n, r) {
var i = Math.min(x.t + a.t, n);
r.s = 0; // assumes a,x >= 0
r.t = i;
while (i > 0)
r[--i] = 0;
var j;
for (j = r.t - x.t; i < j; ++i)
r[i + x.t] = am(x, 0, a[i], r, i, 0, x.t);
for (j = Math.min(a.t, n); i < j; ++i)
am(x, 0, a[i], r, i, 0, n - i);
return clamp(r);
}
function mulUpperTo(x, a, n, r) {
--n;
var i = r.t = x.t + a.t - n;
r.s = 0; // assumes a,x >= 0
while (--i >= 0)
r[i] = 0;
for (i = Math.max(n - x.t, 0); i < a.t; ++i)
r[x.t + i - n] = am(x, n - i, a[i], r, 0, 0, x.t + i - n);
clamp(r);
return dshrTo(r, 1, r);
}
// Barrett modular reduction
function Barrett(m) {
// setup Barrett
this.r2 = nbi(2 * m.t);
this.q3 = nbi(2 * m.t);
dshlTo(ONE, 2 * m.t, this.r2);
this.mu = div(this.r2, m);
this.m = m;
}
extend(Barrett, {
convert: function (x) {
if (x.s < 0 || x.t > 2 * this.m.t)
return mod(x, this.m);
else if (compare(x, this.m) < 0)
return x;
else {
var r = nbi(x.t);
copyTo(x, r);
this.reduce(r);
return r;
}
},
revert: function (x) {
return x;
},
// x = x mod m (HAC 14.42)
reduce: function (x) {
dshrTo(x, this.m.t - 1, this.r2);
if (x.t > this.m.t + 1) {
x.t = this.m.t + 1;
clamp(x);
}
mulUpperTo(this.mu, this.r2, this.m.t + 1, this.q3);
mulLowerTo(this.m, this.q3, this.m.t + 1, this.r2);
while (compare(x, this.r2) < 0)
dAddOffset(x, 1, this.m.t + 1);
subTo(x, this.r2, x);
while (compare(x, this.m) >= 0)
subTo(x, this.m, x);
},
// r = x^2 mod m; x != r
sqrTo: function (x, r) {
sqrTo(x, r);
this.reduce(r);
},
// r = x*y mod m; x,y != r
mulTo: function (x, y, r) {
mulTo(x, y, r);
this.reduce(r);
}
});
// x^e % m (HAC 14.85)
function expMod(x, e, m) {
var i = bitLength(e), k, r = nbv(1), z;
if (i <= 0)
return r;
else if (i < 18)
k = 1;
else if (i < 48)
k = 3;
else if (i < 144)
k = 4;
else if (i < 768)
k = 5;
else
k = 6;
if (i < 8)
z = new Classic(m);
else if (isEven(m))
z = new Barrett(m);
else
z = new Montgomery(m);
// precomputation
var g = new Array(), n = 3, k1 = k - 1, km = (1 << k) - 1;
g[1] = z.convert(x);
if (k > 1) {
var g2 = nbi(m.t * 2);
z.sqrTo(g[1], g2);
while (n <= km) {
g[n] = nbi(m.t * 2);
z.mulTo(g2, g[n - 2], g[n]);
n += 2;
}
}
var j = e.t - 1, w, is1 = true, r2 = nbi(m.t * 2), t;
i = nbits(e[j]) - 1;
while (j >= 0) {
if (i >= k1)
w = (e[j] >> (i - k1)) & km;
else {
w = (e[j] & ((1 << (i + 1)) - 1)) << (k1 - i);
if (j > 0)
w |= e[j - 1] >> (DB + i - k1);
}
n = k;
while ((w & 1) == 0) {
w >>= 1;
--n;
}
if ((i -= n) < 0) {
i += DB;
--j;
}
if (is1) { // ret == 1, don't bother squaring or multiplying it
copyTo(g[w], r);
is1 = false;
}
else {
while (n > 1) {
z.sqrTo(r, r2);
z.sqrTo(r2, r);
n -= 2;
}
if (n > 0)
z.sqrTo(r, r2);
else {
t = r;
r = r2;
r2 = t;
}
z.mulTo(r2, g[w], r);
}
while (j >= 0 && (e[j] & (1 << i)) == 0) {
z.sqrTo(r, r2);
t = r;
r = r2;
r2 = t;
if (--i < 0) {
i = DB - 1;
--j;
}
}
}
return z.revert(r);
} // </editor-fold>
/*
* EC Field Elements, Points, Curves
* optimized release of http://www-cs-students.stanford.edu/~tjw/jsbn/ec.js
*
*/ // <editor-fold defaultstate="collapsed">
// EC Field Elemets
function newFE(a, x) {
a.r.reduce(x);
x.q = a.q;
x.r = a.r;
return x;
}
function copyFE(a, x) {
x.q = a.q;
x.r = a.r;
return x;
}
function negFE(a) {
return copyFE(a, sub(a.q, a));
}
function addFE(a, b) {
var r = add(a, b);
if (compare(r, a.q) > 0)
subTo(r, a.q, r);
return copyFE(a, r);
}
function subFE(a, b) {
var r = sub(a, b);
if (r.s < 0)
addTo(a.q, r, r);
return copyFE(a, r);
}
function mulFE(a, b) {
return newFE(a, mul(a, b));
}
function sqrFE(a) {
return newFE(a, sqr(a));
}
function shlFE(a, i) {
return newFE(a, shl(a, i));
}
function invFE(a) {
return copyFE(a, invMod(a, a.q));
}
// EC Points
function newEC(curve, x, y, z) {
return {
curve: curve,
x: x,
y: y,
z: z || newFE(curve, ONE)
};
}
function getX(point) {
if (!point.zinv)
point.zinv = invFE(point.z);
return mulFE(point.x, point.zinv);
}
function getY(point) {
if (!point.zinv)
point.zinv = invFE(point.z);
return mulFE(point.y, point.zinv);
}
function isInfinity(a) {
if ((!a.x) && (!a.y))
return true;
return isZero(a.z) && !isZero(a.y);
}
function getInfinity(a) {
return a.curve.infinity;
}
function equalsEC(a, b) {
if (a === b)
return true;
if (isInfinity(a))
return isInfinity(b);
if (isInfinity(b))
return isInfinity(a);
var u, v;
// u = Y2 * Z1 - Y1 * Z2
u = subFE(mulFE(b.y, a.z), mulFE(a.y, b.z));
if (!isZero(u))
return false;
// v = X2 * Z1 - X1 * Z2
v = subFE(mulFE(b.x, a.z), mulFE(a.x, b.z));
return isZero(v);
}
function negEC(a) {
return newEC(a.curve, a.x, negFE(a.y), a.z);
}
function addEC(a, b) {
if (isInfinity(a))
return b;
if (isInfinity(b))
return a;
// u = Y2 * Z1 - Y1 * Z2
var u = subFE(mulFE(b.y, a.z), mulFE(a.y, b.z));
// v = X2 * Z1 - X1 * Z2
var v = subFE(mulFE(b.x, a.z), mulFE(a.x, b.z));
if (isZero(v)) {
if (isZero(u)) {
return twiceEC(a); // a == b, so double
}
return getInfinity(a); // a = -b, so infinity
}
var x1 = a.x;
var y1 = a.y;
var v2 = sqrFE(v);
var v3 = mulFE(v2, v);
var x1v2 = mulFE(x1, v2);
var zu2 = mulFE(sqrFE(u), a.z);
// x3 = v * (z2 * (z1 * u^2 - 2 * x1 * v^2) - v^3)
var x3 = mulFE(subFE(mulFE(subFE(zu2, shlFE(x1v2, 1)), b.z), v3), v);
// y3 = z2 * (3 * x1 * u * v^2 - y1 * v^3 - z1 * u^3) + u * v^3
var y3 = addFE(mulFE(subFE(subFE(mulFE(mulFE(x1v2, THREE), u), mulFE(y1, v3)), mulFE(zu2, u)), b.z), mulFE(u, v3));
// z3 = v^3 * z1 * z2
var z3 = mulFE(mulFE(v3, a.z), b.z);
return newEC(a.curve, x3, y3, z3);
}
function twiceEC(b) {
if (isInfinity(b))
return b;
if (sig(b.y) === 0)
return getInfinity(b);
var x1 = b.x;
var y1 = b.y;
var y1z1 = mulFE(y1, b.z);
var y1sqz1 = mulFE(y1z1, y1);
var a = b.curve.a;
// w = 3 * x1^2 + a * z1^2
var w = mulFE(sqrFE(x1), THREE);
if (!isZero(a)) {
w = addFE(w, mulFE(sqrFE(b.z), a));
}
// x3 = 2 * y1 * z1 * (w^2 - 8 * x1 * y1^2 * z1)
var x3 = mulFE(shlFE(subFE(sqrFE(w), mulFE(shlFE(x1, 3), y1sqz1)), 1), y1z1);
// y3 = 4 * y1^2 * z1 * (3 * w * x1 - 2 * y1^2 * z1) - w^3
var y3 = subFE(mulFE(shlFE(subFE(mulFE(mulFE(w, THREE), x1), shlFE(y1sqz1, 1)), 2), y1sqz1), mulFE(sqrFE(w), w));
// z3 = 8 * (y1 * z1)^3
var z3 = shlFE(mulFE(sqrFE(y1z1), y1z1), 3);
return newEC(b.curve, x3, y3, z3);
}
// Simple NAF (Non-Adjacent Form) multiplication algorithm
function mulEC(a, k) {
if (isInfinity(a))
return a;
if (sig(k) === 0)
return getInfinity(a);
var e = k;
var h = mul(e, THREE);
var neg = negEC(a);
var R = a;
var i;
for (i = bitLength(h) - 2; i > 0; --i) {
R = twiceEC(R);
var hBit = testBit(h, i);
var eBit = testBit(e, i);
if (hBit !== eBit) {
R = addEC(R, hBit ? a : neg);
}
}
return R;
}
function mul2AndAddEC(a, k) {
var nbits = bitLength(k);
var R = a,
Q = getInfinity(a);
for (var i = 0; i < nbits - 1; i++) {
if (testBit(k, i) === 1)
Q = addEC(Q, R);
R = twiceEC(R);
}
if (testBit(k, nbits - 1) === 1)
Q = addEC(Q, R);
return Q;
}
// Compute a*j + x*k (simultaneous multiplication)
function mulTwoEC(a, j, x, k) {
var i;
if (bitLength(j) > bitLength(k))
i = bitLength(j) - 1;
else
i = bitLength(k) - 1;
var R = getInfinity(a);
var both = addEC(a, x);
while (i >= 0) {
R = twiceEC(R);
if (testBit(j, i)) {
if (testBit(k, i)) {
R = addEC(R, both);
}
else {
R = addEC(R, a);
}
}
else {
if (testBit(k, i)) {
R = addEC(R, x);
}
}
--i;
}
return R;
}
// EC Curve
function newCurve(q, a, b) {
var curve = {};
curve.q = q;
curve.r = new Barrett(q);
curve.a = newFE(curve, a);
curve.b = newFE(curve, b);
curve.infinity = newEC(curve);
return curve;
} // </editor-fold>
/*
* Converion tools (hex, binary)
*
*/ // <editor-fold defaultstate="collapsed">
function atobi(d) {
var k = 8;
var a = new Uint8Array(d);
var r = nbi(a.length * 8 / DB);
r.t = 0;
r.s = 0;
var sh = 0;
for (var i = 0, n = a.length; i < n; i++) {
var x = a[i];
if (sh === 0)
r[r.t++] = x;
else if (sh + k > DB) {
r[r.t - 1] |= (x & ((1 << (DB - sh)) - 1)) << sh;
r[r.t++] = (x >> (DB - sh));
}
else
r[r.t - 1] |= x << sh;
sh += k;
if (sh >= DB)
sh -= DB;
}
return clamp(r);
}
function bitoa(s, bitLength) {
var k = 8;
var km = (1 << k) - 1, d, m = false, r = [], i = s.t;
var p = DB - (i * DB) % k;
if (i-- > 0) {
if (p < DB && (d = s[i] >> p) > 0) {
m = true;
r.push(d);
}
while (i >= 0) {
if (p < k) {
d = (s[i] & ((1 << p) - 1)) << (k - p);
d |= s[--i] >> (p += DB - k);
}
else {
d = (s[i] >> (p -= k)) & km;
if (p <= 0) {
p += DB;
--i;
}
}
if (d > 0)
m = true;
if (m)
r.push(d);
}
}
var r8 = new Uint8Array(bitLength ? bitLength / 8 : r.length);
if (m)
r8.set(r.reverse());
return r8.buffer;
}
function htobi(s) {
if (typeof s === 'number' || s instanceof Number)
return nbv(s);
s = s.replace(/[^\-A-Fa-f0-9]/g, '');
if (!s)
s = '0';
var k = 4;
var r = nbi(s.length / 7);
var i = s.length, mi = false, sh = 0;
while (--i >= 0) {
var c = s.charAt(i);
if (c === '-') {
mi = true;
continue;
}
var x = parseInt(s.charAt(i), 16);
mi = false;
if (sh === 0)
r[r.t++] = x;
else if (sh + k > DB) {
r[r.t - 1] |= (x & ((1 << (DB - sh)) - 1)) << sh;
r[r.t++] = (x >> (DB - sh));
}
else
r[r.t - 1] |= x << sh;
sh += k;
if (sh >= DB)
sh -= DB;
}
if (mi)
subTo(ZERO, r, r);
return clamp(r);
}
function bitoh(x) {
if (x.s < 0)
return "-" + bitoh(negTo(x, nbi(x.t)));
var k = 4;
var km = (1 << k) - 1, d, m = false, r = "", i = x.t;
var p = DB - (i * DB) % k;
if (i-- > 0) {
if (p < DB && (d = x[i] >> p) > 0) {
m = true;
r = d.toString(16);
}
while (i >= 0) {
if (p < k) {
d = (x[i] & ((1 << p) - 1)) << (k - p);
d |= x[--i] >> (p += DB - k);
}
else {
d = (x[i] >> (p -= k)) & km;
if (p <= 0) {
p += DB;
--i;
}
}
if (d > 0)
m = true;
if (m)
r += d.toString(16);
}
}
return "0x" + (m ? r : "0");
}
// biginteger to big-endian integer bytearray
function bitoi(s) {
var i = s.t, r = [];
r[0] = s.s;
var p = DB - (i * DB) % 8, d, k = 0;
if (i-- > 0) {
if (p < DB && (d = s[i] >> p) !== (s.s & DM) >> p)
r[k++] = d | (s.s << (DB - p));
while (i >= 0) {
if (p < 8) {
d = (s[i] & ((1 << p) - 1)) << (8 - p);
d |= s[--i] >> (p += DB - 8);
}
else {
d = (s[i] >> (p -= 8)) & 0xff;
if (p <= 0) {
p += DB;
--i;
}
}
if ((d & 0x80) !== 0)
d |= -256;
if (k === 0 && (s.s & 0x80) !== (d & 0x80))
++k;
if (k > 0 || d !== s.s)
r[k++] = d;
}
}
return new Uint8Array(r).buffer;
}
// big-endian integer bytearray to biginteger
function itobi(d) {
var k = 8, s = new Uint8Array(d),
r = nbi(s.length / 7);
r.t = 0;
r.s = 0;
var i = s.length, sh = 0;
while (--i >= 0) {
var x = s[i] & 0xff;
if (sh === 0)
r[r.t++] = x;
else if (sh + k > DB) {
r[r.t - 1] |= (x & ((1 << (DB - sh)) - 1)) << sh;
r[r.t++] = (x >> (DB - sh));
}
else
r[r.t - 1] |= x << sh;
sh += k;
if (sh >= DB)
sh -= DB;
}
if ((s[0] & 0x80) !== 0) {
r.s = -1;
if (sh > 0)
r[r.t - 1] |= ((1 << (DB - sh)) - 1) << sh;
}
return clamp(r);
}
// Swap bytes in buffer
function swap(s) {
var src = new Uint8Array(s),
dst = new Uint8Array(src.length);
for (var i = 0, n = src.length; i < n; i++)
dst[n - i - 1] = src[i];
return dst.buffer;
}
// Calculate hash of data
function hash(d) {
if (this.hash)
d = this.hash.digest(d);
// Swap hash for SignalCom
if (this.procreator === 'SC' ||
(this.procreator === 'VN' && this.hash.version === 2012))
d = swap(d);
return d;
}
// Check buffer
function buffer(d) {
if (d instanceof CryptoOperationData)
return d;
else if (d && d?.buffer instanceof CryptoOperationData)
return d.byteOffset === 0 && d.byteLength === d.buffer.byteLength ?
d.buffer : new Uint8Array(new Uint8Array(d, d.byteOffset, d.byteLength)).buffer;
else
throw new DataError('CryptoOperationData or CryptoOperationDataView required');
}
// Check double buffer
function to2(d) {
var b = buffer(d);
if (b.byteLength % 2 > 0)
throw new DataError('Buffer length must be even');
var n = b.byteLength / 2;
return [atobi(new Uint8Array(b, 0, n)), atobi(new Uint8Array(b, n, n))];
}
function from2(x, y, bitLength) {
var a = bitoa(x, bitLength),
b = bitoa(y, bitLength),
d = new Uint8Array(a.byteLength + b.byteLength);
d.set(new Uint8Array(a));
d.set(new Uint8Array(b), a.byteLength);
return d.buffer;
}
function getSeed(length) {
GostRandom = GostRandom || root.GostRandom;
var randomSource = GostRandom ? new (GostRandom || root.GostRandom) : rootCrypto;
if (randomSource.getRandomValues) {
var d = new Uint8Array(Math.ceil(length / 8));
randomSource.getRandomValues(d);
return d;
} else
throw new NotSupportedError('Random generator not found');
} // </editor-fold>
/**
* Algorithm name GOST R 34.10<br><br>
*
* The sign method returns sign data generated with the supplied privateKey.<br>
*
* @memberOf GostSign
* @method sign
* @instance
* @param {(CryptoOperationData|TypedArray)} privateKey Private key
* @param {(CryptoOperationData|TypedArray)} data Data
* @returns {CryptoOperationData} Signature
*/
function sign(privateKey, data) // <editor-fold defaultstate="collapsed">
{
// Stage 1
var b = buffer(data);
var alpha = atobi(hash.call(this, b));
var q = this.q;
var x = mod(atobi(buffer(privateKey)), q);
// Stage 2
var e = mod(alpha, q);
if (isZero(e))
e = ONE;
var s = ZERO;
while (isZero(s)) {
var r = ZERO;
while (isZero(r)) {
// Stage 3
var k = mod(atobi(this.ukm ||
getSeed(this.bitLength)), q); // pseudo random 0 < k < q
// Stage 4
if (this.curve) {
// Gost R 34.10-2001 || Gost R 34.10-2012
var P = this.P;
var C = mulEC(P, k);
r = mod(getX(C), q);
} else {
// Gost R 34.10-94
var p = this.p, a = this.a;
r = mod(expMod(a, k, p), q);
}
}
// Stage 5
s = mod(add(mul(r, x), mul(k, e)), q);
}
// Stage 6
// console.log('s', bitoh(s));
// console.log('r', bitoh(r));
var zetta;
// Integer structure for SignalCom algorithm
if (this.procreator === 'SC') {
zetta = {
r: bitoh(r),
s: bitoh(s)
};
} else {
zetta = from2(r, s, this.bitLength);
// Swap bytes for CryptoPro algorithm
if (this.procreator === 'CP' || this.procreator === 'VN')
zetta = swap(zetta);
}
return zetta;
} // </editor-fold>
/**
* Algorithm name GOST R 34.10<br><br>
*
* The verify method returns signature verification for the supplied publicKey.<br>
*
* @memberOf GostSign
* @method sign
* @instance
* @param {(CryptoOperationData|TypedArray)} publicKey Public key
* @param {(CryptoOperationData|TypedArray)} signature Signature
* @param {(CryptoOperationData|TypedArray)} data Data
* @returns {boolean} Signature verified = true
*/
function verify(publicKey, signature, data) // <editor-fold defaultstate="collapsed">
{
// Stage 1
var q = this.q;
var r, s;
// Ready int for SignalCom algorithm
if (this.procreator === 'SC') {
r = htobi(signature.r);
s = htobi(signature.s);
} else {
if (this.procreator === 'CP' || this.procreator === 'VN')
signature = swap(signature);
var zetta = to2(signature);
// Swap bytes for CryptoPro algorithm
s = zetta[1]; // first 32 octets contain the big-endian representation of s
r = zetta[0]; // and second 32 octets contain the big-endian representation of r
}
if (compare(r, q) >= 0 || compare(s, q) >= 0)
return false;
// Stage 2
var b = buffer(data);
var alpha = atobi(hash.call(this, b));
// Stage 3
var e = mod(alpha, q);
if (isZero(e) === 0)
e = ONE;
// Stage 4
var v = invMod(e, q);
// Stage 5
var z1 = mod(mul(s, v), q);
var z2 = sub(q, mod(mul(r, v), q));
// Stage 6
if (this.curve) {
// Gost R 34.10-2001 || Gost R 34.10-2012
var k2 = to2(publicKey),
curve = this.curve,
P = this.P,
x = newFE(curve, k2[0]), // first 32 octets contain the little-endian representation of x
y = newFE(curve, k2[1]), // and second 32 octets contain the little-endian representation of y.
Q = new newEC(curve, x, y); // This corresponds to the binary representation of (<y>256||<x>256)
var C = mulTwoEC(P, z1, Q, z2);
var R = mod(getX(C), q);
} else {
// Gost R 34.10-94
var p = this.p, a = this.a;
var y = atobi(publicKey);
var R = mod(mod(mul(expMod(a, z1, p), expMod(y, z2, p)), p), q);
}
// Stage 7
return (compare(R, r) === 0);
} // </editor-fold>
/**
* Algorithm name GOST R 34.10<br><br>
*
* The generateKey method returns a new generated key pair using the specified
* AlgorithmIdentifier.
*
* @memberOf GostSign
* @method generateKey
* @instance
* @returns {Object} Object with two CryptoOperationData members: privateKey and publicKey
*/
function generateKey() // <editor-fold defaultstate="collapsed">
{
var curve = this.curve;
if (curve) {
var Q = curve.infinity;
while (isInfinity(Q)) {
// Generate random private key
var d = ZERO;
if (this.ukm) {
d = atobi(this.ukm);
} else {
while (isZero(d))
d = mod(atobi(getSeed(this.bitLength)), this.q); // 0 < d < q
}
// Calculate public key
Q = mulEC(this.P, d);
var x = getX(Q), y = getY(Q);
// console.log('d', bitoh(d));
// console.log('x', bitoh(x));
// console.log('y', bitoh(y));
}
// Return result
return {
privateKey: bitoa(d, this.bitLength),
publicKey: from2(x, y, this.bitLength) // This corresponds to the binary representation of (<y>256||<x>256)
};
} else
throw new NotSupportedError('Key generation for GOST R 34.10-94 not supported');
} // </editor-fold>
/**
* Algorithm name GOST R 34.10 mode MASK<br><br>
*
* The generateMaskKey method returns a new generated key mask using for wrapping.
*
* @memberOf GostSign
* @method generateMaskKey
* @instance
* @returns {Object} Object with two CryptoOperationData members: privateKey and publicKey
*/
function generateMaskKey() // <editor-fold defaultstate="collapsed">
{
var curve = this.curve;
if (curve) {
// Generate random private key
var d = ZERO;
while (isZero(d))
d = mod(atobi(getSeed(this.bitLength)), this.q); // 0 < d < q
// Return result
return bitoa(d, this.bitLength);
} else
throw new NotSupportedError('Key generation for GOST R 34.10-94 not supported');
} // </editor-fold>
/**
* Algorithm name GOST R 34.10<br><br>
*
* Unwrap private key from private key and ukm (mask)
*
* @memberOf GostSign
* @method unwrap
* @instance
* @param {(CryptoOperationData|TypedArray)} baseKey Unwrapping key
* @param {(CryptoOperationData|TypedArray)} data Wrapped key
* @returns {Object} CryptoOperationData unwrapped privateKey
*/
function unwrapKey(baseKey, data) // <editor-fold defaultstate="collapsed">
{
var curve = this.curve;
if (curve) {
var q = this.q;
var x = mod(atobi(buffer(data)), q);
var y = mod(atobi(buffer(baseKey)), q);
var z = this.procreator === 'VN' ? mod(mul(x, y), q) : mod(mul(x, invMod(y, q)), q);
return bitoa(z);
} else
throw new NotSupportedError('Key wrapping GOST R 34.10-94 not supported');
} // </editor-fold>
/**
* Algorithm name GOST R 34.10<br><br>
*
* Wrap private key with private key and ukm (mask)
*
* @memberOf GostSign
* @method unwrap
* @instance
* @param {(CryptoOperationData|TypedArray)} baseKey Wrapping key
* @param {(CryptoOperationData|TypedArray)} data Key
* @returns {Object} CryptoOperationData unwrapped privateKey
*/
function wrapKey(baseKey, data) // <editor-fold defaultstate="collapsed">
{
var curve = this.curve;
if (curve) {
var q = this.q;
var x = mod(atobi(buffer(data)), q);
var y = mod(atobi(buffer(baseKey)), q);
var z = this.procreator === 'VN' ? mod(mul(x, invMod(y, q)), q) : mod(mul(x, y), q);
return bitoa(z);
} else
throw new NotSupportedError('Key wrapping GOST R 34.10-94 not supported');
} // </editor-fold>
/**
* Algorithm name GOST R 34.10<br><br>
*
* @memberOf GostSign
* @method derive
* @instance
* @private
* @param {CryptoOperationData} baseKey Key for deriviation
* @returns {CryptoOperationData}
*/
function derive(baseKey) // <editor-fold defaultstate="collapsed">
{
var k, ukm = atobi(this.ukm);
var q = this.q;
var x = mod(atobi(buffer(baseKey)), q);
if (this.curve) {
// 1) Let K(x,y,UKM) = ((UKM*x)(mod q)) . (y.P) (512 bit), where
// x - senders private key (256 bit)
// x.P - senders public key (512 bit)
// y - recipients private key (256 bit)
// y.P - recipients public key (512 bit)
// UKM - non-zero integer, produced as in step 2 p. 6.1 [GOSTR341001]
// P - base point on the elliptic curve (two 256-bit coordinates)
// UKM*x - x multiplied by UKM as integers
// x.P - a multiple point
var K = mulEC(this.peer_Q, mod(mul(ukm, x), q));
k = from2(getX(K), getY(K), // This corresponds to the binary representation of (<y>256||<x>256)
this.bitLength);
} else {
// 1) Let K(x,y) = a^(x*y) (mod p), where
// x - senders private key, a^x - senders public key
// y - recipients private key, a^y - recipients public key
// a, p - parameters
var p = this.p, a = this.a;
k = bitoa(expMod(this.peer_y, x, p));
}
// 2) Calculate a 256-bit hash of K(x,y,UKM):
// KEK(x,y,UKM) = gostSign (K(x,y,UKM)
return hash.call(this, k);
} // </editor-fold>
/**
* Algorithm name GOST R 34.10<br><br>
*
* The deriveBits method returns length bits on baseKey.
*
* @memberOf GostSign
* @method deriveBits
* @instance
* @param {(CryptoOperationData|TypedArray)} baseKey Key for deriviation
* @param {number} length output bit-length
* @returns {CryptoOperationData} result
*/
function deriveBits(baseKey, length) // <editor-fold defaultstate="collapsed">
{
if (length < 8 || length > this.bitLength || length % 8 > 0)
throw new DataError('Length must be no more than ' + this.bitLength + ' bits and multiple of 8');
var n = length / 8,
b = derive.call(this, baseKey),
r = new Uint8Array(n);
r.set(new Uint8Array(b, 0, n));
return r.buffer;
} // </editor-fold>
/**
* Algorithm name GOST R 34.10<br><br>
*
* The deriveKey method returns 256 bit Key encryption key on baseKey.
*
* This algorithm creates a key encryption key (KEK) using 64 bit UKM,
* the senders private key, and the recipients public key (or the
* reverse of the latter pair
*
* @memberOf GostSign
* @method deriveKey
* @instance
* @param {(CryptoOperationData|TypedArray)} baseKey Key for deriviation
* @returns {CryptoOperationData} result
*/
function deriveKey(baseKey) // <editor-fold defaultstate="collapsed">
{
var b = derive.call(this, baseKey),
r = new Uint8Array(32);
r.set(new Uint8Array(b, 0, 32));
return r.buffer;
} // </editor-fold>
/**
* Gost R 34.10 universal object<br><br>
*
* References: {@link http://tools.ietf.org/html/rfc6986} and {@link http://tools.ietf.org/html/rfc5831}<br><br>
*
* Normalized algorithm identifier common parameters:
*
* <ul>
* <li><b>name</b> Algorithm name 'GOST R 34.10'</li>
* <li><b>version</b> Algorithm version
* <ul>
* <li><b>1994</b> - Old-style GOST R 34.10-94 ExpMod algorithm with GOST R 34.11-94 hash</li>
* <li><b>2001</b> - GOST R 34.10-2001 Eliptic curve algorithm with old GOST R 34.11-94 hash</li>
* <li><b>2012</b> - GOST R 34.10-2012 Eliptic curve algorithm with GOST R 34.11-12 hash, default mode</li>
* </ul>
* </li>
* <li><b>length</b> Length of hash and signature. Key length == hash length for EC algorithms and 2 * hash length for ExpMod algorithm
* <ul>
* <li><b>GOST R 34.10-256</b> - 256 bits digest, default mode</li>
* <li><b>GOST R 34.10-512</b> - 512 bits digest only for GOST R 34.11-2012 hash</li>
* </ul>
* </li>
* <li><b>mode</b> Algorithm mode
* <ul>
* <li><b>SIGN</b> Digital signature mode (default)</li>
* <li><b>DH</b> Diffie-Hellman key generation and key agreement mode</li>
* </ul>
* </li>
* <li><b>sBox</b> Paramset sBox for GOST 34.11-94. Used only if version = 1994 or 2001</li>
* </ul>
*
* Supported algorithms, modes and parameters:
*
* <ul>
* <li>Sign/Verify mode (SIGN)</li>
* <li>DeriveKey/DeriveBits mode (DH)
* <ul>
* <li>{@link CryptoOperationData} <b>ukm</b> User key material. Default - random generated value</li>
* <li>{@link CryptoOperationData} <b>public</b> The peer's EC public key data</li>
* </ul>
* </li>
* <li>GenerateKey mode (SIGN and DH) version = 1994
* <ul>
* <li><b>namedParam</b> Paramset for key generation algorithm. If specified no additianal parameters required</li>
* </ul>
* Additional parameters, if namedParam not specified
* <ul>
* <li><b>modulusLength</b> Bit length of p (512 or 1024 bits). Default = 1024</li>
* <li><b>p</b> {@link CryptoOperationData} Modulus, prime number, 2^(t-1)<p<2^t</li>
* <li><b>q</b> {@link CryptoOperationData} Order of cyclic group, prime number, 2^254<q<2^256, q is a factor of p-1</li>
* <li><b>a</b> {@link CryptoOperationData} Generator, integer, 1<a<p-1, at that aq (mod p) = 1</li>
* </ul>
* </li>
* <li>GenerateKey mode (SIGN and DH) version = 2001 or 2012
* <ul>
* <li><b>namedCurve</b> Paramset for key generation algorithm. If specified no additianal parameters required</li>
* </ul>
* Additional EC parameters, if namedCurve not specified
* <ul>
* <li><b>p</b> {@link CryptoOperationData} Prime number - elliptic curve modulus</li>
* <li><b>a</b> {@link CryptoOperationData} Coefficients a of the elliptic curve E</li>
* <li><b>b</b> {@link CryptoOperationData} Coefficients b of the elliptic curve E</li>
* <li><b>q</b> {@link CryptoOperationData} Prime number - order of cyclic group</li>
* <li><b>x</b> {@link CryptoOperationData} Base point p x-coordinate</li>
* <li><b>y</b> {@link CryptoOperationData} Base point p y-coordinate</li>
* </ul>
* </li>
* </ul>
*
* @class GostSign
* @param {AlgorithmIndentifier} algorithm
*/
function GostSign(algorithm) // <editor-fold defaultstate="collapsed">
{
algorithm = algorithm || {};
this.name = (algorithm.name || 'GOST R 34.10') + '-' +
((algorithm.version || 2012) % 100) + '-' + (algorithm.length || 256) +
(((algorithm.mode || 'SIGN') !== 'SIGN') ? '-' + algorithm.mode : '') +
(typeof algorithm.namedParam === 'string' ? '/' + algorithm.namedParam : '') +
(typeof algorithm.namedCurve === 'string' ? '/' + algorithm.namedCurve : '') +
(typeof algorithm.sBox === 'string' ? '/' + algorithm.sBox : '');
var version = algorithm.version || 2012;
// Functions
switch (algorithm.mode || 'SIGN') {
case 'SIGN':
this.sign = sign;
this.verify = verify;
this.generateKey = generateKey;
break;
case 'DH':
this.deriveBits = deriveBits;
this.deriveKey = deriveKey;
this.generateKey = generateKey;
break;
case 'MASK':
this.wrapKey = wrapKey;
this.unwrapKey = unwrapKey;
this.generateKey = generateMaskKey;
break;
}
// Define parameters
if (version === 1994) {
// Named or parameters algorithm
var param = algorithm.param;
if (!param)
param = GostParams[this.namedParam = (algorithm.namedParam || 'S-A').toUpperCase()];
this.modulusLength = algorithm.modulusLength || param.modulusLength || 1024;
this.p = htobi(param.p);
this.q = htobi(param.q);
this.a = htobi(param.a);
// Public key for derive
if (algorithm['public'])
this.peer_y = atobi(algorithm['public']);
} else {
// Named or parameters algorithm
var param = algorithm.curve;
if (!param)
param = ECGostParams[this.namedCurve = (algorithm.namedCurve || 'S-256-A').toUpperCase()];
var curve = this.curve = newCurve(htobi(param.p), htobi(param.a), htobi(param.b));
this.P = newEC(curve,
newFE(curve, htobi(param.x)),
newFE(curve, htobi(param.y)));
this.q = htobi(param.q);
// Public key for derive
if (algorithm['public']) {
var k2 = to2(algorithm['public']);
this.peer_Q = new newEC(this.curve, // This corresponds to the binary representation of (<y>256||<x>256)
newFE(this.curve, k2[0]), // first 32 octets contain the little-endian representation of x
newFE(this.curve, k2[1])); // and second 32 octets contain the little-endian representation of y.
}
}
// Check bit length
var hashLen, keyLen;
if (this.curve) {
keyLen = algorithm.length || bitLength(this.q);
if (keyLen > 508 && keyLen <= 512)
keyLen = 512;
else if (keyLen > 254 && keyLen <= 256)
keyLen = 256;
else
throw new NotSupportedError('Support keys only 256 or 512 bits length');
hashLen = keyLen;
} else {
keyLen = algorithm.modulusLength || bitLength(this.p);
if (keyLen > 1016 && keyLen <= 1024)
keyLen = 1024;
else if (keyLen > 508 && keyLen <= 512)
keyLen = 512;
else
throw new NotSupportedError('Support keys only 512 or 1024 bits length');
hashLen = 256;
}
this.bitLength = hashLen;
this.keyLength = keyLen;
// Algorithm proceator for result conversion
this.procreator = algorithm.procreator;
// Hash function definition
var hash = algorithm.hash;
if (hash) {
if (typeof hash === 'string' || hash instanceof String)
hash = {name: hash};
if (algorithm.version === 1994 || algorithm.version === 2001) {
hash.version = 1994;
hash.length = 256;
hash.sBox = algorithm.sBox || hash.sBox;
} else {
hash.version = 2012;
hash.length = hashLen;
}
hash.procreator = hash.procreator || algorithm.procreator;
if (!GostDigest)
GostDigest = root.GostDigest;
if (!GostDigest)
throw new NotSupportedError('Object GostDigest not found');
this.hash = new GostDigest(hash);
}
// Pregenerated seed for key exchange algorithms
if (algorithm.ukm) // Now don't check size
this.ukm = algorithm.ukm;
} // </editor-fold>
export default GostSign;