2024 lines
59 KiB
JavaScript
Executable File
2024 lines
59 KiB
JavaScript
Executable File
/**
|
||
* @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 - 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 (<y>256||<x>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);
|
||
} // </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 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) // <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;
|