sha3_demo

sha3 简单 demo,补全 Vela 没有的 sha3

适配设备:Pro

作者:drific

下载量:9 · 点赞:0

可信源码风险提示:保存或下载前请阅读源码和权限声明。
SHA-25656b89b12bc70664f1a190f99bbd984ee3245e5c956e430686c63bbd2822857e2
/**
Author: Drific && DeepSeek-V4.1-Flash
Email: Drific_pl@163.com
声明:部分注释和代码由AI生成,可能包含不实信息
*/
// ====================================================
//  SHA-3 (Keccak) 纯 JS 实现 —— ES5 兼容版,适用 Vela / QuickJS
// ====================================================

var RC_LO = new Uint32Array([
  0x00000001, 0x00008082, 0x0000808A, 0x80008000,
  0x0000808B, 0x80000001, 0x80008081, 0x00008009,
  0x0000008A, 0x00000088, 0x80008009, 0x8000000A,
  0x8000808B, 0x0000008B, 0x00008089, 0x00008003,
  0x00008002, 0x00000080, 0x0000800A, 0x8000000A,
  0x80008081, 0x00008080, 0x80000001, 0x80008008
]);

var RC_HI = new Uint32Array([
  0x00000000, 0x00000000, 0x80000000, 0x80000000,
  0x00000000, 0x00000000, 0x80000000, 0x80000000,
  0x00000000, 0x00000000, 0x00000000, 0x00000000,
  0x00000000, 0x80000000, 0x80000000, 0x80000000,
  0x80000000, 0x80000000, 0x00000000, 0x80000000,
  0x80000000, 0x80000000, 0x00000000, 0x80000000
]);

var RHO = new Uint8Array([
   0,  1, 62, 28, 27,
  36, 44,  6, 55, 20,
   3, 10, 43, 25, 39,
  41, 45, 15, 21,  8,
  18,  2, 61, 56, 14
]);

var _C = new Uint32Array(10);
var _D = new Uint32Array(10);
var _B = new Uint32Array(50);

function keccakF(state) {
  var x, y, round, idx, i1, i2;
  var lo, hi, cPrevLo, cPrevHi, cNextLo, cNextHi;
  var rotLo, rotHi, r, r2, newX, newY, dstIdx;
  var b0lo, b0hi, b1lo, b1hi, b2lo, b2hi;

  for (round = 0; round < 24; round++) {

    // Theta
    for (x = 0; x < 5; x++) {
      lo = 0; hi = 0;
      for (y = 0; y < 5; y++) {
        idx = 2 * (x + 5 * y);
        lo ^= state[idx];
        hi ^= state[idx + 1];
      }
      _C[2 * x] = lo >>> 0;
      _C[2 * x + 1] = hi >>> 0;
    }

    for (x = 0; x < 5; x++) {
      cPrevLo = _C[2 * ((x + 4) % 5)];
      cPrevHi = _C[2 * ((x + 4) % 5) + 1];
      cNextLo = _C[2 * ((x + 1) % 5)];
      cNextHi = _C[2 * ((x + 1) % 5) + 1];
      rotLo = ((cNextLo << 1) | (cNextHi >>> 31)) >>> 0;
      rotHi = ((cNextHi << 1) | (cNextLo >>> 31)) >>> 0;
      _D[2 * x] = (cPrevLo ^ rotLo) >>> 0;
      _D[2 * x + 1] = (cPrevHi ^ rotHi) >>> 0;
    }

    for (x = 0; x < 5; x++) {
      for (y = 0; y < 5; y++) {
        idx = 2 * (x + 5 * y);
        state[idx] = (state[idx] ^ _D[2 * x]) >>> 0;
        state[idx + 1] = (state[idx + 1] ^ _D[2 * x + 1]) >>> 0;
      }
    }

    // Rho + Pi
    for (x = 0; x < 5; x++) {
      for (y = 0; y < 5; y++) {
        idx = 2 * (x + 5 * y);
        r = RHO[x + 5 * y];
        lo = state[idx];
        hi = state[idx + 1];

        if (r === 0) {
          rotLo = lo; rotHi = hi;
        } else if (r === 32) {
          rotLo = hi; rotHi = lo;
        } else if (r < 32) {
          rotLo = ((lo << r) | (hi >>> (32 - r))) >>> 0;
          rotHi = ((hi << r) | (lo >>> (32 - r))) >>> 0;
        } else {
          r2 = r - 32;
          rotLo = ((hi << r2) | (lo >>> (32 - r2))) >>> 0;
          rotHi = ((lo << r2) | (hi >>> (32 - r2))) >>> 0;
        }

        newX = y;
        newY = (2 * x + 3 * y) % 5;
        dstIdx = 2 * (newX + 5 * newY);
        _B[dstIdx] = rotLo;
        _B[dstIdx + 1] = rotHi;
      }
    }

    // Chi
    for (x = 0; x < 5; x++) {
      for (y = 0; y < 5; y++) {
        idx = 2 * (x + 5 * y);
        i1 = 2 * (((x + 1) % 5) + 5 * y);
        i2 = 2 * (((x + 2) % 5) + 5 * y);
        b0lo = _B[idx];     b0hi = _B[idx + 1];
        b1lo = _B[i1];      b1hi = _B[i1 + 1];
        b2lo = _B[i2];      b2hi = _B[i2 + 1];
        state[idx]     = (b0lo ^ ((~b1lo) & b2lo)) >>> 0;
        state[idx + 1] = (b0hi ^ ((~b1hi) & b2hi)) >>> 0;
      }
    }

    // Iota
    state[0] = (state[0] ^ RC_LO[round]) >>> 0;
    state[1] = (state[1] ^ RC_HI[round]) >>> 0;
  }
}

