Progress commit

pull/32/head
HenryNguyen5 6 years ago
parent 9b3bf23d50
commit d976f88080

@ -84,6 +84,7 @@ var cnUtil = function(currencyConfig) {
//RCT vars
var H = "8b655970153799af2aeadc9ff1add0ea6c7251d54154cfa92c173a0dd39c1f94"; //base H for amounts
this.H = H;
var l = JSBigInt(
"7237005577332262213973186563042994240857116359379907606001950938285454250989",
); //curve order (not RCT specific)
@ -238,7 +239,7 @@ var cnUtil = function(currencyConfig) {
throw "integer should be entered as a string for precision";
}
var padding = "";
for (i = 0; i < 63; i++) {
for (var i = 0; i < 63; i++) {
padding += "0";
}
return (
@ -267,7 +268,7 @@ var cnUtil = function(currencyConfig) {
throw "integer should be entered as a string for precision";
}
var padding = "";
for (i = 0; i < 63; i++) {
for (var i = 0; i < 63; i++) {
padding += "0";
}
var a = new JSBigInt(integer);
@ -283,7 +284,7 @@ var cnUtil = function(currencyConfig) {
throw "integer should be entered as a string for precision";
}
var padding = "";
for (i = 0; i < 31; i++) {
for (var i = 0; i < 31; i++) {
padding += "0";
}
var a = new JSBigInt(integer);
@ -313,7 +314,7 @@ var cnUtil = function(currencyConfig) {
var bin1 = hextobin(hex1);
var bin2 = hextobin(hex2);
var xor = new Uint8Array(bin1.length);
for (i = 0; i < xor.length; i++) {
for (var i = 0; i < xor.length; i++) {
xor[i] = bin1[i] ^ bin2[i];
}
return bintohex(xor);
@ -1409,7 +1410,7 @@ var cnUtil = function(currencyConfig) {
}
var j;
//start at index and fill PM left and right -- PM[0] holds Ci
for (i = 0; i < nrings; i++) {
for (var i = 0; i < nrings; i++) {
ai[i] = random_scalar();
j = indices[i];
PM[j][i] = ge_scalarmult_base(ai[i]);
@ -1428,7 +1429,7 @@ var cnUtil = function(currencyConfig) {
* some more payload stuff here
*/
//copy commitments to sig and sum them to commitment
for (i = 0; i < nrings; i++) {
for (var i = 0; i < nrings; i++) {
//if (i < nrings - 1) //for later version
sig.Ci[i] = PM[0][i];
C = ge_add(C, PM[0][i]);
@ -1458,25 +1459,27 @@ var cnUtil = function(currencyConfig) {
try {
let CiH = []; // len 64
let asCi = []; // len 64
let Ctmp;
let Ctmp = this.identity();
for (let i = 0; i < nrings; i++) {
CiH[i] = this.ge_sub(as.Ci[i], this.H2[i]);
asCi[i] = as.Ci[i];
Ctmp = this.ge_add(Ctmp, as.Ci[i]);
}
const equalKeys = Ctmp === C;
console.log(`[verRange] Equal keys? ${equalKeys}
C: ${c}
Ctmp: $${Ctmp}`);
C: ${C}
Ctmp: ${Ctmp}`);
if (!equalKeys) {
return false;
}
if (!this.verifyBorromean(as.asig, asCi, CiH)) {
if (!this.verifyBorromean(as.bsig, asCi, CiH)) {
return false;
}
return true;
} catch (e) {
console.error(`[verRange]`, e);
return false;
}
};
@ -1500,6 +1503,8 @@ var cnUtil = function(currencyConfig) {
// because we don't want to force same secret column for all inputs
this.MLSAG_Gen = function(message, pk, xx, kimg, index) {
var cols = pk.length; //ring size
var i;
// secret index
if (index >= cols) {
throw "index out of range";
@ -1510,7 +1515,7 @@ var cnUtil = function(currencyConfig) {
throw "wrong row count";
}
// check all are len 2
for (var i = 0; i < cols; i++) {
for (i = 0; i < cols; i++) {
if (pk[i].length !== rows) {
throw "pk is not rectangular";
}
@ -1594,7 +1599,6 @@ var cnUtil = function(currencyConfig) {
// in MLSAG_gen
const cols = pk.length;
let c_old = rv.cc;
console.log(`cols ${cols}`);
let i = 0;
let toHash = [];
toHash[0] = message;
@ -1627,11 +1631,12 @@ var cnUtil = function(currencyConfig) {
}
const c = this.sc_sub(c_old, rv.cc);
console.log(`
console.log(`[MLSAG_ver]
c_old: ${c_old}
rc.cc: ${rv.cc}
c: ${c}`);
return c;
return Number(c) === 0;
};
//Ring-ct MG sigs
@ -1669,6 +1674,7 @@ var cnUtil = function(currencyConfig) {
//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;
if (cols < 1) {
@ -1683,34 +1689,46 @@ var cnUtil = function(currencyConfig) {
throw Error("Pubs is not rectangular");
}
}
// key vector of rows + 1 len
const tmp = [];
for (let i = 0; i < rows + 1; i++) {
tmp[i] = this.identity();
}
// key matrix of (cols, tmp)
let M = [];
for (let j = 0; j <= rows; j++) {
for (let i = 0; i < cols; i++) {
if (!M[i]) {
// add dimension
M[i] = [];
}
M[i][j] = this.identity();
}
}
console.log("cols", cols);
console.log("rows", rows);
//create the matrix to mg sig
for (let j = 0; j < rows; j++) {
for (let i = 0; i < cols; i++) {
// add dimension
M[i].push([]);
M[i][j] = pubs[i][j].dest;
M[i][rows] = this.ge_add(M[i][rows], outPk[j].C); //add Ci in last row
M[i][rows] = this.ge_add(M[i][rows], outPk[j]); //add Ci in last row
}
}
console.log(M);
for (let i = 0; i < cols; i++) {
for (let j = 0; j < outPk.length; j++) {
M[i][rows] = this.ge_sub(M[i][rows], outPk[J].C); //subtract output Ci's in last row
M[i][rows] = this.ge_sub(M[i][rows], outPk[j]); //subtract output Ci's in last row
}
//subtract txn fee output in last row
M[i][rows] = this.ge_sub(M[i][rows], txnFeeKey);
}
console.log(M);
console.log(
`[MLSAG_ver input]`,
JSON.stringify({ message, M, mg, kimg }, null, 1),
);
return this.MLSAG_ver(message, M, mg, kimg);
};
@ -1801,6 +1819,7 @@ var cnUtil = function(currencyConfig) {
mask: null,
};
var nrings = 64; //for base 2/current
var i;
//compute range proofs, etc
for (i = 0; i < outAmounts.length; i++) {
var teststart = new Date().getTime();
@ -1870,7 +1889,7 @@ var cnUtil = function(currencyConfig) {
return rv;
};
this.verRct = function(rv, semantics) {
this.verRct = function(rv, semantics, mixRing, kimg) {
if (rv.type === 0x03) {
throw Error("Bulletproof validation not implemented");
}
@ -1901,10 +1920,13 @@ var cnUtil = function(currencyConfig) {
// 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] = verBulletproof(rv.p.bulletproofs[i]);
results[i] = this.verBulletproof(rv.p.bulletproofs[i]);
} else {
// mask -> C if public
results[i] = verRange(rv.outPk[i].C, rv.p.rangeSigs[i]);
results[i] = this.verRange(
rv.outPk[i],
rv.p.rangeSigs[i],
);
}
}
@ -1920,12 +1942,13 @@ var cnUtil = function(currencyConfig) {
} else {
// compute txn fee
const txnFeeKey = this.ge_scalarmult(H, this.d2s(rv.txnFee));
const mgVerd = verRctMg(
const mgVerd = this.verRctMG(
rv.p.MGs[0],
rv.mixRing,
mixRing,
rv.outPk,
txnFeeKey,
this.get_pre_mlsag_hash(rv),
kimg,
);
console.log("mg sig verified?", mgVerd);
if (!mgVerd) {
@ -1933,11 +1956,47 @@ var cnUtil = function(currencyConfig) {
return false;
}
}
return true;
} catch (e) {
console.error("Error in vetRCt: ", e);
console.error("Error in verRct: ", e);
}
};
//decodeRct: (c.f. http://eprint.iacr.org/2015/1098 section 5.1.1)
// uses the attached ecdh info to find the amounts represented by each output commitment
// must know the destination private key to find the correct amount, else will return a random number
this.decodeRct = function(rv, sk, i) {
// where RCTTypeFull is 0x01 and RCTTypeFullBulletproof is 0x03
if (rv.type !== 0x01 && rv.type !== 0x03) {
throw Error("verRct called on non-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(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");
};
@ -2100,6 +2159,7 @@ var cnUtil = function(currencyConfig) {
var buf = "";
buf += this.encode_varint(rv.type);
buf += this.encode_varint(rv.txnFee);
var i;
if (rv.type === 2) {
for (var i = 0; i < rv.pseudoOuts.length; i++) {
buf += rv.pseudoOuts[i];

@ -53,7 +53,6 @@ it("MG_sigs", () => {
let N = 3; // cols
let R = 2; // rows
let xtmp = skvGen(R);
let xm = keyMInit(R, N); // = [[None]*N] #just used to generate test public keys
let sk = skvGen(R);
@ -89,7 +88,7 @@ it("MG_sigs", () => {
let rv = monero_utils.MLSAG_Gen(message, P, sk, kimg, ind);
let c = monero_utils.MLSAG_ver(message, P, rv, kimg);
expect(Number(c)).toEqual(0);
expect(c).toEqual(true);
xtmp = skvGen(R);
xm = keyMInit(R, N); // = [[None]*N] #just used to generate test public keys
@ -110,5 +109,5 @@ it("MG_sigs", () => {
rv = monero_utils.MLSAG_Gen(message, P, sk, kimg, ind);
c = monero_utils.MLSAG_ver(message, P, rv, kimg);
expect(Number(c)).toBeFalsy();
expect(c).toEqual(false);
});

@ -27,66 +27,152 @@
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
const monero_utils = require("../").monero_utils;
const JSBigInt = require("../cryptonote_utils/biginteger").BigInteger;
const { randomBytes } = require("crypto");
it("range_proofs", () => {
//generates a <secret , public> / Pedersen commitment but takes bH as input
function ctskpkGen(bH) {
let sk, pk;
//generates a <secret , public> / Pedersen commitment to the amount
function ctskpkGen(amount) {
let sk = {},
pk = {};
const key_pair1 = monero_utils.random_keypair();
const key_pair2 = monero_utils.random_keypair();
sk.dest = key_pair1.sec;
sk.x = key_pair1.sec;
pk.dest = key_pair1.pub;
sk.mask = key_pair2.sec;
pk.mask = key_pair2.sec;
sk.a = key_pair2.sec;
pk.mask = key_pair2.pub;
const am = monero_utils.d2s(amount.toString());
const bH = monero_utils.ge_scalarmult(monero_utils.H, am);
pk.mask = monero_utils.ge_add(pk.mask, bH);
return { sk, pk };
return [sk, pk];
}
function randomNum(upperLimit) {
return parseInt(randomBytes(1).toString("hex"), 16) % upperLimit;
}
//These functions get keys from blockchain
//replace these when connecting blockchain
//getKeyFromBlockchain grabs a key from the blockchain at "reference_index" to mix with
function getKeyFromBlockchain(reference_index) {
let a = {};
a.dest = monero_utils.random_keypair().pub;
a.mask = monero_utils.random_keypair().pub;
return a;
}
// populateFromBlockchain creates a keymatrix with "mixin" + 1 columns and one of the columns is inPk
// the return values are the key matrix, and the index where inPk was put (random).
function populateFromBlockchain(inPk, mixin) {
const rows = inPk.length;
const inPkCpy = [...inPk];
// ctkeyMatrix
const mixRing = [];
const index = randomNum(mixin);
for (let i = 0; i < rows; i++) {
mixRing[i] = [];
for (let j = 0; j <= mixin; j++) {
if (j !== index) {
mixRing[i][j] = getKeyFromBlockchain(index); /*?*/
} else {
mixRing[i][j] = inPkCpy.pop();
}
}
}
// [[{dest, mask}, {dest, mask},<secretIndex> , {dest, mask}],
// ]
return { mixRing, index };
}
//Ring CT Stuff
//ct range proofs
// ctkey vectors
let sc, pc;
let inSk = [],
inPk = [];
// ctkeys
{
let [sctmp, pctmp] = ctskpkGen(6000);
sc.push(sctmp);
pc.push(pctmp);
console.log(sctmp, pctmp);
inSk.push(sctmp);
inPk.push(pctmp);
console.log("inPk", inPk);
}
/*
{
let [sctmp, pctmp] = ctskpkGen(7000);
sc.push(sctmp);
pc.push(pctmp);
}
inSk.push(sctmp);
inPk.push(pctmp);
}
*/
// xmr amount vector
let amounts;
let amounts = [];
// key vector
let amount_keys;
// key
let mask;
let amount_keys = [];
// add output 500
amounts.push(new JSBigInt(500));
amount_keys.push(monero_utils.hash_to_scalar(monero_utils.Z));
// key vector
let destinations;
{
const { sec: _, pub: Pk } = monero_utils.random_keypair();
destinations.push(Pk);
}
//add output for 12500
amounts.push_back(new JSBigInt(12500));
amounts.push(new JSBigInt(4500));
amount_keys.push(monero_utils.hash_to_scalar(monero_utils.Z));
amounts.push(new JSBigInt(500));
amount_keys.push(monero_utils.hash_to_scalar(monero_utils.Z));
amounts.push(new JSBigInt(500));
amount_keys.push(monero_utils.hash_to_scalar(monero_utils.Z));
{
const { sec: _, pub: Pk } = monero_utils.random_keypair();
destinations.push(Pk);
}
//compute rct data with mixin 500
const s = monero_utils.genRct(monero_utils.Z, sc, pc);
const { index, mixRing } = populateFromBlockchain(inPk, 3);
// generate kimg
const kimg = [monero_utils.generate_key_image_2(inPk[0].dest, inSk[0].x)];
let s = monero_utils.genRct(
monero_utils.Z,
inSk,
kimg,
[[]],
amounts,
mixRing,
amount_keys,
[index],
monero_utils.d2s("0"),
);
// expect(monero_utils.verRct(s, true, mixRing, kimg[0])).toEqual(true);
expect(monero_utils.verRct(s, false, mixRing, kimg[0])).toEqual(true);
//decode received amount
// monero_utils.decodeRct(s, amount_keys[1], 1);
// Ring CT with failing MG sig part should not verify!
// Since sum of inputs != outputs
/*
amounts[1] = new JSBigInt(12501);
s = monero_utils.genRct(
monero_utils.Z,
inSk,
kimg,
[[]],
amounts,
mixRing,
amount_keys,
[index],
"0",
);
expect(monero_utils.verRct(s, true, mixRing, kimg[0])).toEqual(true);
expect(monero_utils.verRct(s, false, mixRing, kimg[0])).toEqual(false);
//decode received amount
monero_utils.decodeRct(s, amount_keys[1], 1);
*/
});

Loading…
Cancel
Save