mirror of
https://github.com/swc-project/swc.git
synced 2024-12-01 09:52:57 +03:00
392 lines
8.9 KiB
TypeScript
392 lines
8.9 KiB
TypeScript
|
// Loaded from https://raw.githubusercontent.com/aricart/tweetnacl-deno/import-type-fixes/src/sign.ts
|
||
|
|
||
|
|
||
|
import { ByteArray, NumArray } from './array.ts';
|
||
|
import { _verify_32 } from './verify.ts';
|
||
|
import { gf, gf0, gf1, D2, A, D, S, M, X, Y, Z, I } from './core.ts';
|
||
|
import { randomBytes } from './random.ts';
|
||
|
import { set25519, sel25519, inv25519, pack25519, unpack25519, par25519, neq25519 } from './curve25519.ts';
|
||
|
import { _hash } from './hash.ts';
|
||
|
import { checkArrayTypes } from './check.ts';
|
||
|
|
||
|
export const enum SignLength {
|
||
|
PublicKey = 32, // public key bytes
|
||
|
SecretKey = 64, // secret key bytes
|
||
|
Seed = 32, // seed bytes
|
||
|
Signature = 64, // signature bytes
|
||
|
}
|
||
|
|
||
|
export interface SignKeyPair {
|
||
|
publicKey: ByteArray;
|
||
|
secretKey: ByteArray;
|
||
|
}
|
||
|
|
||
|
export function sign(msg: ByteArray, secretKey: ByteArray): ByteArray {
|
||
|
checkArrayTypes(msg, secretKey);
|
||
|
|
||
|
if (secretKey.length !== SignLength.SecretKey)
|
||
|
throw new Error('bad secret key size');
|
||
|
|
||
|
const signedMsg = ByteArray(SignLength.Signature + msg.length);
|
||
|
|
||
|
_sign(signedMsg, msg, msg.length, secretKey);
|
||
|
|
||
|
return signedMsg;
|
||
|
}
|
||
|
|
||
|
export function sign_open(signedMsg: ByteArray, publicKey: ByteArray): ByteArray | undefined {
|
||
|
checkArrayTypes(signedMsg, publicKey);
|
||
|
|
||
|
if (publicKey.length !== SignLength.PublicKey)
|
||
|
throw new Error('bad public key size');
|
||
|
|
||
|
const tmp = ByteArray(signedMsg.length);
|
||
|
|
||
|
const mlen = _sign_open(tmp, signedMsg, signedMsg.length, publicKey);
|
||
|
|
||
|
if (mlen < 0) return;
|
||
|
|
||
|
const m = ByteArray(mlen);
|
||
|
|
||
|
for (let i = 0; i < m.length; i++) m[i] = tmp[i];
|
||
|
|
||
|
return m;
|
||
|
}
|
||
|
|
||
|
export function sign_detached(msg: ByteArray, secretKey: ByteArray): ByteArray {
|
||
|
const signedMsg = sign(msg, secretKey);
|
||
|
|
||
|
const sig = ByteArray(SignLength.Signature);
|
||
|
|
||
|
for (let i = 0; i < sig.length; i++) sig[i] = signedMsg[i];
|
||
|
|
||
|
return sig;
|
||
|
}
|
||
|
|
||
|
export function sign_detached_verify(msg: ByteArray, sig: ByteArray, publicKey: ByteArray): boolean {
|
||
|
checkArrayTypes(msg, sig, publicKey);
|
||
|
|
||
|
if (sig.length !== SignLength.Signature)
|
||
|
throw new Error('bad signature size');
|
||
|
|
||
|
if (publicKey.length !== SignLength.PublicKey)
|
||
|
throw new Error('bad public key size');
|
||
|
|
||
|
const sm = ByteArray(SignLength.Signature + msg.length);
|
||
|
const m = ByteArray(SignLength.Signature + msg.length);
|
||
|
|
||
|
let i;
|
||
|
for (i = 0; i < SignLength.Signature; i++) sm[i] = sig[i];
|
||
|
for (i = 0; i < msg.length; i++) sm[i + SignLength.Signature] = msg[i];
|
||
|
|
||
|
return _sign_open(m, sm, sm.length, publicKey) >= 0;
|
||
|
}
|
||
|
|
||
|
export function sign_keyPair(): SignKeyPair {
|
||
|
const pk = ByteArray(SignLength.PublicKey);
|
||
|
const sk = ByteArray(SignLength.SecretKey);
|
||
|
|
||
|
_sign_keypair(pk, sk, false);
|
||
|
|
||
|
return { publicKey: pk, secretKey: sk };
|
||
|
}
|
||
|
|
||
|
export function sign_keyPair_fromSecretKey(secretKey: ByteArray): SignKeyPair {
|
||
|
checkArrayTypes(secretKey);
|
||
|
|
||
|
if (secretKey.length !== SignLength.SecretKey)
|
||
|
throw new Error('bad secret key size');
|
||
|
|
||
|
const pk = ByteArray(SignLength.PublicKey);
|
||
|
|
||
|
for (let i = 0; i < pk.length; i++) pk[i] = secretKey[32 + i];
|
||
|
|
||
|
return { publicKey: pk, secretKey: ByteArray(secretKey) };
|
||
|
}
|
||
|
|
||
|
export function sign_keyPair_fromSeed(seed: ByteArray): SignKeyPair {
|
||
|
checkArrayTypes(seed);
|
||
|
|
||
|
if (seed.length !== SignLength.Seed)
|
||
|
throw new Error('bad seed size');
|
||
|
|
||
|
const pk = ByteArray(SignLength.PublicKey);
|
||
|
const sk = ByteArray(SignLength.SecretKey);
|
||
|
|
||
|
for (let i = 0; i < 32; i++) sk[i] = seed[i];
|
||
|
|
||
|
_sign_keypair(pk, sk, true);
|
||
|
|
||
|
return { publicKey: pk, secretKey: sk };
|
||
|
}
|
||
|
|
||
|
// low level
|
||
|
|
||
|
function _sign_keypair(pk: ByteArray, sk: ByteArray, seeded: boolean): number {
|
||
|
const d = ByteArray(64);
|
||
|
const p = [gf(), gf(), gf(), gf()];
|
||
|
let i;
|
||
|
|
||
|
if (!seeded) sk.set(randomBytes(32));
|
||
|
|
||
|
_hash(d, sk, 32);
|
||
|
d[0] &= 248;
|
||
|
d[31] &= 127;
|
||
|
d[31] |= 64;
|
||
|
|
||
|
scalarbase(p, d);
|
||
|
pack(pk, p);
|
||
|
|
||
|
for (i = 0; i < 32; i++) sk[i + 32] = pk[i];
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
// Note: difference from C - smlen returned, not passed as argument.
|
||
|
function _sign(sm: ByteArray, m: ByteArray, n: number, sk: ByteArray): number {
|
||
|
const d = ByteArray(64), h = ByteArray(64), r = ByteArray(64);
|
||
|
const x = NumArray(64);
|
||
|
const p = [gf(), gf(), gf(), gf()];
|
||
|
let i, j;
|
||
|
|
||
|
_hash(d, sk, 32);
|
||
|
|
||
|
d[0] &= 248;
|
||
|
d[31] &= 127;
|
||
|
d[31] |= 64;
|
||
|
|
||
|
const smlen = n + 64;
|
||
|
|
||
|
for (i = 0; i < n; i++) sm[64 + i] = m[i];
|
||
|
for (i = 0; i < 32; i++) sm[32 + i] = d[32 + i];
|
||
|
|
||
|
_hash(r, sm.subarray(32), n + 32);
|
||
|
reduce(r);
|
||
|
scalarbase(p, r);
|
||
|
pack(sm, p);
|
||
|
|
||
|
for (i = 32; i < 64; i++) sm[i] = sk[i];
|
||
|
|
||
|
_hash(h, sm, n + 64);
|
||
|
reduce(h);
|
||
|
|
||
|
for (i = 0; i < 64; i++) x[i] = 0;
|
||
|
for (i = 0; i < 32; i++) x[i] = r[i];
|
||
|
for (i = 0; i < 32; i++) {
|
||
|
for (j = 0; j < 32; j++) {
|
||
|
x[i + j] += h[i] * d[j];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
modL(sm.subarray(32), x);
|
||
|
|
||
|
return smlen;
|
||
|
}
|
||
|
|
||
|
function _sign_open(m: ByteArray, sm: ByteArray, n: number, pk: ByteArray): number {
|
||
|
const t = ByteArray(32), h = ByteArray(64);
|
||
|
const p = [gf(), gf(), gf(), gf()], q = [gf(), gf(), gf(), gf()];
|
||
|
let i, mlen;
|
||
|
|
||
|
mlen = -1;
|
||
|
|
||
|
if (n < 64 || unpackneg(q, pk)) return -1;
|
||
|
|
||
|
for (i = 0; i < n; i++) m[i] = sm[i];
|
||
|
for (i = 0; i < 32; i++) m[i + 32] = pk[i];
|
||
|
|
||
|
_hash(h, m, n);
|
||
|
reduce(h);
|
||
|
scalarmult(p, q, h);
|
||
|
|
||
|
scalarbase(q, sm.subarray(32));
|
||
|
|
||
|
add(p, q);
|
||
|
pack(t, p);
|
||
|
|
||
|
n -= 64;
|
||
|
|
||
|
if (_verify_32(sm, 0, t, 0)) {
|
||
|
for (i = 0; i < n; i++) m[i] = 0;
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < n; i++) m[i] = sm[i + 64];
|
||
|
|
||
|
mlen = n;
|
||
|
|
||
|
return mlen;
|
||
|
}
|
||
|
|
||
|
export function scalarbase(p: Float64Array[], s: ByteArray) {
|
||
|
const q = [gf(), gf(), gf(), gf()];
|
||
|
|
||
|
set25519(q[0], X);
|
||
|
set25519(q[1], Y);
|
||
|
set25519(q[2], gf1);
|
||
|
|
||
|
M(q[3], X, Y);
|
||
|
|
||
|
scalarmult(p, q, s);
|
||
|
}
|
||
|
|
||
|
export function scalarmult(p: Float64Array[], q: NumArray[], s: ByteArray) {
|
||
|
let b, i;
|
||
|
|
||
|
set25519(p[0], gf0);
|
||
|
set25519(p[1], gf1);
|
||
|
set25519(p[2], gf1);
|
||
|
set25519(p[3], gf0);
|
||
|
|
||
|
for (i = 255; i >= 0; --i) {
|
||
|
b = (s[(i / 8) | 0] >> (i & 7)) & 1;
|
||
|
cswap(p, q, b);
|
||
|
add(q, p);
|
||
|
add(p, p);
|
||
|
cswap(p, q, b);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function pack(r: ByteArray, p: NumArray[]) {
|
||
|
const tx = gf(), ty = gf(), zi = gf();
|
||
|
|
||
|
inv25519(zi, p[2]);
|
||
|
|
||
|
M(tx, p[0], zi);
|
||
|
M(ty, p[1], zi);
|
||
|
|
||
|
pack25519(r, ty);
|
||
|
|
||
|
r[31] ^= par25519(tx) << 7;
|
||
|
}
|
||
|
|
||
|
function unpackneg(r: NumArray[], p: ByteArray) {
|
||
|
const
|
||
|
t = gf(), chk = gf(), num = gf(),
|
||
|
den = gf(), den2 = gf(), den4 = gf(),
|
||
|
den6 = gf();
|
||
|
|
||
|
set25519(r[2], gf1);
|
||
|
unpack25519(r[1], p);
|
||
|
S(num, r[1]);
|
||
|
M(den, num, D);
|
||
|
Z(num, num, r[2]);
|
||
|
A(den, r[2], den);
|
||
|
|
||
|
S(den2, den);
|
||
|
S(den4, den2);
|
||
|
M(den6, den4, den2);
|
||
|
M(t, den6, num);
|
||
|
M(t, t, den);
|
||
|
|
||
|
pow2523(t, t);
|
||
|
M(t, t, num);
|
||
|
M(t, t, den);
|
||
|
M(t, t, den);
|
||
|
M(r[0], t, den);
|
||
|
|
||
|
S(chk, r[0]);
|
||
|
M(chk, chk, den);
|
||
|
if (neq25519(chk, num)) M(r[0], r[0], I);
|
||
|
|
||
|
S(chk, r[0]);
|
||
|
M(chk, chk, den);
|
||
|
if (neq25519(chk, num)) return -1;
|
||
|
|
||
|
if (par25519(r[0]) === (p[31] >> 7)) Z(r[0], gf0, r[0]);
|
||
|
|
||
|
M(r[3], r[0], r[1]);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
function reduce(r: ByteArray) {
|
||
|
const x = NumArray(64);
|
||
|
let i;
|
||
|
|
||
|
for (i = 0; i < 64; i++) x[i] = r[i];
|
||
|
for (i = 0; i < 64; i++) r[i] = 0;
|
||
|
|
||
|
modL(r, x);
|
||
|
}
|
||
|
|
||
|
const L = NumArray([0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10]);
|
||
|
|
||
|
function modL(r: ByteArray, x: NumArray) {
|
||
|
let carry, i, j, k;
|
||
|
|
||
|
for (i = 63; i >= 32; --i) {
|
||
|
carry = 0;
|
||
|
|
||
|
for (j = i - 32, k = i - 12; j < k; ++j) {
|
||
|
x[j] += carry - 16 * x[i] * L[j - (i - 32)];
|
||
|
carry = (x[j] + 128) >> 8;
|
||
|
x[j] -= carry * 256;
|
||
|
}
|
||
|
|
||
|
x[j] += carry;
|
||
|
x[i] = 0;
|
||
|
}
|
||
|
|
||
|
carry = 0;
|
||
|
|
||
|
for (j = 0; j < 32; j++) {
|
||
|
x[j] += carry - (x[31] >> 4) * L[j];
|
||
|
carry = x[j] >> 8;
|
||
|
x[j] &= 255;
|
||
|
}
|
||
|
|
||
|
for (j = 0; j < 32; j++) x[j] -= carry * L[j];
|
||
|
|
||
|
for (i = 0; i < 32; i++) {
|
||
|
x[i + 1] += x[i] >> 8;
|
||
|
r[i] = x[i] & 255;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function add(p: NumArray[], q: NumArray[]) {
|
||
|
const
|
||
|
a = gf(), b = gf(), c = gf(),
|
||
|
d = gf(), e = gf(), f = gf(),
|
||
|
g = gf(), h = gf(), t = gf();
|
||
|
|
||
|
Z(a, p[1], p[0]);
|
||
|
Z(t, q[1], q[0]);
|
||
|
M(a, a, t);
|
||
|
A(b, p[0], p[1]);
|
||
|
A(t, q[0], q[1]);
|
||
|
M(b, b, t);
|
||
|
M(c, p[3], q[3]);
|
||
|
M(c, c, D2);
|
||
|
M(d, p[2], q[2]);
|
||
|
A(d, d, d);
|
||
|
Z(e, b, a);
|
||
|
Z(f, d, c);
|
||
|
A(g, d, c);
|
||
|
A(h, b, a);
|
||
|
|
||
|
M(p[0], e, f);
|
||
|
M(p[1], h, g);
|
||
|
M(p[2], g, f);
|
||
|
M(p[3], e, h);
|
||
|
}
|
||
|
|
||
|
function cswap(p: NumArray[], q: NumArray[], b: number) {
|
||
|
for (let i = 0; i < 4; i++) {
|
||
|
sel25519(p[i], q[i], b);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function pow2523(o: NumArray, i: NumArray) {
|
||
|
const c = gf();
|
||
|
let a;
|
||
|
|
||
|
for (a = 0; a < 16; a++) c[a] = i[a];
|
||
|
|
||
|
for (a = 250; a >= 0; a--) {
|
||
|
S(c, c);
|
||
|
if (a !== 1) M(c, c, i);
|
||
|
}
|
||
|
|
||
|
for (a = 0; a < 16; a++) o[a] = c[a];
|
||
|
}
|