Add test for simple rct signature generation

pull/34/head
HenryNguyen5 6 years ago
parent 0be08905a4
commit cc16607acd

@ -1673,7 +1673,6 @@ var cnUtil = function(currencyConfig) {
// this shows that sum inputs = sum outputs
//Ver:
// verifies the above sig is created corretly
// simple version, assuming only post Rct
this.verRctMG = function(mg, pubs, outPk, txnFeeKey, message, kimg) {
const cols = pubs.length;
@ -1712,6 +1711,26 @@ var cnUtil = function(currencyConfig) {
return this.MLSAG_ver(message, M, mg, kimg);
};
// simple version, assuming only post Rct
this.verRctMGSimple = function(message, mg, pubs, C, kimg) {
try {
const rows = 1;
const cols = pubs.len;
const M = [];
for (let i = 0; i < cols; i++) {
M[i][0] = pubs[i].dest;
M[i][1] = this.ge_sub(pubs[i].mask, C);
}
return MLSAG_ver(message, M, mg, kimg);
} catch (error) {
console.error("[verRctSimple]", error);
return false;
}
};
this.verBulletProof = function() {
throw Error("verBulletProof is not implemented");
};
@ -1940,6 +1959,136 @@ var cnUtil = function(currencyConfig) {
return true;
} catch (e) {
console.error("Error in verRct: ", e);
return false;
}
};
//ver RingCT simple
//assumes only post-rct style inputs (at least for max anonymity)
this.verRctSimple = function(rv, semantics, mixRing, kimgs) {
try {
if (rv.type === 0x04) {
throw Error("Simple Bulletproof validation not implemented");
}
if (rv.type !== 0x02 && rv.type !== 0x04) {
throw Error("verRctSimple called on non simple rctSig");
}
if (semantics) {
if (rv.type == 0x04) {
throw Error(
"Simple Bulletproof validation not implemented",
);
} else {
if (rv.outPk.length !== rv.p.rangeSigs.length) {
throw Error(
"Mismatched sizes of outPk and rv.p.rangeSigs",
);
}
if (rv.pseudoOuts.length !== rv.p.MGs.length) {
throw Error(
"Mismatched sizes of rv.pseudoOuts and rv.p.MGs",
);
}
// originally the check is rv.p.pseudoOuts.length, but this'll throw
// until p.pseudoOuts is added as a property to the rv object
if (rv.p.pseudoOuts) {
throw Error("rv.p.pseudoOuts must be empty");
}
}
} else {
if (rv.type === 0x04) {
throw Error(
"Simple Bulletproof validation not implemented",
);
} else {
// semantics check is early, and mixRing/MGs aren't resolved yet
if (rv.pseudoOuts.length !== mixRing.length) {
throw Error(
"Mismatched sizes of rv.pseudoOuts and mixRing",
);
}
}
}
// if bulletproof, then use rv.p.pseudoOuts, otherwise use rv.pseudoOuts
const pseudoOuts =
rv.type === 0x04 ? rv.p.pseudoOuts : rv.pseudoOuts;
if (semantics) {
let sumOutpks = this.identity();
for (let i = 0; i < rv.outPk.length; i++) {
sumOutpks = this.ge_add(sumOutpks, rv.outPk[i]); // add all of the output commitments
}
const txnFeeKey = this.ge_scalarmult(
this.H,
this.d2s(rv.txnFee),
);
sumOutpks = this.ge_add(txnFeeKey, sumOutpks); // add txnfeekey
let sumPseudoOuts = this.identity();
for (let i = 0; i < pseudoOuts.length; i++) {
sumPseudoOuts = this.ge_add(sumPseudoOuts, pseudoOuts[i]); // sum up all of the pseudoOuts
}
if (sumOutpks !== sumPseudoOuts) {
console.error("Sum check failed");
return false;
}
const results = [];
for (let i = 0; i < rv.outPk.length; i++) {
// might want to parallelize this like its done in the c++ codebase
// via some abstraction library to support browser + node
if (rv.p.rangeSigs.length === 0) {
results[i] = this.verBulletproof(rv.p.bulletproofs[i]);
} else {
// mask -> C if public
results[i] = this.verRange(
rv.outPk[i],
rv.p.rangeSigs[i],
);
}
}
for (let i = 0; i < results.length; i++) {
if (!results[i]) {
console.error(
"Range proof verification failed for output",
i,
);
return false;
}
}
} else {
const message = this.get_pre_mlsag_hash(rv);
const results = [];
for (let i = 0; i < mixRing.length; i++) {
results[i] = this.verRctMGSimple(
message,
rv.p.MGs[i],
mixRing[i],
pseudoOuts[i],
kimgs[i],
);
}
for (let i = 0; i < results.length; i++) {
if (!results[i]) {
console.error(
"Range proof verification failed for output",
i,
);
return false;
}
}
}
return true;
} catch (error) {
console.log("[verRctSimple]", error);
return false;
}
};
@ -1970,7 +2119,7 @@ var cnUtil = function(currencyConfig) {
mask,
);
console.log(C, Ctmp);
console.log("[decodeRct]", C, Ctmp);
if (C !== Ctmp) {
throw Error(
"warning, amount decoded incorrectly, will be unable to spend",
@ -1978,6 +2127,38 @@ var cnUtil = function(currencyConfig) {
}
return { amount, mask };
};
this.decodeRctSimple = function(rv, sk, i) {
if (rv.type !== 0x02 && rv.type !== 0x04) {
throw Error("verRct called on full rctSig");
}
if (i >= rv.ecdhInfo.length) {
throw Error("Bad index");
}
if (rv.outPk.length !== rv.ecdhInfo.length) {
throw Error("Mismatched sizes of rv.outPk and rv.ecdhInfo");
}
// mask amount and mask
const ecdh_info = rv.ecdhInfo[i];
const { mask, amount } = this.decode_rct_ecdh(ecdh_info, sk);
const C = rv.outPk[i];
const Ctmp = this.ge_double_scalarmult_base_vartime(
amount,
this.H,
mask,
);
console.log("[decodeRctSimple]", C, Ctmp);
if (C !== Ctmp) {
throw Error(
"warning, amount decoded incorrectly, will be unable to spend",
);
}
return { amount, mask };
};
this.verBulletProof = function() {
throw Error("verBulletProof is not implemented");
};

@ -82,7 +82,7 @@ it("range_proofs", () => {
mixRing,
amount_keys,
[index],
monero_utils.d2s("0"),
"0",
);
expect(monero_utils.verRct(s, true, mixRing, kimg[0])).toEqual(true);

@ -0,0 +1,107 @@
// Copyright (c) 2014-2018, MyMonero.com
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
const {
ctskpkGen,
populateFromBlockchainSimple,
JSBigInt,
monero_utils,
} = require("./test_utils");
it("should test ringct simple transactions", () => {
//Ring CT Stuff
//ct range proofs
// ctkey vectors
let inSk = [],
inPk = [],
outamounts = [], // output amounts
inamounts = [], // input amounts
amount_keys = [];
//add fake input 3000
//inSk is secret data
//inPk is public data
{
let [sctmp, pctmp] = ctskpkGen(3000);
inSk.push(sctmp);
inPk.push(pctmp);
inamounts.push(3000);
}
//add fake input 3000
//inSk is secret data
//inPk is public data
{
let [sctmp, pctmp] = ctskpkGen(3000);
inSk.push(sctmp);
inPk.push(pctmp);
inamounts.push(3000);
}
outamounts.push(5000);
amount_keys.push(monero_utils.hash_to_scalar(monero_utils.Z));
outamounts.push(999);
amount_keys.push(monero_utils.hash_to_scalar(monero_utils.Z));
const message = monero_utils.random_scalar();
const txnFee = "1";
// generate mixin and indices
let mixRings = [];
let indices = [];
const mixin = 3;
for (let i = 0; i < inPk.length; i++) {
const { mixRing, index } = populateFromBlockchainSimple(inPk[i], mixin);
mixRings.push(mixRing);
indices.push(index);
}
// generate kimg
const kimg = [
monero_utils.generate_key_image_2(inPk[0].dest, inSk[0].x),
monero_utils.generate_key_image_2(inPk[1].dest, inSk[1].x),
];
const s = monero_utils.genRct(
message,
inSk,
kimg,
inamounts,
outamounts,
mixRings,
amount_keys,
indices,
txnFee,
);
expect(monero_utils.verRctSimple(s, true, mixRings, kimg)).toEqual(true);
expect(monero_utils.verRctSimple(s, false, mixRings, kimg)).toEqual(true);
monero_utils.decodeRctSimple(s, amount_keys[1], 1);
});

@ -86,9 +86,25 @@ function populateFromBlockchain(inPk, mixin) {
return { mixRing, index };
}
function populateFromBlockchainSimple(inPk, mixin) {
const index = randomNum(mixin);
const mixRing = [];
for (let i = 0; i <= mixin; i++) {
if (i !== index) {
mixRing[i] = getKeyFromBlockchain(index);
} else {
mixRing[i] = inPk;
}
}
return { mixRing, index };
}
module.exports = {
ctskpkGen,
populateFromBlockchain,
populateFromBlockchainSimple,
getKeyFromBlockchain,
monero_utils,
JSBigInt,

Loading…
Cancel
Save