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