Skip to content

Commit

Permalink
MLSAG speedup and zero-hash check
Browse files Browse the repository at this point in the history
  • Loading branch information
SarangNoether committed Jun 28, 2019
1 parent 6335509 commit 691af47
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 56 deletions.
76 changes: 44 additions & 32 deletions src/ringct/rctSigs.cpp
Expand Up @@ -163,14 +163,21 @@ namespace rct {
return verifyBorromean(bb, P1_p3, P2_p3);
}

//Multilayered Spontaneous Anonymous Group Signatures (MLSAG signatures)
//This is a just slghtly more efficient version than the ones described below
//(will be explained in more detail in Ring Multisig paper
//These are aka MG signatutes in earlier drafts of the ring ct paper
// c.f. https://eprint.iacr.org/2015/1098 section 2.
// Gen creates a signature which proves that for some column in the keymatrix "pk"
// the signer knows a secret key for each row in that column
// Ver verifies that the MG sig was created correctly
// Hash a key to p3 representation
static void hash_to_p3(const key &k, ge_p3 &hash8_p3) {
key hash_key = cn_fast_hash(k);
ge_p2 hash_p2;
ge_fromfe_frombytes_vartime(&hash_p2, hash_key.bytes);
ge_p1p1 hash8_p1p1;
ge_mul8(&hash8_p1p1, &hash_p2);
ge_p1p1_to_p3(&hash8_p3, &hash8_p1p1);
}

// MLSAG signatures
// See paper by Noether (https://eprint.iacr.org/2015/1098)
// This generalization allows for some dimensions not to require linkability;
// this is used in practice for commitment data within signatures
// Note that using more than one linkable dimension is not recommended.
mgSig MLSAG_Gen(const key &message, const keyM & pk, const keyV & xx, const multisig_kLRki *kLRki, key *mscout, const unsigned int index, size_t dsRows, hw::device &hwdev) {
mgSig rv;
size_t cols = pk.size();
Expand Down Expand Up @@ -260,34 +267,32 @@ namespace rct {
return rv;
}

//Multilayered Spontaneous Anonymous Group Signatures (MLSAG signatures)
//This is a just slghtly more efficient version than the ones described below
//(will be explained in more detail in Ring Multisig paper
//These are aka MG signatutes in earlier drafts of the ring ct paper
// c.f. https://eprint.iacr.org/2015/1098 section 2.
// Gen creates a signature which proves that for some column in the keymatrix "pk"
// the signer knows a secret key for each row in that column
// Ver verifies that the MG sig was created correctly
// MLSAG signatures
// See paper by Noether (https://eprint.iacr.org/2015/1098)
// This generalization allows for some dimensions not to require linkability;
// this is used in practice for commitment data within signatures
// Note that using more than one linkable dimension is not recommended.
bool MLSAG_Ver(const key &message, const keyM & pk, const mgSig & rv, size_t dsRows) {

size_t cols = pk.size();
CHECK_AND_ASSERT_MES(cols >= 2, false, "Error! What is c if cols = 1!");
CHECK_AND_ASSERT_MES(cols >= 2, false, "Signature must contain more than one public key");
size_t rows = pk[0].size();
CHECK_AND_ASSERT_MES(rows >= 1, false, "Empty pk");
CHECK_AND_ASSERT_MES(rows >= 1, false, "Bad total row number");
for (size_t i = 1; i < cols; ++i) {
CHECK_AND_ASSERT_MES(pk[i].size() == rows, false, "pk is not rectangular");
CHECK_AND_ASSERT_MES(pk[i].size() == rows, false, "Bad public key matrix dimensions");
}
CHECK_AND_ASSERT_MES(rv.II.size() == dsRows, false, "Bad II size");
CHECK_AND_ASSERT_MES(rv.ss.size() == cols, false, "Bad rv.ss size");
CHECK_AND_ASSERT_MES(rv.II.size() == dsRows, false, "Wrong number of key images present");
CHECK_AND_ASSERT_MES(rv.ss.size() == cols, false, "Bad scalar matrix dimensions");
for (size_t i = 0; i < cols; ++i) {
CHECK_AND_ASSERT_MES(rv.ss[i].size() == rows, false, "rv.ss is not rectangular");
CHECK_AND_ASSERT_MES(rv.ss[i].size() == rows, false, "Bad scalar matrix dimensions");
}
CHECK_AND_ASSERT_MES(dsRows <= rows, false, "Bad dsRows value");
CHECK_AND_ASSERT_MES(dsRows <= rows, false, "Non-double-spend rows cannot exceed total rows");

for (size_t i = 0; i < rv.ss.size(); ++i)
for (size_t j = 0; j < rv.ss[i].size(); ++j)
CHECK_AND_ASSERT_MES(sc_check(rv.ss[i][j].bytes) == 0, false, "Bad ss slot");
CHECK_AND_ASSERT_MES(sc_check(rv.cc.bytes) == 0, false, "Bad cc");
for (size_t i = 0; i < rv.ss.size(); ++i) {
for (size_t j = 0; j < rv.ss[i].size(); ++j) {
CHECK_AND_ASSERT_MES(sc_check(rv.ss[i][j].bytes) == 0, false, "Bad signature scalar");
}
}
CHECK_AND_ASSERT_MES(sc_check(rv.cc.bytes) == 0, false, "Bad initial signature hash");

size_t i = 0, j = 0, ii = 0;
key c, L, R, Hi;
Expand All @@ -296,17 +301,23 @@ namespace rct {
for (i = 0 ; i < dsRows ; i++) {
precomp(Ip[i].k, rv.II[i]);
}
size_t ndsRows = 3 * dsRows; //non Double Spendable Rows (see identity chains paper
size_t ndsRows = 3 * dsRows; // number of dimensions not requiring linkability
keyV toHash(1 + 3 * dsRows + 2 * (rows - dsRows));
toHash[0] = message;
i = 0;
while (i < cols) {
sc_0(c.bytes);
for (j = 0; j < dsRows; j++) {
addKeys2(L, rv.ss[i][j], c_old, pk[i][j]);
hashToPoint(Hi, pk[i][j]);
CHECK_AND_ASSERT_MES(!(Hi == rct::identity()), false, "Data hashed to point at infinity");
addKeys3(R, rv.ss[i][j], Hi, c_old, Ip[j].k);

// Compute R directly
ge_p3 hash8_p3;
hash_to_p3(pk[i][j], hash8_p3);
ge_p2 R_p2;
ge_double_scalarmult_precomp_vartime(&R_p2, rv.ss[i][j].bytes, &hash8_p3, c_old.bytes, Ip[j].k);
key R;
ge_tobytes(R.bytes, &R_p2);

toHash[3 * j + 1] = pk[i][j];
toHash[3 * j + 2] = L;
toHash[3 * j + 3] = R;
Expand All @@ -317,6 +328,7 @@ namespace rct {
toHash[ndsRows + 2 * ii + 2] = L;
}
c = hash_to_scalar(toHash);
CHECK_AND_ASSERT_MES(!(c == rct::zero()), false, "Bad signature hash");
copy(c_old, c);
i = (i + 1);
}
Expand Down
20 changes: 2 additions & 18 deletions tests/performance_tests/main.cpp
Expand Up @@ -57,7 +57,6 @@
#include "rct_mlsag.h"
#include "equality.h"
#include "range_proof.h"
#include "rct_mlsag.h"
#include "bulletproof.h"
#include "crypto_ops.h"
#include "multiexp.h"
Expand Down Expand Up @@ -214,14 +213,8 @@ int main(int argc, char** argv)
TEST_PERFORMANCE1(filter, p, test_cn_fast_hash, 32);
TEST_PERFORMANCE1(filter, p, test_cn_fast_hash, 16384);

TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 3, false);
TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 5, false);
TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 10, false);
TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 100, false);
TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 3, true);
TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 5, true);
TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 10, true);
TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 100, true);
TEST_PERFORMANCE2(filter, p, test_ringct_mlsag, 11, false);
TEST_PERFORMANCE2(filter, p, test_ringct_mlsag, 11, true);

