Skip to content

Commit eb0a5aa

Browse files
author
HenryNguyen5
committed
Add verRct/Range/RctMG
1 parent 8dd8668 commit eb0a5aa

File tree

1 file changed

+175
-2
lines changed

1 file changed

+175
-2
lines changed

cryptonote_utils/cryptonote_utils.js

Lines changed: 175 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ var cnUtil = function(currencyConfig) {
9595
};
9696

9797
var Z = "0000000000000000000000000000000000000000000000000000000000000000"; //zero scalar
98+
this.Z = Z;
99+
98100
//H2 object to speed up some operations
99101
var H2 = [
100102
"8b655970153799af2aeadc9ff1add0ea6c7251d54154cfa92c173a0dd39c1f94",
@@ -1364,7 +1366,7 @@ var cnUtil = function(currencyConfig) {
13641366
}
13651367
const eeComputed = this.array_hash_to_scalar(Lv1);
13661368
const equalKeys = eeComputed === bb.ee;
1367-
console.log(`Keys equal? ${equalKeys}
1369+
console.log(`[verifyBorromean] Keys equal? ${equalKeys}
13681370
${eeComputed}
13691371
${bb.ee}`);
13701372

@@ -1444,6 +1446,41 @@ var cnUtil = function(currencyConfig) {
14441446
return sig;
14451447
};
14461448

1449+
//proveRange and verRange
1450+
//proveRange gives C, and mask such that \sumCi = C
1451+
// c.f. http://eprint.iacr.org/2015/1098 section 5.1
1452+
// and Ci is a commitment to either 0 or 2^i, i=0,...,63
1453+
// thus this proves that "amount" is in [0, 2^64]
1454+
// mask is a such that C = aG + bH, and b = amount
1455+
//verRange verifies that \sum Ci = C and that each Ci is a commitment to 0 or 2^i
1456+
1457+
this.verRange = function(C, as, nrings = 64) {
1458+
try {
1459+
let CiH = []; // len 64
1460+
let asCi = []; // len 64
1461+
let Ctmp;
1462+
for (let i = 0; i < nrings; i++) {
1463+
CiH[i] = this.ge_sub(as.Ci[i], this.H2[i]);
1464+
Ctmp = this.ge_add(Ctmp, as.Ci[i]);
1465+
}
1466+
const equalKeys = Ctmp === C;
1467+
console.log(`[verRange] Equal keys? ${equalKeys}
1468+
C: ${c}
1469+
Ctmp: $${Ctmp}`);
1470+
if (!equalKeys) {
1471+
return false;
1472+
}
1473+
1474+
if (!this.verifyBorromean(as.asig, asCi, CiH)) {
1475+
return false;
1476+
}
1477+
1478+
return true;
1479+
} catch (e) {
1480+
return false;
1481+
}
1482+
};
1483+
14471484
function array_hash_to_scalar(array) {
14481485
var buf = "";
14491486
for (var i = 0; i < array.length; i++) {
@@ -1597,7 +1634,14 @@ var cnUtil = function(currencyConfig) {
15971634
return c;
15981635
};
15991636

1600-
//prepares for MLSAG_Gen
1637+
//Ring-ct MG sigs
1638+
//Prove:
1639+
// c.f. http://eprint.iacr.org/2015/1098 section 4. definition 10.
1640+
// This does the MG sig on the "dest" part of the given key matrix, and
1641+
// the last row is the sum of input commitments from that column - sum output commitments
1642+
// this shows that sum inputs = sum outputs
1643+
//Ver:
1644+
// verifies the above sig is created corretly
16011645
this.proveRctMG = function(message, pubs, inSk, kimg, mask, Cout, index) {
16021646
var cols = pubs.length;
16031647
if (cols < 3) {
@@ -1616,6 +1660,64 @@ var cnUtil = function(currencyConfig) {
16161660
return this.MLSAG_Gen(message, PK, xx, kimg, index);
16171661
};
16181662

1663+
//Ring-ct MG sigs
1664+
//Prove:
1665+
// c.f. http://eprint.iacr.org/2015/1098 section 4. definition 10.
1666+
// This does the MG sig on the "dest" part of the given key matrix, and
1667+
// the last row is the sum of input commitments from that column - sum output commitments
1668+
// this shows that sum inputs = sum outputs
1669+
//Ver:
1670+
// verifies the above sig is created corretly
1671+
// simple version, assuming only post Rct
1672+
this.verRctMG = function(mg, pubs, outPk, txnFeeKey, message, kimg) {
1673+
const cols = pubs.length;
1674+
if (cols < 1) {
1675+
throw Error("Empty pubs");
1676+
}
1677+
const rows = pubs[0].length;
1678+
if (rows < 1) {
1679+
throw Error("Empty pubs");
1680+
}
1681+
for (let i = 0; i < cols.length; ++i) {
1682+
if (pubs[i].length !== rows) {
1683+
throw Error("Pubs is not rectangular");
1684+
}
1685+
}
1686+
// key vector of rows + 1 len
1687+
const tmp = [];
1688+
for (let i = 0; i < rows + 1; i++) {
1689+
tmp[i] = this.identity();
1690+
}
1691+
1692+
// key matrix of (cols, tmp)
1693+
let M = [];
1694+
1695+
//create the matrix to mg sig
1696+
for (let j = 0; j < rows; j++) {
1697+
for (let i = 0; i < cols; i++) {
1698+
// add dimension
1699+
M[i].push([]);
1700+
M[i][j] = pubs[i][j].dest;
1701+
M[i][rows] = this.ge_add(M[i][rows], outPk[j].C); //add Ci in last row
1702+
}
1703+
}
1704+
1705+
for (let i = 0; i < cols; i++) {
1706+
for (let j = 0; j < outPk.length; j++) {
1707+
M[i][rows] = this.ge_sub(M[i][rows], outPk[J].C); //subtract output Ci's in last row
1708+
}
1709+
1710+
//subtract txn fee output in last row
1711+
M[i][rows] = this.ge_sub(M[i][rows], txnFeeKey);
1712+
}
1713+
1714+
return this.MLSAG_ver(message, M, mg, kimg);
1715+
};
1716+
1717+
this.verBulletProof = function() {
1718+
throw Error("verBulletProof is not implemented");
1719+
};
1720+
16191721
this.get_pre_mlsag_hash = function(rv) {
16201722
var hashes = "";
16211723
hashes += rv.message;
@@ -1768,6 +1870,77 @@ var cnUtil = function(currencyConfig) {
17681870
return rv;
17691871
};
17701872

1873+
this.verRct = function(rv, semantics) {
1874+
if (rv.type === 0x03) {
1875+
throw Error("Bulletproof validation not implemented");
1876+
}
1877+
1878+
// where RCTTypeFull is 0x01 and RCTTypeFullBulletproof is 0x03
1879+
if (rv.type !== 0x01 && rv.type !== 0x03) {
1880+
throw Error("verRct called on non-full rctSig");
1881+
}
1882+
if (semantics) {
1883+
//RCTTypeFullBulletproof checks not implemented
1884+
// RCTTypeFull checks
1885+
if (rv.outPk.length !== rv.p.rangeSigs.length) {
1886+
throw Error("Mismatched sizes of outPk and rv.p.rangeSigs");
1887+
}
1888+
if (rv.outPk.length !== rv.ecdhInfo.length) {
1889+
throw Error("Mismatched sizes of outPk and rv.ecdhInfo");
1890+
}
1891+
if (rv.p.MGs.length !== 1) {
1892+
throw Error("full rctSig has not one MG");
1893+
}
1894+
} else {
1895+
// semantics check is early, we don't have the MGs resolved yet
1896+
}
1897+
try {
1898+
if (semantics) {
1899+
const results = [];
1900+
for (let i = 0; i < rv.outPk.length; i++) {
1901+
// might want to parallelize this like its done in the c++ codebase
1902+
// via some abstraction library to support browser + node
1903+
if (rv.p.rangeSigs.length === 0) {
1904+
results[i] = verBulletproof(rv.p.bulletproofs[i]);
1905+
} else {
1906+
// mask -> C if public
1907+
results[i] = verRange(rv.outPk[i].C, rv.p.rangeSigs[i]);
1908+
}
1909+
}
1910+
1911+
for (let i = 0; i < rv.outPk.length; i++) {
1912+
if (!results[i]) {
1913+
console.error(
1914+
"Range proof verification failed for output",
1915+
i,
1916+
);
1917+
return false;
1918+
}
1919+
}
1920+
} else {
1921+
// compute txn fee
1922+
const txnFeeKey = this.ge_scalarmult(H, this.d2s(rv.txnFee));
1923+
const mgVerd = verRctMg(
1924+
rv.p.MGs[0],
1925+
rv.mixRing,
1926+
rv.outPk,
1927+
txnFeeKey,
1928+
this.get_pre_mlsag_hash(rv),
1929+
);
1930+
console.log("mg sig verified?", mgVerd);
1931+
if (!mgVerd) {
1932+
console.error("MG Signature verification failed");
1933+
return false;
1934+
}
1935+
}
1936+
} catch (e) {
1937+
console.error("Error in vetRCt: ", e);
1938+
}
1939+
};
1940+
1941+
this.verBulletProof = function() {
1942+
throw Error("verBulletProof is not implemented");
1943+
};
17711944
//end RCT functions
17721945

17731946
this.add_pub_key_to_extra = function(extra, pubkey) {

0 commit comments

Comments
 (0)