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 assert = require("assert");
  5const createBlakeHash = require("blake-hash");
  6
  7const GENPOINT_PREFIX = "Iden3_PedersenGenerator";
  8const windowSize = 4;
  9const nWindowsPerSegment = 50;
 10
 11exports.hash = pedersenHash;
 12exports.getBasePoint = getBasePoint;
 13
 14function pedersenHash(msg) {
 15    const bitsPerSegment = windowSize*nWindowsPerSegment;
 16    const bits = buffer2bits(msg);
 17
 18    const nSegments = Math.floor((bits.length - 1)/(windowSize*nWindowsPerSegment)) +1;
 19
 20    let accP = [bigInt.zero,bigInt.one];
 21
 22    for (let s=0; s<nSegments; s++) {
 23        let nWindows;
 24        if (s == nSegments-1) {
 25            nWindows = Math.floor(((bits.length - (nSegments - 1)*bitsPerSegment) - 1) / windowSize) +1;
 26        } else {
 27            nWindows = nWindowsPerSegment;
 28        }
 29        let escalar = bigInt.zero;
 30        let exp = bigInt.one;
 31        for (let w=0; w<nWindows; w++) {
 32            let o = s*bitsPerSegment + w*windowSize;
 33            let acc = bigInt.one;
 34            for (let b=0; ((b<windowSize-1)&&(o<bits.length)) ; b++) {
 35                if (bits[o]) {
 36                    acc = acc.add( bigInt.one.shl(b) );
 37                }
 38                o++;
 39            }
 40            if (o<bits.length) {
 41                if (bits[o]) {
 42                    acc = acc.neg();
 43                }
 44                o++;
 45            }
 46            escalar = escalar.add(acc.mul(exp));
 47            exp = exp.shl(windowSize+1);
 48        }
 49
 50        if (escalar.lesser(bigInt.zero)) {
 51            escalar = babyJub.subOrder.add(escalar);
 52        }
 53
 54        accP = babyJub.addPoint(accP, babyJub.mulPointEscalar(getBasePoint(s), escalar));
 55    }
 56
 57    return babyJub.packPoint(accP);
 58}
 59
 60let bases = [];
 61
 62function getBasePoint(pointIdx) {
 63    if (pointIdx<bases.length) return bases[pointIdx];
 64    let p= null;
 65    let tryIdx = 0;
 66    while (p==null) {
 67        const S = GENPOINT_PREFIX + "_" + padLeftZeros(pointIdx, 32) + "_" + padLeftZeros(tryIdx, 32);
 68        const h = createBlakeHash("blake256").update(S).digest();
 69        h[31] = h[31] & 0xBF;  // Set 255th bit to 0 (256th is the signal and 254th is the last possible bit to 1)
 70        p = babyJub.unpackPoint(h);
 71        tryIdx++;
 72    }
 73
 74    const p8 = babyJub.mulPointEscalar(p, 8);
 75
 76    assert(babyJub.inSubgroup(p8), "Point not in curve");
 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