function absorbBlock(state, bytes, offset, rate) {
  var i, laneIdx, byteInLane, b, shift;
  for (i = 0; i < rate; i++) {
    laneIdx = (i / 8) | 0;
    byteInLane = i % 8;
    b = bytes[offset + i];
    if (byteInLane < 4) {
      shift = 8 * byteInLane;
      state[2 * laneIdx] = (state[2 * laneIdx] ^ (b << shift)) >>> 0;
    } else {
      shift = 8 * (byteInLane - 4);
      state[2 * laneIdx + 1] = (state[2 * laneIdx + 1] ^ (b << shift)) >>> 0;
    }
  }
}

function utf8Encode(str) {
  // Vela 的 QuickJS 部分版本没有 TextEncoder,走纯 JS
  if (typeof TextEncoder !== 'undefined') {
    return new TextEncoder().encode(str);
  }
  var bytes = [];
  for (var i = 0; i < str.length; i++) {
    var c = str.charCodeAt(i);
    if (c < 0x80) bytes.push(c);
    else if (c < 0x800) {
      bytes.push(0xc0 | (c >> 6));
      bytes.push(0x80 | (c & 0x3f));
    } else if (c < 0xd800 || c >= 0xe000) {
      bytes.push(0xe0 | (c >> 12));
      bytes.push(0x80 | ((c >> 6) & 0x3f));
      bytes.push(0x80 | (c & 0x3f));
    } else {
      i++;
      var c2 = str.charCodeAt(i);
      var cp = 0x10000 + (((c & 0x3ff) << 10) | (c2 & 0x3ff));
      bytes.push(0xf0 | (cp >> 18));
      bytes.push(0x80 | ((cp >> 12) & 0x3f));
      bytes.push(0x80 | ((cp >> 6) & 0x3f));
      bytes.push(0x80 | (cp & 0x3f));
    }
  }
  return new Uint8Array(bytes);
}

function sha3(message, bits) {
  var rate, outputLen;
  if (bits === 224)      { rate = 144; outputLen = 28; }
  else if (bits === 256) { rate = 136; outputLen = 32; }
  else if (bits === 384) { rate = 104; outputLen = 48; }
  else if (bits === 512) { rate = 72;  outputLen = 64; }
  else throw new Error('Unsupported SHA-3 variant: ' + bits);

  var msg;
  if (typeof message === 'string')          msg = utf8Encode(message);
  else if (message instanceof Uint8Array)   msg = message;
  else if (message instanceof ArrayBuffer)  msg = new Uint8Array(message);
  else throw new Error('Unsupported message type');

  var state = new Uint32Array(50);
  var offset = 0;
  var len = msg.length;

  while (len - offset >= rate) {
    absorbBlock(state, msg, offset, rate);
    keccakF(state);
    offset += rate;
  }

  var lastBlock = new Uint8Array(rate);
  var remaining = len - offset;
  for (var i = 0; i < remaining; i++) lastBlock[i] = msg[offset + i];
  lastBlock[remaining] = 0x06;
  lastBlock[rate - 1] |= 0x80;
  absorbBlock(state, lastBlock, 0, rate);
  keccakF(state);

  var output = new Uint8Array(outputLen);
  for (var j = 0; j < outputLen; j++) {
    var laneIdx = (j / 8) | 0;
    var byteInLane = j % 8;
    if (byteInLane < 4) {
      output[j] = (state[2 * laneIdx] >>> (8 * byteInLane)) & 0xff;
    } else {
      output[j] = (state[2 * laneIdx + 1] >>> (8 * (byteInLane - 4))) & 0xff;
    }
  }
  return output;
}

function toHex(bytes) {
  var s = '';
  for (var i = 0; i < bytes.length; i++) {
    var h = bytes[i].toString(16);
    s += h.length === 1 ? '0' + h : h;
  }
  return s;
}

function sha3_224(message){return toHex(sha3(message, 224));}
function sha3_256(message){return toHex(sha3(message, 256));}
function sha3_384(message){return toHex(sha3(message, 384));}
function sha3_512(message){return toHex(sha3(message, 512));}

const text = 'abcde'
console.log(`sha_224('${text}') = ${sha3_224(text)}`)
console.log(`sha_256('${text}') = ${sha3_256(text)}`)
console.log(`sha_384('${text}') = ${sha3_384(text)}`)
console.log(`sha_512('${text}') = ${sha3_512(text)}`)