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
+238
View File
@@ -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;