UNPKG

@multiversx/sdk-bls-wasm

Version:

BLS signature for Node.js by WebAssembly

688 lines (670 loc) 22.3 kB
(generator => { if (typeof window === 'object') { const exports = {} if (typeof module !== 'undefined' && module.exports) { module.exports = generator(exports, false) } else { window.bls = generator(exports, false) } } else { generator(exports, true) } })((exports, isNodeJs) => { /* eslint-disable */ exports.BN254 = 0 exports.BN381_1 = 1 exports.BLS12_381 = 5 exports.ethMode = false exports.ETH_MODE_DRAFT_05 = 1 exports.ETH_MODE_DRAFT_06 = 2 exports.ETH_MODE_DRAFT_07 = 3 const setup = (exports, curveType) => { const mod = exports.mod const MCLBN_FP_UNIT_SIZE = 6 const MCLBN_FR_UNIT_SIZE = exports.ethMode ? 4 : 6 const BLS_COMPILER_TIME_VAR_ADJ = exports.ethMode ? 200 : 0 const MCLBN_COMPILED_TIME_VAR = (MCLBN_FR_UNIT_SIZE * 10 + MCLBN_FP_UNIT_SIZE) + BLS_COMPILER_TIME_VAR_ADJ const BLS_ID_SIZE = MCLBN_FR_UNIT_SIZE * 8 const BLS_SECRETKEY_SIZE = MCLBN_FP_UNIT_SIZE * 8 const BLS_PUBLICKEY_SIZE = BLS_SECRETKEY_SIZE * 3 * (exports.ethMode ? 1 : 2) const BLS_SIGNATURE_SIZE = BLS_SECRETKEY_SIZE * 3 * (exports.ethMode ? 2 : 1) const _malloc = size => { return mod._blsMalloc(size) } const _free = pos => { mod._blsFree(pos) } const ptrToAsciiStr = (pos, n) => { let s = '' for (let i = 0; i < n; i++) { s += String.fromCharCode(mod.HEAP8[pos + i]) } return s } const asciiStrToPtr = (pos, s) => { for (let i = 0; i < s.length; i++) { mod.HEAP8[pos + i] = s.charCodeAt(i) } } exports.toHex = (a, start, n) => { let s = '' for (let i = 0; i < n; i++) { s += ('0' + a[start + i].toString(16)).slice(-2) } return s } // Uint8Array to hex string exports.toHexStr = a => { return exports.toHex(a, 0, a.length) } // hex string to Uint8Array exports.fromHexStr = s => { if (s.length & 1) throw new Error('fromHexStr:length must be even ' + s.length) const n = s.length / 2 const a = new Uint8Array(n) for (let i = 0; i < n; i++) { a[i] = parseInt(s.slice(i * 2, i * 2 + 2), 16) } return a } /////////////////////////// const copyToUint32Array = (a, pos) => { a.set(mod.HEAP32.subarray(pos / 4, pos / 4 + a.length)) // for (let i = 0; i < a.length; i++) { // a[i] = mod.HEAP32[pos / 4 + i] // } } const copyFromUint32Array = (pos, a) => { mod.HEAP32.set(a, pos / 4) // for (let i = 0; i < a.length; i++) { // mod.HEAP32[pos / 4 + i] = a[i] // } } ////////////////////////////////// const _wrapGetStr = (func, returnAsStr = true) => { return (x, ioMode = 0) => { const maxBufSize = 3096 const pos = _malloc(maxBufSize) const n = func(pos, maxBufSize, x, ioMode) if (n <= 0) { throw new Error('err gen_str:' + x) } let s = null if (returnAsStr) { s = ptrToAsciiStr(pos, n) } else { s = new Uint8Array(mod.HEAP8.subarray(pos, pos + n)) } _free(pos) return s } } const _wrapSerialize = func => { return _wrapGetStr(func, false) } const _wrapDeserialize = func => { return (x, buf) => { const pos = _malloc(buf.length) mod.HEAP8.set(buf, pos) const r = func(x, pos, buf.length) _free(pos) if (r === 0) throw new Error('err _wrapDeserialize', buf) } } /* argNum : n func(x0, ..., x_(n-1), buf, ioMode) => func(x0, ..., x_(n-1), pos, buf.length, ioMode) */ const _wrapInput = (func, argNum, returnValue = false) => { return function () { const args = [...arguments] const buf = args[argNum] const typeStr = Object.prototype.toString.apply(buf) if (['[object String]', '[object Uint8Array]', '[object Array]'].indexOf(typeStr) < 0) { throw new Error(`err bad type:"${typeStr}". Use String or Uint8Array.`) } const ioMode = args[argNum + 1] // may undefined const pos = _malloc(buf.length) if (typeStr === '[object String]') { asciiStrToPtr(pos, buf) } else { mod.HEAP8.set(buf, pos) } const r = func(...args.slice(0, argNum), pos, buf.length, ioMode) _free(pos) if (returnValue) return r if (r) throw new Error('err _wrapInput ' + buf) } } const callSetter = (func, a, p1, p2) => { const pos = _malloc(a.length * 4) func(pos, p1, p2) // p1, p2 may be undefined copyToUint32Array(a, pos) _free(pos) } const callGetter = (func, a, p1, p2) => { const pos = _malloc(a.length * 4) mod.HEAP32.set(a, pos / 4) const s = func(pos, p1, p2) _free(pos) return s } const callShare = (func, a, size, vec, id) => { const pos = a._allocAndCopy() const idPos = id._allocAndCopy() const vecPos = _malloc(size * vec.length) for (let i = 0; i < vec.length; i++) { copyFromUint32Array(vecPos + size * i, vec[i].a_) } func(pos, vecPos, vec.length, idPos) _free(vecPos) _free(idPos) a._saveAndFree(pos) } const callRecover = (func, a, size, vec, idVec) => { const n = vec.length if (n != idVec.length) throw ('recover:bad length') const secPos = a._alloc() const vecPos = _malloc(size * n) const idVecPos = _malloc(BLS_ID_SIZE * n) for (let i = 0; i < n; i++) { copyFromUint32Array(vecPos + size * i, vec[i].a_) copyFromUint32Array(idVecPos + BLS_ID_SIZE * i, idVec[i].a_) } const r = func(secPos, vecPos, idVecPos, n) _free(idVecPos) _free(vecPos) a._saveAndFree(secPos) if (r) throw ('callRecover') } // change curveType exports.blsInit = (curveType = (exports.ethMode ? exports.BLS12_381 : exports.BN254)) => { const r = mod._blsInit(curveType, MCLBN_COMPILED_TIME_VAR) if (r) throw ('blsInit err ' + r) } exports.getCurveOrder = _wrapGetStr(mod._blsGetCurveOrder) exports.getFieldOrder = _wrapGetStr(mod._blsGetFieldOrder) exports.blsIdSetDecStr = _wrapInput(mod._blsIdSetDecStr, 1) exports.blsIdSetHexStr = _wrapInput(mod._blsIdSetHexStr, 1) exports.blsIdGetDecStr = _wrapGetStr(mod._blsIdGetDecStr) exports.blsIdGetHexStr = _wrapGetStr(mod._blsIdGetHexStr) exports.blsIdSerialize = _wrapSerialize(mod._blsIdSerialize) exports.blsSecretKeySerialize = _wrapSerialize(mod._blsSecretKeySerialize) exports.blsPublicKeySerialize = _wrapSerialize(mod._blsPublicKeySerialize) exports.blsSignatureSerialize = _wrapSerialize(mod._blsSignatureSerialize) exports.blsIdDeserialize = _wrapDeserialize(mod._blsIdDeserialize) exports.blsSecretKeyDeserialize = _wrapDeserialize(mod._blsSecretKeyDeserialize) exports.blsPublicKeyDeserialize = _wrapDeserialize(mod._blsPublicKeyDeserialize) exports.blsSignatureDeserialize = _wrapDeserialize(mod._blsSignatureDeserialize) exports.blsPublicKeySerializeUncompressed = _wrapSerialize(mod._blsPublicKeySerializeUncompressed) exports.blsSignatureSerializeUncompressed = _wrapSerialize(mod._blsSignatureSerializeUncompressed) exports.blsPublicKeyDeserializeUncompressed = _wrapDeserialize(mod._blsPublicKeyDeserializeUncompressed) exports.blsSignatureDeserializeUncompressed = _wrapDeserialize(mod._blsSignatureDeserializeUncompressed) exports.blsSecretKeySetLittleEndian = _wrapInput(mod._blsSecretKeySetLittleEndian, 1) exports.blsSecretKeySetLittleEndianMod = _wrapInput(mod._blsSecretKeySetLittleEndianMod, 1) exports.blsHashToSecretKey = _wrapInput(mod._blsHashToSecretKey, 1) exports.blsSign = _wrapInput(mod._blsSign, 2) exports.blsVerify = _wrapInput(mod._blsVerify, 2, true) class Common { constructor (size) { this.a_ = new Uint32Array(size / 4) } deserializeHexStr (s) { this.deserialize(exports.fromHexStr(s)) } serializeToHexStr () { return exports.toHexStr(this.serialize()) } dump (msg = '') { console.log(msg + this.serializeToHexStr()) } clear () { this.a_.fill(0) } // alloc new array _alloc () { return _malloc(this.a_.length * 4) } // alloc and copy a_ to mod.HEAP32[pos / 4] _allocAndCopy () { const pos = this._alloc() mod.HEAP32.set(this.a_, pos / 4) return pos } // save pos to a_ _save (pos) { this.a_.set(mod.HEAP32.subarray(pos / 4, pos / 4 + this.a_.length)) } // save and free _saveAndFree(pos) { this._save(pos) _free(pos) } // set parameter (p1, p2 may be undefined) _setter (func, p1, p2) { const pos = this._alloc() const r = func(pos, p1, p2) this._saveAndFree(pos) if (r) throw new Error('_setter err') } // getter (p1, p2 may be undefined) _getter (func, p1, p2) { const pos = this._allocAndCopy() const s = func(pos, p1, p2) _free(pos) return s } _isEqual (func, rhs) { const xPos = this._allocAndCopy() const yPos = rhs._allocAndCopy() const r = func(xPos, yPos) _free(yPos) _free(xPos) return r === 1 } // func(y, this) and return y _op1 (func) { const y = new this.constructor() const xPos = this._allocAndCopy() const yPos = y._alloc() func(yPos, xPos) y._saveAndFree(yPos) _free(xPos) return y } // func(z, this, y) and return z _op2 (func, y, Cstr = null) { const z = Cstr ? new Cstr() : new this.constructor() const xPos = this._allocAndCopy() const yPos = y._allocAndCopy() const zPos = z._alloc() func(zPos, xPos, yPos) z._saveAndFree(zPos) _free(yPos) _free(xPos) return z } // func(self, y) _update (func, y) { const xPos = this._allocAndCopy() const yPos = y._allocAndCopy() func(xPos, yPos) _free(yPos) this._saveAndFree(xPos) } } exports.Id = class extends Common { constructor () { super(BLS_ID_SIZE) } setInt (x) { this._setter(mod._blsIdSetInt, x) } isEqual (rhs) { return this._isEqual(mod._blsIdIsEqual, rhs) } deserialize (s) { this._setter(exports.blsIdDeserialize, s) } serialize () { return this._getter(exports.blsIdSerialize) } setStr (s, base = 10) { switch (base) { case 10: this._setter(exports.blsIdSetDecStr, s) return case 16: this._setter(exports.blsIdSetHexStr, s) return default: throw ('BlsId.setStr:bad base:' + base) } } getStr (base = 10) { switch (base) { case 10: return this._getter(exports.blsIdGetDecStr) case 16: return this._getter(exports.blsIdGetHexStr) default: throw ('BlsId.getStr:bad base:' + base) } } setLittleEndian (s) { this._setter(exports.blsSecretKeySetLittleEndian, s) } setLittleEndianMod (s) { this._setter(exports.blsSecretKeySetLittleEndianMod, s) } setByCSPRNG () { const a = new Uint8Array(BLS_ID_SIZE) exports.getRandomValues(a) this.setLittleEndian(a) } } exports.deserializeHexStrToId = s => { const r = new exports.Id() r.deserializeHexStr(s) return r } exports.SecretKey = class extends Common { constructor () { super(BLS_SECRETKEY_SIZE) } setInt (x) { this._setter(mod._blsIdSetInt, x) // same as Id } isZero () { return this._getter(mod._blsSecretKeyIsZero) === 1 } isEqual (rhs) { return this._isEqual(mod._blsSecretKeyIsEqual, rhs) } deserialize (s) { this._setter(exports.blsSecretKeyDeserialize, s) } serialize () { return this._getter(exports.blsSecretKeySerialize) } add (rhs) { this._update(mod._blsSecretKeyAdd, rhs) } share (msk, id) { callShare(mod._blsSecretKeyShare, this, BLS_SECRETKEY_SIZE, msk, id) } recover (secVec, idVec) { callRecover(mod._blsSecretKeyRecover, this, BLS_SECRETKEY_SIZE, secVec, idVec) } setHashOf (s) { this._setter(exports.blsHashToSecretKey, s) } setLittleEndian (s) { this._setter(exports.blsSecretKeySetLittleEndian, s) } setLittleEndianMod (s) { this._setter(exports.blsSecretKeySetLittleEndianMod, s) } setByCSPRNG () { const a = new Uint8Array(BLS_SECRETKEY_SIZE) exports.getRandomValues(a) this.setLittleEndian(a) } getPublicKey () { const pub = new exports.PublicKey() const secPos = this._allocAndCopy() const pubPos = pub._alloc() mod._blsGetPublicKey(pubPos, secPos) pub._saveAndFree(pubPos) _free(secPos) return pub } /* input m : message (string or Uint8Array) return BlsSignature */ sign (m) { const sig = new exports.Signature() const secPos = this._allocAndCopy() const sigPos = sig._alloc() exports.blsSign(sigPos, secPos, m) sig._saveAndFree(sigPos) _free(secPos) return sig } } exports.deserializeHexStrToSecretKey = s => { const r = new exports.SecretKey() r.deserializeHexStr(s) return r } exports.PublicKey = class extends Common { constructor () { super(BLS_PUBLICKEY_SIZE) } isZero () { return this._getter(mod._blsPublicKeyIsZero) === 1 } isEqual (rhs) { return this._isEqual(mod._blsPublicKeyIsEqual, rhs) } deserialize (s) { this._setter(exports.blsPublicKeyDeserialize, s) } serialize () { return this._getter(exports.blsPublicKeySerialize) } deserializeUncompressed (s) { this._setter(exports.blsPublicKeyDeserializeUncompressed, s) } serializeUncompressed () { return this._getter(exports.blsPublicKeySerializeUncompressed) } add (rhs) { this._update(mod._blsPublicKeyAdd, rhs) } share (msk, id) { callShare(mod._blsPublicKeyShare, this, BLS_PUBLICKEY_SIZE, msk, id) } recover (secVec, idVec) { callRecover(mod._blsPublicKeyRecover, this, BLS_PUBLICKEY_SIZE, secVec, idVec) } isValidOrder () { return this._getter(mod._blsPublicKeyIsValidOrder) } verify (sig, m) { const pubPos = this._allocAndCopy() const sigPos = sig._allocAndCopy() const r = exports.blsVerify(sigPos, pubPos, m) _free(sigPos) _free(pubPos) return r != 0 } } exports.deserializeHexStrToPublicKey = s => { const r = new exports.PublicKey() r.deserializeHexStr(s) return r } exports.Signature = class extends Common { constructor () { super(BLS_SIGNATURE_SIZE) } isZero () { return this._getter(mod._blsSignatureIsZero) === 1 } isEqual (rhs) { return this._isEqual(mod._blsSignatureIsEqual, rhs) } deserialize (s) { this._setter(exports.blsSignatureDeserialize, s) } serialize () { return this._getter(exports.blsSignatureSerialize) } deserializeUncompressed (s) { this._setter(exports.blsSignatureDeserializeUncompressed, s) } serializeUncompressed () { return this._getter(exports.blsSignatureSerializeUncompressed) } add (rhs) { this._update(mod._blsSignatureAdd, rhs) } recover (secVec, idVec) { callRecover(mod._blsSignatureRecover, this, BLS_SIGNATURE_SIZE, secVec, idVec) } isValidOrder () { return this._getter(mod._blsSignatureIsValidOrder) } // this = aggSig aggregate (sigVec) { const n = sigVec.length const aggSigPos = this._allocAndCopy() const sigVecPos = _malloc(BLS_SIGNATURE_SIZE * n) for (let i = 0; i < n; i++) { mod.HEAP32.set(sigVec[i].a_, (sigVecPos + BLS_SIGNATURE_SIZE * i) / 4) } const r = mod._blsAggregateSignature(aggSigPos, sigVecPos, n) _free(sigVecPos) this._saveAndFree(aggSigPos) return r == 1 } // this = aggSig fastAggregateVerify (pubVec, msg) { const n = pubVec.length const msgSize = msg.length const aggSigPos = this._allocAndCopy() const pubVecPos = _malloc(BLS_PUBLICKEY_SIZE * n) const msgPos = _malloc(msgSize) for (let i = 0; i < n; i++) { mod.HEAP32.set(pubVec[i].a_, (pubVecPos + BLS_PUBLICKEY_SIZE * i) / 4) } mod.HEAP8.set(msg, msgPos) const r = mod._blsFastAggregateVerify(aggSigPos, pubVecPos, n, msgPos, msgSize) _free(msgPos) _free(pubVecPos) _free(aggSigPos) return r == 1 } // this = aggSig // msgVec = (32 * pubVec.length)-size Uint8Array aggregateVerifyNoCheck (pubVec, msgVec) { const n = pubVec.length const msgSize = 32 if (n == 0 || msgVec.length != msgSize * n) { return false } const aggSigPos = this._allocAndCopy() const pubVecPos = _malloc(BLS_PUBLICKEY_SIZE * n) const msgPos = _malloc(msgVec.length) for (let i = 0; i < n; i++) { mod.HEAP32.set(pubVec[i].a_, (pubVecPos + BLS_PUBLICKEY_SIZE * i) / 4) } mod.HEAP8.set(msgVec, msgPos) const r = mod._blsAggregateVerifyNoCheck(aggSigPos, pubVecPos, msgPos, msgSize, n) _free(msgPos) _free(pubVecPos) _free(aggSigPos) return r == 1 } } exports.deserializeHexStrToSignature = s => { const r = new exports.Signature() r.deserializeHexStr(s) return r } // 1 (draft-05) 2 (draft-06) 3 (draft-07) exports.setETHmode = (mode) => { if (mod._blsSetETHmode(mode) != 0) throw new Error(`bad setETHmode ${mode}`) } // make setter check the correctness of the order if doVerify exports.verifySignatureOrder = (doVerify) => { mod._blsSignatureVerifyOrder(doVerify) } // make setter check the correctness of the order if doVerify exports.verifyPublicKeyOrder = (doVerify) => { mod._blsPublicKeyVerifyOrder(doVerify) } exports.areAllMsgDifferent = (msgs, msgSize) => { const n = msgs.length / msgSize if (msgs.length != n * msgSize) return false h = {} for (let i = 0; i < n; i++) { const m = msgs.subarray(i * msgSize, (i + 1) * msgSize) if (m in h) return false h[m] = true } return true } /* return true if all pub[i].verify(sigs[i], msgs[i]) msgs is array of 32-byte Uint8Array */ exports.multiVerify = (pubs, sigs, msgs) => { const MSG_SIZE = 32 const RAND_SIZE = 8 // 64-bit rand const threadNum = 0 // not used const n = sigs.length if (pubs.length != n || msgs.length != n) return false for (let i = 0; i < n; i++) { if (msgs[i].length != MSG_SIZE) return false } const sigPos = _malloc(BLS_SIGNATURE_SIZE * n) const pubPos = _malloc(BLS_PUBLICKEY_SIZE * n) const msgPos = _malloc(MSG_SIZE * n) const randPos = _malloc(RAND_SIZE * n) exports.getRandomValues(mod.HEAP8.subarray(randPos, randPos + RAND_SIZE * n)) for (let i = 0; i < n; i++) { mod.HEAP32.set(sigs[i].a_, (sigPos + BLS_SIGNATURE_SIZE * i) / 4) mod.HEAP32.set(pubs[i].a_, (pubPos + BLS_PUBLICKEY_SIZE * i) / 4) mod.HEAP8.set(msgs[i], msgPos + MSG_SIZE * i) } const r = mod._blsMultiVerify(sigPos, pubPos, msgPos, MSG_SIZE, randPos, RAND_SIZE, n, threadNum) _free(randPos) _free(msgPos) _free(pubPos) _free(sigPos) return r == 1 } exports.blsInit(curveType) if (exports.ethMode) { exports.setETHmode(exports.ETH_MODE_DRAFT_07) } } // setup() const _cryptoGetRandomValues = function(p, n) { const a = new Uint8Array(n) exports.getRandomValues(a) for (let i = 0; i < n; i++) { exports.mod.HEAP8[p + i] = a[i] } } // f(a:array) fills a with random value exports.setRandFunc = f => { exports.getRandomValues = f } exports.init = (curveType = exports.BN254) => { exports.curveType = curveType const name = 'bls_c' return new Promise(resolve => { if (isNodeJs) { const crypto = require('crypto') exports.getRandomValues = crypto.randomFillSync const path = require('path') const js = require(`./${name}.js`) const Module = { cryptoGetRandomValues : _cryptoGetRandomValues, locateFile: baseName => { return path.join(__dirname, baseName) } } js(Module) .then(_mod => { exports.mod = _mod setup(exports, curveType) resolve() }) } else { const crypto = window.crypto || window.msCrypto exports.getRandomValues = x => crypto.getRandomValues(x) fetch(`./${name}.wasm`) // eslint-disable-line .then(response => response.arrayBuffer()) .then(buffer => new Uint8Array(buffer)) .then(() => { if (typeof module !== 'undefined' && module.exports) { exports.mod = require('./bls_c')() } else { exports.mod = Module() // eslint-disable-line } exports.mod.cryptoGetRandomValues = _cryptoGetRandomValues exports.mod.onRuntimeInitialized = () => { setup(exports, curveType) resolve() } }) } }) } return exports })