Import ZeroCoin adapted sources
authoralex <alex@alex-VirtualBox.(none)>
Sun, 8 Sep 2013 14:47:29 +0000 (18:47 +0400)
committeralex <alex@alex-VirtualBox.(none)>
Sun, 8 Sep 2013 14:47:29 +0000 (18:47 +0400)
Import and build/linking only. Provided functionality isn't used yet.

27 files changed:
novacoin-qt.pro
src/makefile.bsd
src/makefile.linux-mingw
src/makefile.mingw
src/makefile.osx
src/makefile.unix
src/obj/.gitignore
src/obj/zerocoin/.gitignore [new file with mode: 0644]
src/zerocoin/Accumulator.cpp [new file with mode: 0644]
src/zerocoin/Accumulator.h [new file with mode: 0644]
src/zerocoin/AccumulatorProofOfKnowledge.cpp [new file with mode: 0644]
src/zerocoin/AccumulatorProofOfKnowledge.h [new file with mode: 0644]
src/zerocoin/Coin.cpp [new file with mode: 0644]
src/zerocoin/Coin.h [new file with mode: 0644]
src/zerocoin/CoinSpend.cpp [new file with mode: 0644]
src/zerocoin/CoinSpend.h [new file with mode: 0644]
src/zerocoin/Commitment.cpp [new file with mode: 0644]
src/zerocoin/Commitment.h [new file with mode: 0644]
src/zerocoin/ParamGeneration.cpp [new file with mode: 0644]
src/zerocoin/ParamGeneration.h [new file with mode: 0644]
src/zerocoin/Params.cpp [new file with mode: 0644]
src/zerocoin/Params.h [new file with mode: 0644]
src/zerocoin/SerialNumberSignatureOfKnowledge.cpp [new file with mode: 0644]
src/zerocoin/SerialNumberSignatureOfKnowledge.h [new file with mode: 0644]
src/zerocoin/SpendMetaData.cpp [new file with mode: 0644]
src/zerocoin/SpendMetaData.h [new file with mode: 0644]
src/zerocoin/Zerocoin.h [new file with mode: 0644]

index a69730f..e4c1371 100644 (file)
@@ -166,6 +166,16 @@ HEADERS += src/qt/bitcoingui.h \
     src/kernel.h \
     src/scrypt.h \
     src/pbkdf2.h \
+    src/zerocoin/Accumulator.h \
+    src/zerocoin/AccumulatorProofOfKnowledge.h \
+    src/zerocoin/Coin.h \
+    src/zerocoin/CoinSpend.h \
+    src/zerocoin/Commitment.h \
+    src/zerocoin/ParamGeneration.h \
+    src/zerocoin/Params.h \
+    src/zerocoin/SerialNumberSignatureOfKnowledge.h \
+    src/zerocoin/SpendMetaData.h \
+    src/zerocoin/Zerocoin.h \
     src/serialize.h \
     src/strlcpy.h \
     src/main.h \
@@ -285,7 +295,16 @@ SOURCES += src/qt/bitcoin.cpp src/qt/bitcoingui.cpp \
     src/scrypt-x86.S \
     src/scrypt-x86_64.S \
     src/scrypt.cpp \
-    src/pbkdf2.cpp
+    src/pbkdf2.cpp \
+    src/zerocoin/Accumulator.cpp \
+    src/zerocoin/AccumulatorProofOfKnowledge.cpp \
+    src/zerocoin/Coin.cpp \
+    src/zerocoin/CoinSpend.cpp \
+    src/zerocoin/Commitment.cpp \
+    src/zerocoin/ParamGeneration.cpp \
+    src/zerocoin/Params.cpp \
+    src/zerocoin/SerialNumberSignatureOfKnowledge.cpp \
+    src/zerocoin/SpendMetaData.cpp
 
 RESOURCES += \
     src/qt/bitcoin.qrc
index e54a80a..31e74de 100644 (file)
@@ -95,7 +95,7 @@ DEBUGFLAGS=-g
 
 # CXXFLAGS can be specified on the make command line, so we use xCXXFLAGS that only
 # adds some defaults in front. Unfortunately, CXXFLAGS=... $(CXXFLAGS) does not work.
-xCXXFLAGS=-O0 -msse2 -pthread -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter \
+xCXXFLAGS=-O0 -msse2 -pthread -Wall -Wextra -Wno-ignored-qualifiers -Wformat -Wformat-security -Wno-unused-parameter \
     $(DEBUGFLAGS) $(DEFS) $(HARDENING) $(CXXFLAGS)
 
 # LDFLAGS can be specified on the make command line, so we use xLDFLAGS that only
@@ -135,7 +135,16 @@ OBJS= \
     obj/pbkdf2.o \
     obj/scrypt.o \
     obj/scrypt-x86.o \
-    obj/scrypt-x86_64.o
+    obj/scrypt-x86_64.o \
+    obj/zerocoin/Accumulator.o \
+    obj/zerocoin/AccumulatorProofOfKnowledge.o \
+    obj/zerocoin/Coin.o \
+    obj/zerocoin/CoinSpend.o \
+    obj/zerocoin/Commitment.o \
+    obj/zerocoin/ParamGeneration.o \
+    obj/zerocoin/Params.o \
+    obj/zerocoin/SerialNumberSignatureOfKnowledge.o \
+    obj/zerocoin/SpendMetaData.o
 
 
 all: novacoind
@@ -181,6 +190,13 @@ obj/%.o: %.cpp
              -e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \
          rm -f $(@:%.o=%.d)
 
