mirror of
https://codeberg.org/anoncontributorxmr/monero.git
synced 2024-11-25 17:02:26 +00:00
CLSAG signatures
This commit is contained in:
parent
c695470cff
commit
4b328c6616
12 changed files with 578 additions and 4 deletions
|
@ -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];
|
||||
|
|
|
@ -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 *);
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
83
tests/performance_tests/sig_clsag.h
Normal file
83
tests/performance_tests/sig_clsag.h
Normal 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;
|
||||
};
|
87
tests/performance_tests/sig_mlsag.h
Normal file
87
tests/performance_tests/sig_mlsag.h
Normal 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;
|
||||
};
|
Loading…
Reference in a new issue