CLSAG signatures

This commit is contained in:
Sarang Noether 2019-08-29 11:35:12 +00:00 committed by moneromooo-monero
parent c695470cff
commit 4b328c6616
12 changed files with 578 additions and 4 deletions

View File

@ -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) { 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 aslide[256];
signed char bslide[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) { 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 aslide[256];
signed char bslide[256]; signed char bslide[256];

View File

@ -79,6 +79,7 @@ typedef ge_cached ge_dsmp[8];
extern const ge_precomp ge_Bi[8]; extern const ge_precomp ge_Bi[8];
void ge_dsm_precomp(ge_dsmp r, const ge_p3 *s); 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_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 *); void ge_double_scalarmult_base_vartime_p3(ge_p3 *, const unsigned char *, const ge_p3 *, const unsigned char *);
/* From ge_frombytes.c, modified */ /* 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(ge_p2 *, const unsigned char *, const ge_p3 *);
void ge_scalarmult_p3(ge_p3 *, 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_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(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_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 *); void ge_mul8(ge_p1p1 *, const ge_p2 *);

View File

@ -226,6 +226,9 @@ namespace config
const unsigned char HASH_KEY_MEMORY = 'k'; 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_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_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 namespace testnet
{ {

View File

@ -511,6 +511,23 @@ namespace rct {
ge_tobytes(aAbB.bytes, &rv); 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) //subtract Keys (subtracts curve points)
//AB = A - B where A, B are curve points //AB = A - B where A, B are curve points

View File

@ -145,6 +145,10 @@ namespace rct {
//B must be input after applying "precomp" //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 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 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 //AB = A - B where A, B are curve points
void subKeys(key &AB, const key &A, const key &B); void subKeys(key &AB, const key &A, const key &B);
//checks if A, B are equal as curve points //checks if A, B are equal as curve points

View File

@ -36,6 +36,7 @@
#include "rctSigs.h" #include "rctSigs.h"
#include "bulletproofs.h" #include "bulletproofs.h"
#include "cryptonote_basic/cryptonote_format_utils.h" #include "cryptonote_basic/cryptonote_format_utils.h"
#include "cryptonote_config.h"
using namespace crypto; using namespace crypto;
using namespace std; using namespace std;
@ -165,6 +166,243 @@ namespace rct {
return verifyBorromean(bb, P1_p3, P2_p3); 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 // MLSAG signatures
// See paper by Noether (https://eprint.iacr.org/2015/1098) // See paper by Noether (https://eprint.iacr.org/2015/1098)
// This generalization allows for some dimensions not to require linkability; // This generalization allows for some dimensions not to require linkability;

View File

@ -76,6 +76,9 @@ namespace rct {
// Ver verifies that the MG sig was created correctly // 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); 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); 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); //mgSig MLSAG_Gen_Old(const keyM & pk, const keyV & xx, const int index);
//proveRange and verRange //proveRange and verRange

View File

@ -163,6 +163,21 @@ namespace rct {
// FIELD(II) - not serialized, it can be reconstructed // FIELD(II) - not serialized, it can be reconstructed
END_SERIALIZE() 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 //contains the data for an Borromean sig
// also contains the "Ci" values such that // also contains the "Ci" values such that
// \sum Ci = C // \sum Ci = C

View File

@ -51,11 +51,15 @@ enum test_op
op_scalarmult8_p3, op_scalarmult8_p3,
op_ge_dsm_precomp, op_ge_dsm_precomp,
op_ge_double_scalarmult_base_vartime, op_ge_double_scalarmult_base_vartime,
op_ge_triple_scalarmult_base_vartime,
op_ge_double_scalarmult_precomp_vartime, op_ge_double_scalarmult_precomp_vartime,
op_ge_triple_scalarmult_precomp_vartime,
op_ge_double_scalarmult_precomp_vartime2, op_ge_double_scalarmult_precomp_vartime2,
op_addKeys2, op_addKeys2,
op_addKeys3, op_addKeys3,
op_addKeys3_2, op_addKeys3_2,
op_addKeys_aGbBcC,
op_addKeys_aAbBcC,
op_isInMainSubgroup, op_isInMainSubgroup,
op_zeroCommitUncached, op_zeroCommitUncached,
}; };
@ -70,15 +74,20 @@ public:
{ {
scalar0 = rct::skGen(); scalar0 = rct::skGen();
scalar1 = rct::skGen(); scalar1 = rct::skGen();
scalar2 = rct::skGen();
point0 = rct::scalarmultBase(rct::skGen()); point0 = rct::scalarmultBase(rct::skGen());
point1 = rct::scalarmultBase(rct::skGen()); point1 = rct::scalarmultBase(rct::skGen());
point2 = rct::scalarmultBase(rct::skGen());
if (ge_frombytes_vartime(&p3_0, point0.bytes) != 0) if (ge_frombytes_vartime(&p3_0, point0.bytes) != 0)
return false; return false;
if (ge_frombytes_vartime(&p3_1, point1.bytes) != 0) if (ge_frombytes_vartime(&p3_1, point1.bytes) != 0)
return false; return false;
if (ge_frombytes_vartime(&p3_2, point2.bytes) != 0)
return false;
ge_p3_to_cached(&cached, &p3_0); ge_p3_to_cached(&cached, &p3_0);
rct::precomp(precomp0, point0); rct::precomp(precomp0, point0);
rct::precomp(precomp1, point1); rct::precomp(precomp1, point1);
rct::precomp(precomp2, point2);
return true; return true;
} }
@ -109,11 +118,15 @@ public:
case op_scalarmult8_p3: rct::scalarmult8(p3_0,point0); break; 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_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_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_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_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_addKeys2: rct::addKeys2(key, scalar0, scalar1, point0); break;
case op_addKeys3: rct::addKeys3(key, scalar0, point0, scalar1, precomp1); 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_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_isInMainSubgroup: rct::isInMainSubgroup(point0); break;
case op_zeroCommitUncached: rct::zeroCommit(9001); break; case op_zeroCommitUncached: rct::zeroCommit(9001); break;
case op_zeroCommitCached: rct::zeroCommit(9000); break; case op_zeroCommitCached: rct::zeroCommit(9000); break;
@ -123,9 +136,9 @@ public:
} }
private: private:
rct::key scalar0, scalar1; rct::key scalar0, scalar1, scalar2;
rct::key point0, point1; rct::key point0, point1, point2;
ge_p3 p3_0, p3_1; ge_p3 p3_0, p3_1, p3_2;
ge_cached cached; ge_cached cached;
ge_dsmp precomp0, precomp1; ge_dsmp precomp0, precomp1, precomp2;
}; };

View File

@ -60,6 +60,8 @@
#include "bulletproof.h" #include "bulletproof.h"
#include "crypto_ops.h" #include "crypto_ops.h"
#include "multiexp.h" #include "multiexp.h"
#include "sig_mlsag.h"
#include "sig_clsag.h"
namespace po = boost::program_options; 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, 32);
TEST_PERFORMANCE1(filter, p, test_cn_fast_hash, 16384); 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, false);
TEST_PERFORMANCE2(filter, p, test_ringct_mlsag, 11, true); 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_scalarmult8_p3);
TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_ge_dsm_precomp); 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_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_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_ge_double_scalarmult_precomp_vartime2);
TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_addKeys2); 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);
TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_addKeys3_2); 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_isInMainSubgroup);
TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_zeroCommitUncached); TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_zeroCommitUncached);
TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_zeroCommitCached); TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_zeroCommitCached);

View File

@ -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<size_t ring_size, bool ver, size_t index>
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;
};

View File

@ -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<size_t ring_size, bool ver>
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;
};