From 4b328c66161d11ddb240ca9c10298b0581aaa6b5 Mon Sep 17 00:00:00 2001 From: Sarang Noether <32460187+SarangNoether@users.noreply.github.com> Date: Thu, 29 Aug 2019 11:35:12 +0000 Subject: CLSAG signatures --- src/ringct/rctSigs.cpp | 238 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 238 insertions(+) (limited to 'src/ringct/rctSigs.cpp') 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; -- cgit v1.2.3 From 82ee01699c2b910e44fd7362bd47d3a1cc9c26af Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sun, 9 Jun 2019 13:02:16 +0000 Subject: Integrate CLSAGs into monero They are allowed from v12, and MLSAGs are rejected from v13. --- src/ringct/rctSigs.cpp | 184 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 166 insertions(+), 18 deletions(-) (limited to 'src/ringct/rctSigs.cpp') diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index cb702ed15..074812156 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -168,11 +168,14 @@ namespace rct { // 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 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, key *mscout, key *mspout) { 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!"); + CHECK_AND_ASSERT_THROW_MES(scalarmultBase(z) == C[l], "C does not match z!"); + CHECK_AND_ASSERT_THROW_MES((kLRki && mscout) || (!kLRki && !mscout), "Only one of kLRki/mscout is present"); + CHECK_AND_ASSERT_THROW_MES((mscout && mspout) || !kLRki, "Multisig pointers are not all present"); // Key images ge_p3 H_p3; @@ -309,9 +312,18 @@ namespace rct { 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); + if (mscout) + *mscout = c; + if (mspout) + *mspout = mu_P; + return sig; } + clsag CLSAG_Gen(const key &message, const keyV & P, const key & p, const keyV & C, const key & z, const unsigned int l) { + return CLSAG_Gen(message, P, p, C, z, l, NULL, NULL, NULL); + } + // 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) @@ -665,7 +677,7 @@ namespace rct { hashes.push_back(hash2rct(h)); keyV kv; - if (rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2) + if (rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG) { kv.reserve((6*2+9) * rv.p.bulletproofs.size()); for (const auto &p: rv.p.bulletproofs) @@ -793,6 +805,35 @@ namespace rct { return result; } + clsag proveRctCLSAGSimple(const key &message, const ctkeyV &pubs, const ctkey &inSk, const key &a, const key &Cout, const multisig_kLRki *kLRki, key *mscout, key *mspout, unsigned int index, hw::device &hwdev) { + //setup vars + size_t rows = 1; + size_t cols = pubs.size(); + CHECK_AND_ASSERT_THROW_MES(cols >= 1, "Empty pubs"); + CHECK_AND_ASSERT_THROW_MES((kLRki && mscout) || (!kLRki && !mscout), "Only one of kLRki/mscout is present"); + keyV tmp(rows + 1); + keyV sk(rows + 1); + size_t i; + keyM M(cols, tmp); + + keyV P, C; + P.reserve(pubs.size()); + C.reserve(pubs.size()); + for (const ctkey &k: pubs) + { + P.push_back(k.dest); + rct::key tmp; + subKeys(tmp, k.mask, Cout); + C.push_back(tmp); + } + + sk[0] = copy(inSk.dest); + sc_sub(sk[1].bytes, inSk.mask.bytes, a.bytes); + clsag result = CLSAG_Gen(message, P, sk[0], C, sk[1], index, kLRki, mscout, mspout); + memwipe(sk.data(), sk.size() * sizeof(key)); + return result; + } + //Ring-ct MG sigs //Prove: @@ -872,6 +913,33 @@ namespace rct { catch (...) { return false; } } + bool verRctCLSAGSimple(const key &message, const clsag &clsag, const ctkeyV & pubs, const key & C) { + try + { + PERF_TIMER(verRctCLSAGSimple); + //setup vars + const size_t cols = pubs.size(); + CHECK_AND_ASSERT_MES(cols >= 1, false, "Empty pubs"); + keyV Pi(cols), Ci(cols); + ge_p3 Cp3; + CHECK_AND_ASSERT_MES_L1(ge_frombytes_vartime(&Cp3, C.bytes) == 0, false, "point conv failed"); + ge_cached Ccached; + ge_p3_to_cached(&Ccached, &Cp3); + ge_p1p1 p1; + //create the matrix to mg sig + for (size_t i = 0; i < cols; i++) { + Pi[i] = pubs[i].dest; + ge_p3 p3; + CHECK_AND_ASSERT_MES_L1(ge_frombytes_vartime(&p3, pubs[i].mask.bytes) == 0, false, "point conv failed"); + ge_sub(&p1, &p3, &Ccached); + ge_p1p1_to_p3(&p3, &p1); + ge_p3_tobytes(Ci[i].bytes, &p3); + } + return CLSAG_Ver(message, Pi, Ci, clsag); + } + catch (...) { return false; } + } + //These functions get keys from blockchain //replace these when connecting blockchain @@ -964,7 +1032,7 @@ namespace rct { //mask amount and mask rv.ecdhInfo[i].mask = copy(outSk[i].mask); rv.ecdhInfo[i].amount = d2h(amounts[i]); - hwdev.ecdhEncode(rv.ecdhInfo[i], amount_keys[i], rv.type == RCTTypeBulletproof2); + hwdev.ecdhEncode(rv.ecdhInfo[i], amount_keys[i], rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG); } //set txn fee @@ -1012,7 +1080,27 @@ namespace rct { } rctSig rv; - rv.type = bulletproof ? (rct_config.bp_version == 0 || rct_config.bp_version >= 2 ? RCTTypeBulletproof2 : RCTTypeBulletproof) : RCTTypeSimple; + if (bulletproof) + { + switch (rct_config.bp_version) + { + case 0: + case 3: + rv.type = RCTTypeCLSAG; + break; + case 2: + rv.type = RCTTypeBulletproof2; + break; + case 1: + rv.type = RCTTypeBulletproof; + break; + default: + ASSERT_MES_AND_THROW("Unsupported BP version: " << rct_config.bp_version); + } + } + else + rv.type = RCTTypeSimple; + rv.message = message; rv.outPk.resize(destinations.size()); if (!bulletproof) @@ -1102,7 +1190,7 @@ namespace rct { //mask amount and mask rv.ecdhInfo[i].mask = copy(outSk[i].mask); rv.ecdhInfo[i].amount = d2h(outamounts[i]); - hwdev.ecdhEncode(rv.ecdhInfo[i], amount_keys[i], rv.type == RCTTypeBulletproof2); + hwdev.ecdhEncode(rv.ecdhInfo[i], amount_keys[i], rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG); } //set txn fee @@ -1112,7 +1200,10 @@ namespace rct { rv.mixRing = mixRing; keyV &pseudoOuts = bulletproof ? rv.p.pseudoOuts : rv.pseudoOuts; pseudoOuts.resize(inamounts.size()); - rv.p.MGs.resize(inamounts.size()); + if (rv.type == RCTTypeCLSAG) + rv.p.CLSAGs.resize(inamounts.size()); + else + rv.p.MGs.resize(inamounts.size()); key sumpouts = zero(); //sum pseudoOut masks keyV a(inamounts.size()); for (i = 0 ; i < inamounts.size() - 1; i++) { @@ -1126,9 +1217,20 @@ namespace rct { key full_message = get_pre_mlsag_hash(rv,hwdev); if (msout) - msout->c.resize(inamounts.size()); - for (i = 0 ; i < inamounts.size(); i++) { - rv.p.MGs[i] = proveRctMGSimple(full_message, rv.mixRing[i], inSk[i], a[i], pseudoOuts[i], kLRki ? &(*kLRki)[i]: NULL, msout ? &msout->c[i] : NULL, index[i], hwdev); + { + msout->c.resize(inamounts.size()); + msout->mu_p.resize(rv.type == RCTTypeCLSAG ? inamounts.size() : 0); + } + for (i = 0 ; i < inamounts.size(); i++) + { + if (rv.type == RCTTypeCLSAG) + { + rv.p.CLSAGs[i] = proveRctCLSAGSimple(full_message, rv.mixRing[i], inSk[i], a[i], pseudoOuts[i], kLRki ? &(*kLRki)[i]: NULL, msout ? &msout->c[i] : NULL, msout ? &msout->mu_p[i] : NULL, index[i], hwdev); + } + else + { + rv.p.MGs[i] = proveRctMGSimple(full_message, rv.mixRing[i], inSk[i], a[i], pseudoOuts[i], kLRki ? &(*kLRki)[i]: NULL, msout ? &msout->c[i] : NULL, index[i], hwdev); + } } return rv; } @@ -1233,13 +1335,22 @@ namespace rct { { CHECK_AND_ASSERT_MES(rvp, false, "rctSig pointer is NULL"); const rctSig &rv = *rvp; - CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2, + CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG, false, "verRctSemanticsSimple called on non simple rctSig"); const bool bulletproof = is_rct_bulletproof(rv.type); if (bulletproof) { CHECK_AND_ASSERT_MES(rv.outPk.size() == n_bulletproof_amounts(rv.p.bulletproofs), false, "Mismatched sizes of outPk and bulletproofs"); - CHECK_AND_ASSERT_MES(rv.p.pseudoOuts.size() == rv.p.MGs.size(), false, "Mismatched sizes of rv.p.pseudoOuts and rv.p.MGs"); + if (rv.type == RCTTypeCLSAG) + { + CHECK_AND_ASSERT_MES(rv.p.MGs.empty(), false, "MGs are not empty for CLSAG"); + CHECK_AND_ASSERT_MES(rv.p.pseudoOuts.size() == rv.p.CLSAGs.size(), false, "Mismatched sizes of rv.p.pseudoOuts and rv.p.CLSAGs"); + } + else + { + CHECK_AND_ASSERT_MES(rv.p.CLSAGs.empty(), false, "CLSAGs are not empty for MLSAG"); + CHECK_AND_ASSERT_MES(rv.p.pseudoOuts.size() == rv.p.MGs.size(), false, "Mismatched sizes of rv.p.pseudoOuts and rv.p.MGs"); + } CHECK_AND_ASSERT_MES(rv.pseudoOuts.empty(), false, "rv.pseudoOuts is not empty"); } else @@ -1333,7 +1444,7 @@ namespace rct { { PERF_TIMER(verRctNonSemanticsSimple); - CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2, + CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG, false, "verRctNonSemanticsSimple called on non simple rctSig"); const bool bulletproof = is_rct_bulletproof(rv.type); // semantics check is early, and mixRing/MGs aren't resolved yet @@ -1356,14 +1467,19 @@ namespace rct { results.resize(rv.mixRing.size()); for (size_t i = 0 ; i < rv.mixRing.size() ; i++) { tpool.submit(&waiter, [&, i] { - results[i] = verRctMGSimple(message, rv.p.MGs[i], rv.mixRing[i], pseudoOuts[i]); + if (rv.type == RCTTypeCLSAG) + { + results[i] = verRctCLSAGSimple(message, rv.p.CLSAGs[i], rv.mixRing[i], pseudoOuts[i]); + } + else + results[i] = verRctMGSimple(message, rv.p.MGs[i], rv.mixRing[i], pseudoOuts[i]); }); } waiter.wait(&tpool); for (size_t i = 0; i < results.size(); ++i) { if (!results[i]) { - LOG_PRINT_L1("verRctMGSimple failed for input " << i); + LOG_PRINT_L1("verRctMGSimple/verRctCLSAGSimple failed for input " << i); return false; } } @@ -1400,7 +1516,7 @@ namespace rct { //mask amount and mask ecdhTuple ecdh_info = rv.ecdhInfo[i]; - hwdev.ecdhDecode(ecdh_info, sk, rv.type == RCTTypeBulletproof2); + hwdev.ecdhDecode(ecdh_info, sk, rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG); mask = ecdh_info.mask; key amount = ecdh_info.amount; key C = rv.outPk[i].mask; @@ -1424,13 +1540,13 @@ namespace rct { } xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, key &mask, hw::device &hwdev) { - CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2, false, "decodeRct called on non simple rctSig"); + CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG, false, "decodeRct called on non simple rctSig"); CHECK_AND_ASSERT_THROW_MES(i < rv.ecdhInfo.size(), "Bad index"); CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.ecdhInfo.size(), "Mismatched sizes of rv.outPk and rv.ecdhInfo"); //mask amount and mask ecdhTuple ecdh_info = rv.ecdhInfo[i]; - hwdev.ecdhDecode(ecdh_info, sk, rv.type == RCTTypeBulletproof2); + hwdev.ecdhDecode(ecdh_info, sk, rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG); mask = ecdh_info.mask; key amount = ecdh_info.amount; key C = rv.outPk[i].mask; @@ -1453,12 +1569,13 @@ namespace rct { return decodeRctSimple(rv, sk, i, mask, hwdev); } - bool signMultisig(rctSig &rv, const std::vector &indices, const keyV &k, const multisig_out &msout, const key &secret_key) { + bool signMultisigMLSAG(rctSig &rv, const std::vector &indices, const keyV &k, const multisig_out &msout, const key &secret_key) { CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull || rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2, false, "unsupported rct type"); CHECK_AND_ASSERT_MES(indices.size() == k.size(), false, "Mismatched k/indices sizes"); CHECK_AND_ASSERT_MES(k.size() == rv.p.MGs.size(), false, "Mismatched k/MGs size"); CHECK_AND_ASSERT_MES(k.size() == msout.c.size(), false, "Mismatched k/msout.c size"); + CHECK_AND_ASSERT_MES(rv.p.CLSAGs.empty(), false, "CLSAGs not empty for MLSAGs"); if (rv.type == RCTTypeFull) { CHECK_AND_ASSERT_MES(rv.p.MGs.size() == 1, false, "MGs not a single element"); @@ -1468,6 +1585,8 @@ namespace rct { CHECK_AND_ASSERT_MES(!rv.p.MGs[n].ss[indices[n]].empty(), false, "empty ss line"); } + // MLSAG: each player contributes a share to the secret-index ss: k - cc*secret_key_share + // cc: msout.c[n], secret_key_share: secret_key for (size_t n = 0; n < indices.size(); ++n) { rct::key diff; sc_mulsub(diff.bytes, msout.c[n].bytes, secret_key.bytes, k[n].bytes); @@ -1475,4 +1594,33 @@ namespace rct { } return true; } + + bool signMultisigCLSAG(rctSig &rv, const std::vector &indices, const keyV &k, const multisig_out &msout, const key &secret_key) { + CHECK_AND_ASSERT_MES(rv.type == RCTTypeCLSAG, false, "unsupported rct type"); + CHECK_AND_ASSERT_MES(indices.size() == k.size(), false, "Mismatched k/indices sizes"); + CHECK_AND_ASSERT_MES(k.size() == rv.p.CLSAGs.size(), false, "Mismatched k/MGs size"); + CHECK_AND_ASSERT_MES(k.size() == msout.c.size(), false, "Mismatched k/msout.c size"); + CHECK_AND_ASSERT_MES(rv.p.MGs.empty(), false, "MGs not empty for CLSAGs"); + CHECK_AND_ASSERT_MES(msout.c.size() == msout.mu_p.size(), false, "Bad mu_p size"); + for (size_t n = 0; n < indices.size(); ++n) { + CHECK_AND_ASSERT_MES(indices[n] < rv.p.CLSAGs[n].s.size(), false, "Index out of range"); + } + + // CLSAG: each player contributes a share to the secret-index ss: k - cc*mu_p*secret_key_share + // cc: msout.c[n], mu_p, msout.mu_p[n], secret_key_share: secret_key + for (size_t n = 0; n < indices.size(); ++n) { + rct::key diff, sk; + sc_mul(sk.bytes, msout.mu_p[n].bytes, secret_key.bytes); + sc_mulsub(diff.bytes, msout.c[n].bytes, sk.bytes, k[n].bytes); + sc_add(rv.p.CLSAGs[n].s[indices[n]].bytes, rv.p.CLSAGs[n].s[indices[n]].bytes, diff.bytes); + } + return true; + } + + bool signMultisig(rctSig &rv, const std::vector &indices, const keyV &k, const multisig_out &msout, const key &secret_key) { + if (rv.type == RCTTypeCLSAG) + return signMultisigCLSAG(rv, indices, k, msout, secret_key); + else + return signMultisigMLSAG(rv, indices, k, msout, secret_key); + } } -- cgit v1.2.3 From 641b08c920f9c68d957e13147cf9c3e329cf83f1 Mon Sep 17 00:00:00 2001 From: Sarang Noether <32460187+SarangNoether@users.noreply.github.com> Date: Tue, 10 Mar 2020 18:46:37 -0400 Subject: CLSAG optimizations --- src/ringct/rctSigs.cpp | 264 +++++++++++++++++++++++++------------------------ 1 file changed, 135 insertions(+), 129 deletions(-) (limited to 'src/ringct/rctSigs.cpp') diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index 074812156..2e56dad58 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -168,12 +168,17 @@ namespace rct { // 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, key *mscout, key *mspout) { + // + // The keys are set as follows: + // P[l] == p*G + // C[l] == z*G + // C[i] == C_nonzero[i] - C_offset (for hashing purposes) for all i + clsag CLSAG_Gen(const key &message, const keyV & P, const key & p, const keyV & C, const key & z, const keyV & C_nonzero, const key & C_offset, const unsigned int l, const multisig_kLRki *kLRki, key *mscout, key *mspout) { 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(n == C_nonzero.size(), "Signing and commitment key vector sizes must match!"); CHECK_AND_ASSERT_THROW_MES(l < n, "Signing index out of range!"); - CHECK_AND_ASSERT_THROW_MES(scalarmultBase(z) == C[l], "C does not match z!"); CHECK_AND_ASSERT_THROW_MES((kLRki && mscout) || (!kLRki && !mscout), "Only one of kLRki/mscout is present"); CHECK_AND_ASSERT_THROW_MES((mscout && mspout) || !kLRki, "Multisig pointers are not all present"); @@ -212,8 +217,8 @@ namespace rct { 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 + keyV mu_P_to_hash(2*n+4); // domain, I, D, P, C, C_offset + keyV mu_C_to_hash(2*n+4); // domain, I, D, P, C, C_offset 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); @@ -223,40 +228,43 @@ namespace rct { 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[i] = C_nonzero[i-n-1]; + mu_C_to_hash[i] = C_nonzero[i-n-1]; } mu_P_to_hash[2*n+1] = sig.I; mu_P_to_hash[2*n+2] = sig.D; + mu_P_to_hash[2*n+3] = C_offset; mu_C_to_hash[2*n+1] = sig.I; mu_C_to_hash[2*n+2] = sig.D; + mu_C_to_hash[2*n+3] = C_offset; 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 + keyV c_to_hash(2*n+5); // domain, P, C, C_offset, 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[i+n] = C_nonzero[i-1]; } - c_to_hash[2*n+1] = message; + c_to_hash[2*n+1] = C_offset; + c_to_hash[2*n+2] = 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; + c_to_hash[2*n+3] = kLRki->L; + c_to_hash[2*n+4] = kLRki->R; } else { - c_to_hash[2*n+2] = aG; - c_to_hash[2*n+3] = aH; + c_to_hash[2*n+3] = aG; + c_to_hash[2*n+4] = aH; } c = hash_to_scalar(c_to_hash); @@ -295,8 +303,8 @@ namespace rct { 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_to_hash[2*n+3] = L; + c_to_hash[2*n+4] = R; c_new = hash_to_scalar(c_to_hash); copy(c,c_new); @@ -320,99 +328,8 @@ namespace rct { return sig; } - clsag CLSAG_Gen(const key &message, const keyV & P, const key & p, const keyV & C, const key & z, const unsigned int l) { - return CLSAG_Gen(message, P, p, C, z, l, NULL, NULL, NULL); - } - - // 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; + clsag CLSAG_Gen(const key &message, const keyV & P, const key & p, const keyV & C, const key & z, const keyV & C_nonzero, const key & C_offset, const unsigned int l) { + return CLSAG_Gen(message, P, p, C, z, C_nonzero, C_offset, l, NULL, NULL, NULL); } // MLSAG signatures @@ -816,12 +733,14 @@ namespace rct { size_t i; keyM M(cols, tmp); - keyV P, C; + keyV P, C, C_nonzero; P.reserve(pubs.size()); C.reserve(pubs.size()); + C_nonzero.reserve(pubs.size()); for (const ctkey &k: pubs) { P.push_back(k.dest); + C_nonzero.push_back(k.mask); rct::key tmp; subKeys(tmp, k.mask, Cout); C.push_back(tmp); @@ -829,7 +748,7 @@ namespace rct { sk[0] = copy(inSk.dest); sc_sub(sk[1].bytes, inSk.mask.bytes, a.bytes); - clsag result = CLSAG_Gen(message, P, sk[0], C, sk[1], index, kLRki, mscout, mspout); + clsag result = CLSAG_Gen(message, P, sk[0], C, sk[1], C_nonzero, Cout, index, kLRki, mscout, mspout); memwipe(sk.data(), sk.size() * sizeof(key)); return result; } @@ -913,29 +832,116 @@ namespace rct { catch (...) { return false; } } - bool verRctCLSAGSimple(const key &message, const clsag &clsag, const ctkeyV & pubs, const key & C) { + bool verRctCLSAGSimple(const key &message, const clsag &sig, const ctkeyV & pubs, const key & C_offset) { try { PERF_TIMER(verRctCLSAGSimple); - //setup vars - const size_t cols = pubs.size(); - CHECK_AND_ASSERT_MES(cols >= 1, false, "Empty pubs"); - keyV Pi(cols), Ci(cols); - ge_p3 Cp3; - CHECK_AND_ASSERT_MES_L1(ge_frombytes_vartime(&Cp3, C.bytes) == 0, false, "point conv failed"); - ge_cached Ccached; - ge_p3_to_cached(&Ccached, &Cp3); - ge_p1p1 p1; - //create the matrix to mg sig - for (size_t i = 0; i < cols; i++) { - Pi[i] = pubs[i].dest; - ge_p3 p3; - CHECK_AND_ASSERT_MES_L1(ge_frombytes_vartime(&p3, pubs[i].mask.bytes) == 0, false, "point conv failed"); - ge_sub(&p1, &p3, &Ccached); - ge_p1p1_to_p3(&p3, &p1); - ge_p3_tobytes(Ci[i].bytes, &p3); + const size_t n = pubs.size(); + + // Check data + CHECK_AND_ASSERT_MES(n >= 1, false, "Empty pubs"); + 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!"); + CHECK_AND_ASSERT_MES(!(sig.I == rct::identity()), false, "Bad key image!"); + + // Cache commitment offset for efficient subtraction later + ge_p3 C_offset_p3; + CHECK_AND_ASSERT_MES(ge_frombytes_vartime(&C_offset_p3, C_offset.bytes) == 0, false, "point conv failed"); + ge_cached C_offset_cached; + ge_p3_to_cached(&C_offset_cached, &C_offset_p3); + + // Prepare key images + key c = copy(sig.c1); + key D_8 = scalarmult8(sig.D); + CHECK_AND_ASSERT_MES(!(D_8 == rct::identity()), false, "Bad auxiliary key image!"); + 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+4); // domain, I, D, P, C, C_offset + keyV mu_C_to_hash(2*n+4); // domain, I, D, P, C, C_offset + 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] = pubs[i-1].dest; + mu_C_to_hash[i] = pubs[i-1].dest; + } + for (size_t i = n+1; i < 2*n+1; ++i) { + mu_P_to_hash[i] = pubs[i-n-1].mask; + mu_C_to_hash[i] = pubs[i-n-1].mask; + } + mu_P_to_hash[2*n+1] = sig.I; + mu_P_to_hash[2*n+2] = sig.D; + mu_P_to_hash[2*n+3] = C_offset; + mu_C_to_hash[2*n+1] = sig.I; + mu_C_to_hash[2*n+2] = sig.D; + mu_C_to_hash[2*n+3] = C_offset; + key mu_P, mu_C; + mu_P = hash_to_scalar(mu_P_to_hash); + mu_C = hash_to_scalar(mu_C_to_hash); + + // Set up round hash + keyV c_to_hash(2*n+5); // domain, P, C, C_offset, 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] = pubs[i-1].dest; + c_to_hash[i+n] = pubs[i-1].mask; + } + c_to_hash[2*n+1] = C_offset; + c_to_hash[2*n+2] = 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; + ge_p3 temp_p3; + ge_p1p1 temp_p1; + + 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 for L/R + precomp(P_precomp.k,pubs[i].dest); + + CHECK_AND_ASSERT_MES(ge_frombytes_vartime(&temp_p3, pubs[i].mask.bytes) == 0, false, "point conv failed"); + ge_sub(&temp_p1,&temp_p3,&C_offset_cached); + ge_p1p1_to_p3(&temp_p3,&temp_p1); + ge_dsm_precomp(C_precomp.k,&temp_p3); + + // 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,pubs[i].dest); + 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+3] = L; + c_to_hash[2*n+4] = 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; } - return CLSAG_Ver(message, Pi, Ci, clsag); + sc_sub(c_new.bytes,c.bytes,sig.c1.bytes); + return sc_isnonzero(c_new.bytes) == 0; } catch (...) { return false; } } -- cgit v1.2.3 From 703944c4d4faf6ad86a69ec3808a87b20ce76a32 Mon Sep 17 00:00:00 2001 From: Sarang Noether <32460187+SarangNoether@users.noreply.github.com> Date: Fri, 27 Mar 2020 15:29:32 -0400 Subject: CLSAG device support --- src/ringct/rctSigs.cpp | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) (limited to 'src/ringct/rctSigs.cpp') diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index 2e56dad58..2a7b36b66 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -173,7 +173,7 @@ namespace rct { // P[l] == p*G // C[l] == z*G // C[i] == C_nonzero[i] - C_offset (for hashing purposes) for all i - clsag CLSAG_Gen(const key &message, const keyV & P, const key & p, const keyV & C, const key & z, const keyV & C_nonzero, const key & C_offset, const unsigned int l, const multisig_kLRki *kLRki, key *mscout, key *mspout) { + clsag CLSAG_Gen(const key &message, const keyV & P, const key & p, const keyV & C, const key & z, const keyV & C_nonzero, const key & C_offset, const unsigned int l, const multisig_kLRki *kLRki, key *mscout, key *mspout, hw::device &hwdev) { 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!"); @@ -189,16 +189,21 @@ namespace rct { ge_p3_tobytes(H.bytes,&H_p3); key D; - scalarmultKey(D,H,z); + + // Initial values + key a; + key aG; + key aH; // Multisig if (kLRki) { sig.I = kLRki->ki; + scalarmultKey(D,H,z); } else { - scalarmultKey(sig.I,H,p); + hwdev.clsag_prepare(p,z,sig.I,D,H,a,aG,aH); } geDsmp I_precomp; @@ -209,13 +214,6 @@ namespace rct { // 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+4); // domain, I, D, P, C, C_offset keyV mu_C_to_hash(2*n+4); // domain, I, D, P, C, C_offset @@ -266,7 +264,7 @@ namespace rct { c_to_hash[2*n+3] = aG; c_to_hash[2*n+4] = aH; } - c = hash_to_scalar(c_to_hash); + hwdev.clsag_hash(c_to_hash,c); size_t i; i = (l + 1) % n; @@ -305,7 +303,7 @@ namespace rct { c_to_hash[2*n+3] = L; c_to_hash[2*n+4] = R; - c_new = hash_to_scalar(c_to_hash); + hwdev.clsag_hash(c_to_hash,c_new); copy(c,c_new); i = (i + 1) % n; @@ -314,11 +312,8 @@ namespace rct { } // 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); + hwdev.clsag_sign(c,a,p,z,mu_P,mu_C,sig.s[l]); + memwipe(&a, sizeof(key)); if (mscout) *mscout = c; @@ -329,7 +324,7 @@ namespace rct { } clsag CLSAG_Gen(const key &message, const keyV & P, const key & p, const keyV & C, const key & z, const keyV & C_nonzero, const key & C_offset, const unsigned int l) { - return CLSAG_Gen(message, P, p, C, z, C_nonzero, C_offset, l, NULL, NULL, NULL); + return CLSAG_Gen(message, P, p, C, z, C_nonzero, C_offset, l, NULL, NULL, NULL, hw::get_device("default")); } // MLSAG signatures @@ -748,7 +743,7 @@ namespace rct { sk[0] = copy(inSk.dest); sc_sub(sk[1].bytes, inSk.mask.bytes, a.bytes); - clsag result = CLSAG_Gen(message, P, sk[0], C, sk[1], C_nonzero, Cout, index, kLRki, mscout, mspout); + clsag result = CLSAG_Gen(message, P, sk[0], C, sk[1], C_nonzero, Cout, index, kLRki, mscout, mspout, hwdev); memwipe(sk.data(), sk.size() * sizeof(key)); return result; } -- cgit v1.2.3