+obj/zerocoin/%.o: zerocoin/%.cpp
+       $(CXX) -c $(xCXXFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $<
+       @cp $(@:%.o=%.d) $(@:%.o=%.P); \
+         sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
+             -e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \
+         rm -f $(@:%.o=%.d)
+
 novacoind: $(OBJS:obj/%=obj/%)
        $(LINK) $(xCXXFLAGS) -o $@ $^ $(xLDFLAGS) $(LIBS)
 
@@ -199,8 +215,10 @@ test_novacoin: $(TESTOBJS) $(filter-out obj/init.o,$(OBJS:obj/%=obj/%))
 clean:
        -rm -f novacoind test_novacoin
        -rm -f obj/*.o
+       -rm -f obj/zerocoin/*.o
        -rm -f obj-test/*.o
        -rm -f obj/*.P
+       -rm -f obj/zerocoin/*.P
        -rm -f obj-test/*.P
        -rm -f obj/build.h
 
index 9777ad6..2a3f815 100644 (file)
@@ -40,7 +40,7 @@ LIBS= \
 
 DEFS=-D_MT -DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB -DBOOST_SPIRIT_THREADSAFE
 DEBUGFLAGS=-g
-CFLAGS=-O2 -msse2 -w -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS)
+CFLAGS=-O2 -msse2 -w -Wall -Wextra -Wno-ignored-qualifiers -Wformat -Wformat-security -Wno-unused-parameter $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS)
 LDFLAGS=-Wl,--dynamicbase -Wl,--nxcompat -static-libgcc -static-libstdc++
 
 TESTDEFS = -DTEST_DATA_DIR=$(abspath test/data)
@@ -96,7 +96,16 @@ OBJS= \
     obj/pbkdf2.o \
     obj/scrypt.o \
     obj/scrypt-x86.o \
-    obj/scrypt-x86_64.o
+    obj/scrypt-x86_64.o \
+    obj/zerocoin/Accumulator.o \
+    obj/zerocoin/AccumulatorProofOfKnowledge.o \
+    obj/zerocoin/Coin.o \
+    obj/zerocoin/CoinSpend.o \
+    obj/zerocoin/Commitment.o \
+    obj/zerocoin/ParamGeneration.o \
+    obj/zerocoin/Params.o \
+    obj/zerocoin/SerialNumberSignatureOfKnowledge.o \
+    obj/zerocoin/SpendMetaData.o
 
 all: novacoind.exe
 
@@ -123,6 +132,9 @@ DEFS += -DHAVE_BUILD_INFO
 obj/%.o: %.cpp $(HEADERS)
        $(CXX) -c $(CFLAGS) -o $@ $<
 
+obj/zerocoin/%.o: zerocoin/%.cpp $(HEADERS)
+       $(CXX) -c $(CFLAGS) -o $@ $<
+
 novacoind.exe: $(OBJS:obj/%=obj/%)
        $(CXX) $(CFLAGS) $(LDFLAGS) -o $@ $(LIBPATHS) $^ $(LIBS) -lshlwapi
        $(STRIP) novacoind.exe
@@ -144,6 +156,7 @@ obj/scrypt-x86_64.o: scrypt-x86_64.S
 
 clean:
        -rm -f obj/*.o
+       -rm -f obj/zerocoin/*.o
        -rm -f novacoind.exe
        -rm -f obj-test/*.o
        -rm -f test_novacoin.exe
index 369b5c5..583ec7b 100644 (file)
@@ -28,7 +28,7 @@ LIBS= \
 
 DEFS=-DWIN32 -D_WINDOWS -DBOOST_THREAD_USE_LIB -DBOOST_SPIRIT_THREADSAFE
 DEBUGFLAGS=-g
-CFLAGS=-mthreads -O2 -msse2 -w -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS)
+CFLAGS=-mthreads -O2 -msse2 -w -Wall -Wextra -Wno-ignored-qualifiers -Wformat -Wformat-security -Wno-unused-parameter $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS)
 LDFLAGS=-Wl,--dynamicbase -Wl,--nxcompat
 
 TESTDEFS = -DTEST_DATA_DIR=$(abspath test/data)
@@ -85,7 +85,16 @@ OBJS= \
     obj/pbkdf2.o \
     obj/scrypt.o \
     obj/scrypt-x86.o \
-    obj/scrypt-x86_64.o
+    obj/scrypt-x86_64.o \
+    obj/zerocoin/Accumulator.o \
+    obj/zerocoin/AccumulatorProofOfKnowledge.o \
+    obj/zerocoin/Coin.o \
+    obj/zerocoin/CoinSpend.o \
+    obj/zerocoin/Commitment.o \
+    obj/zerocoin/ParamGeneration.o \
+    obj/zerocoin/Params.o \
+    obj/zerocoin/SerialNumberSignatureOfKnowledge.o \
+    obj/zerocoin/SpendMetaData.o
 
 all: novacoind.exe
 
@@ -111,6 +120,9 @@ test check: test_novacoin.exe FORCE
 obj/%.o: %.cpp $(HEADERS)
        g++ -c $(CFLAGS) -o $@ $<
 
+obj/zerocoin/%.o: zerocoin/%.cpp
+       g++ -c $(CFLAGS) -o $@ $<
+
 obj/scrypt-x86.o: scrypt-x86.S
        $(CXX) -c $(xCXXFLAGS) -MMD -o $@ $<
 
@@ -131,6 +143,7 @@ test_bitcoin.exe: $(TESTOBJS) $(filter-out obj/init.o,$(OBJS:obj/%=obj/%))
 clean:
        -del /Q novacoind test_novacoin
        -del /Q obj\*
+       -del /Q obj\zerocoin\*
        -del /Q obj-test\*
 
 FORCE:
index 9a3dc2e..a821ab9 100644 (file)
@@ -67,7 +67,7 @@ CFLAGS = -g -msse2
 endif
 
 # ppc doesn't work because we don't support big-endian
-CFLAGS += -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter \
+CFLAGS += -Wall -Wextra -Wformat -Wno-ignored-qualifiers -Wformat-security -Wno-unused-parameter \
     $(DEBUGFLAGS) $(DEFS) $(INCLUDEPATHS)
 
 OBJS= \
@@ -103,7 +103,16 @@ OBJS= \
     obj/kernel.o \
     obj/scrypt.o \
     obj/scrypt-x86.o \
-    obj/scrypt-x86_64.o
+    obj/scrypt-x86_64.o \
+    obj/zerocoin/Accumulator.o \
+    obj/zerocoin/AccumulatorProofOfKnowledge.o \
+    obj/zerocoin/Coin.o \
+    obj/zerocoin/CoinSpend.o \
+    obj/zerocoin/Commitment.o \
+    obj/zerocoin/ParamGeneration.o \
+    obj/zerocoin/Params.o \
+    obj/zerocoin/SerialNumberSignatureOfKnowledge.o \
+    obj/zerocoin/SpendMetaData.o
 
 ifndef USE_UPNP
        override USE_UPNP = -
@@ -158,6 +167,13 @@ obj/%.o: %.cpp
              -e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \
          rm -f $(@:%.o=%.d)
 
+obj/zerocoin/%.o: zerocoin/%.cpp
+       $(CXX) -c $(xCXXFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $<
+       @cp $(@:%.o=%.d) $(@:%.o=%.P); \
+         sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
+             -e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \
+         rm -f $(@:%.o=%.d)
+
 obj/scrypt-x86.o: scrypt-x86.S
        $(CXX) -c $(xCXXFLAGS) -MMD -o $@ $<
 
@@ -182,8 +198,10 @@ test_novacoin: $(TESTOBJS) $(filter-out obj/init.o,$(OBJS:obj/%=obj/%))
 clean:
        -rm -f novacoind test_novacoin
        -rm -f obj/*.o
+       -rm -f obj/zerocoin/*.o
        -rm -f obj-test/*.o
        -rm -f obj/*.P
+       -rm -f obj/zerocoin/*.P
        -rm -f obj-test/*.P
        -rm -f obj/build.h
 
index e23a914..fdcc698 100644 (file)
@@ -94,7 +94,7 @@ DEBUGFLAGS=-g
 
 # CXXFLAGS can be specified on the make command line, so we use xCXXFLAGS that only
 # adds some defaults in front. Unfortunately, CXXFLAGS=... $(CXXFLAGS) does not work.
-xCXXFLAGS=-O2 -msse2 -pthread -Wall -Wextra -Wformat -Wformat-security -Wno-unused-parameter \
+xCXXFLAGS=-O2 -msse2 -pthread -Wall -Wextra -Wno-ignored-qualifiers -Wformat -Wformat-security -Wno-unused-parameter \
     $(DEBUGFLAGS) $(DEFS) $(HARDENING) $(CXXFLAGS)
 
 # LDFLAGS can be specified on the make command line, so we use xLDFLAGS that only
@@ -134,8 +134,16 @@ OBJS= \
     obj/pbkdf2.o \
     obj/scrypt.o \
     obj/scrypt-x86.o \
-    obj/scrypt-x86_64.o
-
+    obj/scrypt-x86_64.o \
+    obj/zerocoin/Accumulator.o \
+    obj/zerocoin/AccumulatorProofOfKnowledge.o \
+    obj/zerocoin/Coin.o \
+    obj/zerocoin/CoinSpend.o \
+    obj/zerocoin/Commitment.o \
+    obj/zerocoin/ParamGeneration.o \
+    obj/zerocoin/Params.o \
+    obj/zerocoin/SerialNumberSignatureOfKnowledge.o \
+    obj/zerocoin/SpendMetaData.o
 
 all: novacoind
 
@@ -180,6 +188,13 @@ obj/%.o: %.cpp
              -e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \
          rm -f $(@:%.o=%.d)
 
+obj/zerocoin/%.o: zerocoin/%.cpp
+       $(CXX) -c $(xCXXFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $<
+       @cp $(@:%.o=%.d) $(@:%.o=%.P); \
+         sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
+             -e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \
+         rm -f $(@:%.o=%.d)
+
 novacoind: $(OBJS:obj/%=obj/%)
        $(LINK) $(xCXXFLAGS) -o $@ $^ $(xLDFLAGS) $(LIBS)
 
@@ -198,8 +213,10 @@ test_novacoin: $(TESTOBJS) $(filter-out obj/init.o,$(OBJS:obj/%=obj/%))
 clean:
        -rm -f novacoind test_novacoin
        -rm -f obj/*.o
+       -rm -f obj/zerocoin/*.o
        -rm -f obj-test/*.o
        -rm -f obj/*.P
+       -rm -f obj/zerocoin/*.P
        -rm -f obj-test/*.P
        -rm -f obj/build.h
 
index d6b7ef3..c330091 100644 (file)
@@ -1,2 +1,3 @@
 *
 !.gitignore
+!zerocoin
diff --git a/src/obj/zerocoin/.gitignore b/src/obj/zerocoin/.gitignore
new file mode 100644 (file)
index 0000000..d6b7ef3
--- /dev/null
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/src/zerocoin/Accumulator.cpp b/src/zerocoin/Accumulator.cpp
new file mode 100644 (file)
index 0000000..e05f8ac
--- /dev/null
@@ -0,0 +1,106 @@
+/**
+ * @file       Accumulator.cpp
+ *
+ * @brief      Accumulator and AccumulatorWitness classes for the Zerocoin library.
+ *
+ * @author     Ian Miers, Christina Garman and Matthew Green
+ * @date       June 2013
+ *
+ * @copyright  Copyright 2013 Ian Miers, Christina Garman and Matthew Green
+ * @license    This project is released under the MIT license.
+ **/
+
+#include <sstream>
+#include "Zerocoin.h"
+
+namespace libzerocoin {
+
+//Accumulator class
+Accumulator::Accumulator(const AccumulatorAndProofParams* p, const CoinDenomination d): params(p), denomination(d) {
+       if (!(params->initialized)) {
+               throw ZerocoinException("Invalid parameters for accumulator");
+       }
+
+       this->value = this->params->accumulatorBase;
+}
+
+Accumulator::Accumulator(const Params* p, const CoinDenomination d) {
+       this->params = &(p->accumulatorParams);
+       this->denomination = d;
+
+       if (!(params->initialized)) {
+               throw ZerocoinException("Invalid parameters for accumulator");
+       }
+
+       this->value = this->params->accumulatorBase;
+}
+
+void Accumulator::accumulate(const PublicCoin& coin) {
+       // Make sure we're initialized
+       if(!(this->value)) {
+               throw ZerocoinException("Accumulator is not initialized");
+       }
+
+       if(this->denomination != coin.getDenomination()) {
+               //std::stringstream msg;
+               std::string msg;
+               msg = "Wrong denomination for coin. Expected coins of denomination: ";
+               msg += this->denomination;
+               msg += ". Instead, got a coin of denomination: ";
+               msg += coin.getDenomination();
+               throw std::invalid_argument(msg);
+       }
+
+       if(coin.validate()) {
+               // Compute new accumulator = "old accumulator"^{element} mod N
+               this->value = this->value.pow_mod(coin.getValue(), this->params->accumulatorModulus);
+       } else {
+               throw std::invalid_argument("Coin is not valid");
+       }
+}
+
+const CoinDenomination Accumulator::getDenomination() const {
+       return static_cast<CoinDenomination> (this->denomination);
+}
+
+const Bignum& Accumulator::getValue() const {
+       return this->value;
+}
+
+Accumulator& Accumulator::operator += (const PublicCoin& c) {
+       this->accumulate(c);
+       return *this;
+}
+
+bool Accumulator::operator == (const Accumulator rhs) const {
+       return this->value == rhs.value;
+}
+
+//AccumulatorWitness class
+AccumulatorWitness::AccumulatorWitness(const Params* p,
+                                       const Accumulator& checkpoint, const PublicCoin coin): params(p), witness(checkpoint), element(coin) {
+}
+
+void AccumulatorWitness::AddElement(const PublicCoin& c) {
+       if(element != c) {
+               witness += c;
+       }
+}
+
+const Bignum& AccumulatorWitness::getValue() const {
+       return this->witness.getValue();
+}
+
+bool AccumulatorWitness::VerifyWitness(const Accumulator& a, const PublicCoin &publicCoin) const {
+       Accumulator temp(witness);
+       temp += element;
+       return (temp == a && this->element == publicCoin);
+}
+
+AccumulatorWitness& AccumulatorWitness::operator +=(
+    const PublicCoin& rhs) {
+       this->AddElement(rhs);
+       return *this;
+}
+
+} /* namespace libzerocoin */
diff --git a/src/zerocoin/Accumulator.h b/src/zerocoin/Accumulator.h
new file mode 100644 (file)
index 0000000..17cd58f
--- /dev/null
@@ -0,0 +1,148 @@
+/**
+ * @file       Accumulator.h
+ *
+ * @brief      Accumulator and AccumulatorWitness classes for the Zerocoin library.
+ *
+ * @author     Ian Miers, Christina Garman and Matthew Green
+ * @date       June 2013
+ *
+ * @copyright  Copyright 2013 Ian Miers, Christina Garman and Matthew Green
+ * @license    This project is released under the MIT license.
+ **/
+#ifndef ACCUMULATOR_H_
+#define ACCUMULATOR_H_
+
+namespace libzerocoin {
+/**
+ * \brief Implementation of the RSA-based accumulator.
+ **/
+
+class Accumulator {
+public:
+
+       /**
+        * @brief      Construct an Accumulator from a stream.
+        * @param p    An AccumulatorAndProofParams object containing global parameters
+        * @param d    the denomination of coins we are accumulating
+        * @throw      Zerocoin exception in case of invalid parameters
+        **/
+       template<typename Stream>
+       Accumulator(const AccumulatorAndProofParams* p, Stream& strm): params(p) {
+               strm >> *this;
+       }
+
+       template<typename Stream>
+       Accumulator(const Params* p, Stream& strm) {
+               strm >> *this;
+               this->params = &(p->accumulatorParams);
+       }
+
+       /**
+        * @brief      Construct an Accumulator from a Params object.
+        * @param p    A Params object containing global parameters
+        * @param d the denomination of coins we are accumulating
+        * @throw     Zerocoin exception in case of invalid parameters
+        **/
+       Accumulator(const AccumulatorAndProofParams* p, const CoinDenomination d = ZQ_LOVELACE);
+
+       Accumulator(const Params* p, const CoinDenomination d = ZQ_LOVELACE);
+
+       /**
+        * Accumulate a coin into the accumulator. Validates
+        * the coin prior to accumulation.
+        *
+        * @param coin  A PublicCoin to accumulate.
+        *
+        * @throw               Zerocoin exception if the coin is not valid.
+        *
+        **/
+       void accumulate(const PublicCoin &coin);
+
+       const CoinDenomination getDenomination() const;
+       /** Get the accumulator result
+        *
+        * @return a Bignum containing the result.
+        */
+       const Bignum& getValue() const;
+
+
+       // /**
+       //  * Used to set the accumulator value
+       //  *
+       //  * Use this to handle accumulator checkpoints
+       //  * @param b the value to set the accumulator to.
+       //  * @throw  A ZerocoinException if the accumulator value is invalid.
+       //  */
+       // void setValue(Bignum &b); // shouldn't this be a constructor?
+
+       /** Used to accumulate a coin
+        *
+        * @param c the coin to accumulate
+        * @return a refrence to the updated accumulator.
+        */
+       Accumulator& operator +=(const PublicCoin& c);
+       bool operator==(const Accumulator rhs) const;
+
+       IMPLEMENT_SERIALIZE
+       (
+           READWRITE(value);
+           READWRITE(denomination);
+       )
+private:
+       const AccumulatorAndProofParams* params;
+       Bignum value;
+       // Denomination is stored as an INT because storing
+       // and enum raises amigiuities in the serialize code //FIXME if possible
+       int denomination;
+};
+
+/**A witness that a PublicCoin is in the accumulation of a set of coins
+ *
+ */
+class AccumulatorWitness {
+public:
+       template<typename Stream>
+       AccumulatorWitness(const Params* p, Stream& strm): params(p) {
+               strm >> *this;
+       }
+
+       /**  Construct's a witness.  You must add all elements after the witness
+        * @param p pointer to params
+        * @param checkpoint the last known accumulator value before the element was added
+        * @param coin the coin we want a witness to
+        */
+       AccumulatorWitness(const Params* p, const Accumulator& checkpoint, const PublicCoin coin);
+
+       /** Adds element to the set whose's accumulation we are proving coin is a member of
+        *
+        * @param c the coin to add
+        */
+       void AddElement(const PublicCoin& c);
+
+       /**
+        *
+        * @return the value of the witness
+        */
+       const Bignum& getValue() const;
+
+       /** Checks that this is a witness to the accumulation of coin
+        * @param a             the accumulator we are checking against.
+        * @param publicCoin    the coin we're providing a witness for
+        * @return True if the witness computation validates
+        */
+       bool VerifyWitness(const Accumulator& a, const PublicCoin &publicCoin) const;
+
+       /**
+        * Adds rhs to the set whose's accumulation ware proving coin is a member of
+        * @param rhs the PublicCoin to add
+        * @return
+        */
+       AccumulatorWitness& operator +=(const PublicCoin& rhs);
+private:
+       const Params* params;
+       Accumulator witness;
+       const PublicCoin element;
+};
+
+} /* namespace libzerocoin */
+#endif /* ACCUMULATOR_H_ */
diff --git a/src/zerocoin/AccumulatorProofOfKnowledge.cpp b/src/zerocoin/AccumulatorProofOfKnowledge.cpp
new file mode 100644 (file)
index 0000000..ed9ac91
--- /dev/null
@@ -0,0 +1,143 @@
+/**
+ * @file       AccumulatorProofOfKnowledge.cpp
+ *
+ * @brief      AccumulatorProofOfKnowledge class for the Zerocoin library.
+ *
+ * @author     Ian Miers, Christina Garman and Matthew Green
+ * @date       June 2013
+ *
+ * @copyright  Copyright 2013 Ian Miers, Christina Garman and Matthew Green
+ * @license    This project is released under the MIT license.
+ **/
+
+#include "Zerocoin.h"
+
+namespace libzerocoin {
+
+AccumulatorProofOfKnowledge::AccumulatorProofOfKnowledge(const AccumulatorAndProofParams* p): params(p) {}
+
+AccumulatorProofOfKnowledge::AccumulatorProofOfKnowledge(const AccumulatorAndProofParams* p,
+        const Commitment& commitmentToCoin, const AccumulatorWitness& witness,
+        Accumulator& a): params(p) {
+
+       Bignum sg = params->accumulatorPoKCommitmentGroup.g;
+       Bignum sh = params->accumulatorPoKCommitmentGroup.h;
+
+       Bignum g_n = params->accumulatorQRNCommitmentGroup.g;
+       Bignum h_n = params->accumulatorQRNCommitmentGroup.h;
+
+       Bignum e = commitmentToCoin.getContents();
+       Bignum r = commitmentToCoin.getRandomness();
+
+       Bignum r_1 = Bignum::randBignum(params->accumulatorModulus/4);
+       Bignum r_2 = Bignum::randBignum(params->accumulatorModulus/4);
+       Bignum r_3 = Bignum::randBignum(params->accumulatorModulus/4);
+
+       this->C_e = g_n.pow_mod(e, params->accumulatorModulus) * h_n.pow_mod(r_1, params->accumulatorModulus);
+       this->C_u = witness.getValue() * h_n.pow_mod(r_2, params->accumulatorModulus);
+       this->C_r = g_n.pow_mod(r_2, params->accumulatorModulus) * h_n.pow_mod(r_3, params->accumulatorModulus);
+
+       Bignum r_alpha = Bignum::randBignum(params->maxCoinValue * Bignum(2).pow(params->k_prime + params->k_dprime));
+       if(!(Bignum::randBignum(Bignum(3)) % 2)) {
+               r_alpha = 0-r_alpha;
+       }
+
+       Bignum r_gamma = Bignum::randBignum(params->accumulatorPoKCommitmentGroup.modulus);
+       Bignum r_phi = Bignum::randBignum(params->accumulatorPoKCommitmentGroup.modulus);
+       Bignum r_psi = Bignum::randBignum(params->accumulatorPoKCommitmentGroup.modulus);
+       Bignum r_sigma = Bignum::randBignum(params->accumulatorPoKCommitmentGroup.modulus);
+       Bignum r_xi = Bignum::randBignum(params->accumulatorPoKCommitmentGroup.modulus);
+
+       Bignum r_epsilon =  Bignum::randBignum((params->accumulatorModulus/4) * Bignum(2).pow(params->k_prime + params->k_dprime));
+       if(!(Bignum::randBignum(Bignum(3)) % 2)) {
+               r_epsilon = 0-r_epsilon;
+       }
+       Bignum r_eta = Bignum::randBignum((params->accumulatorModulus/4) * Bignum(2).pow(params->k_prime + params->k_dprime));
+       if(!(Bignum::randBignum(Bignum(3)) % 2)) {
+               r_eta = 0-r_eta;
+       }
+       Bignum r_zeta = Bignum::randBignum((params->accumulatorModulus/4) * Bignum(2).pow(params->k_prime + params->k_dprime));
+       if(!(Bignum::randBignum(Bignum(3)) % 2)) {
+               r_zeta = 0-r_zeta;
+       }
+
+       Bignum r_beta = Bignum::randBignum((params->accumulatorModulus/4) * params->accumulatorPoKCommitmentGroup.modulus * Bignum(2).pow(params->k_prime + params->k_dprime));
+       if(!(Bignum::randBignum(Bignum(3)) % 2)) {
+               r_beta = 0-r_beta;
+       }
+       Bignum r_delta = Bignum::randBignum((params->accumulatorModulus/4) * params->accumulatorPoKCommitmentGroup.modulus * Bignum(2).pow(params->k_prime + params->k_dprime));
+       if(!(Bignum::randBignum(Bignum(3)) % 2)) {
+               r_delta = 0-r_delta;
+       }
+
+       this->st_1 = (sg.pow_mod(r_alpha, params->accumulatorPoKCommitmentGroup.modulus) * sh.pow_mod(r_phi, params->accumulatorPoKCommitmentGroup.modulus)) % params->accumulatorPoKCommitmentGroup.modulus;
+       this->st_2 = (((commitmentToCoin.getCommitmentValue() * sg.inverse(params->accumulatorPoKCommitmentGroup.modulus)).pow_mod(r_gamma, params->accumulatorPoKCommitmentGroup.modulus)) * sh.pow_mod(r_psi, params->accumulatorPoKCommitmentGroup.modulus)) % params->accumulatorPoKCommitmentGroup.modulus;
+       this->st_3 = ((sg * commitmentToCoin.getCommitmentValue()).pow_mod(r_sigma, params->accumulatorPoKCommitmentGroup.modulus) * sh.pow_mod(r_xi, params->accumulatorPoKCommitmentGroup.modulus)) % params->accumulatorPoKCommitmentGroup.modulus;
+
+       this->t_1 = (h_n.pow_mod(r_zeta, params->accumulatorModulus) * g_n.pow_mod(r_epsilon, params->accumulatorModulus)) % params->accumulatorModulus;
+       this->t_2 = (h_n.pow_mod(r_eta, params->accumulatorModulus) * g_n.pow_mod(r_alpha, params->accumulatorModulus)) % params->accumulatorModulus;
+       this->t_3 = (C_u.pow_mod(r_alpha, params->accumulatorModulus) * ((h_n.inverse(params->accumulatorModulus)).pow_mod(r_beta, params->accumulatorModulus))) % params->accumulatorModulus;
+       this->t_4 = (C_r.pow_mod(r_alpha, params->accumulatorModulus) * ((h_n.inverse(params->accumulatorModulus)).pow_mod(r_delta, params->accumulatorModulus)) * ((g_n.inverse(params->accumulatorModulus)).pow_mod(r_beta, params->accumulatorModulus))) % params->accumulatorModulus;
+
+       CHashWriter hasher(0,0);
+       hasher << *params << sg << sh << g_n << h_n << commitmentToCoin.getCommitmentValue() << C_e << C_u << C_r << st_1 << st_2 << st_3 << t_1 << t_2 << t_3 << t_4;
+
+       //According to the proof, this hash should be of length k_prime bits.  It is currently greater than that, which should not be a problem, but we should check this.
+       Bignum c = Bignum(hasher.GetHash());
+
+       this->s_alpha = r_alpha - c*e;
+       this->s_beta = r_beta - c*r_2*e;
+       this->s_zeta = r_zeta - c*r_3;
+       this->s_sigma = r_sigma - c*((e+1).inverse(params->accumulatorPoKCommitmentGroup.groupOrder));
+       this->s_eta = r_eta - c*r_1;
+       this->s_epsilon = r_epsilon - c*r_2;
+       this->s_delta = r_delta - c*r_3*e;
+       this->s_xi = r_xi + c*r*((e+1).inverse(params->accumulatorPoKCommitmentGroup.groupOrder));
+       this->s_phi = (r_phi - c*r) % params->accumulatorPoKCommitmentGroup.groupOrder;
+       this->s_gamma = r_gamma - c*((e-1).inverse(params->accumulatorPoKCommitmentGroup.groupOrder));
+       this->s_psi = r_psi + c*r*((e-1).inverse(params->accumulatorPoKCommitmentGroup.groupOrder));
+}
+
+/** Verifies that a commitment c is accumulated in accumulator a
+ */
+bool AccumulatorProofOfKnowledge:: Verify(const Accumulator& a, const Bignum& valueOfCommitmentToCoin) const {
+       Bignum sg = params->accumulatorPoKCommitmentGroup.g;
+       Bignum sh = params->accumulatorPoKCommitmentGroup.h;
+
+       Bignum g_n = params->accumulatorQRNCommitmentGroup.g;
+       Bignum h_n = params->accumulatorQRNCommitmentGroup.h;
+
+       //According to the proof, this hash should be of length k_prime bits.  It is currently greater than that, which should not be a problem, but we should check this.
+       CHashWriter hasher(0,0);
+       hasher << *params << sg << sh << g_n << h_n << valueOfCommitmentToCoin << C_e << C_u << C_r << st_1 << st_2 << st_3 << t_1 << t_2 << t_3 << t_4;
+
+       Bignum c = Bignum(hasher.GetHash()); //this hash should be of length k_prime bits
+
+       Bignum st_1_prime = (valueOfCommitmentToCoin.pow_mod(c, params->accumulatorPoKCommitmentGroup.modulus) * sg.pow_mod(s_alpha, params->accumulatorPoKCommitmentGroup.modulus) * sh.pow_mod(s_phi, params->accumulatorPoKCommitmentGroup.modulus)) % params->accumulatorPoKCommitmentGroup.modulus;
+       Bignum st_2_prime = (sg.pow_mod(c, params->accumulatorPoKCommitmentGroup.modulus) * ((valueOfCommitmentToCoin * sg.inverse(params->accumulatorPoKCommitmentGroup.modulus)).pow_mod(s_gamma, params->accumulatorPoKCommitmentGroup.modulus)) * sh.pow_mod(s_psi, params->accumulatorPoKCommitmentGroup.modulus)) % params->accumulatorPoKCommitmentGroup.modulus;
+       Bignum st_3_prime = (sg.pow_mod(c, params->accumulatorPoKCommitmentGroup.modulus) * (sg * valueOfCommitmentToCoin).pow_mod(s_sigma, params->accumulatorPoKCommitmentGroup.modulus) * sh.pow_mod(s_xi, params->accumulatorPoKCommitmentGroup.modulus)) % params->accumulatorPoKCommitmentGroup.modulus;
+
+       Bignum t_1_prime = (C_r.pow_mod(c, params->accumulatorModulus) * h_n.pow_mod(s_zeta, params->accumulatorModulus) * g_n.pow_mod(s_epsilon, params->accumulatorModulus)) % params->accumulatorModulus;
+       Bignum t_2_prime = (C_e.pow_mod(c, params->accumulatorModulus) * h_n.pow_mod(s_eta, params->accumulatorModulus) * g_n.pow_mod(s_alpha, params->accumulatorModulus)) % params->accumulatorModulus;
+       Bignum t_3_prime = ((a.getValue()).pow_mod(c, params->accumulatorModulus) * C_u.pow_mod(s_alpha, params->accumulatorModulus) * ((h_n.inverse(params->accumulatorModulus)).pow_mod(s_beta, params->accumulatorModulus))) % params->accumulatorModulus;
+       Bignum t_4_prime = (C_r.pow_mod(s_alpha, params->accumulatorModulus) * ((h_n.inverse(params->accumulatorModulus)).pow_mod(s_delta, params->accumulatorModulus)) * ((g_n.inverse(params->accumulatorModulus)).pow_mod(s_beta, params->accumulatorModulus))) % params->accumulatorModulus;
+
+       bool result = false;
+
+       bool result_st1 = (st_1 == st_1_prime);
+       bool result_st2 = (st_2 == st_2_prime);
+       bool result_st3 = (st_3 == st_3_prime);
+
+       bool result_t1 = (t_1 == t_1_prime);
+       bool result_t2 = (t_2 == t_2_prime);
+       bool result_t3 = (t_3 == t_3_prime);
+       bool result_t4 = (t_4 == t_4_prime);
+
+       bool result_range = ((s_alpha >= -(params->maxCoinValue * Bignum(2).pow(params->k_prime + params->k_dprime + 1))) && (s_alpha <= (params->maxCoinValue * Bignum(2).pow(params->k_prime + params->k_dprime + 1))));
+
+       result = result_st1 && result_st2 && result_st3 && result_t1 && result_t2 && result_t3 && result_t4 && result_range;
+
+       return result;
+}
+
+} /* namespace libzerocoin */
diff --git a/src/zerocoin/AccumulatorProofOfKnowledge.h b/src/zerocoin/AccumulatorProofOfKnowledge.h
new file mode 100644 (file)
index 0000000..4078940
--- /dev/null
@@ -0,0 +1,91 @@
+/**
+ * @file       AccumulatorProofOfKnowledge.h
+ *
+ * @brief      AccumulatorProofOfKnowledge class for the Zerocoin library.
+ *
+ * @author     Ian Miers, Christina Garman and Matthew Green
+ * @date       June 2013
+ *
+ * @copyright  Copyright 2013 Ian Miers, Christina Garman and Matthew Green
+ * @license    This project is released under the MIT license.
+ **/
+
+#ifndef ACCUMULATEPROOF_H_
+#define ACCUMULATEPROOF_H_
+
+namespace libzerocoin {
+
+/**A prove that a value insde the commitment commitmentToCoin is in an accumulator a.
+ *
+ */
+class AccumulatorProofOfKnowledge {
+public:
+       AccumulatorProofOfKnowledge(const AccumulatorAndProofParams* p);
+
+       /** Generates a proof that a commitment to a coin c was accumulated
+        * @param p  Cryptographic parameters
+        * @param commitmentToCoin commitment containing the coin we want to prove is accumulated
+        * @param witness The witness to the accumulation of the coin
+        * @param a
+        */
+       AccumulatorProofOfKnowledge(const AccumulatorAndProofParams* p, const Commitment& commitmentToCoin, const AccumulatorWitness& witness, Accumulator& a);
+       /** Verifies that  a commitment c is accumulated in accumulated a
+        */
+       bool Verify(const Accumulator& a,const Bignum& valueOfCommitmentToCoin) const;
+
+       IMPLEMENT_SERIALIZE
+       (
+           READWRITE(C_e);
+           READWRITE(C_u);
+           READWRITE(C_r);
+           READWRITE(st_1);
+           READWRITE(st_2);
+           READWRITE(st_3);
+           READWRITE(t_1);
+           READWRITE(t_2);
+           READWRITE(t_3);
+           READWRITE(t_4);
+           READWRITE(s_alpha);
+           READWRITE(s_beta);
+           READWRITE(s_zeta);
+           READWRITE(s_sigma);
+           READWRITE(s_eta);
+           READWRITE(s_epsilon);
+           READWRITE(s_delta);
+           READWRITE(s_xi);
+           READWRITE(s_phi);
+           READWRITE(s_gamma);
+           READWRITE(s_psi);
+       )
+private:
+       const AccumulatorAndProofParams* params;
+
+       /* Return values for proof */
+       Bignum C_e;
+       Bignum C_u;
+       Bignum C_r;
+
+       Bignum st_1;
+       Bignum st_2;
+       Bignum st_3;
+
+       Bignum t_1;
+       Bignum t_2;
+       Bignum t_3;
+       Bignum t_4;
+
+       Bignum s_alpha;
+       Bignum s_beta;
+       Bignum s_zeta;
+       Bignum s_sigma;
+       Bignum s_eta;
+       Bignum s_epsilon;
+       Bignum s_delta;
+       Bignum s_xi;
+       Bignum s_phi;
+       Bignum s_gamma;
+       Bignum s_psi;
+};
+
+} /* namespace libzerocoin */
+#endif /* ACCUMULATEPROOF_H_ */
diff --git a/src/zerocoin/Coin.cpp b/src/zerocoin/Coin.cpp
new file mode 100644 (file)
index 0000000..4841c5e
--- /dev/null
@@ -0,0 +1,167 @@
+/**
+ * @file       Coin.cpp
+ *
+ * @brief      PublicCoin and PrivateCoin classes for the Zerocoin library.
+ *
+ * @author     Ian Miers, Christina Garman and Matthew Green
+ * @date       June 2013
+ *
+ * @copyright  Copyright 2013 Ian Miers, Christina Garman and Matthew Green
+ * @license    This project is released under the MIT license.
+ **/
+
+#include <stdexcept>
+#include "Zerocoin.h"
+
+namespace libzerocoin {
+
+//PublicCoin class
+PublicCoin::PublicCoin(const Params* p):
+       params(p), denomination(ZQ_LOVELACE) {
+       if(this->params->initialized == false) {
+               throw std::invalid_argument("Params are not initialized");
+       }
+};
+
+PublicCoin::PublicCoin(const Params* p, const Bignum& coin, const CoinDenomination d):
+       params(p), value(coin), denomination(d) {
+       if(this->params->initialized == false) {
+               throw std::invalid_argument("Params are not initialized");
+       }
+};
+
+bool PublicCoin::operator==(const PublicCoin& rhs) const {
+       return this->value == rhs.value;// FIXME check param equality
+}
+
+bool PublicCoin::operator!=(const PublicCoin& rhs) const {
+       return !(*this == rhs);
+}
+
+const Bignum& PublicCoin::getValue() const {
+       return this->value;
+}
+
+const CoinDenomination PublicCoin::getDenomination() const {
+       return static_cast<CoinDenomination>(this->denomination);
+}
+
+bool PublicCoin::validate() const {
+       return (this->params->accumulatorParams.minCoinValue < value) && (value < this->params->accumulatorParams.maxCoinValue) && value.isPrime(params->zkp_iterations);
+}
+
+//PrivateCoin class
+PrivateCoin::PrivateCoin(const Params* p, const CoinDenomination denomination): params(p), publicCoin(p) {
+       // Verify that the parameters are valid
+       if(this->params->initialized == false) {
+               throw std::invalid_argument("Params are not initialized");
+       }
+
+#ifdef ZEROCOIN_FAST_MINT
+       // Mint a new coin with a random serial number using the fast process.
+       // This is more vulnerable to timing attacks so don't mint coins when
+       // somebody could be timing you.
+       this->mintCoinFast(denomination);
+#else
+       // Mint a new coin with a random serial number using the standard process.
+       this->mintCoin(denomination);
+#endif
+       
+}
+
+/**
+ *
+ * @return the coins serial number
+ */
+const Bignum& PrivateCoin::getSerialNumber() const {
+       return this->serialNumber;
+}
+
+const Bignum& PrivateCoin::getRandomness() const {
+       return this->randomness;
+}
+
+void PrivateCoin::mintCoin(const CoinDenomination denomination) {
+       // Repeat this process up to MAX_COINMINT_ATTEMPTS times until
+       // we obtain a prime number
+       for(uint32_t attempt = 0; attempt < MAX_COINMINT_ATTEMPTS; attempt++) {
+
+               // Generate a random serial number in the range 0...{q-1} where
+               // "q" is the order of the commitment group.
+               Bignum s = Bignum::randBignum(this->params->coinCommitmentGroup.groupOrder);
+
+               // Generate a Pedersen commitment to the serial number "s"
+               Commitment coin(&params->coinCommitmentGroup, s);
+
+               // Now verify that the commitment is a prime number
+               // in the appropriate range. If not, we'll throw this coin
+               // away and generate a new one.
+               if (coin.getCommitmentValue().isPrime(ZEROCOIN_MINT_PRIME_PARAM) &&
+                       coin.getCommitmentValue() >= params->accumulatorParams.minCoinValue &&
+                       coin.getCommitmentValue() <= params->accumulatorParams.maxCoinValue) {
+                       // Found a valid coin. Store it.
+                       this->serialNumber = s;
+                       this->randomness = coin.getRandomness();
+                       this->publicCoin = PublicCoin(params,coin.getCommitmentValue(), denomination);
+
+                       // Success! We're done.
+                       return;
+               }
+       }
+
+       // We only get here if we did not find a coin within
+       // MAX_COINMINT_ATTEMPTS. Throw an exception.
+       throw ZerocoinException("Unable to mint a new Zerocoin (too many attempts)");
+}
+
+void PrivateCoin::mintCoinFast(const CoinDenomination denomination) {
+       
+       // Generate a random serial number in the range 0...{q-1} where
+       // "q" is the order of the commitment group.
+       Bignum s = Bignum::randBignum(this->params->coinCommitmentGroup.groupOrder);
+       
+       // Generate a random number "r" in the range 0...{q-1}
+       Bignum r = Bignum::randBignum(this->params->coinCommitmentGroup.groupOrder);
+       
+       // Manually compute a Pedersen commitment to the serial number "s" under randomness "r"
+       // C = g^s * h^r mod p
+       Bignum commitmentValue = this->params->coinCommitmentGroup.g.pow_mod(s, this->params->coinCommitmentGroup.modulus).mul_mod(this->params->coinCommitmentGroup.h.pow_mod(r, this->params->coinCommitmentGroup.modulus), this->params->coinCommitmentGroup.modulus);
+       
+       // Repeat this process up to MAX_COINMINT_ATTEMPTS times until
+       // we obtain a prime number
+       for (uint32_t attempt = 0; attempt < MAX_COINMINT_ATTEMPTS; attempt++) {
+               // First verify that the commitment is a prime number
+               // in the appropriate range. If not, we'll throw this coin
+               // away and generate a new one.
+               if (commitmentValue.isPrime(ZEROCOIN_MINT_PRIME_PARAM) &&
+                       commitmentValue >= params->accumulatorParams.minCoinValue &&
+                       commitmentValue <= params->accumulatorParams.maxCoinValue) {
+                       // Found a valid coin. Store it.
+                       this->serialNumber = s;
+                       this->randomness = r;
+                       this->publicCoin = PublicCoin(params, commitmentValue, denomination);
+                               
+                       // Success! We're done.
+                       return;
+               }
+               
+               // Generate a new random "r_delta" in 0...{q-1}
+               Bignum r_delta = Bignum::randBignum(this->params->coinCommitmentGroup.groupOrder);
+
+               // The commitment was not prime. Increment "r" and recalculate "C":
+               // r = r + r_delta mod q
+               // C = C * h mod p
+               r = (r + r_delta) % this->params->coinCommitmentGroup.groupOrder;
+               commitmentValue = commitmentValue.mul_mod(this->params->coinCommitmentGroup.h.pow_mod(r_delta, this->params->coinCommitmentGroup.modulus), this->params->coinCommitmentGroup.modulus);
+       }
+               
+       // We only get here if we did not find a coin within
+       // MAX_COINMINT_ATTEMPTS. Throw an exception.
+       throw ZerocoinException("Unable to mint a new Zerocoin (too many attempts)");
+}
+       
+const PublicCoin& PrivateCoin::getPublicCoin() const {
+       return this->publicCoin;
+}
+
+} /* namespace libzerocoin */
diff --git a/src/zerocoin/Coin.h b/src/zerocoin/Coin.h
new file mode 100644 (file)
index 0000000..e862aad
--- /dev/null
@@ -0,0 +1,139 @@
+/**
+ * @file       Coin.h
+ *
+ * @brief      PublicCoin and PrivateCoin classes for the Zerocoin library.
+ *
+ * @author     Ian Miers, Christina Garman and Matthew Green
+ * @date       June 2013
+ *
+ * @copyright  Copyright 2013 Ian Miers, Christina Garman and Matthew Green
+ * @license    This project is released under the MIT license.
+ **/
+
+#ifndef COIN_H_
+#define COIN_H_
+#include "../bignum.h"
+#include "Params.h"
+namespace libzerocoin {
+
+enum  CoinDenomination {
+    ZQ_LOVELACE = 1,
+    ZQ_GOLDWASSER = 10,
+    ZQ_RACKOFF = 25,
+    ZQ_PEDERSEN = 50,
+    ZQ_WILLIAMSON = 100 // Malcolm J. Williamson,
+                    // the scientist who actually invented
+                    // Public key cryptography
+};
+
+/** A Public coin is the part of a coin that
+ * is published to the network and what is handled
+ * by other clients. It contains only the value
+ * of commitment to a serial number and the
+ * denomination of the coin.
+ */
+class PublicCoin {
+public:
+       template<typename Stream>
+       PublicCoin(const Params* p, Stream& strm): params(p) {
+               strm >> *this;
+       }
+
+       PublicCoin( const Params* p);
+
+       /**Generates a public coin
+        *
+        * @param p cryptographic paramters
+        * @param coin the value of the commitment.
+        * @param denomination The denomination of the coin. Defaults to ZQ_LOVELACE
+        */
+       PublicCoin( const Params* p, const Bignum& coin, const CoinDenomination d = ZQ_LOVELACE);
+       const Bignum& getValue() const;
+       const CoinDenomination getDenomination() const;
+       bool operator==(const PublicCoin& rhs) const;
+       bool operator!=(const PublicCoin& rhs) const;
+       /** Checks that a coin prime
+        *  and in the appropriate range
+        *  given the parameters
+        * @return true if valid
+        */
+       bool validate() const;
+       IMPLEMENT_SERIALIZE
+       (
+           READWRITE(value);
+           READWRITE(denomination);
+       )
+private:
+       const Params* params;
+       Bignum value;
+       // Denomination is stored as an INT because storing
+       // and enum raises amigiuities in the serialize code //FIXME if possible
+       int denomination;
+};
+
+/**
+ * A private coin. As the name implies, the content
+ * of this should stay private except PublicCoin.
+ *
+ * Contains a coin's serial number, a commitment to it,
+ * and opening randomness for the commitment.
+ *
+ * @warning Failure to keep this secret(or safe),
+ * @warning will result in the theft of your coins
+ * @warning and a TOTAL loss of anonymity.
+ */
+class PrivateCoin {
+public:
+       template<typename Stream>
+       PrivateCoin(const Params* p, Stream& strm): params(p) {
+               strm >> *this;
+       }
+       PrivateCoin(const Params* p,const CoinDenomination denomination = ZQ_LOVELACE);
+       const PublicCoin& getPublicCoin() const;
+       const Bignum& getSerialNumber() const;
+       const Bignum& getRandomness() const;
+
+       IMPLEMENT_SERIALIZE
+       (
+           READWRITE(publicCoin);
+           READWRITE(randomness);
+           READWRITE(serialNumber);
+       )
+private:
+       const Params* params;
+       PublicCoin publicCoin;
+       Bignum randomness;
+       Bignum serialNumber;
+
+       /**
+        * @brief Mint a new coin.
+        * @param denomination the denomination of the coin to mint
+        * @throws ZerocoinException if the process takes too long
+        *
+        * Generates a new Zerocoin by (a) selecting a random serial
+        * number, (b) committing to this serial number and repeating until
+        * the resulting commitment is prime. Stores the
+        * resulting commitment (coin) and randomness (trapdoor).
+        **/
+       void mintCoin(const CoinDenomination denomination);
+       
+       /**
+        * @brief Mint a new coin using a faster process.
+        * @param denomination the denomination of the coin to mint
+        * @throws ZerocoinException if the process takes too long
+        *
+        * Generates a new Zerocoin by (a) selecting a random serial
+        * number, (b) committing to this serial number and repeating until
+        * the resulting commitment is prime. Stores the
+        * resulting commitment (coin) and randomness (trapdoor).
+        * This routine is substantially faster than the
+        * mintCoin() routine, but could be more vulnerable
+        * to timing attacks. Don't use it if you think someone
+        * could be timing your coin minting.
+        **/
+       void mintCoinFast(const CoinDenomination denomination);
+
+};
+
+} /* namespace libzerocoin */
+#endif /* COIN_H_ */
diff --git a/src/zerocoin/CoinSpend.cpp b/src/zerocoin/CoinSpend.cpp
new file mode 100644 (file)
index 0000000..c7890f5
--- /dev/null
@@ -0,0 +1,82 @@
+/**
+ * @file       CoinSpend.cpp
+ *
+ * @brief      CoinSpend class for the Zerocoin library.
+ *
+ * @author     Ian Miers, Christina Garman and Matthew Green
+ * @date       June 2013
+ *
+ * @copyright  Copyright 2013 Ian Miers, Christina Garman and Matthew Green
+ * @license    This project is released under the MIT license.
+ **/
+
+#include "Zerocoin.h"
+
+namespace libzerocoin {
+
+CoinSpend::CoinSpend(const Params* p, const PrivateCoin& coin,
+                     Accumulator& a, const AccumulatorWitness& witness, const SpendMetaData& m):
+       params(p),
+       denomination(coin.getPublicCoin().getDenomination()),
+       coinSerialNumber((coin.getSerialNumber())),
+       accumulatorPoK(&p->accumulatorParams),
+       serialNumberSoK(p),
+       commitmentPoK(&p->serialNumberSoKCommitmentGroup, &p->accumulatorParams.accumulatorPoKCommitmentGroup) {
+
+       // Sanity check: let's verify that the Witness is valid with respect to
+       // the coin and Accumulator provided.
+       if (!(witness.VerifyWitness(a, coin.getPublicCoin()))) {
+               throw std::invalid_argument("Accumulator witness does not verify");
+       }
+
+       // 1: Generate two separate commitments to the public coin (C), each under
+       // a different set of public parameters. We do this because the RSA accumulator
+       // has specific requirements for the commitment parameters that are not
+       // compatible with the group we use for the serial number proof.
+       // Specifically, our serial number proof requires the order of the commitment group
+       // to be the same as the modulus of the upper group. The Accumulator proof requires a
+       // group with a significantly larger order.
+       const Commitment fullCommitmentToCoinUnderSerialParams(&p->serialNumberSoKCommitmentGroup, coin.getPublicCoin().getValue());
+       this->serialCommitmentToCoinValue = fullCommitmentToCoinUnderSerialParams.getCommitmentValue();
+
+       const Commitment fullCommitmentToCoinUnderAccParams(&p->accumulatorParams.accumulatorPoKCommitmentGroup, coin.getPublicCoin().getValue());
+       this->accCommitmentToCoinValue = fullCommitmentToCoinUnderAccParams.getCommitmentValue();
+
+       // 2. Generate a ZK proof that the two commitments contain the same public coin.
+       this->commitmentPoK = CommitmentProofOfKnowledge(&p->serialNumberSoKCommitmentGroup, &p->accumulatorParams.accumulatorPoKCommitmentGroup, fullCommitmentToCoinUnderSerialParams, fullCommitmentToCoinUnderAccParams);
+
+       // Now generate the two core ZK proofs:
+       // 3. Proves that the committed public coin is in the Accumulator (PoK of "witness")
+       this->accumulatorPoK = AccumulatorProofOfKnowledge(&p->accumulatorParams, fullCommitmentToCoinUnderAccParams, witness, a);
+
+       // 4. Proves that the coin is correct w.r.t. serial number and hidden coin secret
+       // (This proof is bound to the coin 'metadata', i.e., transaction hash)
+       this->serialNumberSoK = SerialNumberSignatureOfKnowledge(p, coin, fullCommitmentToCoinUnderSerialParams, signatureHash(m));
+}
+
+const Bignum&
+CoinSpend::getCoinSerialNumber() {
+       return this->coinSerialNumber;
+}
+
+const CoinDenomination
+CoinSpend::getDenomination() {
+       return static_cast<CoinDenomination>(this->denomination);
+}
+
+bool
+CoinSpend::Verify(const Accumulator& a, const SpendMetaData &m) const {
+       // Verify both of the sub-proofs using the given meta-data
+       return  (a.getDenomination() == this->denomination)
+               && commitmentPoK.Verify(serialCommitmentToCoinValue, accCommitmentToCoinValue)
+               && accumulatorPoK.Verify(a, accCommitmentToCoinValue)
+               && serialNumberSoK.Verify(coinSerialNumber, serialCommitmentToCoinValue, signatureHash(m));
+}
+
+const uint256 CoinSpend::signatureHash(const SpendMetaData &m) const {
+       CHashWriter h(0,0);
+       h << m << serialCommitmentToCoinValue << accCommitmentToCoinValue << commitmentPoK << accumulatorPoK;
+       return h.GetHash();
+}
+
+} /* namespace libzerocoin */
diff --git a/src/zerocoin/CoinSpend.h b/src/zerocoin/CoinSpend.h
new file mode 100644 (file)
index 0000000..c8d20b9
--- /dev/null
@@ -0,0 +1,107 @@
+/**
+ * @file       CoinSpend.h
+ *
+ * @brief      CoinSpend class for the Zerocoin library.
+ *
+ * @author     Ian Miers, Christina Garman and Matthew Green
+ * @date       June 2013
+ *
+ * @copyright  Copyright 2013 Ian Miers, Christina Garman and Matthew Green
+ * @license    This project is released under the MIT license.
+ **/
+
+#ifndef COINSPEND_H_
+#define COINSPEND_H_
+
+#include "Params.h"
+#include "Coin.h"
+#include "Commitment.h"
+#include "../bignum.h"
+#include "Accumulator.h"
+#include "AccumulatorProofOfKnowledge.h"
+#include "SerialNumberSignatureOfKnowledge.h"
+#include "SpendMetaData.h"
+#include "../serialize.h"
+
+namespace libzerocoin {
+
+/** The complete proof needed to spend a zerocoin.
+ * Composes together a proof that a coin is accumulated
+ * and that it has a given serial number.
+ */
+class CoinSpend {
+public:
+       template<typename Stream>
+       CoinSpend(const Params* p,  Stream& strm):denomination(ZQ_LOVELACE),
+               accumulatorPoK(&p->accumulatorParams),
+               serialNumberSoK(p),
+               commitmentPoK(&p->serialNumberSoKCommitmentGroup, &p->accumulatorParams.accumulatorPoKCommitmentGroup) {
+               strm >> *this;
+       }
+       /**Generates a proof spending a zerocoin.
+        *
+        * To use this, provide an unspent PrivateCoin, the latest Accumulator
+        * (e.g from the most recent Bitcoin block) containing the public part
+        * of the coin, a witness to that, and whatever medeta data is needed.
+        *
+        * Once constructed, this proof can be serialized and sent.
+        * It is validated simply be calling validate.
+        * @warning Validation only checks that the proof is correct
+        * @warning for the specified values in this class. These values must be validated
+        *  Clients ought to check that
+        * 1) params is the right params
+        * 2) the accumulator actually is in some block
+        * 3) that the serial number is unspent
+        * 4) that the transaction
+        *
+        * @param p cryptographic parameters
+        * @param coin The coin to be spend
+        * @param a The current accumulator containing the coin
+        * @param witness The witness showing that the accumulator contains the coin
+        * @param m arbitrary meta data related to the spend that might be needed by Bitcoin
+        *                      (i.e. the transaction hash)
+        * @throw ZerocoinException if the process fails
+        */
+       CoinSpend(const Params* p, const PrivateCoin& coin, Accumulator& a, const AccumulatorWitness& witness, const SpendMetaData& m);
+
+       /** Returns the serial number of the coin spend by this proof.
+        *
+        * @return the coin's serial number
+        */
+       const Bignum& getCoinSerialNumber();
+
+       /**Gets the denomination of the coin spent in this proof.
+        *
+        * @return the denomination
+        */
+       const CoinDenomination getDenomination();
+
+       bool Verify(const Accumulator& a, const SpendMetaData &metaData) const;
+
+       IMPLEMENT_SERIALIZE
+       (
+           READWRITE(denomination);
+           READWRITE(accCommitmentToCoinValue);
+           READWRITE(serialCommitmentToCoinValue);
+           READWRITE(coinSerialNumber);
+           READWRITE(accumulatorPoK);
+           READWRITE(serialNumberSoK);
+           READWRITE(commitmentPoK);
+       )
+
+private:
+       const Params *params;
+       const uint256 signatureHash(const SpendMetaData &m) const;
+       // Denomination is stored as an INT because storing
+       // and enum raises amigiuities in the serialize code //FIXME if possible
+       int denomination;
+       Bignum accCommitmentToCoinValue;
+       Bignum serialCommitmentToCoinValue;
+       Bignum coinSerialNumber;
+       AccumulatorProofOfKnowledge accumulatorPoK;
+       SerialNumberSignatureOfKnowledge serialNumberSoK;
+       CommitmentProofOfKnowledge commitmentPoK;
+};
+
+} /* namespace libzerocoin */
+#endif /* COINSPEND_H_ */
diff --git a/src/zerocoin/Commitment.cpp b/src/zerocoin/Commitment.cpp
new file mode 100644 (file)
index 0000000..50e7fcd
--- /dev/null
@@ -0,0 +1,172 @@
+/**
+ * @file       Commitment.cpp
+ *
+ * @brief      Commitment and CommitmentProof classes for the Zerocoin library.
+ *
+ * @author     Ian Miers, Christina Garman and Matthew Green
+ * @date       June 2013
+ *
+ * @copyright  Copyright 2013 Ian Miers, Christina Garman and Matthew Green
+ * @license    This project is released under the MIT license.
+ **/
+
+#include <stdlib.h>
+#include "Zerocoin.h"
+
+namespace libzerocoin {
+
+//Commitment class
+Commitment::Commitment::Commitment(const IntegerGroupParams* p,
+                                   const Bignum& value): params(p), contents(value) {
+       this->randomness = Bignum::randBignum(params->groupOrder);
+       this->commitmentValue = (params->g.pow_mod(this->contents, params->modulus).mul_mod(
+                                params->h.pow_mod(this->randomness, params->modulus), params->modulus));
+}
+
+const Bignum& Commitment::getCommitmentValue() const {
+       return this->commitmentValue;
+}
+
+const Bignum& Commitment::getRandomness() const {
+       return this->randomness;
+}
+
+const Bignum& Commitment::getContents() const {
+       return this->contents;
+}
+
+//CommitmentProofOfKnowledge class
+CommitmentProofOfKnowledge::CommitmentProofOfKnowledge(const IntegerGroupParams* ap, const IntegerGroupParams* bp): ap(ap), bp(bp) {}
+
+// TODO: get parameters from the commitment group
+CommitmentProofOfKnowledge::CommitmentProofOfKnowledge(const IntegerGroupParams* aParams,
+        const IntegerGroupParams* bParams, const Commitment& a, const Commitment& b):
+       ap(aParams),bp(bParams)
+{
+       Bignum r1, r2, r3;
+
+       // First: make sure that the two commitments have the
+       // same contents.
+       if (a.getContents() != b.getContents()) {
+               throw std::invalid_argument("Both commitments must contain the same value");
+       }
+
+       // Select three random values "r1, r2, r3" in the range 0 to (2^l)-1 where l is:
+       // length of challenge value + max(modulus 1, modulus 2, order 1, order 2) + margin.
+       // We set "margin" to be a relatively generous  security parameter.
+       //
+       // We choose these large values to ensure statistical zero knowledge.
+       uint32_t randomSize = COMMITMENT_EQUALITY_CHALLENGE_SIZE + COMMITMENT_EQUALITY_SECMARGIN +
+                             std::max(std::max(this->ap->modulus.bitSize(), this->bp->modulus.bitSize()),
+                                      std::max(this->ap->groupOrder.bitSize(), this->bp->groupOrder.bitSize()));
+       Bignum maxRange = (Bignum(2).pow(randomSize) - Bignum(1));
+
+       r1 = Bignum::randBignum(maxRange);
+       r2 = Bignum::randBignum(maxRange);
+       r3 = Bignum::randBignum(maxRange);
+
+       // Generate two random, ephemeral commitments "T1, T2"
+       // of the form:
+       // T1 = g1^r1 * h1^r2 mod p1
+       // T2 = g2^r1 * h2^r3 mod p2
+       //
+       // Where (g1, h1, p1) are from "aParams" and (g2, h2, p2) are from "bParams".
+       Bignum T1 = this->ap->g.pow_mod(r1, this->ap->modulus).mul_mod((this->ap->h.pow_mod(r2, this->ap->modulus)), this->ap->modulus);
+       Bignum T2 = this->bp->g.pow_mod(r1, this->bp->modulus).mul_mod((this->bp->h.pow_mod(r3, this->bp->modulus)), this->bp->modulus);
+
+       // Now hash commitment "A" with commitment "B" as well as the
+       // parameters and the two ephemeral commitments "T1, T2" we just generated
+       this->challenge = calculateChallenge(a.getCommitmentValue(), b.getCommitmentValue(), T1, T2);
+
+       // Let "m" be the contents of the commitments "A, B". We have:
+       // A =  g1^m  * h1^x  mod p1
+       // B =  g2^m  * h2^y  mod p2
+       // T1 = g1^r1 * h1^r2 mod p1
+       // T2 = g2^r1 * h2^r3 mod p2
+       //
+       // Now compute:
+       //  S1 = r1 + (m * challenge)   -- note, not modular arithmetic
+       //  S2 = r2 + (x * challenge)   -- note, not modular arithmetic
+       //  S3 = r3 + (y * challenge)   -- note, not modular arithmetic
+       this->S1 = r1 + (a.getContents() * this->challenge);
+       this->S2 = r2 + (a.getRandomness() * this->challenge);
+       this->S3 = r3 + (b.getRandomness() * this->challenge);
+
+       // We're done. The proof is S1, S2, S3 and "challenge", all of which
+       // are stored in member variables.
+}
+
+bool CommitmentProofOfKnowledge::Verify(const Bignum& A, const Bignum& B) const
+{
+       // Compute the maximum range of S1, S2, S3 and verify that the given values are
+       // in a correct range. This might be an unnecessary check.
+       uint32_t maxSize = 64 * (COMMITMENT_EQUALITY_CHALLENGE_SIZE + COMMITMENT_EQUALITY_SECMARGIN +
+                                std::max(std::max(this->ap->modulus.bitSize(), this->bp->modulus.bitSize()),
+                                         std::max(this->ap->groupOrder.bitSize(), this->bp->groupOrder.bitSize())));
+
+       if ((uint32_t)this->S1.bitSize() > maxSize ||
+               (uint32_t)this->S2.bitSize() > maxSize ||
+               (uint32_t)this->S3.bitSize() > maxSize ||
+               this->S1 < Bignum(0) ||
+               this->S2 < Bignum(0) ||
+               this->S3 < Bignum(0) ||
+               this->challenge < Bignum(0) ||
+               this->challenge > (Bignum(2).pow(COMMITMENT_EQUALITY_CHALLENGE_SIZE) - Bignum(1))) {
+               // Invalid inputs. Reject.
+               return false;
+       }
+
+       // Compute T1 = g1^S1 * h1^S2 * inverse(A^{challenge}) mod p1
+       Bignum T1 = A.pow_mod(this->challenge, ap->modulus).inverse(ap->modulus).mul_mod(
+                       (ap->g.pow_mod(S1, ap->modulus).mul_mod(ap->h.pow_mod(S2, ap->modulus), ap->modulus)),
+                       ap->modulus);
+
+       // Compute T2 = g2^S1 * h2^S3 * inverse(B^{challenge}) mod p2
+       Bignum T2 = B.pow_mod(this->challenge, bp->modulus).inverse(bp->modulus).mul_mod(
+                       (bp->g.pow_mod(S1, bp->modulus).mul_mod(bp->h.pow_mod(S3, bp->modulus), bp->modulus)),
+                       bp->modulus);
+
+       // Hash T1 and T2 along with all of the public parameters
+       Bignum computedChallenge = calculateChallenge(A, B, T1, T2);
+
+       // Return success if the computed challenge matches the incoming challenge
+       if(computedChallenge == this->challenge) {
+               return true;
+       }
+
+       // Otherwise return failure
+       return false;
+}
+
+const Bignum CommitmentProofOfKnowledge::calculateChallenge(const Bignum& a, const Bignum& b, const Bignum &commitOne, const Bignum &commitTwo) const {
+       CHashWriter hasher(0,0);
+
+       // Hash together the following elements:
+       // * A string identifying the proof
+       // * Commitment A
+       // * Commitment B
+       // * Ephemeral commitment T1
+       // * Ephemeral commitment T2
+       // * A serialized instance of the commitment A parameters
+       // * A serialized instance of the commitment B parameters
+
+       hasher << std::string(ZEROCOIN_COMMITMENT_EQUALITY_PROOF);
+       hasher << commitOne;
+       hasher << std::string("||");
+       hasher << commitTwo;
+       hasher << std::string("||");
+       hasher << a;
+       hasher << std::string("||");
+       hasher << b;
+       hasher << std::string("||");
+       hasher << *(this->ap);
+       hasher << std::string("||");
+       hasher << *(this->bp);
+
+       // Convert the SHA256 result into a Bignum
+       // Note that if we ever change the size of the hash function we will have
+       // to update COMMITMENT_EQUALITY_CHALLENGE_SIZE appropriately!
+       return Bignum(hasher.GetHash());
+}
+
+} /* namespace libzerocoin */
diff --git a/src/zerocoin/Commitment.h b/src/zerocoin/Commitment.h
new file mode 100644 (file)
index 0000000..d8630a3
--- /dev/null
@@ -0,0 +1,105 @@
+/**
+ * @file       Commitment.h
+ *
+ * @brief      Commitment and CommitmentProof classes for the Zerocoin library.
+ *
+ * @author     Ian Miers, Christina Garman and Matthew Green
+ * @date       June 2013
+ *
+ * @copyright  Copyright 2013 Ian Miers, Christina Garman and Matthew Green
+ * @license    This project is released under the MIT license.
+ **/
+
+#ifndef COMMITMENT_H_
+#define COMMITMENT_H_
+
+#include "Params.h"
+#include "../serialize.h"
+
+// We use a SHA256 hash for our PoK challenges. Update the following
+// if we ever change hash functions.
+#define COMMITMENT_EQUALITY_CHALLENGE_SIZE  256
+
+// A 512-bit security parameter for the statistical ZK PoK.
+#define COMMITMENT_EQUALITY_SECMARGIN       512
+
+namespace libzerocoin {
+
+/**
+ * A commitment, complete with contents and opening randomness.
+ * These should remain secret. Publish only the commitment value.
+ */
+class Commitment {
+public:
+       /**Generates a Pedersen commitment to the given value.
+        *
+        * @param p the group parameters for the coin
+        * @param value the value to commit to
+        */
+       Commitment(const IntegerGroupParams* p, const Bignum& value);
+       const Bignum& getCommitmentValue() const;
+       const Bignum& getRandomness() const;
+       const Bignum& getContents() const;
+private:
+       const IntegerGroupParams *params;
+       Bignum commitmentValue;
+       Bignum randomness;
+       const Bignum contents;
+       IMPLEMENT_SERIALIZE
+       (
+           READWRITE(commitmentValue);
+           READWRITE(randomness);
+           READWRITE(contents);
+       )
+};
+
+/**Proof that two commitments open to the same value.
+ *
+ */
+class CommitmentProofOfKnowledge {
+public:
+       CommitmentProofOfKnowledge(const IntegerGroupParams* ap, const IntegerGroupParams* bp);
+       /** Generates a proof that two commitments, a and b, open to the same value.
+        *
+        * @param ap the IntegerGroup for commitment a
+        * @param bp the IntegerGroup for commitment b
+        * @param a the first commitment
+        * @param b the second commitment
+        */
+       CommitmentProofOfKnowledge(const IntegerGroupParams* aParams, const IntegerGroupParams* bParams, const Commitment& a, const Commitment& b);
+       //FIXME: is it best practice that this is here?
+       template<typename Stream>
+       CommitmentProofOfKnowledge(const IntegerGroupParams* aParams,
+                                  const IntegerGroupParams* bParams, Stream& strm): ap(aParams), bp(bParams)
+       {
+               strm >> *this;
+       }
+
+       const Bignum calculateChallenge(const Bignum& a, const Bignum& b, const Bignum &commitOne, const Bignum &commitTwo) const;
+
+       /**Verifies the proof
+        *
+        * @return true if the proof is valid.
+        */
+       /**Verifies the proof of equality of the two commitments
+        *
+        * @param A value of commitment one
+        * @param B value of commitment two
+        * @return
+        */
+       bool Verify(const Bignum& A, const Bignum& B) const;
+       IMPLEMENT_SERIALIZE
+       (
+           READWRITE(S1);
+           READWRITE(S2);
+           READWRITE(S3);
+           READWRITE(challenge);
+       )
+private:
+       const IntegerGroupParams *ap, *bp;
+
+       Bignum S1, S2, S3, challenge;
+};
+
+} /* namespace libzerocoin */
+#endif /* COMMITMENT_H_ */
diff --git a/src/zerocoin/ParamGeneration.cpp b/src/zerocoin/ParamGeneration.cpp
new file mode 100644 (file)
index 0000000..d5bd36b
--- /dev/null
@@ -0,0 +1,654 @@
+/// \file       ParamGeneration.cpp
+///
+/// \brief      Parameter manipulation routines for the Zerocoin cryptographic
+///             components.
+///
+/// \author     Ian Miers, Christina Garman and Matthew Green
+/// \date       June 2013
+///
+/// \copyright  Copyright 2013 Ian Miers, Christina Garman and Matthew Green
+/// \license    This project is released under the MIT license.
+
+#include <string>
+#include "Zerocoin.h"
+
+using namespace std;
+
+namespace libzerocoin {
+
+/// \brief Fill in a set of Zerocoin parameters from a modulus "N".
+/// \param N                A trusted RSA modulus
+/// \param aux              An optional auxiliary string used in derivation
+/// \param securityLevel    A security level
+///
+/// \throws         ZerocoinException if the process fails
+///
+/// Fills in a ZC_Params data structure deterministically from
+/// a trustworthy RSA modulus "N", which is provided as a Bignum.
+///
+/// Note: this routine makes the fundamental assumption that "N"
+/// encodes a valid RSA-style modulus of the form "e1*e2" for some
+/// unknown safe primes "e1" and "e2". These factors must not
+/// be known to any party, or the security of Zerocoin is
+/// compromised. The integer "N" must be a MINIMUM of 1023
+/// in length, and 3072 bits is strongly recommended.
+///
+
+void
+CalculateParams(Params &params, Bignum N, string aux, uint32_t securityLevel)
+{
+       params.initialized = false;
+       params.accumulatorParams.initialized = false;
+
+       // Verify that |N| is > 1023 bits.
+       uint32_t NLen = N.bitSize();
+       if (NLen < 1023) {
+               throw ZerocoinException("Modulus must be at least 1023 bits");
+       }
+
+       // Verify that "securityLevel" is  at least 80 bits (minimum).
+       if (securityLevel < 80) {
+               throw ZerocoinException("Security level must be at least 80 bits.");
+       }
+
+       // Set the accumulator modulus to "N".
+       params.accumulatorParams.accumulatorModulus = N;
+
+       // Calculate the required size of the field "F_p" into which
+       // we're embedding the coin commitment group. This may throw an
+       // exception if the securityLevel is too large to be supported
+       // by the current modulus.
+       uint32_t pLen = 0;
+       uint32_t qLen = 0;
+       calculateGroupParamLengths(NLen - 2, securityLevel, &pLen, &qLen);
+
+       // Calculate candidate parameters ("p", "q") for the coin commitment group
+       // using a deterministic process based on "N", the "aux" string, and
+       // the dedicated string "COMMITMENTGROUP".
+       params.coinCommitmentGroup = deriveIntegerGroupParams(calculateSeed(N, aux, securityLevel, STRING_COMMIT_GROUP),
+                                    pLen, qLen);
+
+       // Next, we derive parameters for a second Accumulated Value commitment group.
+       // This is a Schnorr group with the specific property that the order of the group
+       // must be exactly equal to "q" from the commitment group. We set
+       // the modulus of the new group equal to "2q+1" and test to see if this is prime.
+       params.serialNumberSoKCommitmentGroup = deriveIntegerGroupFromOrder(params.coinCommitmentGroup.modulus);
+
+       // Calculate the parameters for the internal commitment
+       // using the same process.
+       params.accumulatorParams.accumulatorPoKCommitmentGroup = deriveIntegerGroupParams(calculateSeed(N, aux, securityLevel, STRING_AIC_GROUP),
+               qLen + 300, qLen + 1);
+
+       // Calculate the parameters for the accumulator QRN commitment generators. This isn't really
+       // a whole group, just a pair of random generators in QR_N.
+       uint32_t resultCtr;
+       params.accumulatorParams.accumulatorQRNCommitmentGroup.g = generateIntegerFromSeed(NLen - 1,
+               calculateSeed(N, aux, securityLevel, STRING_QRNCOMMIT_GROUPG),
+               &resultCtr).pow_mod(Bignum(2), N);
+       params.accumulatorParams.accumulatorQRNCommitmentGroup.h = generateIntegerFromSeed(NLen - 1,
+               calculateSeed(N, aux, securityLevel, STRING_QRNCOMMIT_GROUPG),
+               &resultCtr).pow_mod(Bignum(2), N);
+
+       // Calculate the accumulator base, which we calculate as "u = C**2 mod N"
+       // where C is an arbitrary value. In the unlikely case that "u = 1" we increment
+       // "C" and repeat.
+       Bignum constant(ACCUMULATOR_BASE_CONSTANT);
+       params.accumulatorParams.accumulatorBase = Bignum(1);
+       for (uint32_t count = 0; count < MAX_ACCUMGEN_ATTEMPTS && params.accumulatorParams.accumulatorBase.isOne(); count++) {
+               params.accumulatorParams.accumulatorBase = constant.pow_mod(Bignum(2), params.accumulatorParams.accumulatorModulus);
+       }
+
+       // Compute the accumulator range. The upper range is the largest possible coin commitment value.
+       // The lower range is sqrt(upper range) + 1. Since OpenSSL doesn't have
+       // a square root function we use a slightly higher approximation.
+       params.accumulatorParams.maxCoinValue = params.coinCommitmentGroup.modulus;
+       params.accumulatorParams.minCoinValue = Bignum(2).pow((params.coinCommitmentGroup.modulus.bitSize() / 2) + 3);
+
+       // If all went well, mark params as successfully initialized.
+       params.accumulatorParams.initialized = true;
+
+       // If all went well, mark params as successfully initialized.
+       params.initialized = true;
+}
+
+/// \brief Format a seed string by hashing several values.
+/// \param N                A Bignum
+/// \param aux              An auxiliary string
+/// \param securityLevel    The security level in bits
+/// \param groupName        A group description string
+/// \throws         ZerocoinException if the process fails
+///
+/// Returns the hash of the value.
+
+uint256
+calculateGeneratorSeed(uint256 seed, uint256 pSeed, uint256 qSeed, string label, uint32_t index, uint32_t count)
+{
+       CHashWriter hasher(0,0);
+       uint256     hash;
+
+       // Compute the hash of:
+       // <modulus>||<securitylevel>||<auxString>||groupName
+       hasher << seed;
+       hasher << string("||");
+       hasher << pSeed;
+       hasher << string("||");
+       hasher << qSeed;
+       hasher << string("||");
+       hasher << label;
+       hasher << string("||");
+       hasher << index;
+       hasher << string("||");
+       hasher << count;
+
+       return hasher.GetHash();
+}
+
+/// \brief Format a seed string by hashing several values.
+/// \param N                A Bignum
+/// \param aux              An auxiliary string
+/// \param securityLevel    The security level in bits
+/// \param groupName        A group description string
+/// \throws         ZerocoinException if the process fails
+///
+/// Returns the hash of the value.
+
+uint256
+calculateSeed(Bignum modulus, string auxString, uint32_t securityLevel, string groupName)
+{
+       CHashWriter hasher(0,0);
+       uint256     hash;
+
+       // Compute the hash of:
+       // <modulus>||<securitylevel>||<auxString>||groupName
+       hasher << modulus;
+       hasher << string("||");
+       hasher << securityLevel;
+       hasher << string("||");
+       hasher << auxString;
+       hasher << string("||");
+       hasher << groupName;
+
+       return hasher.GetHash();
+}
+
+uint256
+calculateHash(uint256 input)
+{
+       CHashWriter hasher(0,0);
+
+       // Compute the hash of "input"
+       hasher << input;
+
+       return hasher.GetHash();
+}
+
+/// \brief Calculate field/group parameter sizes based on a security level.
+/// \param maxPLen          Maximum size of the field (modulus "p") in bits.
+/// \param securityLevel    Required security level in bits (at least 80)
+/// \param pLen             Result: length of "p" in bits
+/// \param qLen             Result: length of "q" in bits
+/// \throws                 ZerocoinException if the process fails
+///
+/// Calculates the appropriate sizes of "p" and "q" for a prime-order
+/// subgroup of order "q" embedded within a field "F_p". The sizes
+/// are based on a 'securityLevel' provided in symmetric-equivalent
+/// bits. Our choices slightly exceed the specs in FIPS 186-3:
+///
+/// securityLevel = 80:     pLen = 1024, qLen = 256
+/// securityLevel = 112:    pLen = 2048, qLen = 256
+/// securityLevel = 128:    qLen = 3072, qLen = 320
+///
+/// If the length of "p" exceeds the length provided in "maxPLen", or
+/// if "securityLevel < 80" this routine throws an exception.
+
+void
+calculateGroupParamLengths(uint32_t maxPLen, uint32_t securityLevel,
+                           uint32_t *pLen, uint32_t *qLen)
+{
+       *pLen = *qLen = 0;
+
+       if (securityLevel < 80) {
+               throw ZerocoinException("Security level must be at least 80 bits.");
+       } else if (securityLevel == 80) {
+               *qLen = 256;
+               *pLen = 1024;
+       } else if (securityLevel <= 112) {
+               *qLen = 256;
+               *pLen = 2048;
+       } else if (securityLevel <= 128) {
+               *qLen = 320;
+               *pLen = 3072;
+       } else {
+               throw ZerocoinException("Security level not supported.");
+       }
+
+       if (*pLen > maxPLen) {
+               throw ZerocoinException("Modulus size is too small for this security level.");
+       }
+}
+
+/// \brief Deterministically compute a set of group parameters using NIST procedures.
+/// \param seedStr  A byte string seeding the process.
+/// \param pLen     The desired length of the modulus "p" in bits
+/// \param qLen     The desired length of the order "q" in bits
+/// \return         An IntegerGroupParams object
+///
+/// Calculates the description of a group G of prime order "q" embedded within
+/// a field "F_p". The input to this routine is in arbitrary seed. It uses the
+/// algorithms described in FIPS 186-3 Appendix A.1.2 to calculate
+/// primes "p" and "q". It uses the procedure in Appendix A.2.3 to
+/// derive two generators "g", "h".
+
+IntegerGroupParams
+deriveIntegerGroupParams(uint256 seed, uint32_t pLen, uint32_t qLen)
+{
+       IntegerGroupParams result;
+       Bignum p;
+       Bignum q;
+       uint256 pSeed, qSeed;
+
+       // Calculate "p" and "q" and "domain_parameter_seed" from the
+       // "seed" buffer above, using the procedure described in NIST
+       // FIPS 186-3, Appendix A.1.2.
+       calculateGroupModulusAndOrder(seed, pLen, qLen, &(result.modulus),
+                                     &(result.groupOrder), &pSeed, &qSeed);
+
+       // Calculate the generators "g", "h" using the process described in
+       // NIST FIPS 186-3, Appendix A.2.3. This algorithm takes ("p", "q",
+       // "domain_parameter_seed", "index"). We use "index" value 1
+       // to generate "g" and "index" value 2 to generate "h".
+       result.g = calculateGroupGenerator(seed, pSeed, qSeed, result.modulus, result.groupOrder, 1);
+       result.h = calculateGroupGenerator(seed, pSeed, qSeed, result.modulus, result.groupOrder, 2);
+
+       // Perform some basic tests to make sure we have good parameters
+       if ((uint32_t)(result.modulus.bitSize()) < pLen ||          // modulus is pLen bits long
+               (uint32_t)(result.groupOrder.bitSize()) < qLen ||       // order is qLen bits long
+               !(result.modulus.isPrime()) ||                          // modulus is prime
+               !(result.groupOrder.isPrime()) ||                       // order is prime
+               !((result.g.pow_mod(result.groupOrder, result.modulus)).isOne()) || // g^order mod modulus = 1
+               !((result.h.pow_mod(result.groupOrder, result.modulus)).isOne()) || // h^order mod modulus = 1
+               ((result.g.pow_mod(Bignum(100), result.modulus)).isOne()) ||        // g^100 mod modulus != 1
+               ((result.h.pow_mod(Bignum(100), result.modulus)).isOne()) ||        // h^100 mod modulus != 1
+               result.g == result.h ||                                 // g != h
+               result.g.isOne()) {                                     // g != 1
+               // If any of the above tests fail, throw an exception
+               throw ZerocoinException("Group parameters are not valid");
+       }
+
+       return result;
+}
+
+/// \brief Deterministically compute a  set of group parameters with a specified order.
+/// \param groupOrder   The order of the group
+/// \return         An IntegerGroupParams object
+///
+/// Given "q" calculates the description of a group G of prime order "q" embedded within
+/// a field "F_p".
+
+IntegerGroupParams
+deriveIntegerGroupFromOrder(Bignum &groupOrder)
+{
+       IntegerGroupParams result;
+
+       // Set the order to "groupOrder"
+       result.groupOrder = groupOrder;
+
+       // Try possible values for "modulus" of the form "groupOrder * 2 * i" where
+       // "p" is prime and i is a counter starting at 1.
+       for (uint32_t i = 1; i < NUM_SCHNORRGEN_ATTEMPTS; i++) {
+               // Set modulus equal to "groupOrder * 2 * i"
+               result.modulus = (result.groupOrder * Bignum(i*2)) + Bignum(1);
+
+               // Test the result for primality
+               // TODO: This is a probabilistic routine and thus not the right choice
+               if (result.modulus.isPrime(256)) {
+
+                       // Success.
+                       //
+                       // Calculate the generators "g", "h" using the process described in
+                       // NIST FIPS 186-3, Appendix A.2.3. This algorithm takes ("p", "q",
+                       // "domain_parameter_seed", "index"). We use "index" value 1
+                       // to generate "g" and "index" value 2 to generate "h".
+                       uint256 seed = calculateSeed(groupOrder, "", 128, "");
+                       uint256 pSeed = calculateHash(seed);
+                       uint256 qSeed = calculateHash(pSeed);
+                       result.g = calculateGroupGenerator(seed, pSeed, qSeed, result.modulus, result.groupOrder, 1);
+                       result.h = calculateGroupGenerator(seed, pSeed, qSeed, result.modulus, result.groupOrder, 2);
+
+                       // Perform some basic tests to make sure we have good parameters
+                       if (!(result.modulus.isPrime()) ||                          // modulus is prime
+                               !(result.groupOrder.isPrime()) ||                       // order is prime
+                               !((result.g.pow_mod(result.groupOrder, result.modulus)).isOne()) || // g^order mod modulus = 1
+                               !((result.h.pow_mod(result.groupOrder, result.modulus)).isOne()) || // h^order mod modulus = 1
+                               ((result.g.pow_mod(Bignum(100), result.modulus)).isOne()) ||        // g^100 mod modulus != 1
+                               ((result.h.pow_mod(Bignum(100), result.modulus)).isOne()) ||        // h^100 mod modulus != 1
+                               result.g == result.h ||                                 // g != h
+                               result.g.isOne()) {                                     // g != 1
+                               // If any of the above tests fail, throw an exception
+                               throw ZerocoinException("Group parameters are not valid");
+                       }
+
+                       return result;
+               }
+       }
+
+       // If we reached this point group generation has failed. Throw an exception.
+       throw ZerocoinException("Too many attempts to generate Schnorr group.");
+}
+
+/// \brief Deterministically compute a group description using NIST procedures.
+/// \param seed                         A byte string seeding the process.
+/// \param pLen                         The desired length of the modulus "p" in bits
+/// \param qLen                         The desired length of the order "q" in bits
+/// \param resultModulus                A value "p" describing a finite field "F_p"
+/// \param resultGroupOrder             A value "q" describing the order of a subgroup
+/// \param resultDomainParameterSeed    A resulting seed for use in later calculations.
+///
+/// Calculates the description of a group G of prime order "q" embedded within
+/// a field "F_p". The input to this routine is in arbitrary seed. It uses the
+/// algorithms described in FIPS 186-3 Appendix A.1.2 to calculate
+/// primes "p" and "q".
+
+void
+calculateGroupModulusAndOrder(uint256 seed, uint32_t pLen, uint32_t qLen,
+                              Bignum *resultModulus, Bignum *resultGroupOrder,
+                              uint256 *resultPseed, uint256 *resultQseed)
+{
+       // Verify that the seed length is >= qLen
+       if (qLen > (sizeof(seed)) * 8) {
+               // TODO: The use of 256-bit seeds limits us to 256-bit group orders. We should probably change this.
+               // throw ZerocoinException("Seed is too short to support the required security level.");
+       }
+
+#ifdef ZEROCOIN_DEBUG
+       cout << "calculateGroupModulusAndOrder: pLen = " << pLen << endl;
+#endif
+
+       // Generate a random prime for the group order.
+       // This may throw an exception, which we'll pass upwards.
+       // Result is the value "resultGroupOrder", "qseed" and "qgen_counter".
+       uint256     qseed;
+       uint32_t    qgen_counter;
+       *resultGroupOrder = generateRandomPrime(qLen, seed, &qseed, &qgen_counter);
+
+       // Using ⎡pLen / 2 + 1⎤ as the length and qseed as the input_seed, use the random prime
+       // routine to obtain p0 , pseed, and pgen_counter. We pass exceptions upward.
+       uint32_t    p0len = ceil((pLen / 2.0) + 1);
+       uint256     pseed;
+       uint32_t    pgen_counter;
+       Bignum p0 = generateRandomPrime(p0len, qseed, &pseed, &pgen_counter);
+
+       // Set x = 0, old_counter = pgen_counter
+       uint32_t    old_counter = pgen_counter;
+
+       // Generate a random integer "x" of pLen bits
+       uint32_t iterations;
+       Bignum x = generateIntegerFromSeed(pLen, pseed, &iterations);
+       pseed += (iterations + 1);
+
+       // Set x = 2^{pLen−1} + (x mod 2^{pLen–1}).
+       Bignum powerOfTwo = Bignum(2).pow(pLen-1);
+       x = powerOfTwo + (x % powerOfTwo);
+
+       // t = ⎡x / (2 * resultGroupOrder * p0)⎤.
+       // TODO: we don't have a ceiling function
+       Bignum t = x / (Bignum(2) * (*resultGroupOrder) * p0);
+
+       // Now loop until we find a valid prime "p" or we fail due to
+       // pgen_counter exceeding ((4*pLen) + old_counter).
+       for ( ; pgen_counter <= ((4*pLen) + old_counter) ; pgen_counter++) {
+               // If (2 * t * resultGroupOrder * p0 + 1) > 2^{pLen}, then
+               // t = ⎡2^{pLen−1} / (2 * resultGroupOrder * p0)⎤.
+               powerOfTwo = Bignum(2).pow(pLen);
+               Bignum prod = (Bignum(2) * t * (*resultGroupOrder) * p0) + Bignum(1);
+               if (prod > powerOfTwo) {
+                       // TODO: implement a ceil function
+                       t = Bignum(2).pow(pLen-1) / (Bignum(2) * (*resultGroupOrder) * p0);
+               }
+
+               // Compute a candidate prime resultModulus = 2tqp0 + 1.
+               *resultModulus = (Bignum(2) * t * (*resultGroupOrder) * p0) + Bignum(1);
+
+               // Verify that resultModulus is prime. First generate a pseudorandom integer "a".
+               Bignum a = generateIntegerFromSeed(pLen, pseed, &iterations);
+               pseed += iterations + 1;
+
+               // Set a = 2 + (a mod (resultModulus–3)).
+               a = Bignum(2) + (a % ((*resultModulus) - Bignum(3)));
+
+               // Set z = a^{2 * t * resultGroupOrder} mod resultModulus
+               Bignum z = a.pow_mod(Bignum(2) * t * (*resultGroupOrder), (*resultModulus));
+
+               // If GCD(z–1, resultModulus) == 1 AND (z^{p0} mod resultModulus == 1)
+               // then we have found our result. Return.
+               if ((resultModulus->gcd(z - Bignum(1))).isOne() &&
+                       (z.pow_mod(p0, (*resultModulus))).isOne()) {
+                       // Success! Return the seeds and primes.
+                       *resultPseed = pseed;
+                       *resultQseed = qseed;
+                       return;
+               }
+
+               // This prime did not work out. Increment "t" and try again.
+               t = t + Bignum(1);
+       } // loop continues until pgen_counter exceeds a limit
+
+       // We reach this point only if we exceeded our maximum iteration count.
+       // Throw an exception.
+       throw ZerocoinException("Unable to generate a prime modulus for the group");
+}
+
+/// \brief Deterministically compute a generator for a given group.
+/// \param seed                         A first seed for the process.
+/// \param pSeed                        A second seed for the process.
+/// \param qSeed                        A third seed for the process.
+/// \param modulus                      Proposed prime modulus for the field.
+/// \param groupOrder                   Proposed order of the group.
+/// \param index                        Index value, selects which generator you're building.
+/// \return                             The resulting generator.
+/// \throws                             A ZerocoinException if error.
+///
+/// Generates a random group generator deterministically as a function of (seed,pSeed,qSeed)
+/// Uses the algorithm described in FIPS 186-3 Appendix A.2.3.
+
+Bignum
+calculateGroupGenerator(uint256 seed, uint256 pSeed, uint256 qSeed, Bignum modulus, Bignum groupOrder, uint32_t index)
+{
+       Bignum result;
+
+       // Verify that 0 <= index < 256
+       if (index > 255) {
+               throw ZerocoinException("Invalid index for group generation");
+       }
+
+       // Compute e = (modulus - 1) / groupOrder
+       Bignum e = (modulus - Bignum(1)) / groupOrder;
+
+       // Loop until we find a generator
+       for (uint32_t count = 1; count < MAX_GENERATOR_ATTEMPTS; count++) {
+               // hash = Hash(seed || pSeed || qSeed || “ggen” || index || count
+               uint256 hash = calculateGeneratorSeed(seed, pSeed, qSeed, "ggen", index, count);
+               Bignum W(hash);
+
+               // Compute result = W^e mod p
+               result = W.pow_mod(e, modulus);
+
+               // If result > 1, we have a generator
+               if (result > 1) {
+                       return result;
+               }
+       }
+
+       // We only get here if we failed to find a generator
+       throw ZerocoinException("Unable to find a generator, too many attempts");
+}
+
+/// \brief Deterministically compute a random prime number.
+/// \param primeBitLen                  Desired bit length of the prime.
+/// \param in_seed                      Input seed for the process.
+/// \param out_seed                     Result: output seed from the process.
+/// \param prime_gen_counter            Result: number of iterations required.
+/// \return                             The resulting prime number.
+/// \throws                             A ZerocoinException if error.
+///
+/// Generates a random prime number of primeBitLen bits from a given input
+/// seed. Uses the Shawe-Taylor algorithm as described in FIPS 186-3
+/// Appendix C.6. This is a recursive function.
+
+Bignum
+generateRandomPrime(uint32_t primeBitLen, uint256 in_seed, uint256 *out_seed,
+                    uint32_t *prime_gen_counter)
+{
+       // Verify that primeBitLen is not too small
+       if (primeBitLen < 2) {
+               throw ZerocoinException("Prime length is too short");
+       }
+
+       // If primeBitLen < 33 bits, perform the base case.
+       if (primeBitLen < 33) {
+               Bignum result(0);
+
+               // Set prime_seed = in_seed, prime_gen_counter = 0.
+               uint256     prime_seed = in_seed;
+               (*prime_gen_counter) = 0;
+
+               // Loop up to "4 * primeBitLen" iterations.
+               while ((*prime_gen_counter) < (4 * primeBitLen)) {
+
+                       // Generate a pseudorandom integer "c" of length primeBitLength bits
+                       uint32_t iteration_count;
+                       Bignum c = generateIntegerFromSeed(primeBitLen, prime_seed, &iteration_count);
+#ifdef ZEROCOIN_DEBUG
+                       cout << "generateRandomPrime: primeBitLen = " << primeBitLen << endl;
+                       cout << "Generated c = " << c << endl;
+#endif
+
+                       prime_seed += (iteration_count + 1);
+                       (*prime_gen_counter)++;
+
+                       // Set "intc" to be the least odd integer >= "c" we just generated
+                       uint32_t intc = c.getulong();
+                       intc = (2 * floor(intc / 2.0)) + 1;
+#ifdef ZEROCOIN_DEBUG
+                       cout << "Should be odd. c = " << intc << endl;
+                       cout << "The big num is: c = " << c << endl;
+#endif
+
+                       // Perform trial division on this (relatively small) integer to determine if "intc"
+                       // is prime. If so, return success.
+                       if (primalityTestByTrialDivision(intc)) {
+                               // Return "intc" converted back into a Bignum and "prime_seed". We also updated
+                               // the variable "prime_gen_counter" in previous statements.
+                               result = intc;
+                               *out_seed = prime_seed;
+
+                               // Success
+                               return result;
+                       }
+               } // while()
+
+               // If we reached this point there was an error finding a candidate prime
+               // so throw an exception.
+               throw ZerocoinException("Unable to find prime in Shawe-Taylor algorithm");
+
+               // END OF BASE CASE
+       }
+       // If primeBitLen >= 33 bits, perform the recursive case.
+       else {
+               // Recurse to find a new random prime of roughly half the size
+               uint32_t newLength = ceil((double)primeBitLen / 2.0) + 1;
+               Bignum c0 = generateRandomPrime(newLength, in_seed, out_seed, prime_gen_counter);
+
+               // Generate a random integer "x" of primeBitLen bits using the output
+               // of the previous call.
+               uint32_t numIterations;
+               Bignum x = generateIntegerFromSeed(primeBitLen, *out_seed, &numIterations);
+               (*out_seed) += numIterations + 1;
+
+               // Compute "t" = ⎡x / (2 * c0⎤
+               // TODO no Ceiling call
+               Bignum t = x / (Bignum(2) * c0);
+
+               // Repeat the following procedure until we find a prime (or time out)
+               for (uint32_t testNum = 0; testNum < MAX_PRIMEGEN_ATTEMPTS; testNum++) {
+
+                       // If ((2 * t * c0) + 1 > 2^{primeBitLen}),
+                       // then t = ⎡2^{primeBitLen} – 1 / (2 * c0)⎤.
+                       if ((Bignum(2) * t * c0) > (Bignum(2).pow(Bignum(primeBitLen)))) {
+                               t = ((Bignum(2).pow(Bignum(primeBitLen))) - Bignum(1)) / (Bignum(2) * c0);
+                       }
+
+                       // Set c = (2 * t * c0) + 1
+                       Bignum c = (Bignum(2) * t * c0) + Bignum(1);
+
+                       // Increment prime_gen_counter
+                       (*prime_gen_counter)++;
+
+                       // Test "c" for primality as follows:
+                       // 1. First pick an integer "a" in between 2 and (c - 2)
+                       Bignum a = generateIntegerFromSeed(c.bitSize(), (*out_seed), &numIterations);
+                       a = Bignum(2) + (a % (c - Bignum(3)));
+                       (*out_seed) += (numIterations + 1);
+
+                       // 2. Compute "z" = a^{2*t} mod c
+                       Bignum z = a.pow_mod(Bignum(2) * t, c);
+
+                       // 3. Check if "c" is prime.
+                       //    Specifically, verify that gcd((z-1), c) == 1 AND (z^c0 mod c) == 1
+                       // If so we return "c" as our result.
+                       if (c.gcd(z - Bignum(1)).isOne() && z.pow_mod(c0, c).isOne()) {
+                               // Return "c", out_seed and prime_gen_counter
+                               // (the latter two of which were already updated)
+                               return c;
+                       }
+
+                       // 4. If the test did not succeed, increment "t" and loop
+                       t = t + Bignum(1);
+               } // end of test loop
+       }
+
+       // We only reach this point if the test loop has iterated MAX_PRIMEGEN_ATTEMPTS
+       // and failed to identify a valid prime. Throw an exception.
+       throw ZerocoinException("Unable to generate random prime (too many tests)");
+}
+
+Bignum
+generateIntegerFromSeed(uint32_t numBits, uint256 seed, uint32_t *numIterations)
+{
+       Bignum      result(0);
+       uint32_t    iterations = ceil((double)numBits / (double)HASH_OUTPUT_BITS);
+
+#ifdef ZEROCOIN_DEBUG
+       cout << "numBits = " << numBits << endl;
+       cout << "iterations = " << iterations << endl;
+#endif
+
+       // Loop "iterations" times filling up the value "result" with random bits
+       for (uint32_t count = 0; count < iterations; count++) {
+               // result += ( H(pseed + count) * 2^{count * p0len} )
+               result += Bignum(calculateHash(seed + count)) * Bignum(2).pow(count * HASH_OUTPUT_BITS);
+       }
+
+       result = Bignum(2).pow(numBits - 1) + (result % (Bignum(2).pow(numBits - 1)));
+
+       // Return the number of iterations and the result
+       *numIterations = iterations;
+       return result;
+}
+
+/// \brief Determines whether a uint32_t is a prime through trial division.
+/// \param candidate       Candidate to test.
+/// \return                true if the value is prime, false otherwise
+///
+/// Performs trial division to determine whether a uint32_t is prime.
+
+bool
+primalityTestByTrialDivision(uint32_t candidate)
+{
+       // TODO: HACK HACK WRONG WRONG
+       Bignum canBignum(candidate);
+
+       return canBignum.isPrime();
+}
+
+} // namespace libzerocoin
diff --git a/src/zerocoin/ParamGeneration.h b/src/zerocoin/ParamGeneration.h
new file mode 100644 (file)
index 0000000..de2d452
--- /dev/null
@@ -0,0 +1,53 @@
+/// \file       ParamGeneration.h
+///
+/// \brief      Parameter generation routines for Zerocoin.
+///
+/// \author     Ian Miers, Christina Garman and Matthew Green
+/// \date       June 2013
+///
+/// \copyright  Copyright 2013 Ian Miers, Christina Garman and Matthew Green
+/// \license    This project is released under the MIT license.
+
+#ifndef PARAMGENERATION_H_
+#define PARAMGENERATION_H_
+
+namespace libzerocoin {
+
+void CalculateParams(Params &params, Bignum N, std::string aux, uint32_t securityLevel);
+void calculateGroupParamLengths(uint32_t maxPLen, uint32_t securityLevel,
+                                uint32_t *pLen, uint32_t *qLen);
+
+// Constants
+#define STRING_COMMIT_GROUP         "COIN_COMMITMENT_GROUP"
+#define STRING_AVC_GROUP            "ACCUMULATED_VALUE_COMMITMENT_GROUP"
+#define STRING_AVC_ORDER            "ACCUMULATED_VALUE_COMMITMENT_ORDER"
+#define STRING_AIC_GROUP            "ACCUMULATOR_INTERNAL_COMMITMENT_GROUP"
+#define STRING_QRNCOMMIT_GROUPG     "ACCUMULATOR_QRN_COMMITMENT_GROUPG"
+#define STRING_QRNCOMMIT_GROUPH     "ACCUMULATOR_QRN_COMMITMENT_GROUPH"
+#define ACCUMULATOR_BASE_CONSTANT   31
+#define MAX_PRIMEGEN_ATTEMPTS       10000
+#define MAX_ACCUMGEN_ATTEMPTS       10000
+#define MAX_GENERATOR_ATTEMPTS      10000
+#define NUM_SCHNORRGEN_ATTEMPTS     10000
+
+// Prototypes
+bool                primalityTestByTrialDivision(uint32_t candidate);
+uint256             calculateSeed(Bignum modulus, std::string auxString, uint32_t securityLevel, std::string groupName);
+uint256             calculateGeneratorSeed(uint256 seed, uint256 pSeed, uint256 qSeed, std::string label, uint32_t index, uint32_t count);
+
+uint256             calculateHash(uint256 input);
+IntegerGroupParams  deriveIntegerGroupParams(uint256 seed, uint32_t pLen, uint32_t qLen);
+IntegerGroupParams  deriveIntegerGroupFromOrder(Bignum &groupOrder);
+void                calculateGroupModulusAndOrder(uint256 seed, uint32_t pLen, uint32_t qLen,
+        Bignum *resultModulus, Bignum *resultGroupOrder,
+        uint256 *resultPseed, uint256 *resultQseed);
+Bignum              calculateGroupGenerator(uint256 seed, uint256 pSeed, uint256 qSeed, Bignum modulus,
+        Bignum groupOrder, uint32_t index);
+Bignum              generateRandomPrime(uint32_t primeBitLen, uint256 in_seed, uint256 *out_seed,
+                                        uint32_t *prime_gen_counter);
+Bignum              generateIntegerFromSeed(uint32_t numBits, uint256 seed, uint32_t *numIterations);
+bool                primalityTestByTrialDivision(uint32_t candidate);
+
+}/* namespace libzerocoin */
+
+#endif /* PARAMGENERATION_H_ */
diff --git a/src/zerocoin/Params.cpp b/src/zerocoin/Params.cpp
new file mode 100644 (file)
index 0000000..c275044
--- /dev/null
@@ -0,0 +1,45 @@
+/**
+* @file       Params.cpp
+*
+* @brief      Parameter class for Zerocoin.
+*
+* @author     Ian Miers, Christina Garman and Matthew Green
+* @date       June 2013
+*
+* @copyright  Copyright 2013 Ian Miers, Christina Garman and Matthew Green
+* @license    This project is released under the MIT license.
+**/
+#include "Zerocoin.h"
+
+namespace libzerocoin {
+
+Params::Params(Bignum N, uint32_t securityLevel) {
+       this->zkp_hash_len = securityLevel;
+       this->zkp_iterations = securityLevel;
+
+       this->accumulatorParams.k_prime = ACCPROOF_KPRIME;
+       this->accumulatorParams.k_dprime = ACCPROOF_KDPRIME;
+
+       // Generate the parameters
+       CalculateParams(*this, N, ZEROCOIN_PROTOCOL_VERSION, securityLevel);
+
+       this->accumulatorParams.initialized = true;
+       this->initialized = true;
+}
+
+AccumulatorAndProofParams::AccumulatorAndProofParams() {
+       this->initialized = false;
+}
+
+IntegerGroupParams::IntegerGroupParams() {
+       this->initialized = false;
+}
+
+Bignum IntegerGroupParams::randomElement() const {
+       // The generator of the group raised
+       // to a random number less than the order of the group
+       // provides us with a uniformly distributed random number.
+       return this->g.pow_mod(Bignum::randBignum(this->groupOrder),this->modulus);
+}
+
+} /* namespace libzerocoin */
diff --git a/src/zerocoin/Params.h b/src/zerocoin/Params.h
new file mode 100644 (file)
index 0000000..60a5af4
--- /dev/null
@@ -0,0 +1,216 @@
+/**
+* @file       Params.h
+*
+* @brief      Parameter classes for Zerocoin.
+*
+* @author     Ian Miers, Christina Garman and Matthew Green
+* @date       June 2013
+*
+* @copyright  Copyright 2013 Ian Miers, Christina Garman and Matthew Green
+* @license    This project is released under the MIT license.
+**/
+#ifndef PARAMS_H_
+#define PARAMS_H_
+
+namespace libzerocoin {
+
+class IntegerGroupParams {
+public:
+       /** @brief Integer group class, default constructor
+       *
+       * Allocates an empty (uninitialized) set of parameters.
+       **/
+       IntegerGroupParams();
+
+       /**
+        * Generates a random group element
+        * @return a random element in the group.
+        */
+       Bignum randomElement() const;
+       bool initialized;
+
+       /**
+        * A generator for the group.
+        */
+       Bignum g;
+
+       /**
+        * A second generator for the group.
+        * Note log_g(h) and log_h(g) must
+        * be unknown.
+        */
+       Bignum h;
+
+       /**
+        * The modulus for the group.
+        */
+       Bignum modulus;
+
+       /**
+        * The order of the group
+        */
+       Bignum groupOrder;
+
+       IMPLEMENT_SERIALIZE
+       (
+           READWRITE(initialized);
+           READWRITE(g);
+           READWRITE(h);
+           READWRITE(modulus);
+           READWRITE(groupOrder);
+       )
+};
+
+class AccumulatorAndProofParams {
+public:
+       /** @brief Construct a set of Zerocoin parameters from a modulus "N".
+       * @param N                A trusted RSA modulus
+       * @param securityLevel    A security level expressed in symmetric bits (default 80)
+       *
+       * Allocates and derives a set of Zerocoin parameters from
+       * a trustworthy RSA modulus "N". This routine calculates all
+       * of the remaining parameters (group descriptions etc.) from N
+       * using a verifiable, deterministic procedure.
+       *
+       * Note: this constructor makes the fundamental assumption that "N"
+       * encodes a valid RSA-style modulus of the form "e1 * e2" where
+       * "e1" and "e2" are safe primes. The factors "e1", "e2" MUST NOT
+       * be known to any party, or the security of Zerocoin is
+       * compromised. The integer "N" must be a MINIMUM of 1024
+       * in length. 3072 bits is strongly recommended.
+       **/
+       AccumulatorAndProofParams();
+
+       //AccumulatorAndProofParams(Bignum accumulatorModulus);
+
+       bool initialized;
+
+       /**
+        * Modulus used for the accumulator.
+        * Product of two safe primes who's factorization is unknown.
+        */
+       Bignum accumulatorModulus;
+
+       /**
+        * The initial value for the accumulator
+        * A random Quadratic residue mod n thats not 1
+        */
+       Bignum accumulatorBase;
+
+       /**
+        * Lower bound on the value for committed coin.
+        * Required by the accumulator proof.
+        */
+       Bignum minCoinValue;
+
+       /**
+        * Upper bound on the value for a comitted coin.
+        * Required by the accumulator proof.
+        */
+       Bignum maxCoinValue;
+
+       /**
+        * The second of two groups used to form a commitment to
+        * a coin (which it self is a commitment to a serial number).
+        * This one differs from serialNumberSokCommitment due to
+        * restrictions from Camenisch and Lysyanskaya's paper.
+        */
+       IntegerGroupParams accumulatorPoKCommitmentGroup;
+
+       /**
+        * Hidden order quadratic residue group mod N.
+        * Used in the accumulator proof.
+        */
+       IntegerGroupParams accumulatorQRNCommitmentGroup;
+
+       /**
+        * Security parameter.
+        * Bit length of the challenges used in the accumulator proof.
+        */
+       uint32_t k_prime;
+
+       /**
+        * Security parameter.
+        * The statistical zero-knowledgeness of the accumulator proof.
+        */
+       uint32_t k_dprime;
+
+       IMPLEMENT_SERIALIZE
+       (
+           READWRITE(initialized);
+           READWRITE(accumulatorModulus);
+           READWRITE(accumulatorBase);
+           READWRITE(accumulatorPoKCommitmentGroup);
+           READWRITE(accumulatorQRNCommitmentGroup);
+           READWRITE(minCoinValue);
+           READWRITE(maxCoinValue);
+           READWRITE(k_prime);
+           READWRITE(k_dprime);
+       )
+};
+
+class Params {
+public:
+       /** @brief Construct a set of Zerocoin parameters from a modulus "N".
+       * @param N                A trusted RSA modulus
+       * @param securityLevel    A security level expressed in symmetric bits (default 80)
+       *
+       * Allocates and derives a set of Zerocoin parameters from
+       * a trustworthy RSA modulus "N". This routine calculates all
+       * of the remaining parameters (group descriptions etc.) from N
+       * using a verifiable, deterministic procedure.
+       *
+       * Note: this constructor makes the fundamental assumption that "N"
+       * encodes a valid RSA-style modulus of the form "e1 * e2" where
+       * "e1" and "e2" are safe primes. The factors "e1", "e2" MUST NOT
+       * be known to any party, or the security of Zerocoin is
+       * compromised. The integer "N" must be a MINIMUM of 1024
+       * in length. 3072 bits is strongly recommended.
+       **/
+       Params(Bignum accumulatorModulus,
+              uint32_t securityLevel = ZEROCOIN_DEFAULT_SECURITYLEVEL);
+
+       bool initialized;
+
+       AccumulatorAndProofParams accumulatorParams;
+
+       /**
+        * The Quadratic Residue group from which we form
+        * a coin as a commitment  to a serial number.
+        */
+       IntegerGroupParams coinCommitmentGroup;
+
+       /**
+        * One of two groups used to form a commitment to
+        * a coin (which it self is a commitment to a serial number).
+        * This is the one used in the serial number poof.
+        * It's order must be equal to the modulus of coinCommitmentGroup.
+        */
+       IntegerGroupParams serialNumberSoKCommitmentGroup;
+
+       /**
+        * The number of iterations to use in the serial
+        * number proof.
+        */
+       uint32_t zkp_iterations;
+
+       /**
+        * The amount of the hash function we use for
+        * proofs.
+        */
+       uint32_t zkp_hash_len;
+
+       IMPLEMENT_SERIALIZE
+       (
+           READWRITE(initialized);
+           READWRITE(accumulatorParams);
+           READWRITE(coinCommitmentGroup);
+           READWRITE(serialNumberSoKCommitmentGroup);
+           READWRITE(zkp_iterations);
+           READWRITE(zkp_hash_len);
+       )
+};
+
+} /* namespace libzerocoin */
+
+#endif /* PARAMS_H_ */
diff --git a/src/zerocoin/SerialNumberSignatureOfKnowledge.cpp b/src/zerocoin/SerialNumberSignatureOfKnowledge.cpp
new file mode 100644 (file)
index 0000000..1654c50
--- /dev/null
@@ -0,0 +1,139 @@
+/**
+* @file       SerialNumberSignatureOfKnowledge.cpp
+*
+* @brief      SerialNumberSignatureOfKnowledge class for the Zerocoin library.
+*
+* @author     Ian Miers, Christina Garman and Matthew Green
+* @date       June 2013
+*
+* @copyright  Copyright 2013 Ian Miers, Christina Garman and Matthew Green
+* @license    This project is released under the MIT license.
+**/
+
+#include "Zerocoin.h"
+
+namespace libzerocoin {
+
+SerialNumberSignatureOfKnowledge::SerialNumberSignatureOfKnowledge(const Params* p): params(p) { }
+
+SerialNumberSignatureOfKnowledge::SerialNumberSignatureOfKnowledge(const
+        Params* p, const PrivateCoin& coin, const Commitment& commitmentToCoin,
+        uint256 msghash):params(p),
+       s_notprime(p->zkp_iterations),
+       sprime(p->zkp_iterations) {
+
+       // Sanity check: verify that the order of the "accumulatedValueCommitmentGroup" is
+       // equal to the modulus of "coinCommitmentGroup". Otherwise we will produce invalid
+       // proofs.
+       if (params->coinCommitmentGroup.modulus != params->serialNumberSoKCommitmentGroup.groupOrder) {
+               throw ZerocoinException("Groups are not structured correctly.");
+       }
+
+       Bignum a = params->coinCommitmentGroup.g;
+       Bignum b = params->coinCommitmentGroup.h;
+       Bignum g = params->serialNumberSoKCommitmentGroup.g;
+       Bignum h = params->serialNumberSoKCommitmentGroup.h;
+
+       CHashWriter hasher(0,0);
+       hasher << *params << commitmentToCoin.getCommitmentValue() << coin.getSerialNumber();
+
+       vector<Bignum> r(params->zkp_iterations);
+       vector<Bignum> v(params->zkp_iterations);
+       vector<Bignum> c(params->zkp_iterations);
+
+
+       for(uint32_t i=0; i < params->zkp_iterations; i++) {
+               //FIXME we really ought to use one BN_CTX for all of these
+               // operations for performance reasons, not the one that
+               // is created individually  by the wrapper
+               r[i] = Bignum::randBignum(params->coinCommitmentGroup.groupOrder);
+               v[i] = Bignum::randBignum(params->serialNumberSoKCommitmentGroup.groupOrder);
+       }
+
+       // Openssl's rng is not thread safe, so we don't call it in a parallel loop,
+       // instead we generate the random values beforehand and run the calculations
+       // based on those values in parallel.
+#ifdef ZEROCOIN_THREADING
+       #pragma omp parallel for
+#endif
+       for(uint32_t i=0; i < params->zkp_iterations; i++) {
+               // compute g^{ {a^x b^r} h^v} mod p2
+               c[i] = challengeCalculation(coin.getSerialNumber(), r[i], v[i]);
+       }
+
+       // We can't hash data in parallel either
+       // because OPENMP cannot not guarantee loops
+       // execute in order.
+       for(uint32_t i=0; i < params->zkp_iterations; i++) {
+               hasher << c[i];
+       }
+       this->hash = hasher.GetHash();
+       unsigned char *hashbytes =  (unsigned char*) &hash;
+
+#ifdef ZEROCOIN_THREADING
+       #pragma omp parallel for
+#endif
+       for(uint32_t i = 0; i < params->zkp_iterations; i++) {
+               int bit = i % 8;
+               int byte = i / 8;
+
+               bool challenge_bit = ((hashbytes[byte] >> bit) & 0x01);
+               if (challenge_bit) {
+                       s_notprime[i]       = r[i];
+                       sprime[i]           = v[i];
+               } else {
+                       s_notprime[i]       = r[i] - coin.getRandomness();
+                       sprime[i]           = v[i] - (commitmentToCoin.getRandomness() *
+                                                     b.pow_mod(r[i] - coin.getRandomness(), params->serialNumberSoKCommitmentGroup.groupOrder));
+               }
+       }
+}
+
+inline Bignum SerialNumberSignatureOfKnowledge::challengeCalculation(const Bignum& a_exp,const Bignum& b_exp,
+        const Bignum& h_exp) const {
+
+       Bignum a = params->coinCommitmentGroup.g;
+       Bignum b = params->coinCommitmentGroup.h;
+       Bignum g = params->serialNumberSoKCommitmentGroup.g;
+       Bignum h = params->serialNumberSoKCommitmentGroup.h;
+
+       Bignum exponent = (a.pow_mod(a_exp, params->serialNumberSoKCommitmentGroup.groupOrder)
+                          * b.pow_mod(b_exp, params->serialNumberSoKCommitmentGroup.groupOrder)) % params->serialNumberSoKCommitmentGroup.groupOrder;
+
+       return (g.pow_mod(exponent, params->serialNumberSoKCommitmentGroup.modulus) * h.pow_mod(h_exp, params->serialNumberSoKCommitmentGroup.modulus)) % params->serialNumberSoKCommitmentGroup.modulus;
+}
+
+bool SerialNumberSignatureOfKnowledge::Verify(const Bignum& coinSerialNumber, const Bignum& valueOfCommitmentToCoin,
+        const uint256 msghash) const {
+       Bignum a = params->coinCommitmentGroup.g;
+       Bignum b = params->coinCommitmentGroup.h;
+       Bignum g = params->serialNumberSoKCommitmentGroup.g;
+       Bignum h = params->serialNumberSoKCommitmentGroup.h;
+       CHashWriter hasher(0,0);
+       hasher << *params << valueOfCommitmentToCoin <<coinSerialNumber;
+
+       vector<CBigNum> tprime(params->zkp_iterations);
+       unsigned char *hashbytes = (unsigned char*) &this->hash;
+#ifdef ZEROCOIN_THREADING
+       #pragma omp parallel for
+#endif
+       for(uint32_t i = 0; i < params->zkp_iterations; i++) {
+               int bit = i % 8;
+               int byte = i / 8;
+               bool challenge_bit = ((hashbytes[byte] >> bit) & 0x01);
+               if(challenge_bit) {
+                       tprime[i] = challengeCalculation(coinSerialNumber, s_notprime[i], sprime[i]);
+               } else {
+                       Bignum exp = b.pow_mod(s_notprime[i], params->serialNumberSoKCommitmentGroup.groupOrder);
+                       tprime[i] = ((valueOfCommitmentToCoin.pow_mod(exp, params->serialNumberSoKCommitmentGroup.modulus) % params->serialNumberSoKCommitmentGroup.modulus) *
+                                    (h.pow_mod(sprime[i], params->serialNumberSoKCommitmentGroup.modulus) % params->serialNumberSoKCommitmentGroup.modulus)) %
+                                   params->serialNumberSoKCommitmentGroup.modulus;
+               }
+       }
+       for(uint32_t i = 0; i < params->zkp_iterations; i++) {
+               hasher << tprime[i];
+       }
+       return hasher.GetHash() == hash;
+}
+
+} /* namespace libzerocoin */
diff --git a/src/zerocoin/SerialNumberSignatureOfKnowledge.h b/src/zerocoin/SerialNumberSignatureOfKnowledge.h
new file mode 100644 (file)
index 0000000..3177618
--- /dev/null
@@ -0,0 +1,75 @@
+/**
+* @file       SerialNumberSignatureOfKnowledge.h
+*
+* @brief      SerialNumberSignatureOfKnowledge class for the Zerocoin library.
+*
+* @author     Ian Miers, Christina Garman and Matthew Green
+* @date       June 2013
+*
+* @copyright  Copyright 2013 Ian Miers, Christina Garman and Matthew Green
+* @license    This project is released under the MIT license.
+**/
+
+#ifndef SERIALNUMBERPROOF_H_
+#define SERIALNUMBERPROOF_H_
+
+#include <list>
+#include <vector>
+#include <bitset>
+#include "Params.h"
+#include "Coin.h"
+#include "Commitment.h"
+#include "../bignum.h"
+#include "../serialize.h"
+#include "Accumulator.h"
+#include "../util.h"
+
+using namespace std;
+namespace libzerocoin {
+
+/**A Signature of knowledge on the hash of metadata attesting that the signer knows the values
+ *  necessary to open a commitment which contains a coin(which it self is of course a commitment)
+ * with a given serial number.
+ */
+class SerialNumberSignatureOfKnowledge {
+public:
+       SerialNumberSignatureOfKnowledge(const Params* p);
+       /** Creates a Signature of knowledge object that a commitment to a coin contains a coin with serial number x
+        *
+        * @param p params
+        * @param coin the coin we are going to prove the serial number of.
+        * @param commitmentToCoin the commitment to the coin
+        * @param msghash hash of meta data to create a signature of knowledge on.
+        */
+       SerialNumberSignatureOfKnowledge(const Params* p, const PrivateCoin& coin, const Commitment& commitmentToCoin, uint256 msghash);
+
+       /** Verifies the Signature of knowledge.
+        *
+        * @param msghash hash of meta data to create a signature of knowledge on.
+        * @return
+        */
+       bool Verify(const Bignum& coinSerialNumber, const Bignum& valueOfCommitmentToCoin,const uint256 msghash) const;
+
+       IMPLEMENT_SERIALIZE
+       (
+           READWRITE(s_notprime);
+           READWRITE(sprime);
+           READWRITE(hash);
+       )
+private:
+       const Params* params;
+       // challenge hash
+       uint256 hash; //TODO For efficiency, should this be a bitset where Templates define params?
+
+       // challenge response values
+       // this is s_notprime instead of s
+       // because the serialization macros
+       // define something named s and it conflicts
+       vector<Bignum> s_notprime;
+       vector<Bignum> sprime;
+       inline Bignum challengeCalculation(const Bignum& a_exp, const Bignum& b_exp,
+                                          const Bignum& h_exp) const;
+};
+
+} /* namespace libzerocoin */
+#endif /* SERIALNUMBERPROOF_H_ */
diff --git a/src/zerocoin/SpendMetaData.cpp b/src/zerocoin/SpendMetaData.cpp
new file mode 100644 (file)
index 0000000..83d5619
--- /dev/null
@@ -0,0 +1,19 @@
+/**
+* @file       SpendMetaData.cpp
+*
+* @brief      SpendMetaData class for the Zerocoin library.
+*
+* @author     Ian Miers, Christina Garman and Matthew Green
+* @date       June 2013
+*
+* @copyright  Copyright 2013 Ian Miers, Christina Garman and Matthew Green
+* @license    This project is released under the MIT license.
+**/
+
+#include "Zerocoin.h"
+
+namespace libzerocoin {
+
+SpendMetaData::SpendMetaData(uint256 accumulatorId, uint256 txHash): accumulatorId(accumulatorId), txHash(txHash) {}
+
+} /* namespace libzerocoin */
diff --git a/src/zerocoin/SpendMetaData.h b/src/zerocoin/SpendMetaData.h
new file mode 100644 (file)
index 0000000..855d8f9
--- /dev/null
@@ -0,0 +1,52 @@
+/**
+* @file       SpendMetaData.h
+*
+* @brief      SpendMetaData class for the Zerocoin library.
+*
+* @author     Ian Miers, Christina Garman and Matthew Green
+* @date       June 2013
+*
+* @copyright  Copyright 2013 Ian Miers, Christina Garman and Matthew Green
+* @license    This project is released under the MIT license.
+**/
+
+#ifndef SPENDMETADATA_H_
+#define SPENDMETADATA_H_
+
+#include "../uint256.h"
+#include "../serialize.h"
+
+using namespace std;
+namespace libzerocoin {
+
+/** Any meta data needed for actual bitcoin integration.
+ * Can extended provided the getHash() function is updated
+ */
+class SpendMetaData {
+public:
+       /**
+        * Creates meta data associated with a coin spend
+        * @param accumulatorId hash of block containing accumulator
+        * @param txHash hash of transaction
+        */
+       SpendMetaData(uint256 accumulatorId, uint256 txHash);
+
+       /**
+        * The hash of the block containing the accumulator CoinSpend
+        * proves membership in.
+        */
+       uint256 accumulatorId; // The block the accumulator is in
+       /**Contains the hash of the rest of transaction
+        * spending a zerocoin (excluding the coinspend proof)
+        */
+       uint256 txHash; // The Hash of the rest of the transaction the spend proof is n.
+       // Allows us to sign the transaction.
+       IMPLEMENT_SERIALIZE
+       (
+           READWRITE(accumulatorId);
+           READWRITE(txHash);
+       )
+};
+
+} /* namespace libzerocoin */
+#endif /* SPENDMETADATA_H_ */
diff --git a/src/zerocoin/Zerocoin.h b/src/zerocoin/Zerocoin.h
new file mode 100644 (file)
index 0000000..a7f69dc
--- /dev/null
@@ -0,0 +1,60 @@
+/**
+* @file       Zerocoin.h
+*
+* @brief      Exceptions and constants for Zerocoin
+*
+* @author     Ian Miers, Christina Garman and Matthew Green
+* @date       June 2013
+*
+* @copyright  Copyright 2013 Ian Miers, Christina Garman and Matthew Green
+* @license    This project is released under the MIT license.
+**/
+
+#ifndef ZEROCOIN_H_
+#define ZEROCOIN_H_
+
+#include <stdexcept>
+
+#define ZEROCOIN_DEFAULT_SECURITYLEVEL      80
+#define ZEROCOIN_MIN_SECURITY_LEVEL         80
+#define ZEROCOIN_MAX_SECURITY_LEVEL         80
+#define ACCPROOF_KPRIME                     160
+#define ACCPROOF_KDPRIME                    128
+#define MAX_COINMINT_ATTEMPTS               10000
+#define ZEROCOIN_MINT_PRIME_PARAM           20
+#define ZEROCOIN_VERSION_STRING             "0.11"
+#define ZEROCOIN_VERSION_INT                11
+#define ZEROCOIN_PROTOCOL_VERSION           "1"
+#define HASH_OUTPUT_BITS                    256
+#define ZEROCOIN_COMMITMENT_EQUALITY_PROOF  "COMMITMENT_EQUALITY_PROOF"
+#define ZEROCOIN_ACCUMULATOR_PROOF          "ACCUMULATOR_PROOF"
+#define ZEROCOIN_SERIALNUMBER_PROOF         "SERIALNUMBER_PROOF"
+
+// Activate multithreaded mode for proof verification
+#define ZEROCOIN_THREADING 1
+
+// Uses a fast technique for coin generation. Could be more vulnerable
+// to timing attacks. Turn off if an attacker can measure coin minting time.
+#define ZEROCOIN_FAST_MINT 1
+
+// Errors thrown by the Zerocoin library
+
+class ZerocoinException : public std::runtime_error
+{
+public:
+   explicit ZerocoinException(const std::string& str) : std::runtime_error(str) {}
+};
+
+#include "../serialize.h"
+#include "../bignum.h"
+#include "../util.h"
+#include "Params.h"
+#include "Coin.h"
+#include "Commitment.h"
+#include "Accumulator.h"
+#include "AccumulatorProofOfKnowledge.h"
+#include "CoinSpend.h"
+#include "SerialNumberSignatureOfKnowledge.h"
+#include "ParamGeneration.h"
+
+#endif /* ZEROCOIN_H_ */