UNPKG

snarkjs

Version:

zkSNARKs implementation in JavaScript

1,519 lines (1,284 loc) 537 kB
import { Scalar, BigBuffer, buildBn128, buildBls12381, ChaCha, F1Field, utils, getCurveFromR as getCurveFromR$1 } from 'ffjavascript'; var fs = {}; async function open(fileName, openFlags, cacheSize, pageSize) { cacheSize = cacheSize || 4096*64; if (typeof openFlags !== "number" && ["w+", "wx+", "r", "ax+", "a+"].indexOf(openFlags) <0) throw new Error("Invalid open option"); const fd =await fs.promises.open(fileName, openFlags); const stats = await fd.stat(); return new FastFile(fd, stats, cacheSize, pageSize, fileName); } class FastFile { constructor(fd, stats, cacheSize, pageSize, fileName) { this.fileName = fileName; this.fd = fd; this.pos = 0; this.pageSize = pageSize || (1 << 8); while (this.pageSize < stats.blksize) { this.pageSize *= 2; } this.totalSize = stats.size; this.totalPages = Math.floor((stats.size -1) / this.pageSize)+1; this.maxPagesLoaded = Math.floor( cacheSize / this.pageSize)+1; this.pages = {}; this.pendingLoads = []; this.writing = false; this.reading = false; this.avBuffs = []; this.history = {}; } _loadPage(p) { const self = this; const P = new Promise((resolve, reject)=> { self.pendingLoads.push({ page: p, resolve: resolve, reject: reject }); }); self.__statusPage("After Load request: ", p); return P; } __statusPage(s, p) { const logEntry = []; const self=this; if (!self.logHistory) return; logEntry.push("==" + s+ " " +p); let S = ""; for (let i=0; i<self.pendingLoads.length; i++) { if (self.pendingLoads[i].page == p) S = S + " " + i; } if (S) logEntry.push("Pending loads:"+S); if (typeof self.pages[p] != "undefined") { const page = self.pages[p]; logEntry.push("Loaded"); logEntry.push("pendingOps: "+page.pendingOps); if (page.loading) logEntry.push("loading: "+page.loading); if (page.writing) logEntry.push("writing"); if (page.dirty) logEntry.push("dirty"); } logEntry.push("=="); if (!self.history[p]) self.history[p] = []; self.history[p].push(logEntry); } __printHistory(p) { const self = this; if (!self.history[p]) console.log("Empty History ", p); console.log("History "+p); for (let i=0; i<self.history[p].length; i++) { for (let j=0; j<self.history[p][i].length; j++) { console.log("-> " + self.history[p][i][j]); } } } _triggerLoad() { const self = this; if (self.reading) return; if (self.pendingLoads.length==0) return; const pageIdxs = Object.keys(self.pages); const deletablePages = []; for (let i=0; i<pageIdxs.length; i++) { const page = self.pages[parseInt(pageIdxs[i])]; if ((page.dirty == false)&&(page.pendingOps==0)&&(!page.writing)&&(!page.loading)) deletablePages.push(parseInt(pageIdxs[i])); } let freePages = self.maxPagesLoaded - pageIdxs.length; const ops = []; // while pending loads and // the page is loaded or I can recover one. while ( (self.pendingLoads.length>0) && ( (typeof self.pages[self.pendingLoads[0].page] != "undefined" ) ||( (freePages>0) ||(deletablePages.length>0)))) { const load = self.pendingLoads.shift(); if (typeof self.pages[load.page] != "undefined") { self.pages[load.page].pendingOps ++; const idx = deletablePages.indexOf(load.page); if (idx>=0) deletablePages.splice(idx, 1); if (self.pages[load.page].loading) { self.pages[load.page].loading.push(load); } else { load.resolve(); } self.__statusPage("After Load (cached): ", load.page); } else { if (freePages) { freePages--; } else { const fp = deletablePages.shift(); self.__statusPage("Before Unload: ", fp); self.avBuffs.unshift(self.pages[fp]); delete self.pages[fp]; self.__statusPage("After Unload: ", fp); } if (load.page>=self.totalPages) { self.pages[load.page] = getNewPage(); load.resolve(); self.__statusPage("After Load (new): ", load.page); } else { self.reading = true; self.pages[load.page] = getNewPage(); self.pages[load.page].loading = [load]; ops.push(self.fd.read(self.pages[load.page].buff, 0, self.pageSize, load.page*self.pageSize).then((res)=> { self.pages[load.page].size = res.bytesRead; const loading = self.pages[load.page].loading; delete self.pages[load.page].loading; for (let i=0; i<loading.length; i++) { loading[i].resolve(); } self.__statusPage("After Load (loaded): ", load.page); return res; }, (err) => { load.reject(err); })); self.__statusPage("After Load (loading): ", load.page); } } } // if (ops.length>1) console.log(ops.length); Promise.all(ops).then( () => { self.reading = false; if (self.pendingLoads.length>0) setImmediate(self._triggerLoad.bind(self)); self._tryClose(); }); function getNewPage() { if (self.avBuffs.length>0) { const p = self.avBuffs.shift(); p.dirty = false; p.pendingOps = 1; p.size =0; return p; } else { return { dirty: false, buff: new Uint8Array(self.pageSize), pendingOps: 1, size: 0 }; } } } _triggerWrite() { const self = this; if (self.writing) return; const pageIdxs = Object.keys(self.pages); const ops = []; for (let i=0; i<pageIdxs.length; i++) { const page = self.pages[parseInt(pageIdxs[i])]; if (page.dirty) { page.dirty = false; page.writing = true; self.writing = true; ops.push( self.fd.write(page.buff, 0, page.size, parseInt(pageIdxs[i])*self.pageSize).then(() => { page.writing = false; return; }, (err) => { console.log("ERROR Writing: "+err); self.error = err; self._tryClose(); })); } } if (self.writing) { Promise.all(ops).then( () => { self.writing = false; setImmediate(self._triggerWrite.bind(self)); self._tryClose(); if (self.pendingLoads.length>0) setImmediate(self._triggerLoad.bind(self)); }); } } _getDirtyPage() { for (let p in this.pages) { if (this.pages[p].dirty) return p; } return -1; } async write(buff, pos) { if (buff.byteLength == 0) return; const self = this; /* if (buff.byteLength > self.pageSize*self.maxPagesLoaded*0.8) { const cacheSize = Math.floor(buff.byteLength * 1.1); this.maxPagesLoaded = Math.floor( cacheSize / self.pageSize)+1; } */ if (typeof pos == "undefined") pos = self.pos; self.pos = pos+buff.byteLength; if (self.totalSize < pos + buff.byteLength) self.totalSize = pos + buff.byteLength; if (self.pendingClose) throw new Error("Writing a closing file"); const firstPage = Math.floor(pos / self.pageSize); const lastPage = Math.floor((pos + buff.byteLength -1) / self.pageSize); const pagePromises = []; for (let i=firstPage; i<=lastPage; i++) pagePromises.push(self._loadPage(i)); self._triggerLoad(); let p = firstPage; let o = pos % self.pageSize; let r = buff.byteLength; while (r>0) { await pagePromises[p-firstPage]; const l = (o+r > self.pageSize) ? (self.pageSize -o) : r; const srcView = buff.slice( buff.byteLength - r, buff.byteLength - r + l); const dstView = new Uint8Array(self.pages[p].buff.buffer, o, l); dstView.set(srcView); self.pages[p].dirty = true; self.pages[p].pendingOps --; self.pages[p].size = Math.max(o+l, self.pages[p].size); if (p>=self.totalPages) { self.totalPages = p+1; } r = r-l; p ++; o = 0; if (!self.writing) setImmediate(self._triggerWrite.bind(self)); } } async read(len, pos) { const self = this; let buff = new Uint8Array(len); await self.readToBuffer(buff, 0, len, pos); return buff; } async readToBuffer(buffDst, offset, len, pos) { if (len == 0) { return; } const self = this; if (len > self.pageSize*self.maxPagesLoaded*0.8) { const cacheSize = Math.floor(len * 1.1); this.maxPagesLoaded = Math.floor( cacheSize / self.pageSize)+1; } if (typeof pos == "undefined") pos = self.pos; self.pos = pos+len; if (self.pendingClose) throw new Error("Reading a closing file"); const firstPage = Math.floor(pos / self.pageSize); const lastPage = Math.floor((pos + len -1) / self.pageSize); const pagePromises = []; for (let i=firstPage; i<=lastPage; i++) pagePromises.push(self._loadPage(i)); self._triggerLoad(); let p = firstPage; let o = pos % self.pageSize; // Remaining bytes to read let r = pos + len > self.totalSize ? len - (pos + len - self.totalSize): len; while (r>0) { await pagePromises[p - firstPage]; self.__statusPage("After Await (read): ", p); // bytes to copy from this page const l = (o+r > self.pageSize) ? (self.pageSize -o) : r; const srcView = new Uint8Array(self.pages[p].buff.buffer, self.pages[p].buff.byteOffset + o, l); buffDst.set(srcView, offset+len-r); self.pages[p].pendingOps --; self.__statusPage("After Op done: ", p); r = r-l; p ++; o = 0; if (self.pendingLoads.length>0) setImmediate(self._triggerLoad.bind(self)); } this.pos = pos + len; } _tryClose() { const self = this; if (!self.pendingClose) return; if (self.error) { self.pendingCloseReject(self.error); } const p = self._getDirtyPage(); if ((p>=0) || (self.writing) || (self.reading) || (self.pendingLoads.length>0)) return; self.pendingClose(); } close() { const self = this; if (self.pendingClose) throw new Error("Closing the file twice"); return new Promise((resolve, reject) => { self.pendingClose = resolve; self.pendingCloseReject = reject; self._tryClose(); }).then(()=> { self.fd.close(); }, (err) => { self.fd.close(); throw (err); }); } async discard() { const self = this; await self.close(); await fs.promises.unlink(this.fileName); } async writeULE32(v, pos) { const self = this; const tmpBuff32 = new Uint8Array(4); const tmpBuff32v = new DataView(tmpBuff32.buffer); tmpBuff32v.setUint32(0, v, true); await self.write(tmpBuff32, pos); } async writeUBE32(v, pos) { const self = this; const tmpBuff32 = new Uint8Array(4); const tmpBuff32v = new DataView(tmpBuff32.buffer); tmpBuff32v.setUint32(0, v, false); await self.write(tmpBuff32, pos); } async writeULE64(v, pos) { const self = this; const tmpBuff64 = new Uint8Array(8); const tmpBuff64v = new DataView(tmpBuff64.buffer); tmpBuff64v.setUint32(0, v & 0xFFFFFFFF, true); tmpBuff64v.setUint32(4, Math.floor(v / 0x100000000) , true); await self.write(tmpBuff64, pos); } async readULE32(pos) { const self = this; const b = await self.read(4, pos); const view = new Uint32Array(b.buffer); return view[0]; } async readUBE32(pos) { const self = this; const b = await self.read(4, pos); const view = new DataView(b.buffer); return view.getUint32(0, false); } async readULE64(pos) { const self = this; const b = await self.read(8, pos); const view = new Uint32Array(b.buffer); return view[1] * 0x100000000 + view[0]; } async readString(pos) { const self = this; if (self.pendingClose) { throw new Error("Reading a closing file"); } let currentPosition = typeof pos == "undefined" ? self.pos : pos; let currentPage = Math.floor(currentPosition / self.pageSize); let endOfStringFound = false; let str = ""; while (!endOfStringFound) { //Read page let pagePromise = self._loadPage(currentPage); self._triggerLoad(); await pagePromise; self.__statusPage("After Await (read): ", currentPage); let offsetOnPage = currentPosition % self.pageSize; const dataArray = new Uint8Array( self.pages[currentPage].buff.buffer, self.pages[currentPage].buff.byteOffset + offsetOnPage, self.pageSize - offsetOnPage ); let indexEndOfString = dataArray.findIndex(element => element === 0); endOfStringFound = indexEndOfString !== -1; if (endOfStringFound) { str += new TextDecoder().decode(dataArray.slice(0, indexEndOfString)); self.pos = currentPage * this.pageSize + offsetOnPage + indexEndOfString + 1; } else { str += new TextDecoder().decode(dataArray); self.pos = currentPage * this.pageSize + offsetOnPage + dataArray.length; } self.pages[currentPage].pendingOps--; self.__statusPage("After Op done: ", currentPage); currentPosition = self.pos; currentPage++; if (self.pendingLoads.length > 0) setImmediate(self._triggerLoad.bind(self)); } return str; } } function createNew$1(o) { const initialSize = o.initialSize || 1<<20; const fd = new MemFile(); fd.o = o; fd.o.data = new Uint8Array(initialSize); fd.allocSize = initialSize; fd.totalSize = 0; fd.readOnly = false; fd.pos = 0; return fd; } function readExisting$2(o) { const fd = new MemFile(); fd.o = o; fd.allocSize = o.data.byteLength; fd.totalSize = o.data.byteLength; fd.readOnly = true; fd.pos = 0; return fd; } const tmpBuff32$1 = new Uint8Array(4); const tmpBuff32v$1 = new DataView(tmpBuff32$1.buffer); const tmpBuff64$1 = new Uint8Array(8); const tmpBuff64v$1 = new DataView(tmpBuff64$1.buffer); class MemFile { constructor() { this.pageSize = 1 << 14; // for compatibility } _resizeIfNeeded(newLen) { if (newLen > this.allocSize) { const newAllocSize = Math.max( this.allocSize + (1 << 20), Math.floor(this.allocSize * 1.1), newLen ); const newData = new Uint8Array(newAllocSize); newData.set(this.o.data); this.o.data = newData; this.allocSize = newAllocSize; } } async write(buff, pos) { const self =this; if (typeof pos == "undefined") pos = self.pos; if (this.readOnly) throw new Error("Writing a read only file"); this._resizeIfNeeded(pos + buff.byteLength); this.o.data.set(buff.slice(), pos); if (pos + buff.byteLength > this.totalSize) this.totalSize = pos + buff.byteLength; this.pos = pos + buff.byteLength; } async readToBuffer(buffDest, offset, len, pos) { const self = this; if (typeof pos == "undefined") pos = self.pos; if (this.readOnly) { if (pos + len > this.totalSize) throw new Error("Reading out of bounds"); } this._resizeIfNeeded(pos + len); const buffSrc = new Uint8Array(this.o.data.buffer, this.o.data.byteOffset + pos, len); buffDest.set(buffSrc, offset); this.pos = pos + len; } async read(len, pos) { const self = this; const buff = new Uint8Array(len); await self.readToBuffer(buff, 0, len, pos); return buff; } close() { if (this.o.data.byteLength != this.totalSize) { this.o.data = this.o.data.slice(0, this.totalSize); } } async discard() { } async writeULE32(v, pos) { const self = this; tmpBuff32v$1.setUint32(0, v, true); await self.write(tmpBuff32$1, pos); } async writeUBE32(v, pos) { const self = this; tmpBuff32v$1.setUint32(0, v, false); await self.write(tmpBuff32$1, pos); } async writeULE64(v, pos) { const self = this; tmpBuff64v$1.setUint32(0, v & 0xFFFFFFFF, true); tmpBuff64v$1.setUint32(4, Math.floor(v / 0x100000000) , true); await self.write(tmpBuff64$1, pos); } async readULE32(pos) { const self = this; const b = await self.read(4, pos); const view = new Uint32Array(b.buffer); return view[0]; } async readUBE32(pos) { const self = this; const b = await self.read(4, pos); const view = new DataView(b.buffer); return view.getUint32(0, false); } async readULE64(pos) { const self = this; const b = await self.read(8, pos); const view = new Uint32Array(b.buffer); return view[1] * 0x100000000 + view[0]; } async readString(pos) { const self = this; let currentPosition = typeof pos == "undefined" ? self.pos : pos; if (currentPosition > this.totalSize) { if (this.readOnly) { throw new Error("Reading out of bounds"); } this._resizeIfNeeded(pos); } const dataArray = new Uint8Array( self.o.data.buffer, currentPosition, this.totalSize - currentPosition ); let indexEndOfString = dataArray.findIndex(element => element === 0); let endOfStringFound = indexEndOfString !== -1; let str = ""; if (endOfStringFound) { str = new TextDecoder().decode(dataArray.slice(0, indexEndOfString)); self.pos = currentPosition + indexEndOfString + 1; } else { self.pos = currentPosition; } return str; } } const PAGE_SIZE = 1<<22; function createNew(o) { const initialSize = o.initialSize || 0; const fd = new BigMemFile(); fd.o = o; const nPages = initialSize ? Math.floor((initialSize - 1) / PAGE_SIZE)+1 : 0; fd.o.data = []; for (let i=0; i<nPages-1; i++) { fd.o.data.push( new Uint8Array(PAGE_SIZE)); } if (nPages) fd.o.data.push( new Uint8Array(initialSize - PAGE_SIZE*(nPages-1))); fd.totalSize = 0; fd.readOnly = false; fd.pos = 0; return fd; } function readExisting$1(o) { const fd = new BigMemFile(); fd.o = o; fd.totalSize = (o.data.length-1)* PAGE_SIZE + o.data[o.data.length-1].byteLength; fd.readOnly = true; fd.pos = 0; return fd; } const tmpBuff32 = new Uint8Array(4); const tmpBuff32v = new DataView(tmpBuff32.buffer); const tmpBuff64 = new Uint8Array(8); const tmpBuff64v = new DataView(tmpBuff64.buffer); class BigMemFile { constructor() { this.pageSize = 1 << 14; // for compatibility } _resizeIfNeeded(newLen) { if (newLen <= this.totalSize) return; if (this.readOnly) throw new Error("Reading out of file bounds"); const nPages = Math.floor((newLen - 1) / PAGE_SIZE)+1; for (let i= Math.max(this.o.data.length-1, 0); i<nPages; i++) { const newSize = i<nPages-1 ? PAGE_SIZE : newLen - (nPages-1)*PAGE_SIZE; const p = new Uint8Array(newSize); if (i == this.o.data.length-1) p.set(this.o.data[i]); this.o.data[i] = p; } this.totalSize = newLen; } async write(buff, pos) { const self =this; if (typeof pos == "undefined") pos = self.pos; if (this.readOnly) throw new Error("Writing a read only file"); this._resizeIfNeeded(pos + buff.byteLength); const firstPage = Math.floor(pos / PAGE_SIZE); let p = firstPage; let o = pos % PAGE_SIZE; let r = buff.byteLength; while (r>0) { const l = (o+r > PAGE_SIZE) ? (PAGE_SIZE -o) : r; const srcView = buff.slice(buff.byteLength - r, buff.byteLength - r + l); const dstView = new Uint8Array(self.o.data[p].buffer, o, l); dstView.set(srcView); r = r-l; p ++; o = 0; } this.pos = pos + buff.byteLength; } async readToBuffer(buffDst, offset, len, pos) { const self = this; if (typeof pos == "undefined") pos = self.pos; if (this.readOnly) { if (pos + len > this.totalSize) throw new Error("Reading out of bounds"); } this._resizeIfNeeded(pos + len); const firstPage = Math.floor(pos / PAGE_SIZE); let p = firstPage; let o = pos % PAGE_SIZE; // Remaining bytes to read let r = len; while (r>0) { // bytes to copy from this page const l = (o+r > PAGE_SIZE) ? (PAGE_SIZE -o) : r; const srcView = new Uint8Array(self.o.data[p].buffer, o, l); buffDst.set(srcView, offset+len-r); r = r-l; p ++; o = 0; } this.pos = pos + len; } async read(len, pos) { const self = this; const buff = new Uint8Array(len); await self.readToBuffer(buff, 0, len, pos); return buff; } close() { } async discard() { } async writeULE32(v, pos) { const self = this; tmpBuff32v.setUint32(0, v, true); await self.write(tmpBuff32, pos); } async writeUBE32(v, pos) { const self = this; tmpBuff32v.setUint32(0, v, false); await self.write(tmpBuff32, pos); } async writeULE64(v, pos) { const self = this; tmpBuff64v.setUint32(0, v & 0xFFFFFFFF, true); tmpBuff64v.setUint32(4, Math.floor(v / 0x100000000) , true); await self.write(tmpBuff64, pos); } async readULE32(pos) { const self = this; const b = await self.read(4, pos); const view = new Uint32Array(b.buffer); return view[0]; } async readUBE32(pos) { const self = this; const b = await self.read(4, pos); const view = new DataView(b.buffer); return view.getUint32(0, false); } async readULE64(pos) { const self = this; const b = await self.read(8, pos); const view = new Uint32Array(b.buffer); return view[1] * 0x100000000 + view[0]; } async readString(pos) { const self = this; const fixedSize = 2048; let currentPosition = typeof pos == "undefined" ? self.pos : pos; if (currentPosition > this.totalSize) { if (this.readOnly) { throw new Error("Reading out of bounds"); } this._resizeIfNeeded(pos); } let endOfStringFound = false; let str = ""; while (!endOfStringFound) { let currentPage = Math.floor(currentPosition / PAGE_SIZE); let offsetOnPage = currentPosition % PAGE_SIZE; if (self.o.data[currentPage] === undefined) { throw new Error("ERROR"); } let readLength = Math.min(fixedSize, self.o.data[currentPage].length - offsetOnPage); const dataArray = new Uint8Array(self.o.data[currentPage].buffer, offsetOnPage, readLength); let indexEndOfString = dataArray.findIndex(element => element === 0); endOfStringFound = indexEndOfString !== -1; if (endOfStringFound) { str += new TextDecoder().decode(dataArray.slice(0, indexEndOfString)); self.pos = currentPage * PAGE_SIZE + offsetOnPage + indexEndOfString + 1; } else { str += new TextDecoder().decode(dataArray); self.pos = currentPage * PAGE_SIZE + offsetOnPage + dataArray.length; } currentPosition = self.pos; } return str; } } const O_TRUNC = 1024; const O_CREAT = 512; const O_RDWR = 2; const O_RDONLY = 0; /* global fetch */ const DEFAULT_CACHE_SIZE = (1 << 16); const DEFAULT_PAGE_SIZE = (1 << 13); async function createOverride(o, b, c) { if (typeof o === "string") { o = { type: "file", fileName: o, cacheSize: b || DEFAULT_CACHE_SIZE, pageSize: c || DEFAULT_PAGE_SIZE }; } if (o.type == "file") { return await open(o.fileName, O_TRUNC | O_CREAT | O_RDWR, o.cacheSize, o.pageSize); } else if (o.type == "mem") { return createNew$1(o); } else if (o.type == "bigMem") { return createNew(o); } else { throw new Error("Invalid FastFile type: "+o.type); } } async function readExisting(o, b, c) { if (o instanceof Uint8Array) { o = { type: "mem", data: o }; } { if (typeof o === "string") { const buff = await fetch(o).then( function(res) { return res.arrayBuffer(); }).then(function (ab) { return new Uint8Array(ab); }); o = { type: "mem", data: buff }; } } if (o.type == "file") { return await open(o.fileName, O_RDONLY, o.cacheSize, o.pageSize); } else if (o.type == "mem") { return await readExisting$2(o); } else if (o.type == "bigMem") { return await readExisting$1(o); } else { throw new Error("Invalid FastFile type: "+o.type); } } async function readBinFile(fileName, type, maxVersion, cacheSize, pageSize) { const fd = await readExisting(fileName); const b = await fd.read(4); let readedType = ""; for (let i=0; i<4; i++) readedType += String.fromCharCode(b[i]); if (readedType != type) throw new Error(fileName + ": Invalid File format"); let v = await fd.readULE32(); if (v>maxVersion) throw new Error("Version not supported"); const nSections = await fd.readULE32(); // Scan sections let sections = []; for (let i=0; i<nSections; i++) { let ht = await fd.readULE32(); let hl = await fd.readULE64(); if (typeof sections[ht] == "undefined") sections[ht] = []; sections[ht].push({ p: fd.pos, size: hl }); fd.pos += hl; } return {fd, sections}; } async function createBinFile(fileName, type, version, nSections, cacheSize, pageSize) { const fd = await createOverride(fileName, cacheSize, pageSize); const buff = new Uint8Array(4); for (let i=0; i<4; i++) buff[i] = type.charCodeAt(i); await fd.write(buff, 0); // Magic "r1cs" await fd.writeULE32(version); // Version await fd.writeULE32(nSections); // Number of Sections return fd; } async function startWriteSection(fd, idSection) { if (typeof fd.writingSection !== "undefined") throw new Error("Already writing a section"); await fd.writeULE32(idSection); // Header type fd.writingSection = { pSectionSize: fd.pos }; await fd.writeULE64(0); // Temporally set to 0 length } async function endWriteSection(fd) { if (typeof fd.writingSection === "undefined") throw new Error("Not writing a section"); const sectionSize = fd.pos - fd.writingSection.pSectionSize - 8; const oldPos = fd.pos; fd.pos = fd.writingSection.pSectionSize; await fd.writeULE64(sectionSize); fd.pos = oldPos; delete fd.writingSection; } async function startReadUniqueSection(fd, sections, idSection) { if (typeof fd.readingSection !== "undefined") throw new Error("Already reading a section"); if (!sections[idSection]) throw new Error(fd.fileName + ": Missing section "+ idSection ); if (sections[idSection].length>1) throw new Error(fd.fileName +": Section Duplicated " +idSection); fd.pos = sections[idSection][0].p; fd.readingSection = sections[idSection][0]; } async function endReadSection(fd, noCheck) { if (typeof fd.readingSection === "undefined") throw new Error("Not reading a section"); if (!noCheck) { if (fd.pos-fd.readingSection.p != fd.readingSection.size) throw new Error("Invalid section size reading"); } delete fd.readingSection; } async function writeBigInt(fd, n, n8, pos) { const buff = new Uint8Array(n8); Scalar.toRprLE(buff, 0, n, n8); await fd.write(buff, pos); } async function readBigInt(fd, n8, pos) { const buff = await fd.read(n8, pos); return Scalar.fromRprLE(buff, 0, n8); } async function copySection(fdFrom, sections, fdTo, sectionId, size) { if (typeof size === "undefined") { size = sections[sectionId][0].size; } const chunkSize = fdFrom.pageSize; await startReadUniqueSection(fdFrom, sections, sectionId); await startWriteSection(fdTo, sectionId); for (let p=0; p<size; p+=chunkSize) { const l = Math.min(size -p, chunkSize); const buff = await fdFrom.read(l); await fdTo.write(buff); } await endWriteSection(fdTo); await endReadSection(fdFrom, size != sections[sectionId][0].size); } async function readSection(fd, sections, idSection, offset, length) { offset = (typeof offset === "undefined") ? 0 : offset; length = (typeof length === "undefined") ? sections[idSection][0].size - offset : length; if (offset + length > sections[idSection][0].size) { throw new Error("Reading out of the range of the section"); } let buff; if (length < (1 << 30) ) { buff = new Uint8Array(length); } else { buff = new BigBuffer(length); } await fd.readToBuffer(buff, 0, length, sections[idSection][0].p + offset); return buff; } async function sectionIsEqual(fd1, sections1, fd2, sections2, idSection) { const MAX_BUFF_SIZE = fd1.pageSize * 16; await startReadUniqueSection(fd1, sections1, idSection); await startReadUniqueSection(fd2, sections2, idSection); if (sections1[idSection][0].size != sections2[idSection][0].size) return false; const totalBytes=sections1[idSection][0].size; for (let i=0; i<totalBytes; i+= MAX_BUFF_SIZE) { const n = Math.min(totalBytes-i, MAX_BUFF_SIZE); const buff1 = await fd1.read(n); const buff2 = await fd2.read(n); for (let j=0; j<n; j++) if (buff1[j] != buff2[j]) return false; } await endReadSection(fd1); await endReadSection(fd2); return true; } const bls12381r$1 = Scalar.e("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001", 16); const bn128r$1 = Scalar.e("21888242871839275222246405745257275088548364400416034343698204186575808495617"); const bls12381q = Scalar.e("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab", 16); const bn128q = Scalar.e("21888242871839275222246405745257275088696311157297823662689037894645226208583"); async function getCurveFromR(r, options) { let curve; // check that options param is defined and that options.singleThread is defined let singleThread = options && options.singleThread; if (Scalar.eq(r, bn128r$1)) { curve = await buildBn128(singleThread); } else if (Scalar.eq(r, bls12381r$1)) { curve = await buildBls12381(singleThread); } else { throw new Error(`Curve not supported: ${Scalar.toString(r)}`); } return curve; } async function getCurveFromQ(q, options) { let curve; let singleThread = options && options.singleThread; if (Scalar.eq(q, bn128q)) { curve = await buildBn128(singleThread); } else if (Scalar.eq(q, bls12381q)) { curve = await buildBls12381(singleThread); } else { throw new Error(`Curve not supported: ${Scalar.toString(q)}`); } return curve; } async function getCurveFromName(name, options) { let curve; let singleThread = options && options.singleThread; const normName = normalizeName(name); if (["BN128", "BN254", "ALTBN128"].indexOf(normName) >= 0) { curve = await buildBn128(singleThread); } else if (["BLS12381"].indexOf(normName) >= 0) { curve = await buildBls12381(singleThread); } else { throw new Error(`Curve not supported: ${name}`); } return curve; function normalizeName(n) { return n.toUpperCase().match(/[A-Za-z0-9]+/g).join(""); } } var curves = /*#__PURE__*/Object.freeze({ __proto__: null, getCurveFromR: getCurveFromR, getCurveFromQ: getCurveFromQ, getCurveFromName: getCurveFromName }); function number(n) { if (!Number.isSafeInteger(n) || n < 0) throw new Error(`positive integer expected, not ${n}`); } // copied from utils function isBytes(a) { return (a instanceof Uint8Array || (a != null && typeof a === 'object' && a.constructor.name === 'Uint8Array')); } function bytes(b, ...lengths) { if (!isBytes(b)) throw new Error('Uint8Array expected'); if (lengths.length > 0 && !lengths.includes(b.length)) throw new Error(`Uint8Array expected of length ${lengths}, not of length=${b.length}`); } function exists(instance, checkFinished = true) { if (instance.destroyed) throw new Error('Hash instance has been destroyed'); if (checkFinished && instance.finished) throw new Error('Hash#digest() has already been called'); } function output(out, instance) { bytes(out); const min = instance.outputLen; if (out.length < min) { throw new Error(`digestInto() expects output buffer of length at least ${min}`); } } /*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */ const u32 = (arr) => new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4)); const isLE = new Uint8Array(new Uint32Array([0x11223344]).buffer)[0] === 0x44; // The byte swap operation for uint32 const byteSwap = (word) => ((word << 24) & 0xff000000) | ((word << 8) & 0xff0000) | ((word >>> 8) & 0xff00) | ((word >>> 24) & 0xff); // Conditionally byte swap if on a big-endian platform const byteSwapIfBE = isLE ? (n) => n : (n) => byteSwap(n); // In place byte swap for Uint32Array function byteSwap32(arr) { for (let i = 0; i < arr.length; i++) { arr[i] = byteSwap(arr[i]); } } /** * @example utf8ToBytes('abc') // new Uint8Array([97, 98, 99]) */ function utf8ToBytes(str) { if (typeof str !== 'string') throw new Error(`utf8ToBytes expected string, got ${typeof str}`); return new Uint8Array(new TextEncoder().encode(str)); // https://bugzil.la/1681809 } /** * Normalizes (non-hex) string or Uint8Array to Uint8Array. * Warning: when Uint8Array is passed, it would NOT get copied. * Keep in mind for future mutable operations. */ function toBytes(data) { if (typeof data === 'string') data = utf8ToBytes(data); bytes(data); return data; } // For runtime check if class implements interface class Hash { // Safe version that clones internal state clone() { return this._cloneInto(); } } function wrapConstructor(hashCons) { const hashC = (msg) => hashCons().update(toBytes(msg)).digest(); const tmp = hashCons(); hashC.outputLen = tmp.outputLen; hashC.blockLen = tmp.blockLen; hashC.create = () => hashCons(); return hashC; } function wrapConstructorWithOpts(hashCons) { const hashC = (msg, opts) => hashCons(opts).update(toBytes(msg)).digest(); const tmp = hashCons({}); hashC.outputLen = tmp.outputLen; hashC.blockLen = tmp.blockLen; hashC.create = (opts) => hashCons(opts); return hashC; } // Blake is based on ChaCha permutation. // For BLAKE2b, the two extra permutations for rounds 10 and 11 are SIGMA[10..11] = SIGMA[0..1]. // prettier-ignore const SIGMA = /* @__PURE__ */ new Uint8Array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3, 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4, 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8, 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13, 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9, 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11, 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10, 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5, 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3, ]); class BLAKE extends Hash { constructor(blockLen, outputLen, opts = {}, keyLen, saltLen, persLen) { super(); this.blockLen = blockLen; this.outputLen = outputLen; this.length = 0; this.pos = 0; this.finished = false; this.destroyed = false; number(blockLen); number(outputLen); number(keyLen); if (outputLen < 0 || outputLen > keyLen) throw new Error('outputLen bigger than keyLen'); if (opts.key !== undefined && (opts.key.length < 1 || opts.key.length > keyLen)) throw new Error(`key must be up 1..${keyLen} byte long or undefined`); if (opts.salt !== undefined && opts.salt.length !== saltLen) throw new Error(`salt must be ${saltLen} byte long or undefined`); if (opts.personalization !== undefined && opts.personalization.length !== persLen) throw new Error(`personalization must be ${persLen} byte long or undefined`); this.buffer32 = u32((this.buffer = new Uint8Array(blockLen))); } update(data) { exists(this); // Main difference with other hashes: there is flag for last block, // so we cannot process current block before we know that there // is the next one. This significantly complicates logic and reduces ability // to do zero-copy processing const { blockLen, buffer, buffer32 } = this; data = toBytes(data); const len = data.length; const offset = data.byteOffset; const buf = data.buffer; for (let pos = 0; pos < len;) { // If buffer is full and we still have input (don't process last block, same as blake2s) if (this.pos === blockLen) { if (!isLE) byteSwap32(buffer32); this.compress(buffer32, 0, false); if (!isLE) byteSwap32(buffer32); this.pos = 0; } const take = Math.min(blockLen - this.pos, len - pos); const dataOffset = offset + pos; // full block && aligned to 4 bytes && not last in input if (take === blockLen && !(dataOffset % 4) && pos + take < len) { const data32 = new Uint32Array(buf, dataOffset, Math.floor((len - pos) / 4)); if (!isLE) byteSwap32(data32); for (let pos32 = 0; pos + blockLen < len; pos32 += buffer32.length, pos += blockLen) { this.length += blockLen; this.compress(data32, pos32, false); } if (!isLE) byteSwap32(data32); continue; } buffer.set(data.subarray(pos, pos + take), this.pos); this.pos += take; this.length += take; pos += take; } return this; } digestInto(out) { exists(this); output(out, this); const { pos, buffer32 } = this; this.finished = true; // Padding this.buffer.subarray(pos).fill(0); if (!isLE) byteSwap32(buffer32); this.compress(buffer32, 0, true); if (!isLE) byteSwap32(buffer32); const out32 = u32(out); this.get().forEach((v, i) => (out32[i] = byteSwapIfBE(v))); } digest() { const { buffer, outputLen } = this; this.digestInto(buffer); const res = buffer.slice(0, outputLen); this.destroy(); return res; } _cloneInto(to) { const { buffer, length, finished, destroyed, outputLen, pos } = this; to || (to = new this.constructor({ dkLen: outputLen })); to.set(...this.get()); to.length = length; to.finished = finished; to.destroyed = destroyed; to.outputLen = outputLen; to.buffer.set(buffer); to.pos = pos; return to; } } const U32_MASK64 = /* @__PURE__ */ BigInt(2 ** 32 - 1); const _32n = /* @__PURE__ */ BigInt(32); // We are not using BigUint64Array, because they are extremely slow as per 2022 function fromBig(n, le = false) { if (le) return { h: Number(n & U32_MASK64), l: Number((n >> _32n) & U32_MASK64) }; return { h: Number((n >> _32n) & U32_MASK64) | 0, l: Number(n & U32_MASK64) | 0 }; } function split(lst, le = false) { let Ah = new Uint32Array(lst.length); let Al = new Uint32Array(lst.length); for (let i = 0; i < lst.length; i++) { const { h, l } = fromBig(lst[i], le); [Ah[i], Al[i]] = [h, l]; } return [Ah, Al]; } const toBig = (h, l) => (BigInt(h >>> 0) << _32n) | BigInt(l >>> 0); // for Shift in [0, 32) const shrSH = (h, _l, s) => h >>> s; const shrSL = (h, l, s) => (h << (32 - s)) | (l >>> s); // Right rotate for Shift in [1, 32) const rotrSH = (h, l, s) => (h >>> s) | (l << (32 - s)); const rotrSL = (h, l, s) => (h << (32 - s)) | (l >>> s); // Right rotate for Shift in (32, 64), NOTE: 32 is special case. const rotrBH = (h, l, s) => (h << (64 - s)) | (l >>> (s - 32)); const rotrBL = (h, l, s) => (h >>> (s - 32)) | (l << (64 - s)); // Right rotate for shift===32 (just swaps l&h) const rotr32H = (_h, l) => l; const rotr32L = (h, _l) => h; // Left rotate for Shift in [1, 32) const rotlSH = (h, l, s) => (h << s) | (l >>> (32 - s)); const rotlSL = (h, l, s) => (l << s) | (h >>> (32 - s)); // Left rotate for Shift in (32, 64), NOTE: 32 is special case. const rotlBH = (h, l, s) => (l << (s - 32)) | (h >>> (64 - s)); const rotlBL = (h, l, s) => (h << (s - 32)) | (l >>> (64 - s)); // JS uses 32-bit signed integers for bitwise operations which means we cannot // simple take carry out of low bit sum by shift, we need to use division. function add(Ah, Al, Bh, Bl) { const l = (Al >>> 0) + (Bl >>> 0); return { h: (Ah + Bh + ((l / 2 ** 32) | 0)) | 0, l: l | 0 }; } // Addition with more than 2 elements const add3L = (Al, Bl, Cl) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0); const add3H = (low, Ah, Bh, Ch) => (Ah + Bh + Ch + ((low / 2 ** 32) | 0)) | 0; const add4L = (Al, Bl, Cl, Dl) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0); const add4H = (low, Ah, Bh, Ch, Dh) => (Ah + Bh + Ch + Dh + ((low / 2 ** 32) | 0)) | 0; const add5L = (Al, Bl, Cl, Dl, El) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0) + (El >>> 0); const add5H = (low, Ah, Bh, Ch, Dh, Eh) => (Ah + Bh + Ch + Dh + Eh + ((low / 2 ** 32) | 0)) | 0; // prettier-ignore const u64 = { fromBig, split, toBig, shrSH, shrSL, rotrSH, rotrSL, rotrBH, rotrBL, rotr32H, rotr32L, rotlSH, rotlSL, rotlBH, rotlBL, add, add3L, add3H, add4L, add4H, add5H, add5L, }; var u64$1 = u64; // Same as SHA-512 but LE // prettier-ignore const B2B_IV = /* @__PURE__ */ new Uint32Array([ 0xf3bcc908, 0x6a09e667, 0x84caa73b, 0xbb67ae85, 0xfe94f82b, 0x3c6ef372, 0x5f1d36f1, 0xa54ff53a, 0xade682d1, 0x510e527f, 0x2b3e6c1f, 0x9b05688c, 0xfb41bd6b, 0x1f83d9ab, 0x137e2179, 0x5be0cd19 ]); // Temporary buffer const BBUF = /* @__PURE__ */ new Uint32Array(32); // Mixing function G splitted in two halfs function G1b(a, b, c, d, msg, x) { // NOTE: V is LE here const Xl = msg[x], Xh = msg[x + 1]; // prettier-ignore let Al = BBUF[2 * a], Ah = BBUF[2 * a + 1]; // prettier-ignore let Bl = BBUF[2 * b], Bh = BBUF[2 * b + 1]; // prettier-ignore let Cl = BBUF[2 * c], Ch = BBUF[2 * c + 1]; // prettier-ignore let Dl = BBUF[2 * d], Dh = BBUF[2 * d + 1]; // prettier-ignore // v[a] = (v[a] + v[b] + x) | 0; let ll = u64$1.add3L(Al, Bl, Xl); Ah = u64$1.add3H(ll, Ah, Bh, Xh); Al = ll | 0; // v[d] = rotr(v[d] ^ v[a], 32) ({ Dh, Dl } = { Dh: Dh ^ Ah, Dl: Dl ^ Al }); ({ Dh, Dl } = { Dh: u64$1.rotr32H(Dh, Dl), Dl: u64$1.rotr32L(Dh, Dl) }); // v[c] = (v[c] + v[d]) | 0; ({ h: Ch, l: Cl } = u64$1.add(Ch, Cl, Dh, Dl)); // v[b] = rotr(v[b] ^ v[c], 24) ({ Bh, Bl } = { Bh: Bh ^ Ch, Bl: Bl ^ Cl }); ({ Bh, Bl } = { Bh: u64$1.rotrSH(Bh, Bl, 24), Bl: u64$1.rotrSL(Bh, Bl, 24) }); (BBUF[2 * a] = Al), (BBUF[2 * a + 1] = Ah); (BBUF[2 * b] = Bl), (BBUF[2 * b + 1] = Bh); (BBUF[2 * c] = Cl), (BBUF[2 * c + 1] = Ch); (BBUF[2 * d] = Dl), (BBUF[2 * d + 1] = Dh); } function G2b(a, b, c, d, msg, x) { // NOTE: V is LE here const Xl = msg[x], Xh = msg[x + 1]; // prettier-ignore let Al = BBUF[2 * a], Ah = BBUF[2 * a + 1]; // prettier-ignore let Bl = BBUF[2 * b], Bh = BBUF[2 * b + 1]; // prettier-ignore let Cl = BBUF[2 * c], Ch = BBUF[2 * c + 1]; // prettier-ignore let Dl = BBUF[2 * d], Dh = BBUF[2 * d + 1]; // prettier-ignore // v[a] = (v[a] + v[b] + x) | 0; let ll = u64$1.add3L(Al, Bl, Xl); Ah = u64$1.add3H(ll, Ah, Bh, Xh); Al = ll | 0; // v[d] = rotr(v[d] ^ v[a], 16) ({ Dh, Dl } = { Dh: Dh ^ Ah, Dl: Dl ^ Al }); ({ Dh, Dl } = { Dh: u64$1.rotrSH(Dh, Dl, 16), Dl: u64$1.rotrSL(Dh, Dl, 16) }); // v[c] = (v[c] + v[d]) | 0; ({ h: Ch, l: Cl } = u64$1.add(Ch, Cl, Dh, Dl)); // v[b] = rotr(v[b] ^ v[c], 63) ({ Bh, Bl } = { Bh: Bh ^ Ch, Bl: Bl ^ Cl }); ({ Bh, Bl } = { Bh: u64$1.rotrBH(Bh, Bl, 63), Bl: u64$1.rotrBL(Bh, Bl, 63) }); (BBUF[2 * a] = Al), (BBUF[2 * a + 1] = Ah); (BBUF[2 * b] = Bl), (BBUF[2 * b + 1] = Bh); (BBUF[2 * c] = Cl), (BBUF[2 * c + 1] = Ch); (BBUF[2 * d] = Dl), (BBUF[2 * d + 1] = Dh); } class BLAKE2b extends BLAKE { constructor(opts = {}) { super(128, opts.dkLen === undefined ? 64 : opts.dkLen, opts, 64, 16, 16); // Same as SHA-512, but LE this.v0l = B2B_IV[0] | 0; this.v0h = B2B_IV[1] | 0; this.v1l = B2B_IV[2] | 0; this.v1h = B2B_IV[3] | 0; this.v2l = B2B_IV[4] | 0; this.v2h = B2B_IV[5] | 0; this.v3l = B2B_IV[6] | 0; this.v3h = B2B_IV[7] | 0; this.v4l = B2B_IV[8] | 0; this.v4h = B2B_IV[9] | 0; this.v5l = B2B_IV[10] | 0; this.v5h = B2B_IV[11] | 0; this.v6l = B2B_IV[12] | 0; this.v6h = B2B_IV[13] | 0; this.v7l = B2B_IV[14] | 0; this.v7h = B2B_IV[15] | 0; const keyLength = opts.key ? opts.key.length : 0; this.v0l ^= this.outputLen | (keyLength << 8) | (0x01 << 16) | (0x01 << 24); if (opts.salt) { const salt = u32(toBytes(opts.salt)); this.v4l ^= byteSwapIfBE(salt[0]); this.v4h ^= byteSwapIfBE(salt[1]); this.v5l ^= byteSwapIfBE(salt[2]); this.v5h ^= byteSwapIfBE(salt[3]); } if (opts.personalization) { const pers = u32(toBytes(opts.personalization)); this.v6l ^= byteSwapIfBE(pers[0]); this.v6h ^= byteSwapIfBE(pers[1]); this.v7l ^= byteSwapIfBE(pers[2]); this.v7h ^= byteSwapIfBE(pers[3]); } if (opts.key) { // Pad to blockLen and update const tmp = new Uint8Array(this.blockLen); tmp.set(toBytes(opts.key)); this.update(tmp); } } // prettier-ignore get() { let { v0l, v0h, v1l, v1h, v2l, v2h, v3l, v3h, v4l, v4h, v5l, v5h, v6l, v6h, v7l, v7h } = this; return [v0l, v0h, v1l, v1h, v2l, v2h, v3l, v3h, v4l, v4h, v5l, v5h, v6l, v6h, v7l, v7h]; } // prettier-ignore set(v0l, v0h, v1l, v1h, v2l, v2h, v3l, v3h, v4l, v4h, v5l, v5h, v6l, v6h, v7l, v7h) { this.v0l = v0l | 0; this.