TEST_PERFORMANCE2(filter, p, test_equality, memcmp32, true);
TEST_PERFORMANCE2(filter, p, test_equality, memcmp32, false);
Expand Down Expand Up @@ -251,15 +244,6 @@ int main(int argc, char** argv)
TEST_PERFORMANCE6(filter, p, test_aggregated_bulletproof, false, 2, 1, 1, 0, 64);
TEST_PERFORMANCE6(filter, p, test_aggregated_bulletproof, true, 2, 1, 1, 0, 64); // 64 proof, each with 2 amounts

TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 3, false);
TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 5, false);
TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 10, false);
TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 100, false);
TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 3, true);
TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 5, true);
TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 10, true);
TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 100, true);

TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_sc_add);
TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_sc_sub);
TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_sc_mul);
Expand Down
12 changes: 6 additions & 6 deletions tests/performance_tests/rct_mlsag.h
Expand Up @@ -35,13 +35,13 @@

#include "single_tx_test_base.h"

template<size_t inputs, size_t ring_size, bool ver>
template<size_t ring_size, bool ver>
class test_ringct_mlsag : public single_tx_test_base
{
public:
static const size_t cols = ring_size;
static const size_t rows = inputs;
static const size_t loop_count = 100;
static const size_t rows = 2; // single spend and commitment data
static const size_t loop_count = 1000;

bool init()
{
Expand All @@ -65,17 +65,17 @@ class test_ringct_mlsag : public single_tx_test_base
{
sk[j] = xm[ind][j];
}
IIccss = MLSAG_Gen(rct::identity(), P, sk, NULL, NULL, ind, rows, hw::get_device("default"));
IIccss = MLSAG_Gen(rct::identity(), P, sk, NULL, NULL, ind, rows-1, hw::get_device("default"));

return true;
}

bool test()
{
if (ver)
MLSAG_Ver(rct::identity(), P, IIccss, rows);
MLSAG_Ver(rct::identity(), P, IIccss, rows-1);
else
MLSAG_Gen(rct::identity(), P, sk, NULL, NULL, ind, rows, hw::get_device("default"));
MLSAG_Gen(rct::identity(), P, sk, NULL, NULL, ind, rows-1, hw::get_device("default"));
return true;
}

Expand Down

0 comments on commit 691af47

Please sign in to comment.