mirror of
				https://git.wownero.com/wownero/wownero.git
				synced 2024-08-15 01:03:23 +00:00 
			
		
		
		
	CLSAG optimizations
This commit is contained in:
		
							parent
							
								
									82ee01699c
								
							
						
					
					
						commit
						641b08c920
					
				
					 4 changed files with 221 additions and 218 deletions
				
			
		| 
						 | 
				
			
			@ -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;
 | 
			
		||||
            }
 | 
			
		||||
            return CLSAG_Ver(message, Pi, Ci, clsag);
 | 
			
		||||
            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;
 | 
			
		||||
            }
 | 
			
		||||
            sc_sub(c_new.bytes,c.bytes,sig.c1.bytes);
 | 
			
		||||
            return sc_isnonzero(c_new.bytes) == 0;
 | 
			
		||||
        }
 | 
			
		||||
        catch (...) { return false; }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -77,9 +77,10 @@ namespace rct {
 | 
			
		|||
    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, key *mscout, key *mspout);
 | 
			
		||||
    clsag CLSAG_Gen(const key &message, const keyV & P, const key & p, const keyV & C, const key & z, const unsigned int l);
 | 
			
		||||
    bool CLSAG_Ver(const key &message, const keyV & P, const keyV & C, const clsag & sig);
 | 
			
		||||
    clsag CLSAG_Gen(const key &message, const keyV & P, const key & p, const keyV & C, const keyV & C_nonzero, const key & C_offset, const key & z, 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 keyV & C_nonzero, const key & C_offset, const key & z, const unsigned int l);
 | 
			
		||||
    clsag proveRctCLSAGSimple(const key &, const ctkeyV &, const ctkey &, const key &, const key &, const multisig_kLRki *, key *, key *, unsigned int, hw::device &);
 | 
			
		||||
    bool verRctCLSAGSimple(const key &, const clsag &, const ctkeyV &, const key &);
 | 
			
		||||
 | 
			
		||||
    //proveRange and verRange
 | 
			
		||||
    //proveRange gives C, and mask such that \sumCi = C
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -61,7 +61,6 @@
 | 
			
		|||
#include "crypto_ops.h"
 | 
			
		||||
#include "multiexp.h"
 | 
			
		||||
#include "sig_mlsag.h"
 | 
			
		||||
#include "sig_clsag.h"
 | 
			
		||||
 | 
			
		||||
namespace po = boost::program_options;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -216,7 +215,6 @@ int main(int argc, char** argv)
 | 
			
		|||
  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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -140,165 +140,163 @@ TEST(ringct, MG_sigs)
 | 
			
		|||
 | 
			
		||||
