@signumjs/crypto
Version:
Cryptographic functions for building Signum Network apps.
210 lines • 9.65 kB
JavaScript
;
/** @ignore */
/** @internal*/
/* tslint:disable */
Object.defineProperty(exports, "__esModule", { value: true });
exports.ECKCDSA = void 0;
/**
* Original work Copyright (c) 2018 PoC-Consortium
* Modified work Copyright (c) 2019 Burst Apps Team
*/
/********* DIGITAL SIGNATURES *********/
/* deterministic EC-KCDSA
*
* s is the private key for signing
* P is the corresponding public key
* Z is the context data (signer public key or certificate, etc)
*
* signing:
*
* m = hash(Z, message)
* x = hash(m, s)
* keygen25519(Y, NULL, x);
* r = hash(Y);
* h = m XOR r
* sign25519(v, h, x, s);
*
* output (v,r) as the signature
*
* verification:
*
* m = hash(Z, message);
* h = m XOR r
* verify25519(Y, v, h, P)
*
* confirm r === hash(Y)
*
* It would seem to me that it would be simpler to have the signer directly do
* h = hash(m, Y) and send that to the recipient instead of r, who can verify
* the signature by checking h === hash(m, Y). If there are any problems with
* such a scheme, please let me know.
*
* Also, EC-KCDSA (like most DS algorithms) picks x random, which is a waste of
* perfectly good entropy, but does allow Y to be calculated in advance of (or
* parallel to) hashing the message.
*/
/* Signature generation primitive, calculates (x-h)s mod q
* h [in] signature hash (of message, signature pub key, and context data)
* x [in] signature private key
* s [in] private key for signing
* returns signature value on success, undefined on failure (use different x or h)
*/
const curve25519_1 = require("./curve25519");
class ECKCDSA {
static sign(h, x, s) {
// v = (x - h) s mod q
let w, i;
let h1 = new Array(32);
let x1 = new Array(32);
let tmp1 = new Array(64);
let tmp2 = new Array(64);
// Don't clobber the arguments, be nice!
curve25519_1.Curve25519.cpy32(h1, h);
curve25519_1.Curve25519.cpy32(x1, x);
// Reduce modulo group order
let tmp3 = new Array(32);
curve25519_1.Curve25519.divmod(tmp3, h1, 32, curve25519_1.Curve25519.ORDER, 32);
curve25519_1.Curve25519.divmod(tmp3, x1, 32, curve25519_1.Curve25519.ORDER, 32);
// v = x1 - h1
// If v is negative, add the group order to it to become positive.
// If v was already positive we don't have to worry about overflow
// when adding the order because v < ORDER and 2*ORDER < 2^256
let v = new Array(32);
curve25519_1.Curve25519.mula_small(v, x1, 0, h1, 32, -1);
curve25519_1.Curve25519.mula_small(v, v, 0, curve25519_1.Curve25519.ORDER, 32, 1);
// tmp1 = (x-h)*s mod q
curve25519_1.Curve25519.mula32(tmp1, v, s, 32, 1);
curve25519_1.Curve25519.divmod(tmp2, tmp1, 64, curve25519_1.Curve25519.ORDER, 32);
for (w = 0, i = 0; i < 32; i++)
w |= v[i] = tmp1[i];
return w !== 0 ? v : undefined;
}
/* Signature verification primitive, calculates Y = vP + hG
* v [in] signature value
* h [in] signature hash
* P [in] public key
* Returns signature public key
*/
static verify(v, h, P) {
/* Y = v abs(P) + h G */
let d = new Array(32);
let p = [curve25519_1.Curve25519.createUnpackedArray(), curve25519_1.Curve25519.createUnpackedArray()];
let s = [curve25519_1.Curve25519.createUnpackedArray(), curve25519_1.Curve25519.createUnpackedArray()];
let yx = [curve25519_1.Curve25519.createUnpackedArray(), curve25519_1.Curve25519.createUnpackedArray(), curve25519_1.Curve25519.createUnpackedArray()];
let yz = [curve25519_1.Curve25519.createUnpackedArray(), curve25519_1.Curve25519.createUnpackedArray(), curve25519_1.Curve25519.createUnpackedArray()];
let t1 = [curve25519_1.Curve25519.createUnpackedArray(), curve25519_1.Curve25519.createUnpackedArray(), curve25519_1.Curve25519.createUnpackedArray()];
let t2 = [curve25519_1.Curve25519.createUnpackedArray(), curve25519_1.Curve25519.createUnpackedArray(), curve25519_1.Curve25519.createUnpackedArray()];
let vi = 0, hi = 0, di = 0, nvh = 0, i, j, k;
/* set p[0] to G and p[1] to P */
curve25519_1.Curve25519.set(p[0], 9);
curve25519_1.Curve25519.unpack(p[1], P);
/* set s[0] to P+G and s[1] to P-G */
/* s[0] = (Py^2 + Gy^2 - 2 Py Gy)/(Px - Gx)^2 - Px - Gx - 486662 */
/* s[1] = (Py^2 + Gy^2 + 2 Py Gy)/(Px - Gx)^2 - Px - Gx - 486662 */
curve25519_1.Curve25519.x_to_y2(t1[0], t2[0], p[1]); /* t2[0] = Py^2 */
curve25519_1.Curve25519.sqrt(t1[0], t2[0]); /* t1[0] = Py or -Py */
j = curve25519_1.Curve25519.is_negative(t1[0]); /* ... check which */
curve25519_1.Curve25519.add(t2[0], t2[0], curve25519_1.Curve25519.C39420360); /* t2[0] = Py^2 + Gy^2 */
curve25519_1.Curve25519.mul(t2[1], curve25519_1.Curve25519.BASE_2Y, t1[0]); /* t2[1] = 2 Py Gy or -2 Py Gy */
curve25519_1.Curve25519.sub(t1[j], t2[0], t2[1]); /* t1[0] = Py^2 + Gy^2 - 2 Py Gy */
curve25519_1.Curve25519.add(t1[1 - j], t2[0], t2[1]); /* t1[1] = Py^2 + Gy^2 + 2 Py Gy */
curve25519_1.Curve25519.cpy(t2[0], p[1]); /* t2[0] = Px */
curve25519_1.Curve25519.sub(t2[0], t2[0], curve25519_1.Curve25519.C9); /* t2[0] = Px - Gx */
curve25519_1.Curve25519.sqr(t2[1], t2[0]); /* t2[1] = (Px - Gx)^2 */
curve25519_1.Curve25519.recip(t2[0], t2[1], 0); /* t2[0] = 1/(Px - Gx)^2 */
curve25519_1.Curve25519.mul(s[0], t1[0], t2[0]); /* s[0] = t1[0]/(Px - Gx)^2 */
curve25519_1.Curve25519.sub(s[0], s[0], p[1]); /* s[0] = t1[0]/(Px - Gx)^2 - Px */
curve25519_1.Curve25519.sub(s[0], s[0], curve25519_1.Curve25519.C486671); /* s[0] = X(P+G) */
curve25519_1.Curve25519.mul(s[1], t1[1], t2[0]); /* s[1] = t1[1]/(Px - Gx)^2 */
curve25519_1.Curve25519.sub(s[1], s[1], p[1]); /* s[1] = t1[1]/(Px - Gx)^2 - Px */
curve25519_1.Curve25519.sub(s[1], s[1], curve25519_1.Curve25519.C486671); /* s[1] = X(P-G) */
curve25519_1.Curve25519.mul_small(s[0], s[0], 1); /* reduce s[0] */
curve25519_1.Curve25519.mul_small(s[1], s[1], 1); /* reduce s[1] */
/* prepare the chain */
for (i = 0; i < 32; i++) {
vi = (vi >> 8) ^ (v[i] & 0xFF) ^ ((v[i] & 0xFF) << 1);
hi = (hi >> 8) ^ (h[i] & 0xFF) ^ ((h[i] & 0xFF) << 1);
nvh = ~(vi ^ hi);
di = (nvh & (di & 0x80) >> 7) ^ vi;
di ^= nvh & (di & 0x01) << 1;
di ^= nvh & (di & 0x02) << 1;
di ^= nvh & (di & 0x04) << 1;
di ^= nvh & (di & 0x08) << 1;
di ^= nvh & (di & 0x10) << 1;
di ^= nvh & (di & 0x20) << 1;
di ^= nvh & (di & 0x40) << 1;
d[i] = di & 0xFF;
}
di = ((nvh & (di & 0x80) << 1) ^ vi) >> 8;
/* initialize state */
curve25519_1.Curve25519.set(yx[0], 1);
curve25519_1.Curve25519.cpy(yx[1], p[di]);
curve25519_1.Curve25519.cpy(yx[2], s[0]);
curve25519_1.Curve25519.set(yz[0], 0);
curve25519_1.Curve25519.set(yz[1], 1);
curve25519_1.Curve25519.set(yz[2], 1);
/* y[0] is (even)P + (even)G
* y[1] is (even)P + (odd)G if current d-bit is 0
* y[1] is (odd)P + (even)G if current d-bit is 1
* y[2] is (odd)P + (odd)G
*/
vi = 0;
hi = 0;
/* and go for it! */
for (i = 32; i-- !== 0;) {
vi = (vi << 8) | (v[i] & 0xFF);
hi = (hi << 8) | (h[i] & 0xFF);
di = (di << 8) | (d[i] & 0xFF);
for (j = 8; j-- !== 0;) {
curve25519_1.Curve25519.mont_prep(t1[0], t2[0], yx[0], yz[0]);
curve25519_1.Curve25519.mont_prep(t1[1], t2[1], yx[1], yz[1]);
curve25519_1.Curve25519.mont_prep(t1[2], t2[2], yx[2], yz[2]);
k = ((vi ^ vi >> 1) >> j & 1)
+ ((hi ^ hi >> 1) >> j & 1);
curve25519_1.Curve25519.mont_dbl(yx[2], yz[2], t1[k], t2[k], yx[0], yz[0]);
k = (di >> j & 2) ^ ((di >> j & 1) << 1);
curve25519_1.Curve25519.mont_add(t1[1], t2[1], t1[k], t2[k], yx[1], yz[1], p[di >> j & 1]);
curve25519_1.Curve25519.mont_add(t1[2], t2[2], t1[0], t2[0], yx[2], yz[2], s[((vi ^ hi) >> j & 2) >> 1]);
}
}
k = (vi & 1) + (hi & 1);
curve25519_1.Curve25519.recip(t1[0], yz[k], 0);
curve25519_1.Curve25519.mul(t1[1], yx[k], t1[0]);
let Y = [];
curve25519_1.Curve25519.pack(t1[1], Y);
return Y;
}
/* Key-pair generation
* P [out] your public key
* s [out] your private key for signing
* k [out] your private key for key agreement
* k [in] 32 random bytes
* s may be NULL if you don't care
*
* WARNING: if s is not NULL, this function has data-dependent timing */
static keygen(k) {
let P = [];
let s = [];
k = k || [];
curve25519_1.Curve25519.clamp(k);
curve25519_1.Curve25519.core(P, s, k, null);
return { p: P, s: s, k: k };
}
/*
* Get private key for encryption
*/
static clamp(k) {
curve25519_1.Curve25519.clamp(k);
return k;
}
/*
* Get shared key for encryption
*/
static sharedkey(privateKey, publicKey) {
let P = [];
curve25519_1.Curve25519.core(P, null, privateKey, publicKey);
return P;
}
}
exports.ECKCDSA = ECKCDSA;
//# sourceMappingURL=ec-kcdsa.js.map