/**
* @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
*
*/ //
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'
}
}; //
/*
* BigInteger arithmetic tools
* optimized release of http://www-cs-students.stanford.edu/~tjw/jsbn/jsbn.js
*
*/ //
// 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];
} //
/*
* Classic, Barret, Mongomery reductions, optimized ExpMod algorithms
* optimized release of http://www-cs-students.stanford.edu/~tjw/jsbn/jsbn2.js
*
*/ //
// 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);
} //
/*
* EC Field Elements, Points, Curves
* optimized release of http://www-cs-students.stanford.edu/~tjw/jsbn/ec.js
*
*/ //
// 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;
} //
/*
* Converion tools (hex, binary)
*
*/ //
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');
} //
/**
* Algorithm name GOST R 34.10
*
* The sign method returns sign data generated with the supplied privateKey.
*
* @memberOf GostSign
* @method sign
* @instance
* @param {(CryptoOperationData|TypedArray)} privateKey Private key
* @param {(CryptoOperationData|TypedArray)} data Data
* @returns {CryptoOperationData} Signature
*/
function sign(privateKey, data) //
{
// 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;
} //
/**
* Algorithm name GOST R 34.10
*
* The verify method returns signature verification for the supplied publicKey.
*
* @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) //
{
// 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 (256||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);
} //
/**
* Algorithm name GOST R 34.10
*
* 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() //
{
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 (256||256)
};
} else
throw new NotSupportedError('Key generation for GOST R 34.10-94 not supported');
} //
/**
* Algorithm name GOST R 34.10 mode MASK
*
* 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() //
{
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');
} //
/**
* Algorithm name GOST R 34.10
*
* 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) //
{
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');
} //
/**
* Algorithm name GOST R 34.10
*
* 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) //
{
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');
} //
/**
* Algorithm name GOST R 34.10
*
* @memberOf GostSign
* @method derive
* @instance
* @private
* @param {CryptoOperationData} baseKey Key for deriviation
* @returns {CryptoOperationData}
*/
function derive(baseKey) //
{
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 - sender’s private key (256 bit)
// x.P - sender’s public key (512 bit)
// y - recipient’s private key (256 bit)
// y.P - recipient’s 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 (256||256)
this.bitLength);
} else {
// 1) Let K(x,y) = a^(x*y) (mod p), where
// x - sender’s private key, a^x - sender’s public key
// y - recipient’s private key, a^y - recipient’s 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);
} //
/**
* Algorithm name GOST R 34.10
*
* 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) //
{
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;
} //
/**
* Algorithm name GOST R 34.10
*
* The deriveKey method returns 256 bit Key encryption key on baseKey.
*
* This algorithm creates a key encryption key (KEK) using 64 bit UKM,
* the sender’s private key, and the recipient’s 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) //
{
var b = derive.call(this, baseKey),
r = new Uint8Array(32);
r.set(new Uint8Array(b, 0, 32));
return r.buffer;
} //
/**
* Gost R 34.10 universal object
*
* References: {@link http://tools.ietf.org/html/rfc6986} and {@link http://tools.ietf.org/html/rfc5831}
*
* Normalized algorithm identifier common parameters:
*
*
* - name Algorithm name 'GOST R 34.10'
* - version Algorithm version
*
* - 1994 - Old-style GOST R 34.10-94 ExpMod algorithm with GOST R 34.11-94 hash
* - 2001 - GOST R 34.10-2001 Eliptic curve algorithm with old GOST R 34.11-94 hash
* - 2012 - GOST R 34.10-2012 Eliptic curve algorithm with GOST R 34.11-12 hash, default mode
*
*
* - length Length of hash and signature. Key length == hash length for EC algorithms and 2 * hash length for ExpMod algorithm
*
* - GOST R 34.10-256 - 256 bits digest, default mode
* - GOST R 34.10-512 - 512 bits digest only for GOST R 34.11-2012 hash
*
*
* - mode Algorithm mode
*
* - SIGN Digital signature mode (default)
* - DH Diffie-Hellman key generation and key agreement mode
*
*
* - sBox Paramset sBox for GOST 34.11-94. Used only if version = 1994 or 2001
*
*
* Supported algorithms, modes and parameters:
*
*
* - Sign/Verify mode (SIGN)
* - DeriveKey/DeriveBits mode (DH)
*
* - {@link CryptoOperationData} ukm User key material. Default - random generated value
* - {@link CryptoOperationData} public The peer's EC public key data
*
*
* - GenerateKey mode (SIGN and DH) version = 1994
*
* - namedParam Paramset for key generation algorithm. If specified no additianal parameters required
*
* Additional parameters, if namedParam not specified
*
* - modulusLength Bit length of p (512 or 1024 bits). Default = 1024
* - p {@link CryptoOperationData} Modulus, prime number, 2^(t-1)
*
- q {@link CryptoOperationData} Order of cyclic group, prime number, 2^254
* - a {@link CryptoOperationData} Generator, integer, 1
*
*
* - GenerateKey mode (SIGN and DH) version = 2001 or 2012
*
* - namedCurve Paramset for key generation algorithm. If specified no additianal parameters required
*
* Additional EC parameters, if namedCurve not specified
*
* - p {@link CryptoOperationData} Prime number - elliptic curve modulus
* - a {@link CryptoOperationData} Coefficients a of the elliptic curve E
* - b {@link CryptoOperationData} Coefficients b of the elliptic curve E
* - q {@link CryptoOperationData} Prime number - order of cyclic group
* - x {@link CryptoOperationData} Base point p x-coordinate
* - y {@link CryptoOperationData} Base point p y-coordinate
*
*
*
*
* @class GostSign
* @param {AlgorithmIndentifier} algorithm
*/
function GostSign(algorithm) //
{
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 (256||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;
} //
export default GostSign;