@zlattice/lattice-js
Version:
Lattice blockchain TypeScript SDK with dual module support (CJS + ESM)
212 lines • 6.67 kB
JavaScript
import { Hash, createView, toBytes, wrapConstructor, } from "../../crypto/sm3/utils.js";
const BoolA = (A, B, C) => (A & B) | (A & C) | (B & C);
const BoolB = (A, B, C) => A ^ B ^ C;
const BoolC = (A, B, C) => (A & B) | (~A & C);
// Polyfill for Safari 14
function setBigUint64(view, byteOffset, value, isLE) {
if (typeof view.setBigUint64 === "function")
view.setBigUint64(byteOffset, value, isLE);
const _32n = BigInt(32);
const _u32_max = BigInt(0xffffffff);
const wh = Number((value >> _32n) & _u32_max);
const wl = Number(value & _u32_max);
const h = isLE ? 4 : 0;
const l = isLE ? 0 : 4;
view.setUint32(byteOffset + h, wh, isLE);
view.setUint32(byteOffset + l, wl, isLE);
}
/**
* 循环左移
*/
export function rotl(x, n) {
const s = n & 31;
return (x << s) | (x >>> (32 - s));
}
/**
* 二进制异或运算
*/
function xor(x, y) {
const result = new Uint8Array(x.length);
for (let i = x.length - 1; i >= 0; i--)
result[i] = (x[i] ^ y[i]) & 0xff;
return result;
}
/**
* 压缩函数中的置换函数 P0(X) = X xor (X <<< 9) xor (X <<< 17)
*/
function P0(X) {
return X ^ rotl(X, 9) ^ rotl(X, 17);
}
/**
* 消息扩展中的置换函数 P1(X) = X xor (X <<< 15) xor (X <<< 23)
*/
function P1(X) {
return X ^ rotl(X, 15) ^ rotl(X, 23);
}
// Base SHA2 class (RFC 6234)
export class SHA2 extends Hash {
constructor(blockLen, outputLen, padOffset, isLE) {
super();
this.blockLen = blockLen;
this.outputLen = outputLen;
this.padOffset = padOffset;
this.isLE = isLE;
this.finished = false;
this.length = 0;
this.pos = 0;
this.destroyed = false;
this.buffer = new Uint8Array(blockLen);
this.view = createView(this.buffer);
}
update(data) {
const { view, buffer, blockLen } = this;
data = toBytes(data);
const len = data.length;
for (let pos = 0; pos < len;) {
const take = Math.min(blockLen - this.pos, len - pos);
if (take === blockLen) {
const dataView = createView(data);
for (; blockLen <= len - pos; pos += blockLen)
this.process(dataView, pos);
continue;
}
buffer.set(data.subarray(pos, pos + take), this.pos);
this.pos += take;
pos += take;
if (this.pos === blockLen) {
this.process(view, 0);
this.pos = 0;
}
}
this.length += data.length;
this.roundClean();
return this;
}
digestInto(out) {
this.finished = true;
const { buffer, view, blockLen, isLE } = this;
let { pos } = this;
buffer[pos++] = 0b10000000;
this.buffer.subarray(pos).fill(0);
if (this.padOffset > blockLen - pos) {
this.process(view, 0);
pos = 0;
}
for (let i = pos; i < blockLen; i++)
buffer[i] = 0;
setBigUint64(view, blockLen - 8, BigInt(this.length * 8), isLE);
this.process(view, 0);
const oview = createView(out);
const len = this.outputLen;
if (len % 4)
throw new Error("_sha2: outputLen should be aligned to 32bit");
const outLen = len / 4;
const state = this.get();
if (outLen > state.length)
throw new Error("_sha2: outputLen bigger than state");
for (let i = 0; i < outLen; i++)
oview.setUint32(4 * i, state[i], isLE);
}
digest() {
const { buffer, outputLen } = this;
this.digestInto(buffer);
const res = buffer.slice(0, outputLen);
this.destroy();
return res;
}
_cloneInto(to) {
to || (to = new this.constructor());
to.set(...this.get());
const { blockLen, buffer, length, finished, destroyed, pos } = this;
to.length = length;
to.pos = pos;
to.finished = finished;
to.destroyed = destroyed;
if (length % blockLen)
to.buffer.set(buffer);
return to;
}
}
const IV = new Uint32Array([
0x7380166f, 0x4914b2b9, 0x172442d7, 0xda8a0600, 0xa96f30bc, 0x163138aa,
0xe38dee4d, 0xb0fb0e4e,
]);
const SM3_W = new Uint32Array(68);
const SM3_M = new Uint32Array(64);
const T1 = 0x79cc4519;
const T2 = 0x7a879d8a;
class SM3 extends SHA2 {
constructor() {
super(64, 32, 8, false);
this.A = IV[0] | 0;
this.B = IV[1] | 0;
this.C = IV[2] | 0;
this.D = IV[3] | 0;
this.E = IV[4] | 0;
this.F = IV[5] | 0;
this.G = IV[6] | 0;
this.H = IV[7] | 0;
}
get() {
const { A, B, C, D, E, F, G, H } = this;
return [A, B, C, D, E, F, G, H];
}
set(A, B, C, D, E, F, G, H) {
this.A = A | 0;
this.B = B | 0;
this.C = C | 0;
this.D = D | 0;
this.E = E | 0;
this.F = F | 0;
this.G = G | 0;
this.H = H | 0;
}
process(view, offset) {
for (let i = 0; i < 16; i++, offset += 4)
SM3_W[i] = view.getUint32(offset, false);
for (let i = 16; i < 68; i++) {
SM3_W[i] =
P1(SM3_W[i - 16] ^ SM3_W[i - 9] ^ rotl(SM3_W[i - 3], 15)) ^
rotl(SM3_W[i - 13], 7) ^
SM3_W[i - 6];
}
for (let i = 0; i < 64; i++) {
SM3_M[i] = SM3_W[i] ^ SM3_W[i + 4];
}
let { A, B, C, D, E, F, G, H } = this;
for (let j = 0; j < 64; j++) {
const small = j >= 0 && j <= 15;
const T = small ? T1 : T2;
const SS1 = rotl(rotl(A, 12) + E + rotl(T, j), 7);
const SS2 = SS1 ^ rotl(A, 12);
const TT1 = ((small ? BoolB(A, B, C) : BoolA(A, B, C)) + D + SS2 + SM3_M[j]) | 0;
const TT2 = ((small ? BoolB(E, F, G) : BoolC(E, F, G)) + H + SS1 + SM3_W[j]) | 0;
D = C;
C = rotl(B, 9);
B = A;
A = TT1;
H = G;
G = rotl(F, 19);
F = E;
E = P0(TT2);
}
A = (A ^ this.A) | 0;
B = (B ^ this.B) | 0;
C = (C ^ this.C) | 0;
D = (D ^ this.D) | 0;
E = (E ^ this.E) | 0;
F = (F ^ this.F) | 0;
G = (G ^ this.G) | 0;
H = (H ^ this.H) | 0;
this.set(A, B, C, D, E, F, G, H);
}
roundClean() {
SM3_W.fill(0);
}
destroy() {
this.set(0, 0, 0, 0, 0, 0, 0, 0);
this.buffer.fill(0);
}
}
export const sm3 = wrapConstructor(() => new SM3());
//# sourceMappingURL=sm3.js.map