js sm3

// 左补0到指定长度
function leftPad(str, totalLength) {
    const len = str.length;
    return Array(totalLength > len ? ((totalLength - len) + 1) : 0).join(0) + str;
}

// 二进制转化为十六进制
function binary2hex(binary) {
    const binaryLength = 8;
    let hex = '';
    for (let i = 0; i < binary.length / binaryLength; i += 1) {
        hex += leftPad(parseInt(binary.substr(i * binaryLength, binaryLength), 2).toString(16), 2);
    }
    return hex;
}

// 十六进制转化为二进制
function hex2binary(hex) {
    const hexLength = 2;
    let binary = '';
    for (let i = 0; i < hex.length / hexLength; i += 1) {
        binary += leftPad(parseInt(hex.substr(i * hexLength, hexLength), 16).toString(2), 8);
    }
    return binary;
}

// utf16码点值转化为utf8二进制
function utf16CodePoint2utf8Binary(ch) {
    const utf8Arr = [];
    const codePoint = ch.codePointAt(0);

    if (codePoint >= 0x00 && codePoint <= 0x7f) {
        utf8Arr.push(codePoint);
    } else if (codePoint >= 0x80 && codePoint <= 0x7ff) {
        utf8Arr.push((192 | (31 & (codePoint >> 6))));
        utf8Arr.push((128 | (63 & codePoint)))
    } else if ((codePoint >= 0x800 && codePoint <= 0xd7ff) || (codePoint >= 0xe000 && codePoint <= 0xffff)) {
        utf8Arr.push((224 | (15 & (codePoint >> 12))));
        utf8Arr.push((128 | (63 & (codePoint >> 6))));
        utf8Arr.push((128 | (63 & codePoint)))
    } else if (codePoint >= 0x10000 && codePoint <= 0x10ffff) {
        utf8Arr.push((240 | (7 & (codePoint >> 18))));
        utf8Arr.push((128 | (63 & (codePoint >> 12))));
        utf8Arr.push((128 | (63 & (codePoint >> 6))));
        utf8Arr.push((128 | (63 & codePoint)))
    }

    let binary = '';
    //  for (let utf8Code of utf8Arr) {
    //    const b = utf8Code.toString(2);
    //    binary += leftPad(b, Math.ceil(b.length / 8) * 8);
    //  }

    for (let i = 0; i < utf8Arr.length; i++) {
        let utf8Code = utf8Arr[i];
        const b = utf8Code.toString(2);
        binary += leftPad(b, Math.ceil(b.length / 8) * 8);
    }

    return binary;
}

// 普通字符串转化为二进制
function str2binary(str) {
    let binary = '';
    //  for (const ch of str) {
    //    binary += utf16CodePoint2utf8Binary(ch);
    //  }

    for (let i = 0; i < str.length; i++) {
        binary += utf16CodePoint2utf8Binary(str[i]);
    }
    return binary;
}

// 循环左移
function rol(str, n) {
    return str.substring(n % str.length) + str.substr(0, n % str.length);
}

// 二进制运算
function binaryCal(x, y, method) {
    const a = x || '';
    const b = y || '';
    const result = [];
    let prevResult;
    // for (let i = 0; i < a.length; i += 1) { // 小端
    for (let i = a.length - 1; i >= 0; i -= 1) {
        // 大端
        prevResult = method(a[i], b[i], prevResult);
        result[i] = prevResult[0];
    }
    // console.log(`x     :${x}\ny     :${y}\nresult:${result.join('')}\n`);
    return result.join('');
}

// 二进制异或运算
function xor(x, y) {
    return binaryCal(x, y, (a, b) => [(a === b ? '0' : '1')]);
}

// 二进制与运算
function and(x, y) {
    return binaryCal(x, y, (a, b) => [(a === '1' && b === '1' ? '1' : '0')]);
}

// 二进制或运算
function or(x, y) {
    return binaryCal(x, y, (a, b) => [(a === '1' || b === '1' ? '1' : '0')]);
    // a === '0' && b === '0' ? '0' : '1'
}

// 二进制与运算
function add(x, y) {
    const result = binaryCal(x, y, (a, b, prevResult) => {
            const carry = prevResult ? prevResult[1] : '0' || '0';
            if (a !== b)
                return [carry === '0' ? '1' : '0', carry];
            // a,b不等时,carry不变,结果与carry相反
            // a,b相等时,结果等于原carry,新carry等于a
            return [carry, a];
        }
    );
    // console.log('x: ' + x + '\ny: ' + y + '\n=  ' + result + '\n');
    return result;
}