TEST(ringct, CLSAG)
 | 
			
		||||
{
 | 
			
		||||
  const size_t ring_size = 11;
 | 
			
		||||
  const size_t N = 11;
 | 
			
		||||
  const size_t idx = 5;
 | 
			
		||||
  keyV P, C;
 | 
			
		||||
  key p, z;
 | 
			
		||||
  ctkeyV pubs;
 | 
			
		||||
  key p, t, t2, u;
 | 
			
		||||
  const key message = identity();
 | 
			
		||||
  key backup;
 | 
			
		||||
  ctkey backup;
 | 
			
		||||
  clsag clsag;
 | 
			
		||||
 | 
			
		||||
  for (size_t i = 0; i < ring_size; ++i)
 | 
			
		||||
  for (size_t i = 0; i < N; ++i)
 | 
			
		||||
  {
 | 
			
		||||
    key Sk, Pk;
 | 
			
		||||
    skpkGen(Sk, Pk);
 | 
			
		||||
    P.push_back(Pk);
 | 
			
		||||
    skpkGen(Sk, Pk);
 | 
			
		||||
    C.push_back(Pk);
 | 
			
		||||
  }
 | 
			
		||||
  skpkGen(p, P[idx]);
 | 
			
		||||
  skpkGen(z, C[idx]);
 | 
			
		||||
    key sk;
 | 
			
		||||
    ctkey tmp;
 | 
			
		||||
 | 
			
		||||
  // bad p at creation
 | 
			
		||||
  clsag = CLSAG_Gen(zero(), P, p, C, z, idx); //, hw::get_device("default"));
 | 
			
		||||
  ASSERT_FALSE(CLSAG_Ver(message, P, C, clsag));
 | 
			
		||||
    skpkGen(sk, tmp.dest);
 | 
			
		||||
    skpkGen(sk, tmp.mask);
 | 
			
		||||
 | 
			
		||||
    pubs.push_back(tmp);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Set P[idx]
 | 
			
		||||
  skpkGen(p, pubs[idx].dest);
 | 
			
		||||
 | 
			
		||||
  // Set C[idx]
 | 
			
		||||
  t = skGen();
 | 
			
		||||
  u = skGen();
 | 
			
		||||
  addKeys2(pubs[idx].mask,t,u,H);
 | 
			
		||||
 | 
			
		||||
  // Set commitment offset
 | 
			
		||||
  key Cout;
 | 
			
		||||
  t2 = skGen();
 | 
			
		||||
  addKeys2(Cout,t2,u,H);
 | 
			
		||||
 | 
			
		||||
  // Prepare generation inputs
 | 
			
		||||
  ctkey insk;
 | 
			
		||||
  insk.dest = p;
 | 
			
		||||
  insk.mask = t;
 | 
			
		||||
  
 | 
			
		||||
  // bad message
 | 
			
		||||
  clsag = rct::proveRctCLSAGSimple(zero(),pubs,insk,t2,Cout,NULL,NULL,NULL,idx,hw::get_device("default"));
 | 
			
		||||
  ASSERT_FALSE(rct::verRctCLSAGSimple(message,clsag,pubs,Cout));
 | 
			
		||||
 | 
			
		||||
  // bad index at creation
 | 
			
		||||
  try
 | 
			
		||||
  {
 | 
			
		||||
    clsag = CLSAG_Gen(message, P, p, C, z, (idx + 1) % ring_size); //, hw::get_device("default"));
 | 
			
		||||
    ASSERT_FALSE(CLSAG_Ver(message, P, C, clsag));
 | 
			
		||||
    clsag = rct::proveRctCLSAGSimple(message,pubs,insk,t2,Cout,NULL,NULL,NULL,(idx + 1) % N,hw::get_device("default"));
 | 
			
		||||
    ASSERT_FALSE(rct::verRctCLSAGSimple(message,clsag,pubs,Cout));
 | 
			
		||||
  }
 | 
			
		||||
  catch (...) { /* either exception, or failure to verify above */ }
 | 
			
		||||
 | 
			
		||||
  // bad z at creation
 | 
			
		||||
  try
 | 
			
		||||
  {
 | 
			
		||||
    clsag = CLSAG_Gen(message, P, p, C, skGen(), idx); //, hw::get_device("default"));
 | 
			
		||||
    ASSERT_FALSE(CLSAG_Ver(message, P, C, clsag));
 | 
			
		||||
    ctkey insk2;
 | 
			
		||||
    insk2.dest = insk.dest;
 | 
			
		||||
    insk2.mask = skGen();
 | 
			
		||||
    clsag = rct::proveRctCLSAGSimple(message,pubs,insk2,t2,Cout,NULL,NULL,NULL,idx,hw::get_device("default"));
 | 
			
		||||
    ASSERT_FALSE(rct::verRctCLSAGSimple(message,clsag,pubs,Cout));
 | 
			
		||||
  }
 | 
			
		||||
  catch (...) { /* either exception, or failure to verify above */ }
 | 
			
		||||
 | 
			
		||||
  // bad C at creation
 | 
			
		||||
  backup = C[idx];
 | 
			
		||||
  C[idx] = scalarmultBase(skGen());
 | 
			
		||||
  backup = pubs[idx];
 | 
			
		||||
  pubs[idx].mask = scalarmultBase(skGen());
 | 
			
		||||
  try
 | 
			
		||||
  {
 | 
			
		||||
    clsag = CLSAG_Gen(message, P, p, C, z, idx); //, hw::get_device("default"));
 | 
			
		||||
    ASSERT_FALSE(CLSAG_Ver(message, P, C, clsag));
 | 
			
		||||
    clsag = rct::proveRctCLSAGSimple(message,pubs,insk,t2,Cout,NULL,NULL,NULL,idx,hw::get_device("default"));
 | 
			
		||||
    ASSERT_FALSE(rct::verRctCLSAGSimple(message,clsag,pubs,Cout));
 | 
			
		||||
  }
 | 
			
		||||
  catch (...) { /* either exception, or failure to verify above */ }
 | 
			
		||||
  C[idx] = backup;
 | 
			
		||||
  pubs[idx] = backup;
 | 
			
		||||
 | 
			
		||||
  // bad p at creation
 | 
			
		||||
  try
 | 
			
		||||
  {
 | 
			
		||||
    clsag = CLSAG_Gen(message, P, skGen(), C, z, idx); //, hw::get_device("default"));
 | 
			
		||||
    ASSERT_FALSE(CLSAG_Ver(message, P, C, clsag));
 | 
			
		||||
    ctkey insk2;
 | 
			
		||||
    insk2.dest = skGen();
 | 
			
		||||
    insk2.mask = insk.mask;
 | 
			
		||||
    clsag = rct::proveRctCLSAGSimple(message,pubs,insk2,t2,Cout,NULL,NULL,NULL,idx,hw::get_device("default"));
 | 
			
		||||
    ASSERT_FALSE(rct::verRctCLSAGSimple(message,clsag,pubs,Cout));
 | 
			
		||||
  }
 | 
			
		||||
  catch (...) { /* either exception, or failure to verify above */ }
 | 
			
		||||
 | 
			
		||||
  // bad P at creation
 | 
			
		||||
  backup = P[idx];
 | 
			
		||||
  P[idx] = scalarmultBase(skGen());
 | 
			
		||||
  backup = pubs[idx];
 | 
			
		||||
  pubs[idx].dest = scalarmultBase(skGen());
 | 
			
		||||
  try
 | 
			
		||||
  {
 | 
			
		||||
    clsag = CLSAG_Gen(message, P, p, C, z, idx); //, hw::get_device("default"));
 | 
			
		||||
    ASSERT_FALSE(CLSAG_Ver(message, P, C, clsag));
 | 
			
		||||
    clsag = rct::proveRctCLSAGSimple(message,pubs,insk,t2,Cout,NULL,NULL,NULL,idx,hw::get_device("default"));
 | 
			
		||||
    ASSERT_FALSE(rct::verRctCLSAGSimple(message,clsag,pubs,Cout));
 | 
			
		||||
  }
 | 
			
		||||
  catch (...) { /* either exception, or failure to verify above */ }
 | 
			
		||||
  P[idx] = backup;
 | 
			
		||||
  pubs[idx] = backup;
 | 
			
		||||
 | 
			
		||||
  // good
 | 
			
		||||
  clsag = CLSAG_Gen(message, P, p, C, z, idx); //, hw::get_device("default"));
 | 
			
		||||
  ASSERT_TRUE(CLSAG_Ver(message, P, C, clsag));
 | 
			
		||||
 | 
			
		||||
  // bad message at verification
 | 
			
		||||
  ASSERT_FALSE(CLSAG_Ver(zero(), P, C, clsag));
 | 
			
		||||
 | 
			
		||||
  // bad real P at verification
 | 
			
		||||
  backup = P[idx];
 | 
			
		||||
  P[idx] = scalarmultBase(skGen());
 | 
			
		||||
  ASSERT_FALSE(CLSAG_Ver(zero(), P, C, clsag));
 | 
			
		||||
  P[idx] = backup;
 | 
			
		||||
 | 
			
		||||
  // bad fake P at verification
 | 
			
		||||
  backup = P[(idx + 1) % ring_size];
 | 
			
		||||
  P[(idx + 1) % ring_size] = scalarmultBase(skGen());
 | 
			
		||||
  ASSERT_FALSE(CLSAG_Ver(zero(), P, C, clsag));
 | 
			
		||||
  P[(idx + 1) % ring_size] = backup;
 | 
			
		||||
 | 
			
		||||
  // bad real C at verification
 | 
			
		||||
  backup = C[idx];
 | 
			
		||||
  C[idx] = scalarmultBase(skGen());
 | 
			
		||||
  ASSERT_FALSE(CLSAG_Ver(zero(), P, C, clsag));
 | 
			
		||||
  C[idx] = backup;
 | 
			
		||||
 | 
			
		||||
  // bad fake C at verification
 | 
			
		||||
  backup = C[(idx + 1) % ring_size];
 | 
			
		||||
  C[(idx + 1) % ring_size] = scalarmultBase(skGen());
 | 
			
		||||
  ASSERT_FALSE(CLSAG_Ver(zero(), P, C, clsag));
 | 
			
		||||
  C[(idx + 1) % ring_size] = backup;
 | 
			
		||||
  // Test correct signature
 | 
			
		||||
  clsag = rct::proveRctCLSAGSimple(message,pubs,insk,t2,Cout,NULL,NULL,NULL,idx,hw::get_device("default"));
 | 
			
		||||
  ASSERT_TRUE(rct::verRctCLSAGSimple(message,clsag,pubs,Cout));
 | 
			
		||||
 | 
			
		||||
  // empty s
 | 
			
		||||
  auto sbackup = clsag.s;
 | 
			
		||||
  clsag.s.clear();
 | 
			
		||||
  ASSERT_FALSE(CLSAG_Ver(identity(), P, C, clsag));
 | 
			
		||||
  ASSERT_FALSE(rct::verRctCLSAGSimple(message,clsag,pubs,Cout));
 | 
			
		||||
  clsag.s = sbackup;
 | 
			
		||||
 | 
			
		||||
  // too few s elements
 | 
			
		||||
  backup = clsag.s.back();
 | 
			
		||||
  key backup_key;
 | 
			
		||||
  backup_key = clsag.s.back();
 | 
			
		||||
  clsag.s.pop_back();
 | 
			
		||||
  ASSERT_FALSE(CLSAG_Ver(identity(), P, C, clsag));
 | 
			
		||||
  clsag.s.push_back(backup);
 | 
			
		||||
  ASSERT_FALSE(rct::verRctCLSAGSimple(message,clsag,pubs,Cout));
 | 
			
		||||
  clsag.s.push_back(backup_key);
 | 
			
		||||
 | 
			
		||||
  // too many s elements
 | 
			
		||||
  clsag.s.push_back(skGen());
 | 
			
		||||
  ASSERT_FALSE(CLSAG_Ver(identity(), P, C, clsag));
 | 
			
		||||
  ASSERT_FALSE(rct::verRctCLSAGSimple(message,clsag,pubs,Cout));
 | 
			
		||||
  clsag.s.pop_back();
 | 
			
		||||
 | 
			
		||||
  // bad s in clsag at verification
 | 
			
		||||
  for (auto &s: clsag.s)
 | 
			
		||||
  {
 | 
			
		||||
    backup = s;
 | 
			
		||||
    backup_key = s;
 | 
			
		||||
    s = skGen();
 | 
			
		||||
    ASSERT_FALSE(CLSAG_Ver(identity(), P, C, clsag));
 | 
			
		||||
    s = backup;
 | 
			
		||||
    ASSERT_FALSE(rct::verRctCLSAGSimple(message,clsag,pubs,Cout));
 | 
			
		||||
    s = backup_key;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // bad c1 in clsag at verification
 | 
			
		||||
  backup = clsag.c1;
 | 
			
		||||
  backup_key = clsag.c1;
 | 
			
		||||
  clsag.c1 = skGen();
 | 
			
		||||
  ASSERT_FALSE(CLSAG_Ver(identity(), P, C, clsag));
 | 
			
		||||
  clsag.c1 = backup;
 | 
			
		||||
  ASSERT_FALSE(rct::verRctCLSAGSimple(message,clsag,pubs,Cout));
 | 
			
		||||
  clsag.c1 = backup_key;
 | 
			
		||||
 | 
			
		||||
  // bad I in clsag at verification
 | 
			
		||||
  backup = clsag.I;
 | 
			
		||||
  backup_key = clsag.I;
 | 
			
		||||
  clsag.I = scalarmultBase(skGen());
 | 
			
		||||
  ASSERT_FALSE(CLSAG_Ver(identity(), P, C, clsag));
 | 
			
		||||
  clsag.I = backup;
 | 
			
		||||
  ASSERT_FALSE(rct::verRctCLSAGSimple(message,clsag,pubs,Cout));
 | 
			
		||||
  clsag.I = backup_key;
 | 
			
		||||
 | 
			
		||||
  // bad D in clsag at verification
 | 
			
		||||
  backup = clsag.D;
 | 
			
		||||
  backup_key = clsag.D;
 | 
			
		||||
  clsag.D = scalarmultBase(skGen());
 | 
			
		||||
  ASSERT_FALSE(CLSAG_Ver(identity(), P, C, clsag));
 | 
			
		||||
  clsag.D = backup;
 | 
			
		||||
  ASSERT_FALSE(rct::verRctCLSAGSimple(message,clsag,pubs,Cout));
 | 
			
		||||
  clsag.D = backup_key;
 | 
			
		||||
 | 
			
		||||
  // D not in main subgroup in clsag at verification
 | 
			
		||||
  backup = clsag.D;
 | 
			
		||||
  backup_key = clsag.D;
 | 
			
		||||
  rct::key x;
 | 
			
		||||
  ASSERT_TRUE(epee::string_tools::hex_to_pod("c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", x));
 | 
			
		||||
  clsag.D = rct::addKeys(clsag.D, x);
 | 
			
		||||
  ASSERT_FALSE(CLSAG_Ver(identity(), P, C, clsag));
 | 
			
		||||
  clsag.D = backup;
 | 
			
		||||
  ASSERT_FALSE(rct::verRctCLSAGSimple(message,clsag,pubs,Cout));
 | 
			
		||||
  clsag.D = backup_key;
 | 
			
		||||
 | 
			
		||||
  // swapped I and D in clsag at verification
 | 
			
		||||
  std::swap(clsag.I, clsag.D);
 | 
			
		||||
  ASSERT_FALSE(CLSAG_Ver(identity(), P, C, clsag));
 | 
			
		||||
  ASSERT_FALSE(rct::verRctCLSAGSimple(message,clsag,pubs,Cout));
 | 
			
		||||
  std::swap(clsag.I, clsag.D);
 | 
			
		||||
 | 
			
		||||
  // check it's still good, in case we failed to restore
 | 
			
		||||
  ASSERT_TRUE(CLSAG_Ver(message, P, C, clsag));
 | 
			
		||||
  ASSERT_TRUE(rct::verRctCLSAGSimple(message,clsag,pubs,Cout));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(ringct, range_proofs)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue