diff --git a/Builds/VisualStudio2013/RippleD.vcxproj b/Builds/VisualStudio2013/RippleD.vcxproj index bab6ec822b..ed138af427 100644 --- a/Builds/VisualStudio2013/RippleD.vcxproj +++ b/Builds/VisualStudio2013/RippleD.vcxproj @@ -1780,6 +1780,8 @@ + + @@ -1852,6 +1854,8 @@ + + @@ -2302,6 +2306,10 @@ True + + + + @@ -2310,6 +2318,12 @@ + + True + + + True + True @@ -2426,6 +2440,8 @@ + + diff --git a/Builds/VisualStudio2013/RippleD.vcxproj.filters b/Builds/VisualStudio2013/RippleD.vcxproj.filters index f0bd610bd7..501f0309e5 100644 --- a/Builds/VisualStudio2013/RippleD.vcxproj.filters +++ b/Builds/VisualStudio2013/RippleD.vcxproj.filters @@ -2667,6 +2667,9 @@ ripple\basics + + ripple\basics + ripple\basics @@ -2754,6 +2757,9 @@ ripple\basics + + ripple\basics + ripple\basics @@ -3315,6 +3321,12 @@ ripple\peerfinder\tests + + ripple\protocol + + + ripple\protocol + ripple\protocol @@ -3327,6 +3339,12 @@ ripple\protocol + + ripple\protocol\impl + + + ripple\protocol\impl + ripple\protocol\impl @@ -3462,6 +3480,9 @@ ripple\protocol + + ripple\protocol + ripple\protocol diff --git a/src/ripple/basics/Buffer.h b/src/ripple/basics/Buffer.h new file mode 100644 index 0000000000..374a6ed377 --- /dev/null +++ b/src/ripple/basics/Buffer.h @@ -0,0 +1,149 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_BASICS_BUFFER_H_INCLUDED +#define RIPPLE_BASICS_BUFFER_H_INCLUDED + +#include +#include +#include +#include +#include + +namespace ripple { + +/** Like std::vector but better. + Meets the requirements of BufferFactory. +*/ +class Buffer +{ +private: + std::unique_ptr< + std::uint8_t[]> p_; + std::size_t size_ = 0; + +public: + Buffer() = default; + Buffer (Buffer const&) = delete; + Buffer& operator= (Buffer const&) = delete; + + /** Move-construct. + The other buffer is reset. + */ + Buffer (Buffer&& other) + : p_ (std::move(other.p_)) + , size_ (other.size_) + { + other.size_ = 0; + } + + /** Move-assign. + The other buffer is reset. + */ + Buffer& operator= (Buffer&& other) + { + p_ = std::move(other.p_); + size_ = other.size_; + other.size_ = 0; + return *this; + } + + /** Create an uninitialized buffer with the given size. */ + explicit + Buffer (std::size_t size) + : p_ (size ? + new std::uint8_t[size] : nullptr) + , size_ (size) + { + } + + /** Create a buffer as a copy of existing memory. */ + Buffer (void const* data, std::size_t size) + : p_ (size ? + new std::uint8_t[size] : nullptr) + , size_ (size) + { + std::memcpy(p_.get(), data, size); + } + + /** Returns the number of bytes in the buffer. */ + std::size_t + size() const noexcept + { + return size_; + } + + /** Return a pointer to beginning of the storage. + @note The return type is guaranteed to be a pointer + to a single byte, to facilitate pointer arithmetic. + */ + /** @{ */ + std::uint8_t const* + data() const noexcept + { + return p_.get(); + } + + std::uint8_t* + data() noexcept + { + return p_.get(); + } + /** @} */ + + /** Reset the buffer. + All memory is deallocated. The resulting size is 0. + */ + void + clear() noexcept + { + p_.reset(); + size_ = 0; + } + + /** Reallocate the storage. + Existing data, if any, is discarded. + */ + std::uint8_t* + alloc (std::size_t n) + { + if (n == 0) + { + clear(); + return nullptr; + } + if (n != size_) + { + p_.reset(new std::uint8_t[n]); + size_ = n; + } + return p_.get(); + } + + // Meet the requirements of BufferFactory + void* + operator()(std::size_t n) + { + return alloc(n); + } +}; + +} // ripple + +#endif diff --git a/src/ripple/basics/Slice.h b/src/ripple/basics/Slice.h new file mode 100644 index 0000000000..83ab9a7a0b --- /dev/null +++ b/src/ripple/basics/Slice.h @@ -0,0 +1,110 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_BASICS_SLICE_H_INCLUDED +#define RIPPLE_BASICS_SLICE_H_INCLUDED + +#include +#include +#include +#include + +namespace ripple { + +/** An immutable linear range of bytes. + + A fully constructed Slice is guaranteed to be in a valid state. + Default construction, construction from nullptr, and zero-byte + ranges are disallowed. A Slice is lightweight and copyable, it + retains no ownership of the underlying memory. +*/ +class Slice +{ +private: + std::uint8_t const* data_; + std::size_t size_; + +public: + // Disallowed + Slice() = delete; + + Slice (Slice const&) = default; + + Slice& operator= (Slice const&) = default; + + /** Create a slice pointing to existing memory. */ + Slice (void const* data, std::size_t size) + : data_ (reinterpret_cast< + std::uint8_t const*>(data)) + , size_ (size) + { + assert(data_ != nullptr); + assert(size_ > 0); + } + + /** Returns the number of bytes in the storage. + + This will never be zero. + */ + std::size_t + size() const noexcept + { + return size_; + } + + /** Return a pointer to beginning of the storage. + @note The return type is guaranteed to be a pointer + to a single byte, to facilitate pointer arithmetic. + */ + std::uint8_t const* + data() const noexcept + { + return data_; + } +}; + +template +inline +void +hash_append (Hasher& h, Slice const& v) +{ + h.append(v.data(), v.size()); +} + +inline +bool +operator== (Slice const& lhs, Slice const& rhs) noexcept +{ + return lhs.size() == rhs.size() && + std::memcmp( + lhs.data(), rhs.data(), lhs.size()) == 0; +} + +inline +bool +operator< (Slice const& lhs, Slice const& rhs) noexcept +{ + return std::lexicographical_compare( + lhs.data(), lhs.data() + lhs.size(), + rhs.data(), rhs.data() + rhs.size()); +} + +} // ripple + +#endif diff --git a/src/ripple/protocol/AnyPublicKey.h b/src/ripple/protocol/AnyPublicKey.h new file mode 100644 index 0000000000..059e5ebc6f --- /dev/null +++ b/src/ripple/protocol/AnyPublicKey.h @@ -0,0 +1,185 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_ANYPUBLICKEY_H_INCLUDED +#define RIPPLE_PROTOCOL_ANYPUBLICKEY_H_INCLUDED + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ripple { + +enum class KeyType +{ + unknown, + secp256k1, + ed25519 +}; + +//------------------------------------------------------------------------------ + +/** Variant container for all public keys. */ +class AnyPublicKeySlice + : public Slice +{ +public: +#ifdef _MSC_VER + AnyPublicKeySlice ( + void const* data, std::size_t size) + : Slice (data, size) + { + } +#else + using Slice::Slice; +#endif + + AnyPublicKeySlice() = delete; + + AnyPublicKeySlice ( + AnyPublicKeySlice const&) = default; + + AnyPublicKeySlice& operator= ( + AnyPublicKeySlice const&) = default; + + /** Returns the type of key stored. */ + KeyType + type() const noexcept; + + /** Verify a signature using this public key. */ + bool + verify (void const* msg, std::size_t msg_size, + void const* sig, std::size_t sig_size) const; +}; + +template <> +struct STExchange +{ + using value_type = AnyPublicKeySlice; + + static + void + get (boost::optional& t, + STBlob const& u) + { + t = boost::in_place(u.data(), u.size()); + } + + static + std::unique_ptr + set (SField const& f, AnyPublicKeySlice const& t) + { + return std::make_unique( + f, t.data(), t.size()); + } +}; + +//------------------------------------------------------------------------------ + +/** Variant container for all public keys, with ownership. */ +class AnyPublicKey + : private boost::base_from_member + , public AnyPublicKeySlice +{ +private: + using buffer_type = boost::base_from_member; + +public: + AnyPublicKey() = delete; + AnyPublicKey (AnyPublicKey const&) = delete; + AnyPublicKey& operator= (AnyPublicKey const&) = delete; + +#ifdef _MSC_VER + AnyPublicKey (AnyPublicKey&& other) + : buffer_type(std::move(other.buffer_type::member)) + , AnyPublicKeySlice (buffer_type::member.data(), + buffer_type::member.size()) + { + } + + AnyPublicKey& operator= (AnyPublicKey&& other) + { + buffer_type::member = + std::move(other.buffer_type::member); + return *this; + } +#else + AnyPublicKey (AnyPublicKey&&) = default; + AnyPublicKey& operator= (AnyPublicKey&&) = default; +#endif + + AnyPublicKey (void const* data_, std::size_t size_) + : buffer_type (data_, size_) + , AnyPublicKeySlice ( + member.data(), member.size()) + { + } + + /** Returns ownership of the underlying Buffer. + After calling this function, only the destructor + or the move assignment operator may be called. + */ + Buffer + releaseBuffer() noexcept + { + return std::move(buffer_type::member); + } +}; + +template <> +struct STExchange +{ + using value_type = AnyPublicKey; + + static + void + get (boost::optional& t, + STBlob const& u) + { + t = boost::in_place(u.data(), u.size()); + } + + static + std::unique_ptr + set (SField const& f, AnyPublicKey const& t) + { + return std::make_unique( + f, t.data(), t.size()); + } + + static + std::unique_ptr + set (SField const& f, AnyPublicKey&& t) + { + return std::make_unique( + f, t.releaseBuffer()); + } +}; + +} // ripple + +#endif diff --git a/src/ripple/protocol/AnySecretKey.h b/src/ripple/protocol/AnySecretKey.h new file mode 100644 index 0000000000..a92cc82812 --- /dev/null +++ b/src/ripple/protocol/AnySecretKey.h @@ -0,0 +1,85 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_ANYSECRETKEY_H_INCLUDED +#define RIPPLE_PROTOCOL_ANYSECRETKEY_H_INCLUDED + +#include +#include +#include +#include +#include +#include +#include + +namespace ripple { + +/** Variant container for secret key, with ownership. */ +class AnySecretKey +{ +private: + Buffer p_; + KeyType type_; + +public: + AnySecretKey() = delete; + AnySecretKey (AnySecretKey const&) = delete; + AnySecretKey& operator= (AnySecretKey const&) = delete; + + /** Destroy the key. + The memory area is secure erased. + */ + ~AnySecretKey(); + + AnySecretKey (AnySecretKey&& other); + + AnySecretKey& operator= (AnySecretKey&& other); + + AnySecretKey (KeyType type, + void const* data, std::size_t size); + + /** Returns the type of secret key. */ + KeyType + type() const noexcept + { + return type_; + } + + /** Returns the corresponding public key. */ + AnyPublicKey + publicKey() const; + + /** Create a signature for the given message. */ + Buffer + sign (void const* msg, std::size_t msg_len) const; + + /** Securely generate a new ed25519 secret key. */ + static + AnySecretKey + make_ed25519(); + + /** Securely generate a new secp256k1 key pair. */ + static + std::pair + make_secp256k1_pair(); +}; + +} // ripple + +#endif diff --git a/src/ripple/protocol/RippleAddress.h b/src/ripple/protocol/RippleAddress.h index 259c32e61a..dfb66cbafa 100644 --- a/src/ripple/protocol/RippleAddress.h +++ b/src/ripple/protocol/RippleAddress.h @@ -25,6 +25,7 @@ #include #include #include +#include namespace ripple { @@ -53,6 +54,18 @@ private: public: RippleAddress (); + void const* + data() const noexcept + { + return vchData.data(); + } + + std::size_t + size() const noexcept + { + return vchData.size(); + } + // For public and private key, checks if they are legal. bool isValid () const { diff --git a/src/ripple/protocol/SField.h b/src/ripple/protocol/SField.h index 8dcf0337b5..1265ba8832 100644 --- a/src/ripple/protocol/SField.h +++ b/src/ripple/protocol/SField.h @@ -22,9 +22,16 @@ #include #include +#include +#include namespace ripple { +// Forwards +class STBlob; +template +class STInteger; + enum SerializedTypeID { // special types @@ -139,7 +146,7 @@ public: {} #endif -private: +protected: // These constructors can only be called from FieldNames.cpp SField (SerializedTypeID tid, int fv, const char* fn, int meta = sMD_Default, bool signing = true); @@ -253,6 +260,25 @@ private: static int num; }; +/** A field with a type known at compile time. */ +template +struct TypedField : SField +{ + using type = T; + + template + explicit + TypedField (Args&&... args) + : SField(std::forward(args)...) + { + } + + TypedField (TypedField&& u) + : SField(std::move(u)) + { + } +}; + extern SField const sfInvalid; extern SField const sfGeneric; extern SField const sfLedgerEntry; @@ -272,7 +298,7 @@ extern SField const sfTransactionType; // 32-bit integers (common) extern SField const sfFlags; extern SField const sfSourceTag; -extern SField const sfSequence; +extern TypedField> const sfSequence; extern SField const sfPreviousTxnLgrSeq; extern SField const sfLedgerSequence; extern SField const sfCloseTime; @@ -359,12 +385,12 @@ extern SField const sfRippleEscrow; extern SField const sfDeliveredAmount; // variable length -extern SField const sfPublicKey; +extern TypedField const sfPublicKey; extern SField const sfMessageKey; -extern SField const sfSigningPubKey; +extern TypedField const sfSigningPubKey; extern SField const sfTxnSignature; extern SField const sfGenerator; -extern SField const sfSignature; +extern TypedField const sfSignature; extern SField const sfDomain; extern SField const sfFundCode; extern SField const sfRemoveCode; @@ -413,6 +439,8 @@ extern SField const sfSufficient; extern SField const sfAffectedNodes; extern SField const sfMemos; +//------------------------------------------------------------------------------ + } // ripple #endif diff --git a/src/ripple/protocol/STBlob.h b/src/ripple/protocol/STBlob.h index 9f262fb7d3..6952b8be83 100644 --- a/src/ripple/protocol/STBlob.h +++ b/src/ripple/protocol/STBlob.h @@ -20,7 +20,10 @@ #ifndef RIPPLE_PROTOCOL_STBLOB_H_INCLUDED #define RIPPLE_PROTOCOL_STBLOB_H_INCLUDED +#include +#include #include +#include #include namespace ripple { @@ -30,19 +33,58 @@ class STBlob : public STBase { public: + using value_type = Slice; + STBlob () = default; + /** Construct with size and initializer. + Init will be called as: + void(void* data, std::size_t size) + */ + template + STBlob (SField::ref f, std::size_t size, + Init&& init) + : STBase(f) + { + value.resize(size); + init(value.data(), value.size()); + } + + STBlob (SField::ref f, + void const* data, std::size_t size) + : STBase(f) + { + value.resize(size); + std::memcpy(value.data(), data, size); + } + + STBlob (SField const& f, Buffer&& b) + : STBase(f) + { + // VFALCO TODO Really move the buffer + value.resize(b.size()); + std::memcpy(value.data(), + b.data(), b.size()); + auto tmp = std::move(b); + } + + // VFALCO DEPRECATED STBlob (Blob const& v) : value (v) - { } + { + } + // VFALCO DEPRECATED STBlob (SField::ref n, Blob const& v) - : STBase (n), value (v) - { } + : STBase (n) + , value (v) + { + } STBlob (SField::ref n) : STBase (n) - { } + { + } STBlob (SerialIter&, SField::ref name = sfGeneric); @@ -53,6 +95,19 @@ public: return std::make_unique (name, sit.getVL ()); } + std::size_t + size() const + { + return value.size(); + } + + std::uint8_t const* + data() const + { + return reinterpret_cast< + std::uint8_t const*>(value.data()); + } + SerializedTypeID getSType () const override { @@ -95,6 +150,13 @@ public: value = v; } + void + setValue (void const* data, std::size_t size) + { + value.resize(size); + std::memcpy(value.data(), data, size); + } + explicit operator Blob () const { diff --git a/src/ripple/protocol/STExchange.h b/src/ripple/protocol/STExchange.h new file mode 100644 index 0000000000..c2be05b297 --- /dev/null +++ b/src/ripple/protocol/STExchange.h @@ -0,0 +1,202 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_STEXCHANGE_H_INCLUDED +#define RIPPLE_PROTOCOL_STEXCHANGE_H_INCLUDED + +#include +#include +#include +#include +#include +#include +#include +#include +#include // +#include +#include +#include + +namespace ripple { + +/** Convert between serialized type U and C++ type T. */ +template +struct STExchange; + + +template +struct STExchange, T> +{ + using value_type = U; + + static + void + get (boost::optional& t, + STInteger const& u) + { + t = u.getValue(); + } + + static + std::unique_ptr> + set (SField const& f, T const& t) + { + return std::make_unique< + STInteger>(f, t); + } +}; + +template <> +struct STExchange +{ + using value_type = Slice; + + static + void + get (boost::optional& t, + STBlob const& u) + { + t = boost::in_place(u.data(), u.size()); + } + + static + std::unique_ptr + set (TypedField const& f, + Slice const& t) + { + return std::make_unique( + f, t.data(), t.size()); + } +}; + +template <> +struct STExchange +{ + using value_type = Buffer; + + static + void + get (boost::optional& t, + STBlob const& u) + { + t = boost::in_place( + u.data(), u.size()); + } + + static + std::unique_ptr + set (TypedField const& f, + Buffer const& t) + { + return std::make_unique( + f, t.data(), t.size()); + } + + static + std::unique_ptr + set (TypedField const& f, + Buffer&& t) + { + return std::make_unique( + f, std::move(t)); + } +}; + +//------------------------------------------------------------------------------ + +/** Return the value of a field in an STObject as a given type. */ +/** @{ */ +template +boost::optional +get (STObject const& st, + TypedField const& f) +{ + boost::optional t; + STBase const* const b = + st.peekAtPField(f); + if (! b) + return t; + auto const id = b->getSType(); + if (id == STI_NOTPRESENT) + return t; + auto const u = + dynamic_cast(b); + // This should never happen + if (! u) + throw std::runtime_error ( + "Wrong field type"); + STExchange::get(t, *u); + return t; +} + +template +boost::optional::value_type> +get (STObject const& st, + TypedField const& f) +{ + return get(st, f); +} +/** @} */ + +/** Set a field value in an STObject. */ +template +void +set (STObject& st, + TypedField const& f, T&& t) +{ + st.set(STExchange::type>::set( + f, std::forward(t))); +} + +/** Set a blob field using an init function. */ +template +void +set (STObject& st, + TypedField const& f, + std::size_t size, Init&& init) +{ + st.set(std::make_unique( + f, size, init)); +} + +/** Set a blob field from data. */ +template +void +set (STObject& st, + TypedField const& f, + void const* data, std::size_t size) +{ + st.set(std::make_unique( + f, data, size)); +} + +/** Remove a field in an STObject. */ +template +void +erase (STObject& st, + TypedField const& f) +{ + st.makeFieldAbsent(f); +} + +} // ripple + +#endif diff --git a/src/ripple/protocol/STInteger.h b/src/ripple/protocol/STInteger.h index e135829589..d6874a0f6d 100644 --- a/src/ripple/protocol/STInteger.h +++ b/src/ripple/protocol/STInteger.h @@ -29,6 +29,8 @@ class STInteger : public STBase { public: + using value_type = Integer; + explicit STInteger (Integer v) : value_ (v) diff --git a/src/ripple/protocol/STObject.h b/src/ripple/protocol/STObject.h index 37f076a41a..1851a1e043 100644 --- a/src/ripple/protocol/STObject.h +++ b/src/ripple/protocol/STObject.h @@ -221,6 +221,12 @@ public: const STVector256& getFieldV256 (SField::ref field) const; const STArray& getFieldArray (SField::ref field) const; + /** Set a field. + if the field already exists, it is replaced. + */ + void + set (std::unique_ptr v); + void setFieldU8 (SField::ref field, unsigned char); void setFieldU16 (SField::ref field, std::uint16_t); void setFieldU32 (SField::ref field, std::uint32_t); @@ -419,8 +425,8 @@ private: } private: - boost::ptr_vector mData; - const SOTemplate* mType; + boost::ptr_vector mData; + const SOTemplate* mType; }; } // ripple diff --git a/src/ripple/protocol/Serializer.h b/src/ripple/protocol/Serializer.h index c48c9f53fc..c3e9b0b21a 100644 --- a/src/ripple/protocol/Serializer.h +++ b/src/ripple/protocol/Serializer.h @@ -63,6 +63,18 @@ public: ; } + std::size_t + size() const noexcept + { + return mData.size(); + } + + void const* + data() const noexcept + { + return mData.data(); + } + // assemble functions int add8 (unsigned char byte); int add16 (std::uint16_t); @@ -239,10 +251,6 @@ public: { return mData.end (); } - Blob ::size_type size () const - { - return mData.size (); - } void reserve (size_t n) { mData.reserve (n); diff --git a/src/ripple/protocol/Sign.h b/src/ripple/protocol/Sign.h new file mode 100644 index 0000000000..292aca5612 --- /dev/null +++ b/src/ripple/protocol/Sign.h @@ -0,0 +1,50 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_PROTOCOL_SIGN_H_INCLUDED +#define RIPPLE_PROTOCOL_SIGN_H_INCLUDED + +#include +#include +#include +#include +#include + +namespace ripple { + +/** Sign a STObject using any secret key. + The signature is placed in sfSignature. If + a signature already exists, it is overwritten. +*/ +void +sign (STObject& st, + HashPrefix const& prefix, + AnySecretKey const& sk); + +/** Verify the signature on a STObject. + The signature must be contained in sfSignature. +*/ +bool +verify (STObject const& st, + HashPrefix const& prefix, + AnyPublicKeySlice const& pk); + +} // ripple + +#endif diff --git a/src/ripple/protocol/impl/AnyPublicKey.cpp b/src/ripple/protocol/impl/AnyPublicKey.cpp new file mode 100644 index 0000000000..0ce3b75764 --- /dev/null +++ b/src/ripple/protocol/impl/AnyPublicKey.cpp @@ -0,0 +1,93 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include +#include +#include +#include +#include + +namespace ripple { + +/** Verify a secp256k1 signature. */ +bool +verify_secp256k1 (void const* pk, + void const* msg, std::size_t msg_size, + void const* sig, std::size_t sig_size) +{ + return false; +} + +bool +verify_ed25519 (void const* pk, + void const* msg, std::size_t msg_size, + void const* sig, std::size_t sig_size) +{ + if (sig_size != 64) + return false; + ed25519_public_key epk; + ed25519_signature es; + std::memcpy(epk, pk, 32); + std::memcpy(es, sig, sig_size); + return ed25519_sign_open( + reinterpret_cast(msg), + msg_size, epk, es) == 0; +} + +//------------------------------------------------------------------------------ + +KeyType +AnyPublicKeySlice::type() const noexcept +{ + auto const pk = data(); + auto const pk_size = size(); + + if (pk_size < 1) + return KeyType::unknown; + auto const len = pk_size - 1; + if (len == 32 && + pk[0] == 0xED) + return KeyType::ed25519; + if (len == 33 && + (pk[0] == 0x02 || pk[0] == 0x03)) + return KeyType::secp256k1; + return KeyType::unknown; +} + +bool +AnyPublicKeySlice::verify ( + void const* msg, std::size_t msg_size, + void const* sig, std::size_t sig_size) const +{ + switch(type()) + { + case KeyType::ed25519: + return verify_ed25519(data() + 1, + msg, msg_size, sig, sig_size); + case KeyType::secp256k1: + return verify_secp256k1(data() + 1, + msg, msg_size, sig, sig_size); + default: + break; + } + // throw? + return false; +} + +} // ripple diff --git a/src/ripple/protocol/impl/AnySecretKey.cpp b/src/ripple/protocol/impl/AnySecretKey.cpp new file mode 100644 index 0000000000..702d5a7f48 --- /dev/null +++ b/src/ripple/protocol/impl/AnySecretKey.cpp @@ -0,0 +1,143 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ripple { + +AnySecretKey::~AnySecretKey() +{ + // secure erase + std::fill(p_.data(), p_.data() + p_.size(), 0); +} + +AnySecretKey::AnySecretKey (AnySecretKey&& other) + : p_ (std::move(other.p_)) + , type_ (other.type_) +{ + other.type_ = KeyType::unknown; +} + +AnySecretKey& +AnySecretKey::operator= (AnySecretKey&& other) +{ + p_ = std::move(other.p_); + type_ = other.type_; + other.type_ = KeyType::unknown; + return *this; +} + +AnySecretKey::AnySecretKey (KeyType type, + void const* data, std::size_t size) + : p_ (data, size) + , type_ (type) +{ + if (type_ == KeyType::unknown) + throw std::runtime_error( + "AnySecretKey: unknown type"); + if (type_ == KeyType::ed25519 && + size != 32) + throw std::runtime_error( + "AnySecretKey: wrong ed25519 size"); + if (type_ == KeyType::secp256k1 && + size != 32) + throw std::runtime_error( + "AnySecretKey: wrong secp256k1 size"); +} + +AnyPublicKey +AnySecretKey::publicKey() const +{ + switch (type()) + { + case KeyType::ed25519: + { + unsigned char buf[33]; + buf[0] = 0xED; + ed25519_publickey(p_.data() + 1, &buf[1]); + return AnyPublicKey(buf, sizeof(buf)); + } + default: + throw std::runtime_error( + "AnySecretKey: unknown type"); + }; +} + +Buffer +AnySecretKey::sign ( + void const* msg, std::size_t msg_len) const +{ + switch(type_) + { + case KeyType::ed25519: + { + auto const sk = p_.data() + 1; + ed25519_public_key pk; + ed25519_publickey(sk, pk); + Buffer b(64); + ed25519_sign(reinterpret_cast< + unsigned char const*>(msg), msg_len, + sk, pk, b.data()); + return b; + } + default: + break; + } + throw std::runtime_error( + "AnySecretKey: unknown type"); +} + +AnySecretKey +AnySecretKey::make_ed25519() +{ + std::uint8_t buf[32]; + random_fill(&buf[0], sizeof(buf)); + AnySecretKey ask(KeyType::ed25519, + buf, sizeof(buf)); + // secure erase + std::fill(buf, buf + sizeof(buf), 0); + return ask; +} + +std::pair +AnySecretKey::make_secp256k1_pair() +{ + // VFALCO What a pile + RippleAddress s; + s.setSeedRandom(); + RippleAddress const g = + RippleAddress::createGeneratorPublic(s); + RippleAddress sk; + sk.setAccountPrivate (g, s, 0); + RippleAddress pk; + pk.setAccountPublic (g, 0); + return std::pair( + std::piecewise_construct, std::make_tuple( + KeyType::secp256k1, sk.data(), sk.size()), + std::make_tuple(pk.data(), pk.size())); +} + +} // ripple diff --git a/src/ripple/protocol/impl/SField.cpp b/src/ripple/protocol/impl/SField.cpp index 7eb2b2bac3..d6c7a3151a 100644 --- a/src/ripple/protocol/impl/SField.cpp +++ b/src/ripple/protocol/impl/SField.cpp @@ -41,7 +41,6 @@ typedef std::lock_guard StaticScopedLockType; // Give this translation unit only, permission to construct SFields struct SField::make { -#ifndef _MSC_VER template static SField one(SField const* p, Args&& ...args) { @@ -49,45 +48,14 @@ struct SField::make knownCodeToField[result.fieldCode] = p; return result; } -#else // remove this when VS gets variadic templates - template - static SField one(SField const* p, A0&& arg0) - { - SField result(std::forward(arg0)); - knownCodeToField[result.fieldCode] = p; - return result; - } - template - static SField one(SField const* p, A0&& arg0, A1&& arg1, A2&& arg2) + template + static TypedField one(SField const* p, Args&& ...args) { - SField result(std::forward(arg0), std::forward(arg1), - std::forward(arg2)); + TypedField result(std::forward(args)...); knownCodeToField[result.fieldCode] = p; return result; } - - template - static SField one(SField const* p, A0&& arg0, A1&& arg1, A2&& arg2, - A3&& arg3) - { - SField result(std::forward(arg0), std::forward(arg1), - std::forward(arg2), std::forward(arg3)); - knownCodeToField[result.fieldCode] = p; - return result; - } - - template - static SField one(SField const* p, A0&& arg0, A1&& arg1, A2&& arg2, - A3&& arg3, A4&& arg4) - { - SField result(std::forward(arg0), std::forward(arg1), - std::forward(arg2), std::forward(arg3), - std::forward(arg4)); - knownCodeToField[result.fieldCode] = p; - return result; - } -#endif }; using make = SField::make; @@ -116,7 +84,7 @@ SField const sfTransactionType = make::one(&sfTransactionType, STI_UINT16, 2, "T // 32-bit integers (common) SField const sfFlags = make::one(&sfFlags, STI_UINT32, 2, "Flags"); SField const sfSourceTag = make::one(&sfSourceTag, STI_UINT32, 3, "SourceTag"); -SField const sfSequence = make::one(&sfSequence, STI_UINT32, 4, "Sequence"); +TypedField> const sfSequence = make::one>(&sfSequence, STI_UINT32, 4, "Sequence"); SField const sfPreviousTxnLgrSeq = make::one(&sfPreviousTxnLgrSeq, STI_UINT32, 5, "PreviousTxnLgrSeq", SField::sMD_DeleteFinal); SField const sfLedgerSequence = make::one(&sfLedgerSequence, STI_UINT32, 6, "LedgerSequence"); SField const sfCloseTime = make::one(&sfCloseTime, STI_UINT32, 7, "CloseTime"); @@ -203,20 +171,20 @@ SField const sfRippleEscrow = make::one(&sfRippleEscrow, STI_AMOUNT, 17, " SField const sfDeliveredAmount = make::one(&sfDeliveredAmount, STI_AMOUNT, 18, "DeliveredAmount"); // variable length -SField const sfPublicKey = make::one(&sfPublicKey, STI_VL, 1, "PublicKey"); -SField const sfMessageKey = make::one(&sfMessageKey, STI_VL, 2, "MessageKey"); -SField const sfSigningPubKey = make::one(&sfSigningPubKey, STI_VL, 3, "SigningPubKey"); -SField const sfTxnSignature = make::one(&sfTxnSignature, STI_VL, 4, "TxnSignature", SField::sMD_Default, false); -SField const sfGenerator = make::one(&sfGenerator, STI_VL, 5, "Generator"); -SField const sfSignature = make::one(&sfSignature, STI_VL, 6, "Signature", SField::sMD_Default, false); -SField const sfDomain = make::one(&sfDomain, STI_VL, 7, "Domain"); -SField const sfFundCode = make::one(&sfFundCode, STI_VL, 8, "FundCode"); -SField const sfRemoveCode = make::one(&sfRemoveCode, STI_VL, 9, "RemoveCode"); -SField const sfExpireCode = make::one(&sfExpireCode, STI_VL, 10, "ExpireCode"); -SField const sfCreateCode = make::one(&sfCreateCode, STI_VL, 11, "CreateCode"); -SField const sfMemoType = make::one(&sfMemoType, STI_VL, 12, "MemoType"); -SField const sfMemoData = make::one(&sfMemoData, STI_VL, 13, "MemoData"); -SField const sfMemoFormat = make::one(&sfMemoFormat, STI_VL, 14, "MemoFormat"); +TypedField const sfPublicKey = make::one(&sfPublicKey, STI_VL, 1, "PublicKey"); +TypedField const sfSigningPubKey = make::one(&sfSigningPubKey, STI_VL, 3, "SigningPubKey"); +TypedField const sfSignature = make::one(&sfSignature, STI_VL, 6, "Signature", SField::sMD_Default, false); +SField const sfMessageKey = make::one(&sfMessageKey, STI_VL, 2, "MessageKey"); +SField const sfTxnSignature = make::one(&sfTxnSignature, STI_VL, 4, "TxnSignature", SField::sMD_Default, false); +SField const sfGenerator = make::one(&sfGenerator, STI_VL, 5, "Generator"); +SField const sfDomain = make::one(&sfDomain, STI_VL, 7, "Domain"); +SField const sfFundCode = make::one(&sfFundCode, STI_VL, 8, "FundCode"); +SField const sfRemoveCode = make::one(&sfRemoveCode, STI_VL, 9, "RemoveCode"); +SField const sfExpireCode = make::one(&sfExpireCode, STI_VL, 10, "ExpireCode"); +SField const sfCreateCode = make::one(&sfCreateCode, STI_VL, 11, "CreateCode"); +SField const sfMemoType = make::one(&sfMemoType, STI_VL, 12, "MemoType"); +SField const sfMemoData = make::one(&sfMemoData, STI_VL, 13, "MemoData"); +SField const sfMemoFormat = make::one(&sfMemoFormat, STI_VL, 14, "MemoFormat"); // account SField const sfAccount = make::one(&sfAccount, STI_ACCOUNT, 1, "Account"); diff --git a/src/ripple/protocol/impl/STObject.cpp b/src/ripple/protocol/impl/STObject.cpp index ef58f247fb..0e92a25fe4 100644 --- a/src/ripple/protocol/impl/STObject.cpp +++ b/src/ripple/protocol/impl/STObject.cpp @@ -762,6 +762,24 @@ const STVector256& STObject::getFieldV256 (SField::ref field) const return getFieldByConstRef (field, empty); } +void +STObject::set (std::unique_ptr v) +{ + auto const i = + getFieldIndex(v->getFName()); + if (i != -1) + { + mData.replace(i, v.release()); + } + else + { + if (! isFree()) + throw std::runtime_error( + "missing field in templated STObject"); + mData.push_back(v.release()); + } +} + void STObject::setFieldU8 (SField::ref field, unsigned char v) { setFieldUsingSetValue (field, v); diff --git a/src/ripple/protocol/impl/Sign.cpp b/src/ripple/protocol/impl/Sign.cpp new file mode 100644 index 0000000000..f64c3a16c5 --- /dev/null +++ b/src/ripple/protocol/impl/Sign.cpp @@ -0,0 +1,51 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include + +namespace ripple { + +void +sign (STObject& st, HashPrefix const& prefix, + AnySecretKey const& sk) +{ + Serializer ss; + ss.add32(prefix); + st.add(ss, false); + set(st, sfSignature, + sk.sign(ss.data(), ss.size())); +} + +bool +verify (STObject const& st, + HashPrefix const& prefix, + AnyPublicKeySlice const& pk) +{ + auto const sig = get(st, sfSignature); + if (! sig) + return false; + Serializer ss; + ss.add32(prefix); + st.add(ss, false); + return pk.verify( + ss.data(), ss.size(), + sig->data(), sig->size()); +} + +} // ripple diff --git a/src/ripple/unity/protocol.cpp b/src/ripple/unity/protocol.cpp index c7693f6ded..0ba50c8d8c 100644 --- a/src/ripple/unity/protocol.cpp +++ b/src/ripple/unity/protocol.cpp @@ -19,6 +19,8 @@ #include +#include +#include #include #include #include