// 二进制非运算
function not(x) {
    return binaryCal(x, undefined, a => [a === '1' ? '0' : '1']);
}

function calMulti(method) {
    return (...arr) => arr.reduce((prev, curr) => method(prev, curr));
}


// 压缩函数中的置换函数 P1(X) = X xor (X <<< 9) xor (X <<< 17)
function P0(X) {
    return calMulti(xor)(X, rol(X, 9), rol(X, 17));
}

// 消息扩展中的置换函数 P1(X) = X xor (X <<< 15) xor (X <<< 23)
function P1(X) {
    return calMulti(xor)(X, rol(X, 15), rol(X, 23));
}

// 布尔函数,随j的变化取不同的表达式
function FF(X, Y, Z, j) {
    return j >= 0 && j <= 15 ? calMulti(xor)(X, Y, Z) : calMulti(or)(and(X, Y), and(X, Z), and(Y, Z));
}

// 布尔函数,随j的变化取不同的表达式
function GG(X, Y, Z, j) {
    return j >= 0 && j <= 15 ? calMulti(xor)(X, Y, Z) : or(and(X, Y), and(not(X), Z));
}

// 常量,随j的变化取不同的值
function SM3T(j) {
    return j >= 0 && j <= 15 ? hex2binary('79cc4519') : hex2binary('7a879d8a');
}


function CF(V, Bi) {
    // 消息扩展
    const wordLength = 32;
    const W = [];
    const M = [];
    // W'

    // 将消息分组B划分为16个字W0, W1,…… ,W15 (字为长度为32的比特串)
    for (let i = 0; i < 16; i += 1) {
        W.push(Bi.substr(i * wordLength, wordLength));
    }

    // W[j] <- P1(W[j−16] xor W[j−9] xor (W[j−3] <<< 15)) xor (W[j−13] <<< 7) xor W[j−6]
    for (let j = 16; j < 68; j += 1) {
        W.push(calMulti(xor)(P1(calMulti(xor)(W[j - 16], W[j - 9], rol(W[j - 3], 15))), rol(W[j - 13], 7), W[j - 6]));
    }

    // W′[j] = W[j] xor W[j+4]
    for (let j = 0; j < 64; j += 1) {
        M.push(xor(W[j], W[j + 4]));
    }

    // 压缩
    const wordRegister = [];
    // 字寄存器
    for (let j = 0; j < 8; j += 1) {
        wordRegister.push(V.substr(j * wordLength, wordLength));
    }

    let A = wordRegister[0];
    let B = wordRegister[1];
    let C = wordRegister[2];
    let D = wordRegister[3];
    let E = wordRegister[4];
    let F = wordRegister[5];
    let G = wordRegister[6];
    let H = wordRegister[7];

    // 中间变量
    let SS1;
    let SS2;
    let TT1;
    let TT2;
    for (let j = 0; j < 64; j += 1) {
        SS1 = rol(calMulti(add)(rol(A, 12), E, rol(SM3T(j), j)), 7);
        SS2 = xor(SS1, rol(A, 12));

        TT1 = calMulti(add)(FF(A, B, C, j), D, SS2, M[j]);
        TT2 = calMulti(add)(GG(E, F, G, j), H, SS1, W[j]);

        D = C;
        C = rol(B, 9);
        B = A;
        A = TT1;
        H = G;
        G = rol(F, 19);
        F = E;
        E = P0(TT2);
    }

    return xor(Array(A, B, C, D, E, F, G, H).join(''), V);
}

function sm3(content) {
    let binary = ""
    if (typeof content == 'string') {
        binary = str2binary(content);
    } else {
        for (a of content) {
            binary += a.toString(2).padStart(8, "0");
        }
    }
    // 填充
    const len = binary.length;
    // k是满足len + 1 + k = 448mod512的最小的非负整数
    let k = len % 512;
    // 如果 448 <= (512 % len) < 512,需要多补充 (len % 448) 比特'0'以满足总比特长度为512的倍数
    k = k >= 448 ? 512 - (k % 448) - 1 : 448 - k - 1;
    const m = `${binary}1${leftPad('', k)}${leftPad(len.toString(2), 64)}`.toString();
    // k个0

    // 迭代压缩
    const n = (len + k + 65) / 512;

    let V = hex2binary('7380166f4914b2b9172442d7da8a0600a96f30bc163138aae38dee4db0fb0e4e');
    for (let i = 0; i <= n - 1; i += 1) {
        const B = m.substr(512 * i, 512);
        V = CF(V, B);
    }
    return binary2hex(V);
}




©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容