aboutsummaryrefslogtreecommitdiff
path: root/src/ringct/rctOps.cpp
diff options
context:
space:
mode:
authorRiccardo Spagni <ric@spagni.net>2016-08-28 22:41:11 +0200
committerRiccardo Spagni <ric@spagni.net>2016-08-28 22:41:12 +0200
commit8a5b766d17761f5fbdd3e30e638daa98a40a4c8a (patch)
treeea05e3f0fd47fd1d8728e64d081292d337825cb9 /src/ringct/rctOps.cpp
parenta569b264bc4d4ca1a07c2eadcc24b5ab75fd0c84 (diff)
parent887db9f93670da8c1eb28c9d53d6d4f055486e3b (diff)
downloadmonzero-core-8a5b766d17761f5fbdd3e30e638daa98a40a4c8a.tar.gz
monzero-core-8a5b766d17761f5fbdd3e30e638daa98a40a4c8a.tar.xz
monzero-core-8a5b766d17761f5fbdd3e30e638daa98a40a4c8a.zip
Merge pull request #961
887db9f blockchain: testnet heights for v3, v4, and v5 (moneromooo-monero) f24ab58 ringct: remove unused code (moneromooo-monero) b38452b ringct: pass structure by const ref, not value (moneromooo-monero) fd11271 ringct: use memcpy/memset instead of handwritten loop where appropriate (moneromooo-monero) 5d38206 ringct: remove spurious copies (moneromooo-monero) 16732a8 rct: faster Cryptonote/rct conversions (moneromooo-monero) fbd7c35 wallet: fix some "may be used uninitialized" warnings (moneromooo-monero) 4a41dd4 wallet: do not generate 0 change (moneromooo-monero) a0925e6 core: use full rct signatures if just one input (moneromooo-monero) 94fd881 rct: early out on failure on verRange (moneromooo-monero) 45349b6 wallet: do not ask for duplicate histograms (moneromooo-monero) b951bc8 wallet: transfer_selected_rct now also selects fake outs (moneromooo-monero) 4f887de increase minimum mixin to 4 on hard fork 5 (moneromooo-monero) 0815c72 core: allow v1 txes after HF 5 when sweeping unmixable outputs (moneromooo-monero) f782d45 tests: hard fork list must end with a 0 (moneromooo-monero) 074e602 ringct: use Cryptonote serialization to hash non prunable data (moneromooo-monero) c3b3260 New "Halfway RingCT" outputs for coinbase transactions (moneromooo-monero) 6f526cd rct: log why verification fails (moneromooo-monero) d4b8991 rct: serialize txnFee as varint (moneromooo-monero) d4b62a1 rct amount key modified as per luigi1111's recommendations (moneromooo-monero) 93f5c62 rct: rework v2 txes into prunable and non prunable data (moneromooo-monero) d93746b rct: rework the verification preparation process (moneromooo-monero) 3ab2ab3 rct: change the simple flag to a type (moneromooo-monero) c5be4b0 rct: avoid the need for the last II element (Shen Noether) a47ceee wallet: do not store signatures in the wallet cache (moneromooo-monero) 0263dd2 core: add some locking around pool use (moneromooo-monero) 2c9d951 wallet2: factor m_spent changes (moneromooo-monero) 1303cda wallet: always use new algorithm for RPC transfers (moneromooo-monero) b337aea rct: do not serialize senderPk - it is not used anymore (moneromooo-monero) e5a9a47 core_tests: fix a couple pre-rct tests using rct (moneromooo-monero) 230fca2 wallet: use the prefered rct case only when enough rct outs exist (moneromooo-monero) c27194a wallet: do not try to use rct txes a few blocks before the fork (moneromooo-monero) 1bf0698 tx_pool: log why a transaction was rejected for version checks (moneromooo-monero) 37bdf6e change fork settings to allow pre-rct txes for one more fork cycle (moneromooo-monero) cc85cc6 simplewallet: better check_tx_key feedback (moneromooo-monero) 9b70856 rct: make the amount key derivable by a third party with the tx key (moneromooo-monero) cf33e1a rct: do not serialize public keys in outPk (moneromooo-monero) 83ab315 wallet2_api: zero amounts are now allowed with rct (moneromooo-monero) 096ac06 wallet2_api: update on_money_{received,spent} prototypes for rct changes (moneromooo-monero) 3cb2ede rpc: send global indices along with blocks/transacions on refresh (moneromooo-monero) 414b424 core: always use the new simple rct variant (moneromooo-monero) ce5de8b tests: add tests for wallet output selection (moneromooo-monero) 84c82cd wallet: better tx input selection (moneromooo-monero) 1e21651 rct: use the already defined H where possible (moneromooo-monero) 07d353d wallet: handle 0 change properly (moneromooo-monero) e81a2b2 port get_tx_key/check_tx_key to rct (moneromooo-monero) e06faef tests: add basic tests for simple rct api (moneromooo-monero) a4d4d61 integrate simple rct api (moneromooo-monero) 1e8d37e serialization: add override for serializing bool (moneromooo-monero) dbb5f2d ringct: optimization/cleanup of hash functions (Shen Noether) 4fd01f2 ringct: "simple" ringct variant (Shen Noether) 37c895e wallet: rct specific output selection (moneromooo-monero) 1181c57 wallet: make sweep_all work with rct txes too (moneromooo-monero) c2ec6d3 mixable transactions must be rct for v3 (moneromooo-monero) 1017a75 wallet: factor transfer_rct code with transfer code (moneromooo-monero) f5465d8 Condition v2 txes on v3 hard fork (moneromooo-monero) 59a66e2 move the rct commitments to the output_amounts database (moneromooo-monero) 6d0e471 rct: add the tx prefix hash into the MLSAG (moneromooo-monero) 35dce5c ringct: fix size unit mismatch calling keccak (moneromooo-monero) 20e50ec ringct: do not serialize what can be reconstructed (moneromooo-monero) 106e3dc Add rct core tests (moneromooo-monero) ada5275 Use the supplied hard fork version in validate_miner_transaction (moneromooo-monero) acbe06d wallet: update spent status when an accepted tx disappears (moneromooo-monero) 089df4a wallet: reset output spent status on blockchain reorg (moneromooo-monero) 73d59f1 ringct: catch errors from ge_frombytes_vartime (moneromooo-monero) 161551e tests: test for ringct rctSig data sizes (moneromooo-monero) 359f469 ringct: add missing size check for ecdhInfo (moneromooo-monero) 229968e ringct: change asserts to return false for boolean functions (moneromooo-monero) dc4aad7 add rct to the protocol (moneromooo-monero) 211d1db db_lmdb: update reset for recent db changes (moneromooo-monero) dee42d6 ringct: add functions to commit to an amount (moneromooo-monero) cc7f449 make rct tx serialization work (moneromooo-monero) e70e8a6 crypto: error out where appropriate (moneromooo-monero) 54f7429 ringct: allow no outputs, and add tests for this and fees (moneromooo-monero) e99904a ringct: make fee optional (moneromooo-monero) f8c04ad ringct: txn fee stuff (Shen Noether) 66f9626 ringct: new {gen,decode}Rct APIs for convenience (moneromooo-monero) 789b2e2 ringct: add more convenience functions (moneromooo-monero) 9856443 core: link against libringct (moneromooo-monero) 4258dab core: new /getrandom_rctouts.bin binary RPC call (moneromooo-monero) c3a2e14 ringct: add convenience functions to bridge ringct and cryptonote (moneromooo-monero) eb56d0f blockchain_db: add functions for adding/removing/getting rct commitments (moneromooo-monero) 82072e7 ringct: restore verRange check in debug mode (moneromooo-monero) 63856ca ringct: add check for destinations/amount size being equal (moneromooo-monero) e816a09 ringct: fix off by 1 in mixin usage (moneromooo-monero) 09c5ea4 ringct: simplify random key generation (moneromooo-monero) 53cdf4d tests: new ringct test for checking H2 values (Shen Noether) 56f6549 ringct: cosmetic fixes (Shen Noether) 55ff136 ringct: changes to hashToPointSimple to calcualte H2 values (Shen Noether) 63733b1 ringct: compare keys with bitwise equality, not crypto ops (Shen Noether) 98f4c6f ringct: fix size argument to cn_fast_hash (Shen Noether) 720ac85 tests: zero inputs/outputs are in fact supposed to be accepted (moneromooo-monero) 84948ea ringct: add a test for prooveRange being non deterministic (moneromooo-monero) 09fb9f4 Fix sc_0 to skGen in ProveRange (Shen Noether) d37c1db ringct: add a few consts where appropriate (moneromooo-monero) 700248f tests: more ringct range proof tests (moneromooo-monero) d02f999 rct: add serialization machinery to rct types (moneromooo-monero) 0ff8305 serialization: declare do_serialize specializations before use (moneromooo-monero) 8b135e7 Added note on generating H2 (Shen Noether) 4d639d9 Fixed missing last index H2 (Shen Noether) 9e82b69 remove original Cryptonote blockchain_storage blockchain format (moneromooo-monero) 86b4426 ringct: lock access to the PRNG (moneromooo-monero) 4d7f073 ringct: add simple input validation (moneromooo-monero) 57779ab tests: add some more ringct building block tests (moneromooo-monero) b656001 ringct: add convenience operators to key (moneromooo-monero) 2d6303f tests: add Shen Noether's basic ringct tests (moneromooo-monero) 9b1afe5 ringct: import of Shen Noether's ring confidential transactions (moneromooo-monero)
Diffstat (limited to 'src/ringct/rctOps.cpp')
-rw-r--r--src/ringct/rctOps.cpp475
1 files changed, 475 insertions, 0 deletions
diff --git a/src/ringct/rctOps.cpp b/src/ringct/rctOps.cpp
new file mode 100644
index 000000000..488e47ca0
--- /dev/null
+++ b/src/ringct/rctOps.cpp
@@ -0,0 +1,475 @@
+// Copyright (c) 2016, Monero Research Labs
+//
+// Author: Shen Noether <shen.noether@gmx.com>
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "misc_log_ex.h"
+#include "rctOps.h"
+using namespace crypto;
+using namespace std;
+
+namespace rct {
+
+ //Various key initialization functions
+
+ //Creates a zero scalar
+ void zero(key &zero) {
+ memset(&zero, 0, 32);
+ }
+
+ //Creates a zero scalar
+ key zero() {
+ static const key z = { {0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 , 0x00, 0x00, 0x00,0x00 } };
+ return z;
+ }
+
+ //Creates a zero elliptic curve point
+ void identity(key &Id) {
+ Id[0] = (unsigned char)(0x01);
+ memset(Id.bytes+1, 0, 31);
+ }
+
+ //Creates a zero elliptic curve point
+ key identity() {
+ key Id;
+ Id[0] = (unsigned char)(0x01);
+ memset(Id.bytes+1, 0, 31);
+ return Id;
+ }
+
+ //copies a scalar or point
+ void copy(key &AA, const key &A) {
+ memcpy(&AA, &A, 32);
+ }
+
+ //copies a scalar or point
+ key copy(const key &A) {
+ key AA;
+ memcpy(&AA, &A, 32);
+ return AA;
+ }
+
+
+ //initializes a key matrix;
+ //first parameter is rows,
+ //second is columns
+ keyM keyMInit(int rows, int cols) {
+ keyM rv(cols);
+ int i = 0;
+ for (i = 0 ; i < cols ; i++) {
+ rv[i] = keyV(rows);
+ }
+ return rv;
+ }
+
+
+
+
+ //Various key generation functions
+
+ //generates a random scalar which can be used as a secret key or mask
+ void skGen(key &sk) {
+ sk = crypto::rand<key>();
+ sc_reduce32(sk.bytes);
+ }
+
+ //generates a random scalar which can be used as a secret key or mask
+ key skGen() {
+ key sk = crypto::rand<key>();
+ sc_reduce32(sk.bytes);
+ return sk;
+ }
+
+ //Generates a vector of secret key
+ //Mainly used in testing
+ keyV skvGen(int rows ) {
+ keyV rv(rows);
+ int i = 0;
+ for (i = 0 ; i < rows ; i++) {
+ skGen(rv[i]);
+ }
+ return rv;
+ }
+
+ //generates a random curve point (for testing)
+ key pkGen() {
+ key sk = skGen();
+ key pk = scalarmultBase(sk);
+ return pk;
+ }
+
+ //generates a random secret and corresponding public key
+ void skpkGen(key &sk, key &pk) {
+ skGen(sk);
+ scalarmultBase(pk, sk);
+ }
+
+ //generates a random secret and corresponding public key
+ tuple<key, key> skpkGen() {
+ key sk = skGen();
+ key pk = scalarmultBase(sk);
+ return make_tuple(sk, pk);
+ }
+
+ //generates C =aG + bH from b, a is given..
+ void genC(key & C, const key & a, xmr_amount amount) {
+ key bH = scalarmultH(d2h(amount));
+ addKeys1(C, a, bH);
+ }
+
+ //generates a <secret , public> / Pedersen commitment to the amount
+ tuple<ctkey, ctkey> ctskpkGen(xmr_amount amount) {
+ ctkey sk, pk;
+ skpkGen(sk.dest, pk.dest);
+ skpkGen(sk.mask, pk.mask);
+ key am = d2h(amount);
+ key bH = scalarmultH(am);
+ addKeys(pk.mask, pk.mask, bH);
+ return make_tuple(sk, pk);
+ }
+
+
+ //generates a <secret , public> / Pedersen commitment but takes bH as input
+ tuple<ctkey, ctkey> ctskpkGen(key bH) {
+ ctkey sk, pk;
+ skpkGen(sk.dest, pk.dest);
+ skpkGen(sk.mask, pk.mask);
+ addKeys(pk.mask, pk.mask, bH);
+ return make_tuple(sk, pk);
+ }
+
+ key zeroCommit(xmr_amount amount) {
+ key mask = identity();
+ mask = scalarmultBase(mask);
+ key am = d2h(amount);
+ key bH = scalarmultH(am);
+ addKeys(mask, mask, bH);
+ return mask;
+ }
+
+ key commit(xmr_amount amount, key mask) {
+ mask = scalarmultBase(mask);
+ key am = d2h(amount);
+ key bH = scalarmultH(am);
+ addKeys(mask, mask, bH);
+ return mask;
+ }
+
+ //generates a random uint long long (for testing)
+ xmr_amount randXmrAmount(xmr_amount upperlimit) {
+ return h2d(skGen()) % (upperlimit);
+ }
+
+ //Scalar multiplications of curve points
+
+ //does a * G where a is a scalar and G is the curve basepoint
+ void scalarmultBase(key &aG,const key &a) {
+ ge_p3 point;
+ sc_reduce32copy(aG.bytes, a.bytes); //do this beforehand!
+ ge_scalarmult_base(&point, aG.bytes);
+ ge_p3_tobytes(aG.bytes, &point);
+ }
+
+ //does a * G where a is a scalar and G is the curve basepoint
+ key scalarmultBase(const key & a) {
+ ge_p3 point;
+ key aG;
+ sc_reduce32copy(aG.bytes, a.bytes); //do this beforehand
+ ge_scalarmult_base(&point, aG.bytes);
+ ge_p3_tobytes(aG.bytes, &point);
+ return aG;
+ }
+
+ //does a * P where a is a scalar and P is an arbitrary point
+ void scalarmultKey(key & aP, const key &P, const key &a) {
+ ge_p3 A;
+ ge_p2 R;
+ CHECK_AND_ASSERT_THROW_MES(ge_frombytes_vartime(&A, P.bytes) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__));
+ ge_scalarmult(&R, a.bytes, &A);
+ ge_tobytes(aP.bytes, &R);
+ }
+
+ //does a * P where a is a scalar and P is an arbitrary point
+ key scalarmultKey(const key & P, const key & a) {
+ ge_p3 A;
+ ge_p2 R;
+ CHECK_AND_ASSERT_THROW_MES(ge_frombytes_vartime(&A, P.bytes) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__));
+ ge_scalarmult(&R, a.bytes, &A);
+ key aP;
+ ge_tobytes(aP.bytes, &R);
+ return aP;
+ }
+
+
+ //Computes aH where H= toPoint(cn_fast_hash(G)), G the basepoint
+ key scalarmultH(const key & a) {
+ ge_p3 A;
+ ge_p2 R;
+ CHECK_AND_ASSERT_THROW_MES(ge_frombytes_vartime(&A, H.bytes) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__));
+ ge_scalarmult(&R, a.bytes, &A);
+ key aP;
+ ge_tobytes(aP.bytes, &R);
+ return aP;
+ }
+
+ //Curve addition / subtractions
+
+ //for curve points: AB = A + B
+ void addKeys(key &AB, const key &A, const key &B) {
+ ge_p3 B2, A2;
+ CHECK_AND_ASSERT_THROW_MES(ge_frombytes_vartime(&B2, B.bytes) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__));
+ CHECK_AND_ASSERT_THROW_MES(ge_frombytes_vartime(&A2, A.bytes) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__));
+ ge_cached tmp2;
+ ge_p3_to_cached(&tmp2, &B2);
+ ge_p1p1 tmp3;
+ ge_add(&tmp3, &A2, &tmp2);
+ ge_p1p1_to_p3(&A2, &tmp3);
+ ge_p3_tobytes(AB.bytes, &A2);
+ }
+
+
+ //addKeys1
+ //aGB = aG + B where a is a scalar, G is the basepoint, and B is a point
+ void addKeys1(key &aGB, const key &a, const key & B) {
+ key aG = scalarmultBase(a);
+ addKeys(aGB, aG, B);
+ }
+
+ //addKeys2
+ //aGbB = aG + bB where a, b are scalars, G is the basepoint and B is a point
+ void addKeys2(key &aGbB, const key &a, const key &b, const key & B) {
+ ge_p2 rv;
+ ge_p3 B2;
+ CHECK_AND_ASSERT_THROW_MES(ge_frombytes_vartime(&B2, B.bytes) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__));
+ ge_double_scalarmult_base_vartime(&rv, b.bytes, &B2, a.bytes);
+ ge_tobytes(aGbB.bytes, &rv);
+ }
+
+ //Does some precomputation to make addKeys3 more efficient
+ // input B a curve point and output a ge_dsmp which has precomputation applied
+ void precomp(ge_dsmp rv, const key & B) {
+ ge_p3 B2;
+ CHECK_AND_ASSERT_THROW_MES(ge_frombytes_vartime(&B2, B.bytes) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__));
+ ge_dsm_precomp(rv, &B2);
+ }
+
+ //addKeys3
+ //aAbB = a*A + b*B where a, b are scalars, A, B are curve points
+ //B must be input after applying "precomp"
+ void addKeys3(key &aAbB, const key &a, const key &A, const key &b, const ge_dsmp B) {
+ ge_p2 rv;
+ ge_p3 A2;
+ CHECK_AND_ASSERT_THROW_MES(ge_frombytes_vartime(&A2, A.bytes) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__));
+ ge_double_scalarmult_precomp_vartime(&rv, a.bytes, &A2, b.bytes, B);
+ ge_tobytes(aAbB.bytes, &rv);
+ }
+
+
+ //subtract Keys (subtracts curve points)
+ //AB = A - B where A, B are curve points
+ void subKeys(key & AB, const key &A, const key &B) {
+ ge_p3 B2, A2;
+ CHECK_AND_ASSERT_THROW_MES(ge_frombytes_vartime(&B2, B.bytes) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__));
+ CHECK_AND_ASSERT_THROW_MES(ge_frombytes_vartime(&A2, A.bytes) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__));
+ ge_cached tmp2;
+ ge_p3_to_cached(&tmp2, &B2);
+ ge_p1p1 tmp3;
+ ge_sub(&tmp3, &A2, &tmp2);
+ ge_p1p1_to_p3(&A2, &tmp3);
+ ge_p3_tobytes(AB.bytes, &A2);
+ }
+
+ //checks if A, B are equal as curve points
+ //without doing curve operations
+ bool equalKeys(const key & a, const key & b) {
+ bool rv = true;
+ for (int i = 0; i < 32; ++i) {
+ if (a.bytes[i] != b.bytes[i]) {
+ rv = false;
+ }
+ }
+ return rv;
+ }
+
+ //Hashing - cn_fast_hash
+ //be careful these are also in crypto namespace
+ //cn_fast_hash for arbitrary multiples of 32 bytes
+ void cn_fast_hash(key &hash, const void * data, const std::size_t l) {
+ keccak((uint8_t *)data, l, hash.bytes, 32);
+ }
+
+ void hash_to_scalar(key &hash, const void * data, const std::size_t l) {
+ cn_fast_hash(hash, data, l);
+ sc_reduce32(hash.bytes);
+ }
+
+ //cn_fast_hash for a 32 byte key
+ void cn_fast_hash(key & hash, const key & in) {
+ keccak((uint8_t *)in.bytes, 32, hash.bytes, 32);
+ }
+
+ void hash_to_scalar(key & hash, const key & in) {
+ cn_fast_hash(hash, in);
+ sc_reduce32(hash.bytes);
+ }
+
+ //cn_fast_hash for a 32 byte key
+ key cn_fast_hash(const key & in) {
+ key hash;
+ keccak((uint8_t *)in.bytes, 32, hash.bytes, 32);
+ return hash;
+ }
+
+ key hash_to_scalar(const key & in) {
+ key hash = cn_fast_hash(in);
+ sc_reduce32(hash.bytes);
+ return hash;
+ }
+
+ //cn_fast_hash for a 128 byte unsigned char
+ key cn_fast_hash128(const void * in) {
+ key hash;
+ keccak((uint8_t *)in, 128, hash.bytes, 32);
+ return hash;
+ }
+
+ key hash_to_scalar128(const void * in) {
+ key hash = cn_fast_hash128(in);
+ sc_reduce32(hash.bytes);
+ return hash;
+ }
+
+ //cn_fast_hash for multisig purpose
+ //This takes the outputs and commitments
+ //and hashes them into a 32 byte sized key
+ key cn_fast_hash(ctkeyV PC) {
+ key rv = identity();
+ std::size_t l = (std::size_t)PC.size();
+ size_t i = 0, j = 0;
+ vector<char> m(l * 64);
+ for (i = 0 ; i < l ; i++) {
+ memcpy(&m[i * 64], &PC[i].dest, 32);
+ memcpy(&m[i * 64 + 32], &PC[i].mask, 32);
+ }
+ cn_fast_hash(rv, &m[0], 64*l);
+ return rv;
+ }
+
+ key hash_to_scalar(ctkeyV PC) {
+ key rv = cn_fast_hash(PC);
+ sc_reduce32(rv.bytes);
+ return rv;
+ }
+
+ //cn_fast_hash for a key-vector of arbitrary length
+ //this is useful since you take a number of keys
+ //put them in the key vector and it concatenates them
+ //and then hashes them
+ key cn_fast_hash(const keyV &keys) {
+ size_t l = keys.size();
+ vector<unsigned char> m(l * 32);
+ size_t i;
+ for (i = 0 ; i < l ; i++) {
+ memcpy(&m[i * 32], keys[i].bytes, 32);
+ }
+ key rv;
+ cn_fast_hash(rv, &m[0], 32 * l);
+ //dp(rv);
+ return rv;
+ }
+
+ key hash_to_scalar(const keyV &keys) {
+ key rv = cn_fast_hash(keys);
+ sc_reduce32(rv.bytes);
+ return rv;
+ }
+
+ key hashToPointSimple(const key & hh) {
+ key pointk;
+ ge_p1p1 point2;
+ ge_p2 point;
+ ge_p3 res;
+ key h = cn_fast_hash(hh);
+ CHECK_AND_ASSERT_THROW_MES(ge_frombytes_vartime(&res, h.bytes) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__));
+ ge_p3_to_p2(&point, &res);
+ ge_mul8(&point2, &point);
+ ge_p1p1_to_p3(&res, &point2);
+ ge_p3_tobytes(pointk.bytes, &res);
+ return pointk;
+ }
+
+ key hashToPoint(const key & hh) {
+ key pointk;
+ ge_p2 point;
+ ge_p1p1 point2;
+ ge_p3 res;
+ key h = cn_fast_hash(hh);
+ ge_fromfe_frombytes_vartime(&point, h.bytes);
+ ge_mul8(&point2, &point);
+ ge_p1p1_to_p3(&res, &point2);
+ ge_p3_tobytes(pointk.bytes, &res);
+ return pointk;
+ }
+
+ void hashToPoint(key & pointk, const key & hh) {
+ ge_p2 point;
+ ge_p1p1 point2;
+ ge_p3 res;
+ key h = cn_fast_hash(hh);
+ ge_fromfe_frombytes_vartime(&point, h.bytes);
+ ge_mul8(&point2, &point);
+ ge_p1p1_to_p3(&res, &point2);
+ ge_p3_tobytes(pointk.bytes, &res);
+ }
+
+ //sums a vector of curve points (for scalars use sc_add)
+ void sumKeys(key & Csum, const keyV & Cis) {
+ identity(Csum);
+ size_t i = 0;
+ for (i = 0; i < Cis.size(); i++) {
+ addKeys(Csum, Csum, Cis[i]);
+ }
+ }
+
+ //Elliptic Curve Diffie Helman: encodes and decodes the amount b and mask a
+ // where C= aG + bH
+ void ecdhEncode(ecdhTuple & unmasked, const key & sharedSec) {
+ key sharedSec1 = hash_to_scalar(sharedSec);
+ key sharedSec2 = hash_to_scalar(sharedSec1);
+ //encode
+ sc_add(unmasked.mask.bytes, unmasked.mask.bytes, sharedSec1.bytes);
+ sc_add(unmasked.amount.bytes, unmasked.amount.bytes, sharedSec2.bytes);
+ }
+ void ecdhDecode(ecdhTuple & masked, const key & sharedSec) {
+ key sharedSec1 = hash_to_scalar(sharedSec);
+ key sharedSec2 = hash_to_scalar(sharedSec1);
+ //decode
+ sc_sub(masked.mask.bytes, masked.mask.bytes, sharedSec1.bytes);
+ sc_sub(masked.amount.bytes, masked.amount.bytes, sharedSec2.bytes);
+ }
+}