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