aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShen Noether <Shen.Noether@gmx.com>2016-11-17 23:17:21 +0000
committermoneromooo-monero <moneromooo-monero@users.noreply.github.com>2016-12-04 21:54:11 +0000
commit76958fc75abc18c928474eea91ac05fd5e0fcb41 (patch)
tree8644fe15b761d9121c23e67d0cd553505f8a0c04
parentMerge pull request #1403 (diff)
downloadmonero-76958fc75abc18c928474eea91ac05fd5e0fcb41.tar.xz
ringct: switch to Borromean signatures
-rw-r--r--src/cryptonote_core/cryptonote_boost_serialization.h8
-rw-r--r--src/ringct/rctOps.cpp15
-rw-r--r--src/ringct/rctOps.h3
-rw-r--r--src/ringct/rctSigs.cpp145
-rw-r--r--src/ringct/rctSigs.h17
-rw-r--r--src/ringct/rctTypes.h22
-rw-r--r--tests/unit_tests/ringct.cpp39
-rw-r--r--tests/unit_tests/serialization.cpp14
8 files changed, 110 insertions, 153 deletions
diff --git a/src/cryptonote_core/cryptonote_boost_serialization.h b/src/cryptonote_core/cryptonote_boost_serialization.h
index 19b1a687e..663ef5070 100644
--- a/src/cryptonote_core/cryptonote_boost_serialization.h
+++ b/src/cryptonote_core/cryptonote_boost_serialization.h
@@ -207,11 +207,11 @@ namespace boost
}
template <class Archive>
- inline void serialize(Archive &a, rct::asnlSig &x, const boost::serialization::version_type ver)
+ inline void serialize(Archive &a, rct::boroSig &x, const boost::serialization::version_type ver)
{
- a & x.L1;
- a & x.s2;
- a & x.s;
+ a & x.s0;
+ a & x.s1;
+ a & x.ee;
}
template <class Archive>
diff --git a/src/ringct/rctOps.cpp b/src/ringct/rctOps.cpp
index cf55897a7..21f29ccf5 100644
--- a/src/ringct/rctOps.cpp
+++ b/src/ringct/rctOps.cpp
@@ -267,7 +267,7 @@ namespace rct {
ge_p3_tobytes(AB.bytes, &A2);
}
- //checks if A, B are equal as curve points
+ //checks if A, B are equal in terms of bytes (may say no if one is a non-reduced scalar)
//without doing curve operations
bool equalKeys(const key & a, const key & b) {
bool rv = true;
@@ -359,6 +359,19 @@ namespace rct {
return rv;
}
+ key cn_fast_hash(const key64 keys) {
+ key rv;
+ cn_fast_hash(rv, &keys[0], 64 * sizeof(keys[0]));
+ //dp(rv);
+ return rv;
+ }
+
+ key hash_to_scalar(const key64 keys) {
+ key rv = cn_fast_hash(keys);
+ sc_reduce32(rv.bytes);
+ return rv;
+ }
+
key hashToPointSimple(const key & hh) {
key pointk;
ge_p1p1 point2;
diff --git a/src/ringct/rctOps.h b/src/ringct/rctOps.h
index cd3a6dc0d..90f54b050 100644
--- a/src/ringct/rctOps.h
+++ b/src/ringct/rctOps.h
@@ -158,6 +158,9 @@ namespace rct {
//for mg sigs
key cn_fast_hash(const keyV &keys);
key hash_to_scalar(const keyV &keys);
+ //for ANSL
+ 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);
diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp
index b773be1e5..fb67c77c4 100644
--- a/src/ringct/rctSigs.cpp
+++ b/src/ringct/rctSigs.cpp
@@ -40,94 +40,67 @@ using namespace crypto;
using namespace std;
namespace rct {
- //Schnorr Non-linkable
- //Gen Gives a signature (L1, s1, s2) proving that the sender knows "x" such that xG = one of P1 or P2
- //Ver Verifies that signer knows an "x" such that xG = one of P1 or P2
- //These are called in the below ASNL sig generation
-
- void GenSchnorrNonLinkable(key & L1, key & s1, key & s2, const key & x, const key & P1, const key & P2, unsigned int index) {
- key c1, c2, L2;
- key a = skGen();
- if (index == 0) {
- scalarmultBase(L1, a);
- hash_to_scalar(c2, L1);
- skGen(s2);
- addKeys2(L2, s2, c2, P2);
- hash_to_scalar(c1, L2);
- //s1 = a - x * c1
- sc_mulsub(s1.bytes, x.bytes, c1.bytes, a.bytes);
- }
- else if (index == 1) {
- scalarmultBase(L2, a);
- hash_to_scalar(c1, L2);
- skGen(s1);
- addKeys2(L1, s1, c1, P1);
- hash_to_scalar(c2, L1);
- sc_mulsub(s2.bytes, x.bytes, c2.bytes, a.bytes);
- }
- else {
- throw std::runtime_error("GenSchnorrNonLinkable: invalid index (should be 0 or 1)");
+ namespace {
+ struct verRangeWrapper_ {
+ void operator()(const key & C, const rangeSig & as, bool &result) const {
+ result = verRange(C, as);
}
- }
+ };
+ constexpr const verRangeWrapper_ verRangeWrapper{};
- //Schnorr Non-linkable
- //Gen Gives a signature (L1, s1, s2) proving that the sender knows "x" such that xG = one of P1 or P2
- //Ver Verifies that signer knows an "x" such that xG = one of P1 or P2
- //These are called in the below ASNL sig generation
- bool VerSchnorrNonLinkable(const key & P1, const key & P2, const key & L1, const key & s1, const key & s2) {
- key c2, L2, c1, L1p;
- hash_to_scalar(c2, L1);
- addKeys2(L2, s2, c2, P2);
- hash_to_scalar(c1, L2);
- addKeys2(L1p, s1, c1, P1);
-
- return equalKeys(L1, L1p);
+ struct verRctMGSimpleWrapper_ {
+ void operator()(const key &message, const mgSig &mg, const ctkeyV & pubs, const key & C, bool &result) const {
+ result = verRctMGSimple(message, mg, pubs, C);
+ }
+ };
+ constexpr const verRctMGSimpleWrapper_ verRctMGSimpleWrapper{};
}
- //Aggregate Schnorr Non-linkable Ring Signature (ASNL)
- // c.f. http://eprint.iacr.org/2015/1098 section 5.
- // These are used in range proofs (alternatively Borromean could be used)
- // Gen gives a signature which proves the signer knows, for each i,
- // an x[i] such that x[i]G = one of P1[i] or P2[i]
- // Ver Verifies the signer knows a key for one of P1[i], P2[i] at each i
- asnlSig GenASNL(key64 x, key64 P1, key64 P2, bits indices) {
- DP("Generating Aggregate Schnorr Non-linkable Ring Signature\n");
- key64 s1;
- int j = 0;
- asnlSig rv;
- rv.s = zero();
- for (j = 0; j < ATOMS; j++) {
- GenSchnorrNonLinkable(rv.L1[j], s1[j], rv.s2[j], x[j], P1[j], P2[j], indices[j]);
- sc_add(rv.s.bytes, rv.s.bytes, s1[j].bytes);
+ //Borromean (c.f. gmax/andytoshi's paper)
+ boroSig genBorromean(const key64 x, const key64 P1, const key64 P2, const bits indices) {
+ key64 L[2], c[2], s[2], alpha, P[2];
+ int naught = 0, prime = 0, ii = 0, jj=0;
+ for (ii = 0 ; ii < 64 ; ii++) {
+ naught = indices[ii]; prime = (indices[ii] + 1) % 2;
+ copy(P[0][ii], P1[ii]); //could probably user pointers
+ copy(P[1][ii], P2[ii]);
+ skGen(alpha[ii]);
+ scalarmultBase(L[naught][ii], alpha[ii]);
+ c[prime][ii] = hash_to_scalar(L[naught][ii]);
+ skGen(s[prime][ii]);
+ addKeys2(L[prime][ii], s[prime][ii], c[prime][ii], P[prime][ii]);
+ }
+ boroSig bb;
+ bb.ee = cn_fast_hash(L[1]); //or L[1]..
+ key LL, cc;
+ for (jj = 0 ; jj < 64 ; jj++) {
+ naught = indices[jj]; prime = (indices[jj] + 1) % 2;
+ if (!indices[jj]) {
+ sc_mulsub(bb.s0[jj].bytes, x[jj].bytes, bb.ee.bytes, alpha[jj].bytes);
+ copy(bb.s1[jj], s[1][jj]);
+ } else {
+ copy(bb.s0[jj], s[0][jj]);
+ addKeys2(LL, bb.s0[jj], bb.ee, P[0][jj]); //different L0
+ cc = hash_to_scalar(LL);
+ sc_mulsub(bb.s1[jj].bytes, x[jj].bytes, cc.bytes, alpha[jj].bytes);
+ }
}
- return rv;
- }
-
- //Aggregate Schnorr Non-linkable Ring Signature (ASNL)
- // c.f. http://eprint.iacr.org/2015/1098 section 5.
- // These are used in range proofs (alternatively Borromean could be used)
- // Gen gives a signature which proves the signer knows, for each i,
- // an x[i] such that x[i]G = one of P1[i] or P2[i]
- // Ver Verifies the signer knows a key for one of P1[i], P2[i] at each i
- bool VerASNL(const key64 P1, const key64 P2, const asnlSig &as) {
- PERF_TIMER(VerASNL);
- DP("Verifying Aggregate Schnorr Non-linkable Ring Signature\n");
- key LHS = identity();
- key RHS = scalarmultBase(as.s);
- key c2, L2, c1;
- int j = 0;
- for (j = 0; j < ATOMS; j++) {
- hash_to_scalar(c2, as.L1[j]);
- addKeys2(L2, as.s2[j], c2, P2[j]);
- addKeys(LHS, LHS, as.L1[j]);
- hash_to_scalar(c1, L2);
- addKeys(RHS, RHS, scalarmultKey(P1[j], c1));
- }
- key cc;
- sc_sub(cc.bytes, LHS.bytes, RHS.bytes);
- return sc_isnonzero(cc.bytes) == 0;
+ return bb;
}
+ //see above.
+ bool verifyBorromean(const boroSig &bb, const key64 P1, const key64 P2) {
+ key64 Lv1, chash; key LL;
+ int ii = 0;
+ for (ii = 0 ; ii < 64 ; ii++) {
+ addKeys2(LL, bb.s0[ii], bb.ee, P1[ii]);
+ chash[ii] = hash_to_scalar(LL);
+ addKeys2(Lv1[ii], bb.s1[ii], chash[ii], P2[ii]);
+ }
+ key eeComputed = cn_fast_hash(Lv1); //hash function fine
+ return equalKeys(eeComputed, bb.ee);
+ }
+
//Multilayered Spontaneous Anonymous Group Signatures (MLSAG signatures)
//These are aka MG signatutes in earlier drafts of the ring ct paper
// c.f. http://eprint.iacr.org/2015/1098 section 2.
@@ -323,7 +296,7 @@ namespace rct {
sc_add(mask.bytes, mask.bytes, ai[i].bytes);
addKeys(C, C, sig.Ci[i]);
}
- sig.asig = GenASNL(ai, sig.Ci, CiH, b);
+ sig.asig = genBorromean(ai, sig.Ci, CiH, b);
return sig;
}
@@ -345,7 +318,7 @@ namespace rct {
}
if (!equalKeys(C, Ctmp))
return false;
- if (!VerASNL(as.Ci, CiH, as.asig))
+ if (!verifyBorromean(as.asig, as.Ci, CiH))
return false;
return true;
}
@@ -371,10 +344,10 @@ namespace rct {
for (auto r: rv.p.rangeSigs)
{
for (size_t n = 0; n < 64; ++n)
- kv.push_back(r.asig.L1[n]);
+ kv.push_back(r.asig.s0[n]);
for (size_t n = 0; n < 64; ++n)
- kv.push_back(r.asig.s2[n]);
- kv.push_back(r.asig.s);
+ kv.push_back(r.asig.s1[n]);
+ kv.push_back(r.asig.ee);
for (size_t n = 0; n < 64; ++n)
kv.push_back(r.Ci[n]);
}
diff --git a/src/ringct/rctSigs.h b/src/ringct/rctSigs.h
index a4fecade4..1fe4aa074 100644
--- a/src/ringct/rctSigs.h
+++ b/src/ringct/rctSigs.h
@@ -66,21 +66,8 @@ using namespace crypto;
namespace rct {
- //Schnorr Non-linkable
- //Gen Gives a signature (L1, s1, s2) proving that the sender knows "x" such that xG = one of P1 or P2
- //Ver Verifies that signer knows an "x" such that xG = one of P1 or P2
- //These are called in the below ASNL sig generation
- void GenSchnorrNonLinkable(key & L1, key & s1, key & s2, const key & x, const key & P1, const key & P2, unsigned int index);
- bool VerSchnorrNonLinkable(const key & P1, const key & P2, const key & L1, const key & s1, const key & s2);
-
- //Aggregate Schnorr Non-linkable Ring Signature (ASNL)
- // c.f. http://eprint.iacr.org/2015/1098 section 5.
- // These are used in range proofs (alternatively Borromean could be used)
- // Gen gives a signature which proves the signer knows, for each i,
- // an x[i] such that x[i]G = one of P1[i] or P2[i]
- // Ver Verifies the signer knows a key for one of P1[i], P2[i] at each i
- asnlSig GenASNL(key64 x, key64 P1, key64 P2, bits indices);
- bool VerASNL(const key64 P1, const key64 P2, const asnlSig &as);
+ boroSig genBorromean(const key64 x, const key64 P1, const key64 P2, const bits indices);
+ bool verifyBorromean(const boroSig &bb, const key64 P1, const key64 P2);
//Multilayered Spontaneous Anonymous Group Signatures (MLSAG signatures)
//These are aka MG signatutes in earlier drafts of the ring ct paper
diff --git a/src/ringct/rctTypes.h b/src/ringct/rctTypes.h
index b1921b71a..71cc61ddc 100644
--- a/src/ringct/rctTypes.h
+++ b/src/ringct/rctTypes.h
@@ -125,12 +125,10 @@ namespace rct {
typedef unsigned int bits[ATOMS];
typedef key key64[64];
- //just contains the necessary keys to represent asnlSigs
- //c.f. http://eprint.iacr.org/2015/1098
- struct asnlSig {
- key64 L1;
- key64 s2;
- key s;
+ struct boroSig {
+ key64 s0;
+ key64 s1;
+ key ee;
};
//Container for precomp
@@ -151,14 +149,14 @@ namespace rct {
// FIELD(II) - not serialized, it can be reconstructed
END_SERIALIZE()
};
- //contains the data for an asnl sig
+ //contains the data for an Borromean sig
// also contains the "Ci" values such that
// \sum Ci = C
// and the signature proves that each Ci is either
// a Pedersen commitment to 0 or to 2^i
//thus proving that C is in the range of [0, 2^64]
struct rangeSig {
- asnlSig asig;
+ boroSig asig;
key64 Ci;
BEGIN_SERIALIZE_OBJECT()
@@ -452,7 +450,7 @@ inline std::ostream &operator <<(std::ostream &o, const rct::key &v) { return pr
BLOB_SERIALIZER(rct::key);
BLOB_SERIALIZER(rct::key64);
BLOB_SERIALIZER(rct::ctkey);
-BLOB_SERIALIZER(rct::asnlSig);
+BLOB_SERIALIZER(rct::boroSig);
VARIANT_TAG(debug_archive, rct::key, "rct::key");
VARIANT_TAG(debug_archive, rct::key64, "rct::key64");
@@ -464,7 +462,7 @@ VARIANT_TAG(debug_archive, rct::ctkeyM, "rct::ctkeyM");
VARIANT_TAG(debug_archive, rct::ecdhTuple, "rct::ecdhTuple");
VARIANT_TAG(debug_archive, rct::mgSig, "rct::mgSig");
VARIANT_TAG(debug_archive, rct::rangeSig, "rct::rangeSig");
-VARIANT_TAG(debug_archive, rct::asnlSig, "rct::asnlSig");
+VARIANT_TAG(debug_archive, rct::boroSig, "rct::boroSig");
VARIANT_TAG(debug_archive, rct::rctSig, "rct::rctSig");
VARIANT_TAG(binary_archive, rct::key, 0x90);
@@ -477,7 +475,7 @@ VARIANT_TAG(binary_archive, rct::ctkeyM, 0x96);
VARIANT_TAG(binary_archive, rct::ecdhTuple, 0x97);
VARIANT_TAG(binary_archive, rct::mgSig, 0x98);
VARIANT_TAG(binary_archive, rct::rangeSig, 0x99);
-VARIANT_TAG(binary_archive, rct::asnlSig, 0x9a);
+VARIANT_TAG(binary_archive, rct::boroSig, 0x9a);
VARIANT_TAG(binary_archive, rct::rctSig, 0x9b);
VARIANT_TAG(json_archive, rct::key, "rct_key");
@@ -490,7 +488,7 @@ VARIANT_TAG(json_archive, rct::ctkeyM, "rct_ctkeyM");
VARIANT_TAG(json_archive, rct::ecdhTuple, "rct_ecdhTuple");
VARIANT_TAG(json_archive, rct::mgSig, "rct_mgSig");
VARIANT_TAG(json_archive, rct::rangeSig, "rct_rangeSig");
-VARIANT_TAG(json_archive, rct::asnlSig, "rct_asnlSig");
+VARIANT_TAG(json_archive, rct::boroSig, "rct_boroSig");
VARIANT_TAG(json_archive, rct::rctSig, "rct_rctSig");
#endif /* RCTTYPES_H */
diff --git a/tests/unit_tests/ringct.cpp b/tests/unit_tests/ringct.cpp
index 1abf2511d..5ab77d4aa 100644
--- a/tests/unit_tests/ringct.cpp
+++ b/tests/unit_tests/ringct.cpp
@@ -40,29 +40,12 @@
using namespace crypto;
using namespace rct;
-TEST(ringct, SNL)
-{
- key x, P1;
- skpkGen(x, P1);
-
- key P2 = pkGen();
- key P3 = pkGen();
-
- key L1, s1, s2;
- GenSchnorrNonLinkable(L1, s1, s2, x, P1, P2, 0);
-
- // a valid one
- // an invalid one
- ASSERT_TRUE(VerSchnorrNonLinkable(P1, P2, L1, s1, s2));
- ASSERT_FALSE(VerSchnorrNonLinkable(P1, P3, L1, s1, s2));
-}
-
-TEST(ringct, ASNL)
+TEST(ringct, Borromean)
{
int j = 0;
- //Tests for ASNL
- //#ASNL true one, false one, C != sum Ci, and one out of the range..
+ //Tests for Borromean signatures
+ //#boro true one, false one, C != sum Ci, and one out of the range..
int N = 64;
key64 xv;
key64 P1v;
@@ -86,22 +69,22 @@ TEST(ringct, ASNL)
}
//#true one
- asnlSig L1s2s = GenASNL(xv, P1v, P2v, indi);
- ASSERT_TRUE(VerASNL(P1v, P2v, L1s2s));
+ boro bb = genBorromean(xv, P1v, P2v, indi);
+ ASSERT_TRUE(verifyBorromean(bb, P1v, P2v));
//#false one
indi[3] = (indi[3] + 1) % 2;
- L1s2s = GenASNL(xv, P1v, P2v, indi);
- ASSERT_FALSE(VerASNL(P1v, P2v, L1s2s));
+ bb = genBorromean(xv, P1v, P2v, indi);
+ ASSERT_FALSE(verifyBorromean(bb, P1v, P2v));
//#true one again
indi[3] = (indi[3] + 1) % 2;
- L1s2s = GenASNL(xv, P1v, P2v, indi);
- ASSERT_TRUE(VerASNL(P1v, P2v, L1s2s));
+ bb = genBorromean(xv, P1v, P2v, indi);
+ ASSERT_TRUE(verifyBorromean(bb, P1v, P2v));
//#false one
- L1s2s = GenASNL(xv, P2v, P1v, indi);
- ASSERT_FALSE(VerASNL(P1v, P2v, L1s2s));
+ bb = genBorromean(xv, P2v, P1v, indi);
+ ASSERT_FALSE(verifyBorromean(bb, P1v, P2v));
}
TEST(ringct, MG_sigs)
diff --git a/tests/unit_tests/serialization.cpp b/tests/unit_tests/serialization.cpp
index b592f456b..f8afb2e94 100644
--- a/tests/unit_tests/serialization.cpp
+++ b/tests/unit_tests/serialization.cpp
@@ -457,7 +457,7 @@ TEST(Serialization, serializes_ringct_types)
rct::ctkeyV ctkeyv0, ctkeyv1;
rct::ctkeyM ctkeym0, ctkeym1;
rct::ecdhTuple ecdh0, ecdh1;
- rct::asnlSig asnl0, asnl1;
+ rct::boroSig boro0, boro1;
rct::mgSig mg0, mg1;
rct::rangeSig rg0, rg1;
rct::rctSig s0, s1;
@@ -541,13 +541,13 @@ TEST(Serialization, serializes_ringct_types)
for (size_t n = 0; n < 64; ++n)
{
- asnl0.L1[n] = rct::skGen();
- asnl0.s2[n] = rct::skGen();
+ boro0.s0[n] = rct::skGen();
+ boro0.s1[n] = rct::skGen();
}
- asnl0.s = rct::skGen();
- ASSERT_TRUE(serialization::dump_binary(asnl0, blob));
- ASSERT_TRUE(serialization::parse_binary(blob, asnl1));
- ASSERT_TRUE(!memcmp(&asnl0, &asnl1, sizeof(asnl0)));
+ boro0.ee = rct::skGen();
+ ASSERT_TRUE(serialization::dump_binary(boro0, blob));
+ ASSERT_TRUE(serialization::parse_binary(blob, boro1));
+ ASSERT_TRUE(!memcmp(&boro0, &boro1, sizeof(boro0)));
// create a full rct signature to use its innards
rct::ctkeyV sc, pc;