UNPKG

@zlattice/lattice-js

Version:

Lattice blockchain TypeScript SDK with dual module support (CJS + ESM)

192 lines 5.96 kB
/* eslint-disable class-methods-use-this */ import * as utils from '@noble/curves/abstract/utils'; import { ONE } from './bn.js'; export function bigintToValue(bigint) { let h = bigint.toString(16); if (h[0] !== '-') { // 正数 if (h.length % 2 === 1) h = `0${h}`; // 补齐到整字节 else if (!h.match(/^[0-7]/)) h = `00${h}`; // 非0开头,则补一个全0字节 } else { // 负数 h = h.substring(1); let len = h.length; if (len % 2 === 1) len += 1; // 补齐到整字节 else if (!h.match(/^[0-7]/)) len += 2; // 非0开头,则补一个全0字节 let maskString = ''; for (let i = 0; i < len; i++) maskString += 'f'; const mask = utils.hexToNumber(maskString); // 对绝对值取反,加1 const output = (mask ^ bigint) + ONE; h = output.toString(16).replace(/^-/, ''); } return h; } class ASN1Object { constructor(tlv = null, t = '00', l = '00', v = '') { this.tlv = tlv; this.t = t; this.l = l; this.v = v; } /** * 获取 der 编码比特流16进制串 */ getEncodedHex() { if (!this.tlv) { this.v = this.getValue(); this.l = this.getLength(); this.tlv = this.t + this.l + this.v; } return this.tlv; } getLength() { const n = this.v.length / 2; // 字节数 let nHex = n.toString(16); if (nHex.length % 2 === 1) nHex = `0${nHex}`; // 补齐到整字节 if (n < 128) { // 短格式,以 0 开头 return nHex; } // 长格式,以 1 开头 const head = 128 + nHex.length / 2; // 1(1位) + 真正的长度占用字节数(7位) + 真正的长度 return `${head.toString(16)}${nHex}`; } getValue() { return ''; } } class DERInteger extends ASN1Object { constructor(bigint) { super(); this.t = '02'; // 整型标签说明 if (bigint) this.v = bigintToValue(bigint); } getValue() { return this.v; } } class DEROctetString extends ASN1Object { constructor(s) { super(); this.s = s; this.hV = ''; this.t = '04'; // octstr 标签说明 if (s) this.v = s.toLowerCase(); } getValue() { return this.v; } } class DERSequence extends ASN1Object { constructor(asn1Array) { super(); this.asn1Array = asn1Array; this.t = '30'; } getValue() { this.v = this.asn1Array.map(asn1Object => asn1Object.getEncodedHex()).join(''); return this.v; } } /** * 获取 l 占用字节数 */ function getLenOfL(str, start) { if (+str[start + 2] < 8) return 1; // l 以0开头,则表示短格式,只占一个字节 // 长格式,取第一个字节后7位作为长度真正占用字节数,再加上本身 const encoded = str.slice(start + 2, start + 6); const headHex = encoded.slice(0, 2); const head = Number.parseInt(headHex, 16); const nHexLength = (head - 128) * 2; return nHexLength; } /** * 获取 l */ function getL(str, start) { // 获取 l const len = getLenOfL(str, start); const l = str.substring(start + 2, start + 2 + len * 2); if (!l) return -1; const bigint = +l[0] < 8 ? utils.hexToNumber(l) : utils.hexToNumber(l.substring(2)); return +bigint.toString(); } /** * 获取 v 的位置 */ function getStartOfV(str, start) { const len = getLenOfL(str, start); return start + (len + 1) * 2; } /** * ASN.1 der 编码,针对 sm2 签名 */ export function encodeDer(r, s) { const derR = new DERInteger(r); const derS = new DERInteger(s); const derSeq = new DERSequence([derR, derS]); return derSeq.getEncodedHex(); } export function encodeEnc(x, y, hash, cipher) { const derX = new DERInteger(x); const derY = new DERInteger(y); const derHash = new DEROctetString(hash); const derCipher = new DEROctetString(cipher); const derSeq = new DERSequence([derX, derY, derHash, derCipher]); return derSeq.getEncodedHex(); } /** * 解析 ASN.1 der,针对 sm2 验签 */ export function decodeDer(input) { // 结构: // input = | tSeq | lSeq | vSeq | // vSeq = | tR | lR | vR | tS | lS | vS | const start = getStartOfV(input, 0); const vIndexR = getStartOfV(input, start); const lR = getL(input, start); const vR = input.substring(vIndexR, vIndexR + lR * 2); const nextStart = vIndexR + vR.length; const vIndexS = getStartOfV(input, nextStart); const lS = getL(input, nextStart); const vS = input.substring(vIndexS, vIndexS + lS * 2); // const r = new BigInteger(vR, 16) // const s = new BigInteger(vS, 16) const r = utils.hexToNumber(vR); const s = utils.hexToNumber(vS); return { r, s }; } /** * 解析 ASN.1 der,针对 sm2 加密 */ export function decodeEnc(input) { // Extracts a sequence from the input based on the current start index. function extractSequence(input, start) { const vIndex = getStartOfV(input, start); const length = getL(input, start); const value = input.substring(vIndex, vIndex + length * 2); const nextStart = vIndex + value.length; return { value, nextStart }; } const start = getStartOfV(input, 0); const { value: vR, nextStart: startS } = extractSequence(input, start); const { value: vS, nextStart: startHash } = extractSequence(input, startS); const { value: hash, nextStart: startCipher } = extractSequence(input, startHash); const { value: cipher } = extractSequence(input, startCipher); const x = utils.hexToNumber(vR); const y = utils.hexToNumber(vS); return { x, y, hash, cipher }; } //# sourceMappingURL=asn1.js.map