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