arnaucube
arnaucube/circomlibPublic Self-hosted repository
circomlib/src/pedersenHash.js
src/pedersenHash.jsRaw
  1const bn128 = require("snarkjs").bn128;
  2const bigInt = require("snarkjs").bigInt;
  3const babyJub = require("./babyjub");
  4const createBlakeHash = require("blake-hash");
  5
  6const GENPOINT_PREFIX = "PedersenGenerator";
  7const windowSize = 4;
  8const nWindowsPerSegment = 50;
  9
 10exports.hash = pedersenHash;
 11exports.getBasePoint = getBasePoint;
 12
 13function pedersenHash(msg) {
 14    const bitsPerSegment = windowSize*nWindowsPerSegment;
 15    const bits = buffer2bits(msg);
 16
 17    const nSegments = Math.floor((bits.length - 1)/(windowSize*nWindowsPerSegment)) +1;
 18
 19    let accP = [bigInt.zero,bigInt.one];
 20
 21    for (let s=0; s<nSegments; s++) {
 22        let nWindows;
 23        if (s == nSegments-1) {
 24            nWindows = Math.floor(((bits.length - (nSegments - 1)*bitsPerSegment) - 1) / windowSize) +1;
 25        } else {
 26            nWindows = nWindowsPerSegment;
 27        }
 28        let escalar = bigInt.zero;
 29        let exp = bigInt.one;
 30        for (let w=0; w<nWindows; w++) {
 31            let o = s*bitsPerSegment + w*windowSize;
 32            let acc = bigInt.one;
 33            for (let b=0; ((b<windowSize-1)&&(o<bits.length)) ; b++) {
 34                if (bits[o]) {
 35                    acc = acc.add( bigInt.one.shl(b) );
 36                }
 37                o++;
 38            }
 39            if (o<bits.length) {
 40                if (bits[o]) {
 41                    acc = acc.neg();
 42                }
 43                o++;
 44            }
 45            escalar = escalar.add(acc.mul(exp));
 46            exp = exp.shl(windowSize+1);
 47        }
 48
 49        if (escalar.lesser(bigInt.zero)) {
 50            escalar = babyJub.subOrder.add(escalar);
 51        }
 52
 53        accP = babyJub.addPoint(accP, babyJub.mulPointEscalar(getBasePoint(s), escalar));
 54    }
 55
 56    return babyJub.packPoint(accP);
 57}
 58
 59let bases = [];
 60
 61function getBasePoint(pointIdx) {
 62    if (pointIdx<bases.length) return bases[pointIdx];
 63    let p= null;
 64    let tryIdx = 0;
 65    while (p==null) {
 66        const S = GENPOINT_PREFIX + "_" + padLeftZeros(pointIdx, 32) + "_" + padLeftZeros(tryIdx, 32);
 67        const h = createBlakeHash("blake256").update(S).digest();
 68        h[31] = h[31] & 0xBF;  // Set 255th bit to 0 (256th is the signal and 254th is the last possible bit to 1)
 69        p = babyJub.unpackPoint(h);
 70        tryIdx++;
 71    }
 72
 73    const p8 = babyJub.mulPointEscalar(p, 8);
 74
 75    if (!babyJub.inSubgroup(p8)) {
 76        throw new Error("Point not in curve");
 77    }
 78
 79    bases[pointIdx] = p8;
 80    return p8;
 81}
 82
 83function padLeftZeros(idx, n) {
 84    let sidx = "" + idx;
 85    while (sidx.length<n) sidx = "0"+sidx;
 86    return sidx;
 87}
 88
 89/*
 90Input a buffer
 91Returns an array of booleans. 0 is LSB of first byte and so on.
 92 */
 93function buffer2bits(buff) {
 94    const res = new Array(buff.length*8);
 95    for (let i=0; i<buff.length; i++) {
 96        const b = buff[i];
 97        res[i*8] = b & 0x01;
 98        res[i*8+1] = b & 0x02;
 99        res[i*8+2] = b & 0x04;
100        res[i*8+3] = b & 0x08;
101        res[i*8+4] = b & 0x10;
102        res[i*8+5] = b & 0x20;
103        res[i*8+6] = b & 0x40;
104        res[i*8+7] = b & 0x80;
105    }
106    return res;
107}
108
109
110
111