Go back to blake

This commit is contained in:
Jordi Baylina 2020-04-19 12:23:55 +02:00
parent 6a1efe4820
commit d5ed1c3ce4
No known key found for this signature in database
GPG Key ID: 7480C80C1BE43112
10 changed files with 88 additions and 56 deletions

@ -177,16 +177,17 @@ template Pedersen(n) {
signal output out[2]; signal output out[2];
var BASE[10][2] = [ var BASE[10][2] = [
[7688621503272331394947188562469131124099290577812125474996268020905176040083,6637287939860384587467947982369268811366630904563077767287326262235485629411], [10457101036533406547632367118273992217979173478358440826365724437999023779287,19824078218392094440610104313265183977899662750282163392862422243483260492317],
[11549681895645637778324638856880330712650895608496649854094912415387988201330,5771732722784528537721081267383956005090479808901717812009343940574217488577], [2671756056509184035029146175565761955751135805354291559563293617232983272177,2663205510731142763556352975002641716101654201788071096152948830924149045094],
[18790245153471844934157747708238883966079935875787657036767664036124524381945,18300275459419441151064576487317481499516933849631632883767173501999997278432], [5802099305472655231388284418920769829666717045250560929368476121199858275951,5980429700218124965372158798884772646841287887664001482443826541541529227896],
[16301069151422548986850494139112207641738464387919729729324473657161689764196,8215273507373494014441104012907835625670941526105528197815397741007626226499], [7107336197374528537877327281242680114152313102022415488494307685842428166594,2857869773864086953506483169737724679646433914307247183624878062391496185654],
[12597665704678284488008395353749282149622295037737374782196049599390683534185,4072455241781501621593714139281767473040087753548015968773801065193764079468], [20265828622013100949498132415626198973119240347465898028410217039057588424236,1160461593266035632937973507065134938065359936056410650153315956301179689506],
[4729410576230735258214831208080552588881894465489299233097088872252465832672,14367731890670510422926552586486424937476635415639602730590517235570020260326], [1487999857809287756929114517587739322941449154962237464737694709326309567994,14017256862867289575056460215526364897734808720610101650676790868051368668003],
[7546420686025050869200393054526306477146836870617678274607971529534032974471,8663210466512842901413293603100781938253817808912549776944118491282484711929], [14618644331049802168996997831720384953259095788558646464435263343433563860015,13115243279999696210147231297848654998887864576952244320558158620692603342236],
[6544653022506992755201027646251976600601201151329001772892901529509137954387,5932506509962692832681604586561215780097326378431958035490245111470435106811], [6814338563135591367010655964669793483652536871717891893032616415581401894627,13660303521961041205824633772157003587453809761793065294055279768121314853695],
[12376274813795671622507230443130412169480807188767687554607910279743333852725,10116389110458158800073166533660211332390835019644001845057351607297889034557], [3571615583211663069428808372184817973703476260057504149923239576077102575715,11981351099832644138306422070127357074117642951423551606012551622164230222506],
[18268098112071835140361074835791174816144587762778386397940339415400583397725,8120955462199046866292537174552276799123029303901205157708576578886090835495] [18597552580465440374022635246985743886550544261632147935254624835147509493269,6753322320275422086923032033899357299485124665258735666995435957890214041481]
]; ];
var nSegments = ((n-1)\200)+1; var nSegments = ((n-1)\200)+1;

@ -29,16 +29,17 @@ template Pedersen(n) {
component escalarMuls[nexps]; component escalarMuls[nexps];
var PBASE[10][2] = [ var PBASE[10][2] = [
[7688621503272331394947188562469131124099290577812125474996268020905176040083,6637287939860384587467947982369268811366630904563077767287326262235485629411], [10457101036533406547632367118273992217979173478358440826365724437999023779287,19824078218392094440610104313265183977899662750282163392862422243483260492317],
[11549681895645637778324638856880330712650895608496649854094912415387988201330,5771732722784528537721081267383956005090479808901717812009343940574217488577], [2671756056509184035029146175565761955751135805354291559563293617232983272177,2663205510731142763556352975002641716101654201788071096152948830924149045094],
[18790245153471844934157747708238883966079935875787657036767664036124524381945,18300275459419441151064576487317481499516933849631632883767173501999997278432], [5802099305472655231388284418920769829666717045250560929368476121199858275951,5980429700218124965372158798884772646841287887664001482443826541541529227896],
[16301069151422548986850494139112207641738464387919729729324473657161689764196,8215273507373494014441104012907835625670941526105528197815397741007626226499], [7107336197374528537877327281242680114152313102022415488494307685842428166594,2857869773864086953506483169737724679646433914307247183624878062391496185654],
[12597665704678284488008395353749282149622295037737374782196049599390683534185,4072455241781501621593714139281767473040087753548015968773801065193764079468], [20265828622013100949498132415626198973119240347465898028410217039057588424236,1160461593266035632937973507065134938065359936056410650153315956301179689506],
[4729410576230735258214831208080552588881894465489299233097088872252465832672,14367731890670510422926552586486424937476635415639602730590517235570020260326], [1487999857809287756929114517587739322941449154962237464737694709326309567994,14017256862867289575056460215526364897734808720610101650676790868051368668003],
[7546420686025050869200393054526306477146836870617678274607971529534032974471,8663210466512842901413293603100781938253817808912549776944118491282484711929], [14618644331049802168996997831720384953259095788558646464435263343433563860015,13115243279999696210147231297848654998887864576952244320558158620692603342236],
[6544653022506992755201027646251976600601201151329001772892901529509137954387,5932506509962692832681604586561215780097326378431958035490245111470435106811], [6814338563135591367010655964669793483652536871717891893032616415581401894627,13660303521961041205824633772157003587453809761793065294055279768121314853695],
[12376274813795671622507230443130412169480807188767687554607910279743333852725,10116389110458158800073166533660211332390835019644001845057351607297889034557], [3571615583211663069428808372184817973703476260057504149923239576077102575715,11981351099832644138306422070127357074117642951423551606012551622164230222506],
[18268098112071835140361074835791174816144587762778386397940339415400583397725,8120955462199046866292537174552276799123029303901205157708576578886090835495] [18597552580465440374022635246985743886550544261632147935254624835147509493269,6753322320275422086923032033899357299485124665258735666995435957890214041481]
]; ];
var i; var i;

10
package-lock.json generated

@ -292,6 +292,16 @@
"safe-buffer": "^5.1.1" "safe-buffer": "^5.1.1"
} }
}, },
"blake-hash": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/blake-hash/-/blake-hash-1.1.0.tgz",
"integrity": "sha512-rNbOFPT7DC/0XnLBJ0noWuzcV+9kHwEKzRGljHMDLQzYv6WZT1vjV3UkWQuNFzyr5tIL7zSsw7A834pgTl75xQ==",
"requires": {
"bindings": "^1.2.1",
"inherits": "^2.0.3",
"nan": "^2.2.1"
}
},
"blake2b": { "blake2b": {
"version": "2.1.3", "version": "2.1.3",
"resolved": "https://registry.npmjs.org/blake2b/-/blake2b-2.1.3.tgz", "resolved": "https://registry.npmjs.org/blake2b/-/blake2b-2.1.3.tgz",

@ -24,6 +24,7 @@
"author": "0Kims", "author": "0Kims",
"license": "GPL-3.0", "license": "GPL-3.0",
"dependencies": { "dependencies": {
"blake-hash": "^1.1.0",
"blake2b": "^2.1.3", "blake2b": "^2.1.3",
"circom": "0.5.8", "circom": "0.5.8",
"ffjavascript": "0.1.0", "ffjavascript": "0.1.0",

@ -1,4 +1,4 @@
const blake2b = require("blake2b"); const createBlakeHash = require("blake-hash");
const Scalar = require("ffjavascript").Scalar; const Scalar = require("ffjavascript").Scalar;
const F1Field = require("ffjavascript").F1Field; const F1Field = require("ffjavascript").F1Field;
const babyJub = require("./babyjub"); const babyJub = require("./babyjub");
@ -32,19 +32,19 @@ function pruneBuffer(_buff) {
} }
function prv2pub(prv) { function prv2pub(prv) {
const sBuff = pruneBuffer(blake2b(64).update(prv).digest().slice(0,32)); const sBuff = pruneBuffer(createBlakeHash("blake512").update(prv).digest().slice(0,32));
let s = utils.leBuff2int(sBuff); let s = utils.leBuff2int(sBuff);
const A = babyJub.mulPointEscalar(babyJub.Base8, Scalar.shr(s,3)); const A = babyJub.mulPointEscalar(babyJub.Base8, Scalar.shr(s,3));
return A; return A;
} }
function sign(prv, msg) { function sign(prv, msg) {
const h1 = Buffer.from(blake2b(64).update(prv).digest()); const h1 = createBlakeHash("blake512").update(prv).digest();
const sBuff = pruneBuffer(h1.slice(0,32)); const sBuff = pruneBuffer(h1.slice(0,32));
const s = utils.leBuff2int(sBuff); const s = utils.leBuff2int(sBuff);
const A = babyJub.mulPointEscalar(babyJub.Base8, Scalar.shr(s, 3)); const A = babyJub.mulPointEscalar(babyJub.Base8, Scalar.shr(s, 3));
const rBuff = Buffer.from(blake2b(64).update(Buffer.concat([h1.slice(32,64), msg])).digest()); const rBuff = createBlakeHash("blake512").update(Buffer.concat([h1.slice(32,64), msg])).digest();
let r = utils.leBuff2int(rBuff); let r = utils.leBuff2int(rBuff);
const Fr = new F1Field(babyJub.subOrder); const Fr = new F1Field(babyJub.subOrder);
r = Fr.e(r); r = Fr.e(r);
@ -61,13 +61,13 @@ function sign(prv, msg) {
} }
function signMiMC(prv, msg) { function signMiMC(prv, msg) {
const h1 = Buffer.from(blake2b(64).update(prv).digest()); const h1 = createBlakeHash("blake512").update(prv).digest();
const sBuff = pruneBuffer(h1.slice(0,32)); const sBuff = pruneBuffer(h1.slice(0,32));
const s = utils.leBuff2int(sBuff); const s = utils.leBuff2int(sBuff);
const A = babyJub.mulPointEscalar(babyJub.Base8, Scalar.shr(s, 3)); const A = babyJub.mulPointEscalar(babyJub.Base8, Scalar.shr(s, 3));
const msgBuff = utils.leInt2Buff(msg, 32); const msgBuff = utils.leInt2Buff(msg, 32);
const rBuff = Buffer.from(blake2b(64).update(Buffer.concat([h1.slice(32,64), msgBuff])).digest()); const rBuff = createBlakeHash("blake512").update(Buffer.concat([h1.slice(32,64), msgBuff])).digest();
let r = utils.leBuff2int(rBuff); let r = utils.leBuff2int(rBuff);
const Fr = new F1Field(babyJub.subOrder); const Fr = new F1Field(babyJub.subOrder);
r = Fr.e(r); r = Fr.e(r);
@ -81,13 +81,13 @@ function signMiMC(prv, msg) {
} }
function signMiMCSponge(prv, msg) { function signMiMCSponge(prv, msg) {
const h1 = Buffer.from(blake2b(64).update(prv).digest()); const h1 = createBlakeHash("blake512").update(prv).digest();
const sBuff = pruneBuffer(h1.slice(0,32)); const sBuff = pruneBuffer(h1.slice(0,32));
const s = utils.leBuff2int(sBuff); const s = utils.leBuff2int(sBuff);
const A = babyJub.mulPointEscalar(babyJub.Base8, Scalar.shr(s, 3)); const A = babyJub.mulPointEscalar(babyJub.Base8, Scalar.shr(s, 3));
const msgBuff = utils.leInt2Buff(msg, 32); const msgBuff = utils.leInt2Buff(msg, 32);
const rBuff = Buffer.from(blake2b(64).update(Buffer.concat([h1.slice(32,64), msgBuff])).digest()); const rBuff = createBlakeHash("blake512").update(Buffer.concat([h1.slice(32,64), msgBuff])).digest();
let r = utils.leBuff2int(rBuff); let r = utils.leBuff2int(rBuff);
const Fr = new F1Field(babyJub.subOrder); const Fr = new F1Field(babyJub.subOrder);
r = Fr.e(r); r = Fr.e(r);
@ -101,13 +101,13 @@ function signMiMCSponge(prv, msg) {
} }
function signPoseidon(prv, msg) { function signPoseidon(prv, msg) {
const h1 = Buffer.from(blake2b(64).update(prv).digest()); const h1 = createBlakeHash("blake512").update(prv).digest();
const sBuff = pruneBuffer(h1.slice(0,32)); const sBuff = pruneBuffer(h1.slice(0,32));
const s = utils.leBuff2int(sBuff); const s = utils.leBuff2int(sBuff);
const A = babyJub.mulPointEscalar(babyJub.Base8, Scalar.shr(s, 3)); const A = babyJub.mulPointEscalar(babyJub.Base8, Scalar.shr(s, 3));
const msgBuff = utils.leInt2Buff(msg, 32); const msgBuff = utils.leInt2Buff(msg, 32);
const rBuff = Buffer.from(blake2b(64).update(Buffer.concat([h1.slice(32,64), msgBuff])).digest()); const rBuff = createBlakeHash("blake512").update(Buffer.concat([h1.slice(32,64), msgBuff])).digest();
let r = utils.leBuff2int(rBuff); let r = utils.leBuff2int(rBuff);
const Fr = new F1Field(babyJub.subOrder); const Fr = new F1Field(babyJub.subOrder);
r = Fr.e(r); r = Fr.e(r);

@ -1,4 +1,5 @@
const babyJub = require("./babyjub"); const babyJub = require("./babyjub");
const createBlakeHash = require("blake-hash");
const blake2b = require("blake2b"); const blake2b = require("blake2b");
const Scalar = require("ffjavascript").Scalar; const Scalar = require("ffjavascript").Scalar;
@ -9,7 +10,17 @@ const nWindowsPerSegment = 50;
exports.hash = pedersenHash; exports.hash = pedersenHash;
exports.getBasePoint = getBasePoint; exports.getBasePoint = getBasePoint;
function pedersenHash(msg) { function baseHash(type, S) {
if (type == "blake") {
return createBlakeHash("blake256").update(S).digest();
} else if (type == "blake2b") {
return Buffer.from(blake2b(32).update(Buffer.from(S)).digest());
}
}
function pedersenHash(msg, options) {
options = options || {};
options.baseHash = options.baseHash || "blake";
const bitsPerSegment = windowSize*nWindowsPerSegment; const bitsPerSegment = windowSize*nWindowsPerSegment;
const bits = buffer2bits(msg); const bits = buffer2bits(msg);
@ -49,7 +60,7 @@ function pedersenHash(msg) {
escalar = Scalar.add( escalar, babyJub.subOrder); escalar = Scalar.add( escalar, babyJub.subOrder);
} }
accP = babyJub.addPoint(accP, babyJub.mulPointEscalar(getBasePoint(s), escalar)); accP = babyJub.addPoint(accP, babyJub.mulPointEscalar(getBasePoint(options.baseHash, s), escalar));
} }
return babyJub.packPoint(accP); return babyJub.packPoint(accP);
@ -57,13 +68,13 @@ function pedersenHash(msg) {
let bases = []; let bases = [];
function getBasePoint(pointIdx) { function getBasePoint(baseHashType, pointIdx) {
if (pointIdx<bases.length) return bases[pointIdx]; if (pointIdx<bases.length) return bases[pointIdx];
let p= null; let p= null;
let tryIdx = 0; let tryIdx = 0;
while (p==null) { while (p==null) {
const S = GENPOINT_PREFIX + "_" + padLeftZeros(pointIdx, 32) + "_" + padLeftZeros(tryIdx, 32); const S = GENPOINT_PREFIX + "_" + padLeftZeros(pointIdx, 32) + "_" + padLeftZeros(tryIdx, 32);
const h = Buffer.from(blake2b(32).update(Buffer.from(S)).digest()); const h = baseHash(baseHashType, S);
h[31] = h[31] & 0xBF; // Set 255th bit to 0 (256th is the signal and 254th is the last possible bit to 1) h[31] = h[31] & 0xBF; // Set 255th bit to 0 (256th is the signal and 254th is the last possible bit to 1)
p = babyJub.unpackPoint(h); p = babyJub.unpackPoint(h);
tryIdx++; tryIdx++;

@ -7,7 +7,15 @@ if (typeof process.argv[2] != "undefined") {
nBases = 5; nBases = 5;
} }
let baseHash;
if (typeof process.argv[3] != "undefined") {
baseHash = process.argv[3];
} else {
baseHash = "blake";
}
for (let i=0; i < nBases; i++) { for (let i=0; i < nBases; i++) {
const p = pedersenHash.getBasePoint(i); const p = pedersenHash.getBasePoint(baseHash, i);
console.log(`[${p[0]},${p[1]}]`); console.log(`[${p[0]},${p[1]}]`);
} }

@ -1,7 +1,7 @@
const chai = require("chai"); const chai = require("chai");
const path = require("path"); const path = require("path");
const blake2b = require("blake2b"); const createBlakeHash = require("blake-hash");
const eddsa = require("../src/eddsa.js"); const eddsa = require("../src/eddsa.js");
const F = require("../src/babyjub.js").F; const F = require("../src/babyjub.js").F;
@ -94,7 +94,7 @@ describe("Baby Jub test", function () {
it("Should extract the public key from the private one", async () => { it("Should extract the public key from the private one", async () => {
const rawpvk = Buffer.from("0001020304050607080900010203040506070809000102030405060708090021", "hex"); const rawpvk = Buffer.from("0001020304050607080900010203040506070809000102030405060708090021", "hex");
const pvk = eddsa.pruneBuffer(Buffer.from(blake2b(64).update(rawpvk).digest().slice(0,32))); const pvk = eddsa.pruneBuffer(createBlakeHash("blake512").update(rawpvk).digest().slice(0,32));
const S = Scalar.shr(utils.leBuff2int(pvk), 3); const S = Scalar.shr(utils.leBuff2int(pvk), 3);
const A = eddsa.prv2pub(rawpvk); const A = eddsa.prv2pub(rawpvk);

@ -22,24 +22,24 @@ describe("EdDSA js test", function () {
const pubKey = eddsa.prv2pub(prvKey); const pubKey = eddsa.prv2pub(prvKey);
assert.equal(pubKey[0].toString(), assert.equal(pubKey[0].toString(),
"17579234973106307986399040784563986669343100608865726413246909559198451825625"); "13277427435165878497778222415993513565335242147425444199013288855685581939618");
assert.equal(pubKey[1].toString(), assert.equal(pubKey[1].toString(),
"21581828029826859845363968476425861244058376747493285816141526544272562145486"); "13622229784656158136036771217484571176836296686641868549125388198837476602820");
const pPubKey = babyJub.packPoint(pubKey); const pPubKey = babyJub.packPoint(pubKey);
const signature = eddsa.signMiMC(prvKey, msg); const signature = eddsa.signMiMC(prvKey, msg);
assert.equal(signature.R8[0].toString(), assert.equal(signature.R8[0].toString(),
"12672422877531089818651367820728973438446851190471722610781936061829103362897"); "11384336176656855268977457483345535180380036354188103142384839473266348197733");
assert.equal(signature.R8[1].toString(), assert.equal(signature.R8[1].toString(),
"12052234579439634484237590306927118446073354173341433290934144373261241958718"); "15383486972088797283337779941324724402501462225528836549661220478783371668959");
assert.equal(signature.S.toString(), assert.equal(signature.S.toString(),
"1582013862333331285840015273849085014739146294568319205499642618291614907374"); "2523202440825208709475937830811065542425109372212752003460238913256192595070");
const pSignature = eddsa.packSignature(signature); const pSignature = eddsa.packSignature(signature);
assert.equal(pSignature.toString("hex"), ""+ assert.equal(pSignature.toString("hex"), ""+
"3e417cd811f9c9c545a680b962e45d22ccb62b2284b4fe4bbc9fdb50b252a59a" + "dfedb4315d3f2eb4de2d3c510d7a987dcab67089c8ace06308827bf5bcbe02a2"+
"eefbebe2b895393fa0e9b5b31b19e65a63fee5d7b6261d8d5b6b847c5b637f03"); "7ed40dab29bf993c928e789d007387998901a24913d44fddb64b1f21fc149405");
const uSignature = eddsa.unpackSignature(pSignature); const uSignature = eddsa.unpackSignature(pSignature);
assert(eddsa.verifyMiMC(msg, uSignature, pubKey)); assert(eddsa.verifyMiMC(msg, uSignature, pubKey));
@ -55,24 +55,24 @@ describe("EdDSA js test", function () {
const pubKey = eddsa.prv2pub(prvKey); const pubKey = eddsa.prv2pub(prvKey);
assert.equal(pubKey[0].toString(), assert.equal(pubKey[0].toString(),
"17579234973106307986399040784563986669343100608865726413246909559198451825625"); "13277427435165878497778222415993513565335242147425444199013288855685581939618");
assert.equal(pubKey[1].toString(), assert.equal(pubKey[1].toString(),
"21581828029826859845363968476425861244058376747493285816141526544272562145486"); "13622229784656158136036771217484571176836296686641868549125388198837476602820");
const pPubKey = babyJub.packPoint(pubKey); const pPubKey = babyJub.packPoint(pubKey);
const signature = eddsa.signPoseidon(prvKey, msg); const signature = eddsa.signPoseidon(prvKey, msg);
assert.equal(signature.R8[0].toString(), assert.equal(signature.R8[0].toString(),
"12672422877531089818651367820728973438446851190471722610781936061829103362897"); "11384336176656855268977457483345535180380036354188103142384839473266348197733");
assert.equal(signature.R8[1].toString(), assert.equal(signature.R8[1].toString(),
"12052234579439634484237590306927118446073354173341433290934144373261241958718"); "15383486972088797283337779941324724402501462225528836549661220478783371668959");
assert.equal(signature.S.toString(), assert.equal(signature.S.toString(),
"2318334603430781860679872910160434499077270843466490702990199622594868564504"); "248298168863866362217836334079793350221620631973732197668910946177382043688");
const pSignature = eddsa.packSignature(signature); const pSignature = eddsa.packSignature(signature);
assert.equal(pSignature.toString("hex"), ""+ assert.equal(pSignature.toString("hex"), ""+
"3e417cd811f9c9c545a680b962e45d22ccb62b2284b4fe4bbc9fdb50b252a59a" + "dfedb4315d3f2eb4de2d3c510d7a987dcab67089c8ace06308827bf5bcbe02a2"+
"1852c049fc6286138a0ddb57718049a09374fdf0390686c7ac5637b481212005"); "28506bce274aa1b3f7e7c2fd7e4fe09bff8f9aa37a42def7994e98f322888c00");
const uSignature = eddsa.unpackSignature(pSignature); const uSignature = eddsa.unpackSignature(pSignature);
assert(eddsa.verifyPoseidon(msg, uSignature, pubKey)); assert(eddsa.verifyPoseidon(msg, uSignature, pubKey));

@ -8,11 +8,11 @@ const babyJub = require("../src/babyjub.js");
const PBASE = const PBASE =
[ [
[Fr.e("7688621503272331394947188562469131124099290577812125474996268020905176040083"),Fr.e("6637287939860384587467947982369268811366630904563077767287326262235485629411")], [Fr.e("10457101036533406547632367118273992217979173478358440826365724437999023779287"),Fr.e("19824078218392094440610104313265183977899662750282163392862422243483260492317")],
[Fr.e("11549681895645637778324638856880330712650895608496649854094912415387988201330"),Fr.e("5771732722784528537721081267383956005090479808901717812009343940574217488577")], [Fr.e("2671756056509184035029146175565761955751135805354291559563293617232983272177"),Fr.e("2663205510731142763556352975002641716101654201788071096152948830924149045094")],
[Fr.e("18790245153471844934157747708238883966079935875787657036767664036124524381945"),Fr.e("18300275459419441151064576487317481499516933849631632883767173501999997278432")], [Fr.e("5802099305472655231388284418920769829666717045250560929368476121199858275951"),Fr.e("5980429700218124965372158798884772646841287887664001482443826541541529227896")],
[Fr.e("16301069151422548986850494139112207641738464387919729729324473657161689764196"),Fr.e("8215273507373494014441104012907835625670941526105528197815397741007626226499")], [Fr.e("7107336197374528537877327281242680114152313102022415488494307685842428166594"),Fr.e("2857869773864086953506483169737724679646433914307247183624878062391496185654")],
[Fr.e("12597665704678284488008395353749282149622295037737374782196049599390683534185"),Fr.e("4072455241781501621593714139281767473040087753548015968773801065193764079468")] [Fr.e("20265828622013100949498132415626198973119240347465898028410217039057588424236"),Fr.e("1160461593266035632937973507065134938065359936056410650153315956301179689506")]
]; ];
describe("Double Pedersen test", function() { describe("Double Pedersen test", function() {