mirror of
				https://git.wownero.com/wownero/wownero.git
				synced 2024-08-15 01:03:23 +00:00 
			
		
		
		
	MLSAG speedup and additional checks
This commit is contained in:
		
							parent
							
								
									6335509727
								
							
						
					
					
						commit
						3a0451a8be
					
				
					 7 changed files with 75 additions and 101 deletions
				
			
		| 
						 | 
				
			
			@ -101,7 +101,10 @@ static rct::key get_exponent(const rct::key &base, size_t idx)
 | 
			
		|||
{
 | 
			
		||||
  static const std::string salt("bulletproof");
 | 
			
		||||
  std::string hashed = std::string((const char*)base.bytes, sizeof(base)) + salt + tools::get_varint_data(idx);
 | 
			
		||||
  const rct::key e = rct::hashToPoint(rct::hash2rct(crypto::cn_fast_hash(hashed.data(), hashed.size())));
 | 
			
		||||
  rct::key e;
 | 
			
		||||
  ge_p3 e_p3;
 | 
			
		||||
  rct::hash_to_p3(e_p3, rct::hash2rct(crypto::cn_fast_hash(hashed.data(), hashed.size())));
 | 
			
		||||
  ge_p3_tobytes(e.bytes, &e_p3);
 | 
			
		||||
  CHECK_AND_ASSERT_THROW_MES(!(e == rct::identity()), "Exponent is point at infinity");
 | 
			
		||||
  return e;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -620,45 +620,17 @@ namespace rct {
 | 
			
		|||
       sc_reduce32(rv.bytes);
 | 
			
		||||
       return rv;
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
    key hashToPointSimple(const key & hh) {
 | 
			
		||||
        key pointk;
 | 
			
		||||
        ge_p1p1 point2;
 | 
			
		||||
        ge_p2 point;
 | 
			
		||||
        ge_p3 res;
 | 
			
		||||
        key h = cn_fast_hash(hh); 
 | 
			
		||||
        CHECK_AND_ASSERT_THROW_MES_L1(ge_frombytes_vartime(&res, h.bytes) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__));
 | 
			
		||||
        ge_p3_to_p2(&point, &res);
 | 
			
		||||
        ge_mul8(&point2, &point);
 | 
			
		||||
        ge_p1p1_to_p3(&res, &point2);
 | 
			
		||||
        ge_p3_tobytes(pointk.bytes, &res);
 | 
			
		||||
        return pointk;
 | 
			
		||||
    }    
 | 
			
		||||
    
 | 
			
		||||
    key hashToPoint(const key & hh) {
 | 
			
		||||
        key pointk;
 | 
			
		||||
        ge_p2 point;
 | 
			
		||||
        ge_p1p1 point2;
 | 
			
		||||
        ge_p3 res;
 | 
			
		||||
        key h = cn_fast_hash(hh); 
 | 
			
		||||
        ge_fromfe_frombytes_vartime(&point, h.bytes);
 | 
			
		||||
        ge_mul8(&point2, &point);
 | 
			
		||||
        ge_p1p1_to_p3(&res, &point2);        
 | 
			
		||||
        ge_p3_tobytes(pointk.bytes, &res);
 | 
			
		||||
        return pointk;
 | 
			
		||||
    // Hash a key to p3 representation
 | 
			
		||||
    void hash_to_p3(ge_p3 &hash8_p3, const key &k) {
 | 
			
		||||
      key hash_key = cn_fast_hash(k);
 | 
			
		||||
      ge_p2 hash_p2;
 | 
			
		||||
      ge_fromfe_frombytes_vartime(&hash_p2, hash_key.bytes);
 | 
			
		||||
      ge_p1p1 hash8_p1p1;
 | 
			
		||||
      ge_mul8(&hash8_p1p1, &hash_p2);
 | 
			
		||||
      ge_p1p1_to_p3(&hash8_p3, &hash8_p1p1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void hashToPoint(key & pointk, const key & hh) {
 | 
			
		||||
        ge_p2 point;
 | 
			
		||||
        ge_p1p1 point2;
 | 
			
		||||
        ge_p3 res;
 | 
			
		||||
        key h = cn_fast_hash(hh); 
 | 
			
		||||
        ge_fromfe_frombytes_vartime(&point, h.bytes);
 | 
			
		||||
        ge_mul8(&point2, &point);
 | 
			
		||||
        ge_p1p1_to_p3(&res, &point2);        
 | 
			
		||||
        ge_p3_tobytes(pointk.bytes, &res);
 | 
			
		||||
    }    
 | 
			
		||||
 | 
			
		||||
    //sums a vector of curve points (for scalars use sc_add)
 | 
			
		||||
    void sumKeys(key & Csum, const keyV &  Cis) {
 | 
			
		||||
        identity(Csum);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -172,10 +172,7 @@ namespace rct {
 | 
			
		|||
    key cn_fast_hash(const key64 keys);
 | 
			
		||||
    key hash_to_scalar(const key64 keys);
 | 
			
		||||
 | 
			
		||||
    //returns hashToPoint as described in https://github.com/ShenNoether/ge_fromfe_writeup 
 | 
			
		||||
    key hashToPointSimple(const key &in);
 | 
			
		||||
    key hashToPoint(const key &in);
 | 
			
		||||
    void hashToPoint(key &out, const key &in);
 | 
			
		||||
    void hash_to_p3(ge_p3 &hash8_p3, const key &k);
 | 
			
		||||
 | 
			
		||||
    //sums a vector of curve points (for scalars use sc_add)
 | 
			
		||||
    void sumKeys(key & Csum, const key &Cis);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -163,14 +163,11 @@ namespace rct {
 | 
			
		|||
      return verifyBorromean(bb, P1_p3, P2_p3);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Multilayered Spontaneous Anonymous Group Signatures (MLSAG signatures)
 | 
			
		||||
    //This is a just slghtly more efficient version than the ones described below
 | 
			
		||||
    //(will be explained in more detail in Ring Multisig paper
 | 
			
		||||
    //These are aka MG signatutes in earlier drafts of the ring ct paper
 | 
			
		||||
    // c.f. https://eprint.iacr.org/2015/1098 section 2. 
 | 
			
		||||
    // Gen creates a signature which proves that for some column in the keymatrix "pk"
 | 
			
		||||
    //   the signer knows a secret key for each row in that column
 | 
			
		||||
    // Ver verifies that the MG sig was created correctly        
 | 
			
		||||
    // MLSAG signatures
 | 
			
		||||
    // See paper by Noether (https://eprint.iacr.org/2015/1098)
 | 
			
		||||
    // This generalization allows for some dimensions not to require linkability;
 | 
			
		||||
    //   this is used in practice for commitment data within signatures
 | 
			
		||||
    // Note that using more than one linkable dimension is not recommended.
 | 
			
		||||
    mgSig MLSAG_Gen(const key &message, const keyM & pk, const keyV & xx, const multisig_kLRki *kLRki, key *mscout, const unsigned int index, size_t dsRows, hw::device &hwdev) {
 | 
			
		||||
        mgSig rv;
 | 
			
		||||
        size_t cols = pk.size();
 | 
			
		||||
| 
						 | 
				
			
			@ -188,6 +185,7 @@ namespace rct {
 | 
			
		|||
 | 
			
		||||
        size_t i = 0, j = 0, ii = 0;
 | 
			
		||||
        key c, c_old, L, R, Hi;
 | 
			
		||||
        ge_p3 Hi_p3;
 | 
			
		||||
        sc_0(c_old.bytes);
 | 
			
		||||
        vector<geDsmp> Ip(dsRows);
 | 
			
		||||
        rv.II = keyV(dsRows);
 | 
			
		||||
| 
						 | 
				
			
			@ -208,7 +206,8 @@ namespace rct {
 | 
			
		|||
              rv.II[i] = kLRki->ki;
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
              Hi = hashToPoint(pk[index][i]);
 | 
			
		||||
              hash_to_p3(Hi_p3, pk[index][i]);
 | 
			
		||||
              ge_p3_tobytes(Hi.bytes, &Hi_p3);
 | 
			
		||||
              hwdev.mlsag_prepare(Hi, xx[i], alpha[i] , aG[i] , aHP[i] , rv.II[i]);
 | 
			
		||||
              toHash[3 * i + 2] = aG[i];
 | 
			
		||||
              toHash[3 * i + 3] = aHP[i];
 | 
			
		||||
| 
						 | 
				
			
			@ -235,7 +234,8 @@ namespace rct {
 | 
			
		|||
            sc_0(c.bytes);
 | 
			
		||||
            for (j = 0; j < dsRows; j++) {
 | 
			
		||||
                addKeys2(L, rv.ss[i][j], c_old, pk[i][j]);
 | 
			
		||||
                hashToPoint(Hi, pk[i][j]);
 | 
			
		||||
                hash_to_p3(Hi_p3, pk[i][j]);
 | 
			
		||||
                ge_p3_tobytes(Hi.bytes, &Hi_p3);
 | 
			
		||||
                addKeys3(R, rv.ss[i][j], Hi, c_old, Ip[j].k);
 | 
			
		||||
                toHash[3 * j + 1] = pk[i][j];
 | 
			
		||||
                toHash[3 * j + 2] = L; 
 | 
			
		||||
| 
						 | 
				
			
			@ -260,43 +260,42 @@ namespace rct {
 | 
			
		|||
        return rv;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    //Multilayered Spontaneous Anonymous Group Signatures (MLSAG signatures)
 | 
			
		||||
    //This is a just slghtly more efficient version than the ones described below
 | 
			
		||||
    //(will be explained in more detail in Ring Multisig paper
 | 
			
		||||
    //These are aka MG signatutes in earlier drafts of the ring ct paper
 | 
			
		||||
    // c.f. https://eprint.iacr.org/2015/1098 section 2. 
 | 
			
		||||
    // Gen creates a signature which proves that for some column in the keymatrix "pk"
 | 
			
		||||
    //   the signer knows a secret key for each row in that column
 | 
			
		||||
    // Ver verifies that the MG sig was created correctly            
 | 
			
		||||
    // MLSAG signatures
 | 
			
		||||
    // See paper by Noether (https://eprint.iacr.org/2015/1098)
 | 
			
		||||
    // This generalization allows for some dimensions not to require linkability;
 | 
			
		||||
    //   this is used in practice for commitment data within signatures
 | 
			
		||||
    // Note that using more than one linkable dimension is not recommended.
 | 
			
		||||
    bool MLSAG_Ver(const key &message, const keyM & pk, const mgSig & rv, size_t dsRows) {
 | 
			
		||||
 | 
			
		||||
        size_t cols = pk.size();
 | 
			
		||||
        CHECK_AND_ASSERT_MES(cols >= 2, false, "Error! What is c if cols = 1!");
 | 
			
		||||
        CHECK_AND_ASSERT_MES(cols >= 2, false, "Signature must contain more than one public key");
 | 
			
		||||
        size_t rows = pk[0].size();
 | 
			
		||||
        CHECK_AND_ASSERT_MES(rows >= 1, false, "Empty pk");
 | 
			
		||||
        CHECK_AND_ASSERT_MES(rows >= 1, false, "Bad total row number");
 | 
			
		||||
        for (size_t i = 1; i < cols; ++i) {
 | 
			
		||||
          CHECK_AND_ASSERT_MES(pk[i].size() == rows, false, "pk is not rectangular");
 | 
			
		||||
          CHECK_AND_ASSERT_MES(pk[i].size() == rows, false, "Bad public key matrix dimensions");
 | 
			
		||||
        }
 | 
			
		||||
        CHECK_AND_ASSERT_MES(rv.II.size() == dsRows, false, "Bad II size");
 | 
			
		||||
        CHECK_AND_ASSERT_MES(rv.ss.size() == cols, false, "Bad rv.ss size");
 | 
			
		||||
        CHECK_AND_ASSERT_MES(rv.II.size() == dsRows, false, "Wrong number of key images present");
 | 
			
		||||
        CHECK_AND_ASSERT_MES(rv.ss.size() == cols, false, "Bad scalar matrix dimensions");
 | 
			
		||||
        for (size_t i = 0; i < cols; ++i) {
 | 
			
		||||
          CHECK_AND_ASSERT_MES(rv.ss[i].size() == rows, false, "rv.ss is not rectangular");
 | 
			
		||||
          CHECK_AND_ASSERT_MES(rv.ss[i].size() == rows, false, "Bad scalar matrix dimensions");
 | 
			
		||||
        }
 | 
			
		||||
        CHECK_AND_ASSERT_MES(dsRows <= rows, false, "Bad dsRows value");
 | 
			
		||||
        CHECK_AND_ASSERT_MES(dsRows <= rows, false, "Non-double-spend rows cannot exceed total rows");
 | 
			
		||||
 | 
			
		||||
        for (size_t i = 0; i < rv.ss.size(); ++i)
 | 
			
		||||
          for (size_t j = 0; j < rv.ss[i].size(); ++j)
 | 
			
		||||
            CHECK_AND_ASSERT_MES(sc_check(rv.ss[i][j].bytes) == 0, false, "Bad ss slot");
 | 
			
		||||
        CHECK_AND_ASSERT_MES(sc_check(rv.cc.bytes) == 0, false, "Bad cc");
 | 
			
		||||
        for (size_t i = 0; i < rv.ss.size(); ++i) {
 | 
			
		||||
          for (size_t j = 0; j < rv.ss[i].size(); ++j) {
 | 
			
		||||
            CHECK_AND_ASSERT_MES(sc_check(rv.ss[i][j].bytes) == 0, false, "Bad signature scalar");
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        CHECK_AND_ASSERT_MES(sc_check(rv.cc.bytes) == 0, false, "Bad initial signature hash");
 | 
			
		||||
 | 
			
		||||
        size_t i = 0, j = 0, ii = 0;
 | 
			
		||||
        key c,  L, R, Hi;
 | 
			
		||||
        key c,  L, R;
 | 
			
		||||
        key c_old = copy(rv.cc);
 | 
			
		||||
        vector<geDsmp> Ip(dsRows);
 | 
			
		||||
        for (i = 0 ; i < dsRows ; i++) {
 | 
			
		||||
            CHECK_AND_ASSERT_MES(!(rv.II[i] == rct::identity()), false, "Bad key image");
 | 
			
		||||
            precomp(Ip[i].k, rv.II[i]);
 | 
			
		||||
        }
 | 
			
		||||
        size_t ndsRows = 3 * dsRows; //non Double Spendable Rows (see identity chains paper
 | 
			
		||||
        size_t ndsRows = 3 * dsRows; // number of dimensions not requiring linkability
 | 
			
		||||
        keyV toHash(1 + 3 * dsRows + 2 * (rows - dsRows));
 | 
			
		||||
        toHash[0] = message;
 | 
			
		||||
        i = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -304,9 +303,14 @@ namespace rct {
 | 
			
		|||
            sc_0(c.bytes);
 | 
			
		||||
            for (j = 0; j < dsRows; j++) {
 | 
			
		||||
                addKeys2(L, rv.ss[i][j], c_old, pk[i][j]);
 | 
			
		||||
                hashToPoint(Hi, pk[i][j]);
 | 
			
		||||
                CHECK_AND_ASSERT_MES(!(Hi == rct::identity()), false, "Data hashed to point at infinity");
 | 
			
		||||
                addKeys3(R, rv.ss[i][j], Hi, c_old, Ip[j].k);
 | 
			
		||||
 | 
			
		||||
                // Compute R directly
 | 
			
		||||
                ge_p3 hash8_p3;
 | 
			
		||||
                hash_to_p3(hash8_p3, pk[i][j]);
 | 
			
		||||
                ge_p2 R_p2;
 | 
			
		||||
                ge_double_scalarmult_precomp_vartime(&R_p2, rv.ss[i][j].bytes, &hash8_p3, c_old.bytes, Ip[j].k);
 | 
			
		||||
                ge_tobytes(R.bytes, &R_p2);
 | 
			
		||||
 | 
			
		||||
                toHash[3 * j + 1] = pk[i][j];
 | 
			
		||||
                toHash[3 * j + 2] = L; 
 | 
			
		||||
                toHash[3 * j + 3] = R;
 | 
			
		||||
| 
						 | 
				
			
			@ -317,6 +321,7 @@ namespace rct {
 | 
			
		|||
                toHash[ndsRows + 2 * ii + 2] = L;
 | 
			
		||||
            }
 | 
			
		||||
            c = hash_to_scalar(toHash);
 | 
			
		||||
            CHECK_AND_ASSERT_MES(!(c == rct::zero()), false, "Bad signature hash");
 | 
			
		||||
            copy(c_old, c);
 | 
			
		||||
            i = (i + 1);
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -57,7 +57,6 @@
 | 
			
		|||
#include "rct_mlsag.h"
 | 
			
		||||
#include "equality.h"
 | 
			
		||||
#include "range_proof.h"
 | 
			
		||||
#include "rct_mlsag.h"
 | 
			
		||||
#include "bulletproof.h"
 | 
			
		||||
#include "crypto_ops.h"
 | 
			
		||||
#include "multiexp.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -214,14 +213,8 @@ 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_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 3, false);
 | 
			
		||||
  TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 5, false);
 | 
			
		||||
  TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 10, false);
 | 
			
		||||
  TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 100, false);
 | 
			
		||||
  TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 3, true);
 | 
			
		||||
  TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 5, true);
 | 
			
		||||
  TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 10, true);
 | 
			
		||||
  TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 100, true);
 | 
			
		||||
  TEST_PERFORMANCE2(filter, p, test_ringct_mlsag, 11, false);
 | 
			
		||||
  TEST_PERFORMANCE2(filter, p, test_ringct_mlsag, 11, true);
 | 
			
		||||
 | 
			
		||||
  TEST_PERFORMANCE2(filter, p, test_equality, memcmp32, true);
 | 
			
		||||
  TEST_PERFORMANCE2(filter, p, test_equality, memcmp32, false);
 | 
			
		||||
| 
						 | 
				
			
			@ -251,15 +244,6 @@ int main(int argc, char** argv)
 | 
			
		|||
  TEST_PERFORMANCE6(filter, p, test_aggregated_bulletproof, false, 2, 1, 1, 0, 64);
 | 
			
		||||
  TEST_PERFORMANCE6(filter, p, test_aggregated_bulletproof, true, 2, 1, 1, 0, 64); // 64 proof, each with 2 amounts
 | 
			
		||||
 | 
			
		||||
  TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 3, false);
 | 
			
		||||
  TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 5, false);
 | 
			
		||||
  TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 10, false);
 | 
			
		||||
  TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 100, false);
 | 
			
		||||
  TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 3, true);
 | 
			
		||||
  TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 5, true);
 | 
			
		||||
  TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 10, true);
 | 
			
		||||
  TEST_PERFORMANCE3(filter, p, test_ringct_mlsag, 1, 100, true);
 | 
			
		||||
 | 
			
		||||
  TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_sc_add);
 | 
			
		||||
  TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_sc_sub);
 | 
			
		||||
  TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_sc_mul);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -35,13 +35,13 @@
 | 
			
		|||
 | 
			
		||||
#include "single_tx_test_base.h"
 | 
			
		||||
 | 
			
		||||
template<size_t inputs, size_t ring_size, bool ver>
 | 
			
		||||
template<size_t ring_size, bool ver>
 | 
			
		||||
class test_ringct_mlsag : public single_tx_test_base
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
  static const size_t cols = ring_size;
 | 
			
		||||
  static const size_t rows = inputs;
 | 
			
		||||
  static const size_t loop_count = 100;
 | 
			
		||||
  static const size_t rows = 2; // single spend and commitment data
 | 
			
		||||
  static const size_t loop_count = 1000;
 | 
			
		||||
 | 
			
		||||
  bool init()
 | 
			
		||||
  {
 | 
			
		||||
| 
						 | 
				
			
			@ -65,7 +65,7 @@ public:
 | 
			
		|||
    {
 | 
			
		||||
        sk[j] = xm[ind][j];
 | 
			
		||||
    }
 | 
			
		||||
    IIccss = MLSAG_Gen(rct::identity(), P, sk, NULL, NULL, ind, rows, hw::get_device("default"));
 | 
			
		||||
    IIccss = MLSAG_Gen(rct::identity(), P, sk, NULL, NULL, ind, rows-1, hw::get_device("default"));
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -73,9 +73,9 @@ public:
 | 
			
		|||
  bool test()
 | 
			
		||||
  {
 | 
			
		||||
    if (ver)
 | 
			
		||||
      MLSAG_Ver(rct::identity(), P, IIccss, rows);
 | 
			
		||||
      MLSAG_Ver(rct::identity(), P, IIccss, rows-1);
 | 
			
		||||
    else
 | 
			
		||||
      MLSAG_Gen(rct::identity(), P, sk, NULL, NULL, ind, rows, hw::get_device("default"));
 | 
			
		||||
      MLSAG_Gen(rct::identity(), P, sk, NULL, NULL, ind, rows-1, hw::get_device("default"));
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -788,7 +788,20 @@ TEST(ringct, HPow2)
 | 
			
		|||
{
 | 
			
		||||
  key G = scalarmultBase(d2h(1));
 | 
			
		||||
 | 
			
		||||
  key H = hashToPointSimple(G);
 | 
			
		||||
  // Note that H is computed differently than standard hashing
 | 
			
		||||
  // This method is not guaranteed to return a curvepoint for all inputs
 | 
			
		||||
  // Don't use it elsewhere
 | 
			
		||||
  key H = cn_fast_hash(G);
 | 
			
		||||
  ge_p3 H_p3;
 | 
			
		||||
  int decode = ge_frombytes_vartime(&H_p3, H.bytes);
 | 
			
		||||
  ASSERT_EQ(decode, 0); // this is known to pass for the particular value G
 | 
			
		||||
  ge_p2 H_p2;
 | 
			
		||||
  ge_p3_to_p2(&H_p2, &H_p3);
 | 
			
		||||
  ge_p1p1 H8_p1p1;
 | 
			
		||||
  ge_mul8(&H8_p1p1, &H_p2);
 | 
			
		||||
  ge_p1p1_to_p3(&H_p3, &H8_p1p1);
 | 
			
		||||
  ge_p3_tobytes(H.bytes, &H_p3);
 | 
			
		||||
 | 
			
		||||
  for (int j = 0 ; j < ATOMS ; j++) {
 | 
			
		||||
    ASSERT_TRUE(equalKeys(H, H2[j]));
 | 
			
		||||
    addKeys(H, H, H);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue