diff --git a/src/crypto/crypto-ops.c b/src/crypto/crypto-ops.c index 3110d3ce7..508709280 100644 --- a/src/crypto/crypto-ops.c +++ b/src/crypto/crypto-ops.c @@ -1234,6 +1234,56 @@ void ge_double_scalarmult_base_vartime(ge_p2 *r, const unsigned char *a, const g } } +// Computes aG + bB + cC (G is the fixed basepoint) +void ge_triple_scalarmult_base_vartime(ge_p2 *r, const unsigned char *a, const unsigned char *b, const ge_dsmp Bi, const unsigned char *c, const ge_dsmp Ci) { + signed char aslide[256]; + signed char bslide[256]; + signed char cslide[256]; + ge_p1p1 t; + ge_p3 u; + int i; + + slide(aslide, a); + slide(bslide, b); + slide(cslide, c); + + ge_p2_0(r); + + for (i = 255; i >= 0; --i) { + if (aslide[i] || bslide[i] || cslide[i]) break; + } + + for (; i >= 0; --i) { + ge_p2_dbl(&t, r); + + if (aslide[i] > 0) { + ge_p1p1_to_p3(&u, &t); + ge_madd(&t, &u, &ge_Bi[aslide[i]/2]); + } else if (aslide[i] < 0) { + ge_p1p1_to_p3(&u, &t); + ge_msub(&t, &u, &ge_Bi[(-aslide[i])/2]); + } + + if (bslide[i] > 0) { + ge_p1p1_to_p3(&u, &t); + ge_add(&t, &u, &Bi[bslide[i]/2]); + } else if (bslide[i] < 0) { + ge_p1p1_to_p3(&u, &t); + ge_sub(&t, &u, &Bi[(-bslide[i])/2]); + } + + if (cslide[i] > 0) { + ge_p1p1_to_p3(&u, &t); + ge_add(&t, &u, &Ci[cslide[i]/2]); + } else if (cslide[i] < 0) { + ge_p1p1_to_p3(&u, &t); + ge_sub(&t, &u, &Ci[(-cslide[i])/2]); + } + + ge_p1p1_to_p2(r, &t); + } +} + void ge_double_scalarmult_base_vartime_p3(ge_p3 *r3, const unsigned char *a, const ge_p3 *A, const unsigned char *b) { signed char aslide[256]; signed char bslide[256]; @@ -2148,6 +2198,56 @@ void ge_double_scalarmult_precomp_vartime2(ge_p2 *r, const unsigned char *a, con } } +// Computes aA + bB + cC (all points require precomputation) +void ge_triple_scalarmult_precomp_vartime(ge_p2 *r, const unsigned char *a, const ge_dsmp Ai, const unsigned char *b, const ge_dsmp Bi, const unsigned char *c, const ge_dsmp Ci) { + signed char aslide[256]; + signed char bslide[256]; + signed char cslide[256]; + ge_p1p1 t; + ge_p3 u; + int i; + + slide(aslide, a); + slide(bslide, b); + slide(cslide, c); + + ge_p2_0(r); + + for (i = 255; i >= 0; --i) { + if (aslide[i] || bslide[i] || cslide[i]) break; + } + + for (; i >= 0; --i) { + ge_p2_dbl(&t, r); + + if (aslide[i] > 0) { + ge_p1p1_to_p3(&u, &t); + ge_add(&t, &u, &Ai[aslide[i]/2]); + } else if (aslide[i] < 0) { + ge_p1p1_to_p3(&u, &t); + ge_sub(&t, &u, &Ai[(-aslide[i])/2]); + } + + if (bslide[i] > 0) { + ge_p1p1_to_p3(&u, &t); + ge_add(&t, &u, &Bi[bslide[i]/2]); + } else if (bslide[i] < 0) { + ge_p1p1_to_p3(&u, &t); + ge_sub(&t, &u, &Bi[(-bslide[i])/2]); + } + + if (cslide[i] > 0) { + ge_p1p1_to_p3(&u, &t); + ge_add(&t, &u, &Ci[cslide[i]/2]); + } else if (cslide[i] < 0) { + ge_p1p1_to_p3(&u, &t); + ge_sub(&t, &u, &Ci[(-cslide[i])/2]); + } + + ge_p1p1_to_p2(r, &t); + } +} + void ge_double_scalarmult_precomp_vartime2_p3(ge_p3 *r3, const unsigned char *a, const ge_dsmp Ai, const unsigned char *b, const ge_dsmp Bi) { signed char aslide[256]; signed char bslide[256]; diff --git a/src/crypto/crypto-ops.h b/src/crypto/crypto-ops.h index eeb94669b..22f76974b 100644 --- a/src/crypto/crypto-ops.h +++ b/src/crypto/crypto-ops.h @@ -79,6 +79,7 @@ typedef ge_cached ge_dsmp[8]; extern const ge_precomp ge_Bi[8]; void ge_dsm_precomp(ge_dsmp r, const ge_p3 *s); void ge_double_scalarmult_base_vartime(ge_p2 *, const unsigned char *, const ge_p3 *, const unsigned char *); +void ge_triple_scalarmult_base_vartime(ge_p2 *, const unsigned char *, const unsigned char *, const ge_dsmp, const unsigned char *, const ge_dsmp); void ge_double_scalarmult_base_vartime_p3(ge_p3 *, const unsigned char *, const ge_p3 *, const unsigned char *); /* From ge_frombytes.c, modified */ @@ -130,6 +131,7 @@ void sc_reduce(unsigned char *); void ge_scalarmult(ge_p2 *, const unsigned char *, const ge_p3 *); void ge_scalarmult_p3(ge_p3 *, const unsigned char *, const ge_p3 *); void ge_double_scalarmult_precomp_vartime(ge_p2 *, const unsigned char *, const ge_p3 *, const unsigned char *, const ge_dsmp); +void ge_triple_scalarmult_precomp_vartime(ge_p2 *, const unsigned char *, const ge_dsmp, const unsigned char *, const ge_dsmp, const unsigned char *, const ge_dsmp); void ge_double_scalarmult_precomp_vartime2(ge_p2 *, const unsigned char *, const ge_dsmp, const unsigned char *, const ge_dsmp); void ge_double_scalarmult_precomp_vartime2_p3(ge_p3 *, const unsigned char *, const ge_dsmp, const unsigned char *, const ge_dsmp); void ge_mul8(ge_p1p1 *, const ge_p2 *); diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h index 8051ee9fa..7c240423a 100644 --- a/src/cryptonote_config.h +++ b/src/cryptonote_config.h @@ -226,6 +226,9 @@ namespace config const unsigned char HASH_KEY_MEMORY = 'k'; const unsigned char HASH_KEY_MULTISIG[] = {'M', 'u', 'l', 't' , 'i', 's', 'i', 'g', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; const unsigned char HASH_KEY_TXPROOF_V2[] = "TXPROOF_V2"; + const unsigned char HASH_KEY_CLSAG_ROUND[] = "CLSAG_round"; + const unsigned char HASH_KEY_CLSAG_AGG_0[] = "CLSAG_agg_0"; + const unsigned char HASH_KEY_CLSAG_AGG_1[] = "CLSAG_agg_1"; namespace testnet { diff --git a/src/ringct/rctOps.cpp b/src/ringct/rctOps.cpp index b2dd32ada..245a3f477 100644 --- a/src/ringct/rctOps.cpp +++ b/src/ringct/rctOps.cpp @@ -511,6 +511,23 @@ namespace rct { ge_tobytes(aAbB.bytes, &rv); } + // addKeys_aGbBcC + // computes aG + bB + cC + // G is the fixed basepoint and B,C require precomputation + void addKeys_aGbBcC(key &aGbBcC, const key &a, const key &b, const ge_dsmp B, const key &c, const ge_dsmp C) { + ge_p2 rv; + ge_triple_scalarmult_base_vartime(&rv, a.bytes, b.bytes, B, c.bytes, C); + ge_tobytes(aGbBcC.bytes, &rv); + } + + // addKeys_aAbBcC + // computes aA + bB + cC + // A,B,C require precomputation + void addKeys_aAbBcC(key &aAbBcC, const key &a, const ge_dsmp A, const key &b, const ge_dsmp B, const key &c, const ge_dsmp C) { + ge_p2 rv; + ge_triple_scalarmult_precomp_vartime(&rv, a.bytes, A, b.bytes, B, c.bytes, C); + ge_tobytes(aAbBcC.bytes, &rv); + } //subtract Keys (subtracts curve points) //AB = A - B where A, B are curve points diff --git a/src/ringct/rctOps.h b/src/ringct/rctOps.h index 74e0ad833..679ed1441 100644 --- a/src/ringct/rctOps.h +++ b/src/ringct/rctOps.h @@ -145,6 +145,10 @@ namespace rct { //B must be input after applying "precomp" void addKeys3(key &aAbB, const key &a, const key &A, const key &b, const ge_dsmp B); void addKeys3(key &aAbB, const key &a, const ge_dsmp A, const key &b, const ge_dsmp B); + + void addKeys_aGbBcC(key &aGbBcC, const key &a, const key &b, const ge_dsmp B, const key &c, const ge_dsmp C); + void addKeys_aAbBcC(key &aAbBcC, const key &a, const ge_dsmp A, const key &b, const ge_dsmp B, const key &c, const ge_dsmp C); + //AB = A - B where A, B are curve points void subKeys(key &AB, const key &A, const key &B); //checks if A, B are equal as curve points diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index 2e3e7007e..cb702ed15 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -36,6 +36,7 @@ #include "rctSigs.h" #include "bulletproofs.h" #include "cryptonote_basic/cryptonote_format_utils.h" +#include "cryptonote_config.h" using namespace crypto; using namespace std; @@ -165,6 +166,243 @@ namespace rct { return verifyBorromean(bb, P1_p3, P2_p3); } + // Generate a CLSAG signature + // See paper by Goodell et al. (https://eprint.iacr.org/2019/654) + clsag CLSAG_Gen(const key &message, const keyV & P, const key & p, const keyV & C, const key & z, const unsigned int l, const multisig_kLRki *kLRki) { + clsag sig; + size_t n = P.size(); // ring size + CHECK_AND_ASSERT_THROW_MES(n == C.size(), "Signing and commitment key vector sizes must match!"); + CHECK_AND_ASSERT_THROW_MES(l < n, "Signing index out of range!"); + + // Key images + ge_p3 H_p3; + hash_to_p3(H_p3,P[l]); + key H; + ge_p3_tobytes(H.bytes,&H_p3); + + key D; + scalarmultKey(D,H,z); + + // Multisig + if (kLRki) + { + sig.I = kLRki->ki; + } + else + { + scalarmultKey(sig.I,H,p); + } + + geDsmp I_precomp; + geDsmp D_precomp; + precomp(I_precomp.k,sig.I); + precomp(D_precomp.k,D); + + // Offset key image + scalarmultKey(sig.D,D,INV_EIGHT); + + // Initial values + key a; + key aG; + key aH; + skpkGen(a,aG); + scalarmultKey(aH,H,a); + + // Aggregation hashes + keyV mu_P_to_hash(2*n+3); // domain, I, D, P, C + keyV mu_C_to_hash(2*n+3); // domain, I, D, P, C + sc_0(mu_P_to_hash[0].bytes); + memcpy(mu_P_to_hash[0].bytes,config::HASH_KEY_CLSAG_AGG_0,sizeof(config::HASH_KEY_CLSAG_AGG_0)-1); + sc_0(mu_C_to_hash[0].bytes); + memcpy(mu_C_to_hash[0].bytes,config::HASH_KEY_CLSAG_AGG_1,sizeof(config::HASH_KEY_CLSAG_AGG_1)-1); + for (size_t i = 1; i < n+1; ++i) { + mu_P_to_hash[i] = P[i-1]; + mu_C_to_hash[i] = P[i-1]; + } + for (size_t i = n+1; i < 2*n+1; ++i) { + mu_P_to_hash[i] = C[i-n-1]; + mu_C_to_hash[i] = C[i-n-1]; + } + mu_P_to_hash[2*n+1] = sig.I; + mu_P_to_hash[2*n+2] = sig.D; + mu_C_to_hash[2*n+1] = sig.I; + mu_C_to_hash[2*n+2] = sig.D; + key mu_P, mu_C; + mu_P = hash_to_scalar(mu_P_to_hash); + mu_C = hash_to_scalar(mu_C_to_hash); + + // Initial commitment + keyV c_to_hash(2*n+4); // domain, P, C, message, aG, aH + key c; + sc_0(c_to_hash[0].bytes); + memcpy(c_to_hash[0].bytes,config::HASH_KEY_CLSAG_ROUND,sizeof(config::HASH_KEY_CLSAG_ROUND)-1); + for (size_t i = 1; i < n+1; ++i) + { + c_to_hash[i] = P[i-1]; + c_to_hash[i+n] = C[i-1]; + } + c_to_hash[2*n+1] = message; + + // Multisig data is present + if (kLRki) + { + a = kLRki->k; + c_to_hash[2*n+2] = kLRki->L; + c_to_hash[2*n+3] = kLRki->R; + } + else + { + c_to_hash[2*n+2] = aG; + c_to_hash[2*n+3] = aH; + } + c = hash_to_scalar(c_to_hash); + + size_t i; + i = (l + 1) % n; + if (i == 0) + copy(sig.c1, c); + + // Decoy indices + sig.s = keyV(n); + key c_new; + key L; + key R; + key c_p; // = c[i]*mu_P + key c_c; // = c[i]*mu_C + geDsmp P_precomp; + geDsmp C_precomp; + geDsmp H_precomp; + ge_p3 Hi_p3; + + while (i != l) { + sig.s[i] = skGen(); + sc_0(c_new.bytes); + sc_mul(c_p.bytes,mu_P.bytes,c.bytes); + sc_mul(c_c.bytes,mu_C.bytes,c.bytes); + + // Precompute points + precomp(P_precomp.k,P[i]); + precomp(C_precomp.k,C[i]); + + // Compute L + addKeys_aGbBcC(L,sig.s[i],c_p,P_precomp.k,c_c,C_precomp.k); + + // Compute R + hash_to_p3(Hi_p3,P[i]); + ge_dsm_precomp(H_precomp.k, &Hi_p3); + addKeys_aAbBcC(R,sig.s[i],H_precomp.k,c_p,I_precomp.k,c_c,D_precomp.k); + + c_to_hash[2*n+2] = L; + c_to_hash[2*n+3] = R; + c_new = hash_to_scalar(c_to_hash); + copy(c,c_new); + + i = (i + 1) % n; + if (i == 0) + copy(sig.c1,c); + } + + // Compute final scalar + key s0_p_mu_P; + sc_mul(s0_p_mu_P.bytes,mu_P.bytes,p.bytes); + key s0_add_z_mu_C; + sc_muladd(s0_add_z_mu_C.bytes,mu_C.bytes,z.bytes,s0_p_mu_P.bytes); + sc_mulsub(sig.s[l].bytes,c.bytes,s0_add_z_mu_C.bytes,a.bytes); + + return sig; + } + + // Verify a CLSAG signature + // See paper by Goodell et al. (https://eprint.iacr.org/2019/654) + bool CLSAG_Ver(const key &message, const keyV & P, const keyV & C, const clsag & sig) + { + size_t n = P.size(); // ring size + CHECK_AND_ASSERT_MES(n == C.size(), false, "Signing and commitment key vector sizes must match!"); + CHECK_AND_ASSERT_MES(n == sig.s.size(), false, "Signature scalar vector is the wrong size!"); + for (size_t i = 0; i < n; ++i) + CHECK_AND_ASSERT_MES(sc_check(sig.s[i].bytes) == 0, false, "Bad signature scalar!"); + CHECK_AND_ASSERT_MES(sc_check(sig.c1.bytes) == 0, false, "Bad signature commitment!"); + + key c = copy(sig.c1); + key D_8 = scalarmult8(sig.D); + geDsmp I_precomp; + geDsmp D_precomp; + precomp(I_precomp.k,sig.I); + precomp(D_precomp.k,D_8); + + // Aggregation hashes + keyV mu_P_to_hash(2*n+3); // domain, I, D, P, C + keyV mu_C_to_hash(2*n+3); // domain, I, D, P, C + sc_0(mu_P_to_hash[0].bytes); + memcpy(mu_P_to_hash[0].bytes,config::HASH_KEY_CLSAG_AGG_0,sizeof(config::HASH_KEY_CLSAG_AGG_0)-1); + sc_0(mu_C_to_hash[0].bytes); + memcpy(mu_C_to_hash[0].bytes,config::HASH_KEY_CLSAG_AGG_1,sizeof(config::HASH_KEY_CLSAG_AGG_1)-1); + for (size_t i = 1; i < n+1; ++i) { + mu_P_to_hash[i] = P[i-1]; + mu_C_to_hash[i] = P[i-1]; + } + for (size_t i = n+1; i < 2*n+1; ++i) { + mu_P_to_hash[i] = C[i-n-1]; + mu_C_to_hash[i] = C[i-n-1]; + } + mu_P_to_hash[2*n+1] = sig.I; + mu_P_to_hash[2*n+2] = sig.D; + mu_C_to_hash[2*n+1] = sig.I; + mu_C_to_hash[2*n+2] = sig.D; + key mu_P, mu_C; + mu_P = hash_to_scalar(mu_P_to_hash); + mu_C = hash_to_scalar(mu_C_to_hash); + + keyV c_to_hash(2*n+4); // domain, P, C, message, L, R + sc_0(c_to_hash[0].bytes); + memcpy(c_to_hash[0].bytes,config::HASH_KEY_CLSAG_ROUND,sizeof(config::HASH_KEY_CLSAG_ROUND)-1); + for (size_t i = 1; i < n+1; ++i) + { + c_to_hash[i] = P[i-1]; + c_to_hash[i+n] = C[i-1]; + } + c_to_hash[2*n+1] = message; + key c_p; // = c[i]*mu_P + key c_c; // = c[i]*mu_C + key c_new; + key L; + key R; + geDsmp P_precomp; + geDsmp C_precomp; + geDsmp H_precomp; + size_t i = 0; + ge_p3 hash8_p3; + geDsmp hash_precomp; + + while (i < n) { + sc_0(c_new.bytes); + sc_mul(c_p.bytes,mu_P.bytes,c.bytes); + sc_mul(c_c.bytes,mu_C.bytes,c.bytes); + + // Precompute points + precomp(P_precomp.k,P[i]); + precomp(C_precomp.k,C[i]); + + // Compute L + addKeys_aGbBcC(L,sig.s[i],c_p,P_precomp.k,c_c,C_precomp.k); + + // Compute R + hash_to_p3(hash8_p3,P[i]); + ge_dsm_precomp(hash_precomp.k, &hash8_p3); + addKeys_aAbBcC(R,sig.s[i],hash_precomp.k,c_p,I_precomp.k,c_c,D_precomp.k); + + c_to_hash[2*n+2] = L; + c_to_hash[2*n+3] = R; + c_new = hash_to_scalar(c_to_hash); + CHECK_AND_ASSERT_MES(!(c_new == rct::zero()), false, "Bad signature hash"); + copy(c,c_new); + + i = i + 1; + } + sc_sub(c_new.bytes,c.bytes,sig.c1.bytes); + return sc_isnonzero(c_new.bytes) == 0; + } + // MLSAG signatures // See paper by Noether (https://eprint.iacr.org/2015/1098) // This generalization allows for some dimensions not to require linkability; diff --git a/src/ringct/rctSigs.h b/src/ringct/rctSigs.h index 9227eab1e..87d2b994b 100644 --- a/src/ringct/rctSigs.h +++ b/src/ringct/rctSigs.h @@ -76,6 +76,9 @@ namespace rct { // Ver verifies that the MG sig was created correctly 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); bool MLSAG_Ver(const key &message, const keyM &pk, const mgSig &sig, size_t dsRows); + + clsag CLSAG_Gen(const key &message, const keyV & P, const key & p, const keyV & C, const key & z, const unsigned int l, const multisig_kLRki *kLRki); + bool CLSAG_Ver(const key &message, const keyV & P, const keyV & C, const clsag & sig); //mgSig MLSAG_Gen_Old(const keyM & pk, const keyV & xx, const int index); //proveRange and verRange diff --git a/src/ringct/rctTypes.h b/src/ringct/rctTypes.h index ce11981ad..b83c267d0 100644 --- a/src/ringct/rctTypes.h +++ b/src/ringct/rctTypes.h @@ -163,6 +163,21 @@ namespace rct { // FIELD(II) - not serialized, it can be reconstructed END_SERIALIZE() }; + + // CLSAG signature + struct clsag { + keyV s; // scalars + key c1; + + key I; // signing key image + key D; // commitment key image + + BEGIN_SERIALIZE_OBJECT() + FIELD(s) + FIELD(c1) + END_SERIALIZE() + }; + //contains the data for an Borromean sig // also contains the "Ci" values such that // \sum Ci = C diff --git a/tests/performance_tests/crypto_ops.h b/tests/performance_tests/crypto_ops.h index ae00bb517..9db2e413a 100644 --- a/tests/performance_tests/crypto_ops.h +++ b/tests/performance_tests/crypto_ops.h @@ -51,11 +51,15 @@ enum test_op op_scalarmult8_p3, op_ge_dsm_precomp, op_ge_double_scalarmult_base_vartime, + op_ge_triple_scalarmult_base_vartime, op_ge_double_scalarmult_precomp_vartime, + op_ge_triple_scalarmult_precomp_vartime, op_ge_double_scalarmult_precomp_vartime2, op_addKeys2, op_addKeys3, op_addKeys3_2, + op_addKeys_aGbBcC, + op_addKeys_aAbBcC, op_isInMainSubgroup, op_zeroCommitUncached, }; @@ -70,15 +74,20 @@ public: { scalar0 = rct::skGen(); scalar1 = rct::skGen(); + scalar2 = rct::skGen(); point0 = rct::scalarmultBase(rct::skGen()); point1 = rct::scalarmultBase(rct::skGen()); + point2 = rct::scalarmultBase(rct::skGen()); if (ge_frombytes_vartime(&p3_0, point0.bytes) != 0) return false; if (ge_frombytes_vartime(&p3_1, point1.bytes) != 0) return false; + if (ge_frombytes_vartime(&p3_2, point2.bytes) != 0) + return false; ge_p3_to_cached(&cached, &p3_0); rct::precomp(precomp0, point0); rct::precomp(precomp1, point1); + rct::precomp(precomp2, point2); return true; } @@ -109,11 +118,15 @@ public: case op_scalarmult8_p3: rct::scalarmult8(p3_0,point0); break; case op_ge_dsm_precomp: ge_dsm_precomp(dsmp, &p3_0); break; case op_ge_double_scalarmult_base_vartime: ge_double_scalarmult_base_vartime(&tmp_p2, scalar0.bytes, &p3_0, scalar1.bytes); break; + case op_ge_triple_scalarmult_base_vartime: ge_triple_scalarmult_base_vartime(&tmp_p2, scalar0.bytes, scalar1.bytes, precomp1, scalar2.bytes, precomp2); break; case op_ge_double_scalarmult_precomp_vartime: ge_double_scalarmult_precomp_vartime(&tmp_p2, scalar0.bytes, &p3_0, scalar1.bytes, precomp0); break; + case op_ge_triple_scalarmult_precomp_vartime: ge_triple_scalarmult_precomp_vartime(&tmp_p2, scalar0.bytes, precomp0, scalar1.bytes, precomp1, scalar2.bytes, precomp2); break; case op_ge_double_scalarmult_precomp_vartime2: ge_double_scalarmult_precomp_vartime2(&tmp_p2, scalar0.bytes, precomp0, scalar1.bytes, precomp1); break; case op_addKeys2: rct::addKeys2(key, scalar0, scalar1, point0); break; case op_addKeys3: rct::addKeys3(key, scalar0, point0, scalar1, precomp1); break; case op_addKeys3_2: rct::addKeys3(key, scalar0, precomp0, scalar1, precomp1); break; + case op_addKeys_aGbBcC: rct::addKeys_aGbBcC(key, scalar0, scalar1, precomp1, scalar2, precomp2); break; + case op_addKeys_aAbBcC: rct::addKeys_aAbBcC(key, scalar0, precomp0, scalar1, precomp1, scalar2, precomp2); break; case op_isInMainSubgroup: rct::isInMainSubgroup(point0); break; case op_zeroCommitUncached: rct::zeroCommit(9001); break; case op_zeroCommitCached: rct::zeroCommit(9000); break; @@ -123,9 +136,9 @@ public: } private: - rct::key scalar0, scalar1; - rct::key point0, point1; - ge_p3 p3_0, p3_1; + rct::key scalar0, scalar1, scalar2; + rct::key point0, point1, point2; + ge_p3 p3_0, p3_1, p3_2; ge_cached cached; - ge_dsmp precomp0, precomp1; + ge_dsmp precomp0, precomp1, precomp2; }; diff --git a/tests/performance_tests/main.cpp b/tests/performance_tests/main.cpp index ca0528e16..b0cec464c 100644 --- a/tests/performance_tests/main.cpp +++ b/tests/performance_tests/main.cpp @@ -60,6 +60,8 @@ #include "bulletproof.h" #include "crypto_ops.h" #include "multiexp.h" +#include "sig_mlsag.h" +#include "sig_clsag.h" namespace po = boost::program_options; @@ -213,6 +215,9 @@ 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_PERFORMANCE2(filter, p, test_sig_mlsag, 11, true); // MLSAG verification + TEST_PERFORMANCE3(filter, p, test_sig_clsag, 11, true, 0); // CLSAG verification + TEST_PERFORMANCE2(filter, p, test_ringct_mlsag, 11, false); TEST_PERFORMANCE2(filter, p, test_ringct_mlsag, 11, true); @@ -257,11 +262,15 @@ int main(int argc, char** argv) TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_scalarmult8_p3); TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_ge_dsm_precomp); TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_ge_double_scalarmult_base_vartime); + TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_ge_triple_scalarmult_base_vartime); TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_ge_double_scalarmult_precomp_vartime); + TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_ge_triple_scalarmult_precomp_vartime); TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_ge_double_scalarmult_precomp_vartime2); TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_addKeys2); TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_addKeys3); TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_addKeys3_2); + TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_addKeys_aGbBcC); + TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_addKeys_aAbBcC); TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_isInMainSubgroup); TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_zeroCommitUncached); TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_zeroCommitCached); diff --git a/tests/performance_tests/sig_clsag.h b/tests/performance_tests/sig_clsag.h new file mode 100644 index 000000000..0873fa520 --- /dev/null +++ b/tests/performance_tests/sig_clsag.h @@ -0,0 +1,83 @@ +// Copyright (c) 2014-2019, The Monero Project +// +// 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. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + +#pragma once + +#include "ringct/rctSigs.h" +#include "cryptonote_basic/cryptonote_basic.h" + +#include "single_tx_test_base.h" + +template +class test_sig_clsag : public single_tx_test_base +{ +public: + static const size_t n = ring_size; + static const size_t loop_count = 1000; + static const size_t l = index; + + bool init() + { + if (!single_tx_test_base::init()) + return false; + + p = rct::skGen(); + z = rct::skGen(); + P = rct::skvGen(n); + C = rct::skvGen(n); + for (size_t i = 0 ; i < n; i++) + { + P[i] = rct::scalarmultBase(P[i]); + C[i] = rct::scalarmultBase(C[i]); + } + P[l] = rct::scalarmultBase(p); + C[l] = rct::scalarmultBase(z); + + sig = CLSAG_Gen(rct::identity(),P,p,C,z,l,NULL); + + return true; + } + + bool test() + { + if (ver) + return CLSAG_Ver(rct::identity(),P,C,sig); + else + CLSAG_Gen(rct::identity(),P,p,C,z,l,NULL); + return true; + } + +private: + rct::key p; + rct::key z; + rct::keyV P; + rct::keyV C; + rct::clsag sig; +}; diff --git a/tests/performance_tests/sig_mlsag.h b/tests/performance_tests/sig_mlsag.h new file mode 100644 index 000000000..fc987fcf5 --- /dev/null +++ b/tests/performance_tests/sig_mlsag.h @@ -0,0 +1,87 @@ +// Copyright (c) 2014-2019, The Monero Project +// +// 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. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + +#pragma once + +#include "ringct/rctSigs.h" +#include "cryptonote_basic/cryptonote_basic.h" + +#include "single_tx_test_base.h" + +template +class test_sig_mlsag : public single_tx_test_base +{ +public: + static const size_t cols = ring_size; + static const size_t rows = 2; // 1 spend + 1 commitment + static const size_t loop_count = 1000; + + bool init() + { + if (!single_tx_test_base::init()) + return false; + + rct::keyV xtmp = rct::skvGen(rows); + rct::keyM xm = rct::keyMInit(rows, cols);// = [[None]*N] #just used to generate test public keys + sk = rct::skvGen(rows); + P = rct::keyMInit(rows, cols);// = keyM[[None]*N] #stores the public keys; + ind = 0; // fixed spend index + for (size_t j = 0 ; j < rows ; j++) + { + for (size_t i = 0 ; i < cols ; i++) + { + xm[i][j] = rct::skGen(); + P[i][j] = rct::scalarmultBase(xm[i][j]); + } + } + for (size_t j = 0 ; j < rows ; j++) + { + sk[j] = xm[ind][j]; + } + IIccss = MLSAG_Gen(rct::identity(), P, sk, NULL, NULL, ind, rows-1, hw::get_device("default")); + + return true; + } + + bool test() + { + if (ver) + return MLSAG_Ver(rct::identity(), P, IIccss, rows-1); + else + MLSAG_Gen(rct::identity(), P, sk, NULL, NULL, ind, rows-1, hw::get_device("default")); + return true; + } + +private: + rct::keyV sk; + rct::keyM P; + size_t ind; + rct::mgSig IIccss; +};