2022-02-16 00:53:01 -05:00
# pragma once
// libsodium is typeless, which I find confusing. Everything is unsigned
// bytes pointed at by naked pointers. It is well written assembly language
// written in C It is not even C written in C, let alone C++ written in C.
//
// NaCl provides a high level C++ interface to the low level C libsodium
// interface, but I just don't like the people running NaCl and suspect them
// of being in bed with my enemies, whereas I do like the people running
// LibSodium.
//
// It is nonetheless probably stupid to write my own high level interface to
// LibSodium, when one has already been written, but I am going to do so
2022-02-18 15:59:12 -05:00
// anyway, because elliptic curves are just way cool, and because ...
2022-02-16 00:53:01 -05:00
// because ... I am having trouble thinking up a good excuse ... ah yes,
// because when I read the NaCl documentation it says "X has not been
// implemented yet" when X is something that is pretty easy to implement
// if one has direct access to elliptic curve objects, and our Merkle patricia
// blockchain is going to be a great big pile of elliptic curve objects.
// NaCl suffers from the chronic disease both of open source projects,
// and also of high level interfaces to low level data structures, of getting
// fine tuned to the implementer's pet projects, which fine tuning is apt to
// get in the way of someone else's pet project.
//
// LibSodium, being assembly language written in C, rather than C written
// in C, or C++ written in C, has the problems:
// If you mix up the pointer to one kind of object with the pointer to
// another kind of object, you are sol
// If you mix up a pointer to a thirty two byte object with a pointer to a
// sixtyfour byte object, you are really sol
// if you reference something that has been de-allocated, you are sol.
// If you reference something that has not been properly initialized,
// you are sol.
// It is all raw memory, and structure exists only in the head of the
// programmer. The compiler knows nothing of these structures.
//
// That said, there is an immense amount of cryptographic knowledge
// encapsulated in this library, and I need to lift that knowledge into the
// language of C++20, from C that is almost assembly.
// There is a huge amount of knowledge embedded, and translating it
// from what is almost a machine language representation to a C++20
// representation involves a big pile of stuff.
// We are going to need to lift
// https://paragonie.com/blog/2017/06/libsodium-quick-reference-quick-comparison-similar-functions-and-which-one-use or their ristretto equivalents to C++
// Starting with ristretto points and scalars, but they are useless without a
// pile of other things, many of those other things being in
// https://download.libsodium.org/doc/helpers/
// I went there to find out what the hell "sodium_is_zero" means, but
// found a pile of other things that I am going to need, and got distracted
// by no end of odds and ends that I am going to need to be to lift to
// C++20 in order for ristretto points and scalars to be put to any use.
void randombytes_buf ( std : : span < byte > in ) ;
void randombytes_buf ( std : : span < char > in ) ;
namespace ristretto255 {
2023-09-24 01:21:18 -04:00
using
ro : : to_base64_string , ro : : is_serializable ,
ro : : serialize , ro : : bin2hex , ro : : hex2bin ,
ro : : bin2hex , ro : : CompileSizedString ,
ro : : serializable ;
;
2022-02-16 00:53:01 -05:00
// a class representing ristretto255 elliptic points
class point ;
// a class representing ristretto255 scalars
class scalar ;
template < unsigned int > class hsh ;
template < unsigned int > class hash ;
template < class T > decltype ( std : : declval < T > ( ) . blob , bool ( ) ) ConstantTimeEqualityTest ( const T & x , const T & y ) {
if ( T : : constant_time_required ) {
return 0 = = sodium_memcmp ( & x . blob [ 0 ] , & y . blob [ 0 ] , sizeof ( x . blob ) ) ;
}
else return x = = y ;
}
template < class T > decltype ( std : : declval < T > ( ) . blob , wxString ( ) ) to_wxString ( const T & p_blob ) {
std : : array < char , ( sizeof ( p_blob . blob ) * 8 + 11 ) / 6 > sz ;
bits2base64 ( & ( p_blob . blob [ 0 ] ) , 0 , sizeof ( p_blob . blob ) * 8 , std : : span < char > ( sz ) ) ;
return wxString : : FromUTF8Unchecked ( & sz [ 0 ] ) ;
}
// hsh constructs a partial hash, not yet finalized
// normally never explicitly used in code, but rather a nameless rtype value on the stack.
// To which more stuff can be added with the << operator
// usage:
// hash( hsh(a, b) << c << f << g );
// assert( hash(a, b, c, d, e) == hash(hsh(a, b, c) << d << e) );
// hash finalizes hsh.
// Of course you would never use it that way, because you would only
// use it explicitly if you wanted to keep it around
// attempting hash more things into an hsh object that has already
// been finalized will throw an exception.
// Old type C byte array arguments after the first are vulnerable to
// array decay to pointer, so wrap them in std::span(OldTypeCarray)
// or hash them using "<<" rather than putting them in the initializer.
// It always a wise precaution to not use old type C arays, or wrap them
// in a span.
// Old type zero terminated strings work. The trailing zero is included
2023-09-23 01:58:56 -04:00
// in the hash, thus hash("the quick ", "brown fox") != hash("the quick brown fox")
2022-02-16 00:53:01 -05:00
template < unsigned int hashsize = 256 > class hsh {
public :
static_assert ( hashsize > 63 & & hashsize % 64 = = 0 & & crypto_generichash_BYTES_MIN * 8 < = hashsize & & hashsize < = crypto_generichash_BYTES_MAX * 8 , " Bad hash size. " ) ;
static constexpr unsigned int type_indentifier = 2 + ( hashsize + 0x90 * 8 ) / 64 ;
static_assert ( crypto_generichash_BYTES_MAX < 0x90 , " Change in max hash has broken our type ids " ) ;
crypto_generichash_blake2b_state st ;
hsh ( ) {
int i { crypto_generichash_blake2b_init (
& st ,
nullptr , 0 ,
hashsize / 8 )
} ;
assert ( i = = 0 ) ;
}
2023-02-16 23:43:22 -05:00
2023-09-24 01:21:18 -04:00
template < serializable T , typename . . . Args >
hsh < hashsize > & hashinto ( const T & j , Args . . . args ) {
auto sj = ro : : serialize ( j ) ;
int i = crypto_generichash_blake2b_update (
& ( this - > st ) ,
( const unsigned char * ) & sj [ 0 ] ,
sj . size ( )
) ;
2023-09-22 05:49:30 -04:00
if ( i ) throw HashReuseException ( ) ;
2022-02-16 00:53:01 -05:00
if constexpr ( sizeof . . . ( args ) > 0 ) {
( * this ) . hashinto ( args . . . ) ;
}
2023-09-24 01:21:18 -04:00
return * this ;
2022-02-16 00:53:01 -05:00
}
2023-09-24 01:21:18 -04:00
template < serializable T > hsh < hashsize > & operator < < ( const T & j ) {
auto sj = ro : : serialize ( j ) ;
auto i = crypto_generichash_blake2b_update (
& ( this - > st ) ,
( const unsigned char * ) & sj [ 0 ] ,
sj . size ( )
) ;
if ( i ) throw HashReuseException ( ) ;
return * this ;
2022-02-16 00:53:01 -05:00
}
2023-09-24 01:21:18 -04:00
2022-10-05 00:34:55 -04:00
} ;
2023-09-24 01:21:18 -04:00
static_assert ( ! serializable < hsh < 256 > > , " Don't want to partially hash partial hashes " ) ;
2022-02-16 00:53:01 -05:00
// This constructs a finalized hash.
// If it has one argument, and that argument is hsh (unfinalized hash) object,
// it finalizes the hash. (see hsh)
// Usage
// hash(a, b, c ...);
// hash and hsh serialize all their arguments, converting them into machine
// and compiler independent form. If they don't know how to serialize an
// argument type, you get a compile time error. To serialize a new type,
// create a new overload for the function "serialize"
// to hash a wxString, use its ToUTF8 member
// wxString wxsHello(L"Hello world");
2022-02-18 15:59:12 -05:00
// hash hashHello(wxsHello.ToUTF8());
2022-02-16 00:53:01 -05:00
// C array arguments after the first are vulnerable to array decay to pointer, so use hsh and "<<"
// for them. or wrap them in std::span(OldTypeCarray)
// It always a wise precaution to not use old type C arays, or wrap them
// in a span.
// Old type zero terminated utf8 strings work. The trailing zero is included.
// The program should by running in the UTF8 locale, attempts to set that
// locale on startup. and tests for success in the unit test.
template < unsigned int hashsize = 256 > class hash {
2022-03-07 23:46:14 -05:00
static_assert (
hashsize > 63 & & hashsize % 64 = = 0
& & crypto_generichash_BYTES_MIN * 8 < = hashsize
& & hashsize < = crypto_generichash_BYTES_MAX * 8 ,
" Bad hash size. "
) ;
2022-02-16 00:53:01 -05:00
friend point ;
friend scalar ;
friend hsh < hashsize > ;
public :
static constexpr unsigned int type_indentifier = 2 + hashsize / 64 ;
hash ( ) = default ;
std : : array < uint8_t , hashsize / 8 > blob ;
~ hash ( ) = default ;
hash ( hash & & ) = default ; // Move constructor
hash ( const hash & ) = default ; // Copy constructor
hash & operator = ( hash & & ) = default ; // Move assignment.
hash & operator = ( const hash & ) = default ; // Copy assignment.
explicit hash ( hsh < hashsize > & in ) {
int i = crypto_generichash_blake2b_final (
& in . st ,
& blob [ 0 ] , hashsize / 8 ) ;
assert ( i = = 0 ) ;
if ( i ) throw HashReuseException ( ) ;
}
2023-09-24 01:21:18 -04:00
template < serializable T , typename . . . Args > explicit hash ( const T & first , Args . . . args ) {
2022-02-16 00:53:01 -05:00
hsh < hashsize > in ;
in < < first ;
if constexpr ( sizeof . . . ( args ) > 0 ) {
in . hashinto ( args . . . ) ;
}
int i = crypto_generichash_blake2b_final (
& in . st ,
& blob [ 0 ] , hashsize / 8 ) ;
assert ( i = = 0 ) ;
}
hash & operator = ( hsh < hashsize > & & in ) {
int i = crypto_generichash_blake2b_final (
& in . st ,
& blob [ 0 ] , hashsize / 8 ) ;
if ( i ) throw HashReuseException ( ) ;
}
bool operator = = ( const hash < hashsize > & pt ) const & {
return blob = = pt . blob ; //Do not need constant time equality test on hashes
}
bool operator ! = ( const hash < hashsize > & pt ) const & {
return blob ! = pt . blob ; //Do not need constant time equality test on hashes
}
} ;
// a class representing ristretto255 elliptic points,
// which are conveniently of prime order.
class point
{
2022-03-07 23:46:14 -05:00
// We will be reading points from the database, as blobs,
// reading them from the network as blobs,
2023-09-24 06:04:19 -04:00
// and reading them from human entered text as base58 encoded blobs.
2022-03-07 23:46:14 -05:00
// Therefore, invalid point initialization data is all too possible.
2022-02-16 00:53:01 -05:00
public :
static constexpr unsigned int type_indentifier = 1 ;
std : : array < uint8_t , crypto_core_ristretto255_BYTES > blob ;
2022-03-07 23:46:14 -05:00
static_assert (
std : : is_trivially_copyable < std : : array < uint8_t , crypto_core_ristretto255_BYTES > > ( ) ,
" does not support memcpy init "
) ;
static_assert ( sizeof ( blob ) = = 32 ,
" watch for size and alignment bugs. "
" Everyone should standarize on 256 bit public keys except for special needs "
) ;
2022-02-16 00:53:01 -05:00
static point ptZero ;
static point ptBase ;
explicit point ( ) = default ;
2022-03-07 23:46:14 -05:00
// After loading a point as a blog from the network, from the database,
// or from user data typed as text, have to check for validity.
2022-02-16 00:53:01 -05:00
bool valid ( void ) const { return 0 ! = crypto_core_ristretto255_is_valid_point ( & blob [ 0 ] ) ; }
2022-05-23 02:06:01 -04:00
explicit constexpr point ( std : : array < uint8_t , crypto_core_ristretto255_BYTES > & & in ) :
2022-03-07 23:46:14 -05:00
blob { std : : forward < std : : array < uint8_t , crypto_core_ristretto255_BYTES > > ( in ) } { } ;
2022-02-16 00:53:01 -05:00
static_assert ( crypto_core_ristretto255_BYTES = = 32 , " 256 bit points expected " ) ;
~ point ( ) = default ;
point ( point & & ) = default ; // Move constructor
point ( const point & ) = default ; // Copy constructor
point & operator = ( point & & ) = default ; // Move assignment.
point & operator = ( const point & ) = default ; // Copy assignment.
bool operator = = ( const point & pt ) const & {
return ConstantTimeEqualityTest ( * this , pt ) ;
}
point operator + ( const point & pt ) const & {
point me ;
2023-09-23 01:58:56 -04:00
auto i { crypto_core_ristretto255_add ( _Out_ & me . blob [ 0 ] , & blob [ 0 ] , & pt . blob [ 0 ] ) } ;
2022-02-16 00:53:01 -05:00
assert ( i = = 0 ) ;
if ( i ! = 0 ) throw NonRandomScalarException ( ) ;
return me ;
}
point operator - ( const point & pt ) const & {
point me ;
2023-09-23 01:58:56 -04:00
auto i { crypto_core_ristretto255_sub ( _Out_ & me . blob [ 0 ] , & blob [ 0 ] , & pt . blob [ 0 ] ) } ;
2022-02-16 00:53:01 -05:00
assert ( i = = 0 ) ;
if ( i ! = 0 ) throw NonRandomScalarException ( ) ;
return me ;
static_assert ( sizeof ( blob ) = = 32 , " alignment? " ) ;
}
point operator * ( const scalar & ) const & noexcept ;
point operator * ( int ) const & noexcept ;
explicit point ( const hash < 512 > & x ) noexcept {
2022-03-07 23:46:14 -05:00
static_assert ( crypto_core_ristretto255_HASHBYTES * 8 = = 512 ,
" we need 512 bit randoms to ensure our points and scalars are uniformly distributed "
) ;
2022-02-16 00:53:01 -05:00
// There should be scalar from hash, not point from hash
int i {
crypto_core_ristretto255_from_hash ( & blob [ 0 ] , & ( x . blob ) [ 0 ] ) } ;
assert ( i = = 0 ) ;
}
static point random ( void ) {
point me ;
2023-09-23 01:58:56 -04:00
crypto_core_ristretto255_random ( _Out_ & ( me . blob [ 0 ] ) ) ;
2022-02-16 00:53:01 -05:00
return me ;
}
bool operator ! ( ) const & {
return 0 ! = sodium_is_zero ( & blob [ 0 ] , sizeof ( blob ) ) ;
}
static bool constant_time_required ;
} ;
class scalar
{
friend point ;
public :
static constexpr unsigned int type_indentifier = 2 ;
std : : array < uint8_t , crypto_core_ristretto255_SCALARBYTES > blob ;
static_assert ( sizeof ( blob ) = = 32 , " watch for size and alignment bugs. Everyone should standarize on 256 bit secret keys except for special needs " ) ;
explicit scalar ( ) = default ;
~ scalar ( ) = default ;
explicit constexpr scalar ( std : : array < uint8_t , crypto_core_ristretto255_BYTES > & & in ) : blob { in } { } ;
explicit constexpr scalar ( std : : array < uint8_t , crypto_core_ristretto255_BYTES > * in ) : blob ( * in ) { } ;
2022-03-26 23:46:34 -04:00
explicit constexpr scalar ( uintmax_t k ) { for ( auto & j : blob ) { j = k ; k = k > > 8 ; } }
2022-04-01 22:38:06 -04:00
template < class T >
explicit constexpr scalar ( std : : enable_if_t < ro : : is_standard_unsigned_integer < T > , T > i ) : scalar ( uintmax_t ( i ) ) { }
template < class T , class U = std : : enable_if_t < ro : : is_standard_signed_integer < T > , uintmax_t > >
explicit constexpr scalar ( T i ) : scalar ( U ( ro : : iabs < T > ( i ) ) ) {
static_assert ( ro : : is_standard_signed_integer < T > ) ;
if ( i < 0 ) crypto_core_ristretto255_scalar_negate ( & blob [ 0 ] , & blob [ 0 ] ) ;
2022-03-26 23:46:34 -04:00
}
2022-02-16 00:53:01 -05:00
scalar ( scalar & & ) = default ; // Move constructor
scalar ( const scalar & ) = default ; // Copy constructor
scalar & operator = ( scalar & & ) = default ; // Move assignment.
scalar & operator = ( const scalar & ) = default ; // Copy assignment.
2022-03-07 23:46:14 -05:00
/* Don't need constant time equality test
2022-02-16 00:53:01 -05:00
bool operator = = ( const scalar & sc ) const & {
return ConstantTimeEqualityTest ( * this , sc ) ;
2022-03-07 23:46:14 -05:00
} */
std : : strong_ordering operator < = > ( const scalar & sc ) const & noexcept ;
// strangely, contrary to documentation, compiler generates operator>
// but fails to generate operator==
bool operator = = ( const scalar & sc ) const & = default ;
/* {
return ( * this < = > sc ) = = 0 ;
} */
//bool operator!=(const scalar& sc) const& {
// return !ConstantTimeEqualityTest(*this, sc);
// }
2022-02-16 00:53:01 -05:00
scalar operator + ( const scalar sclr ) const & {
scalar me ;
2023-09-23 01:58:56 -04:00
crypto_core_ristretto255_scalar_add ( _Out_ & me . blob [ 0 ] , & blob [ 0 ] , & sclr . blob [ 0 ] ) ;
2022-02-16 00:53:01 -05:00
return me ;
}
static_assert ( sizeof ( scalar : : blob ) = = 32 , " compiled " ) ;
scalar multiplicative_inverse ( ) const & {
scalar me ;
2023-09-23 01:58:56 -04:00
auto i = crypto_core_ristretto255_scalar_invert ( _Out_ & me . blob [ 0 ] , & blob [ 0 ] ) ;
2022-02-16 00:53:01 -05:00
assert ( i = = 0 ) ;
if ( i ! = 0 ) throw NonRandomScalarException ( ) ;
return me ;
}
scalar operator - ( const scalar & sclr ) const & {
scalar me ;
2023-09-23 01:58:56 -04:00
crypto_core_ristretto255_scalar_sub ( _Out_ & me . blob [ 0 ] , & blob [ 0 ] , & sclr . blob [ 0 ] ) ;
2022-02-16 00:53:01 -05:00
return me ;
}
scalar operator * ( const scalar & sclr ) const & {
scalar me ;
2023-09-23 01:58:56 -04:00
crypto_core_ristretto255_scalar_mul ( _Out_ & me . blob [ 0 ] , & blob [ 0 ] , & sclr . blob [ 0 ] ) ;
2022-02-16 00:53:01 -05:00
return me ;
}
scalar operator / ( const scalar sclr ) const & {
return operator * ( sclr . multiplicative_inverse ( ) ) ;
}
2022-03-26 05:39:41 -04:00
scalar operator * ( int64_t i ) const & {
2022-02-16 00:53:01 -05:00
return operator * ( scalar ( i ) ) ;
}
point operator * ( const point & pt ) const & {
point me ;
2023-09-23 01:58:56 -04:00
auto i { crypto_scalarmult_ristretto255 ( _Out_ & me . blob [ 0 ] , & blob [ 0 ] , & pt . blob [ 0 ] ) } ;
2022-02-16 00:53:01 -05:00
assert ( i = = 0 ) ;
if ( i ! = 0 ) throw NonRandomScalarException ( ) ;
return me ;
}
point timesBase ( ) const & {
point me ;
2023-09-23 01:58:56 -04:00
auto i { crypto_scalarmult_ristretto255_base ( _Out_ & me . blob [ 0 ] , & blob [ 0 ] ) } ;
2022-02-16 00:53:01 -05:00
assert ( i = = 0 ) ;
if ( i ! = 0 ) throw NonRandomScalarException ( ) ;
return me ;
}
explicit scalar ( const hash < 512 > & x ) {
static_assert ( crypto_core_ristretto255_HASHBYTES = = 64 , " inconsistent use of magic numbers " ) ;
crypto_core_ristretto255_scalar_reduce ( & blob [ 0 ] , & ( x . blob ) [ 0 ] ) ;
}
static scalar random ( void ) {
scalar me ;
2023-09-23 01:58:56 -04:00
crypto_core_ristretto255_scalar_random ( _Out_ & me . blob [ 0 ] ) ;
2022-02-16 00:53:01 -05:00
return me ;
}
bool valid ( void ) const & {
2022-03-07 23:46:14 -05:00
int x = sodium_is_zero ( & blob [ 0 ] , crypto_core_ed25519_SCALARBYTES ) ;
return x = = 0 & & * this < scOrder ;
// The libsodium library allows unreduced scalars, but I do not
// except, of course, for scOrder itself
2022-02-16 00:53:01 -05:00
}
2022-03-07 23:46:14 -05:00
// We don't need constant time equality test on scalars
// since they normally appear in signatures, or are
// checked against a hash or a point
/*bool operator !() const& {
2022-02-16 00:53:01 -05:00
return 0 ! = sodium_is_zero ( & blob [ 0 ] , sizeof ( blob ) ) ;
2022-03-07 23:46:14 -05:00
} */
2022-02-16 00:53:01 -05:00
/* explicit operator wxString() const&;
explicit operator std : : string ( ) const & ; */
static bool constant_time_required ;
2022-03-07 23:46:14 -05:00
static const scalar & scOrder ;
2022-02-16 00:53:01 -05:00
private :
void reverse ( std : : array < uint8_t , crypto_core_ristretto255_SCALARBYTES > const & ac ) {
auto p = blob . rbegin ( ) ;
for ( auto x : ac ) {
* p + + = x ;
}
}
} ;
2023-09-24 06:04:19 -04:00
static_assert ( ro : : blob_type < scalar > & & ! ro : : blob_type < int > ) ;
2022-02-16 00:53:01 -05:00
static_assert ( ro : : is_blob_field_type < scalar > : : value ) ;
static_assert ( ro : : is_blob_field_type < scalar & > : : value ) ;
static_assert ( ro : : is_blob_field_type < point > : : value ) ;
static_assert ( ro : : is_blob_field_type < hash < 256 > > : : value ) ;
static_assert ( false = = ro : : is_blob_field_type < char * > : : value ) ;
static_assert ( ro : : is_serializable < scalar & > : : value ) ;
static_assert ( ro : : is_serializable < hash < 512 > & > : : value ) ;
static_assert ( ro : : is_blob_field_type < int > : : value = = false ) ;
static_assert ( ro : : is_serializable < unsigned int > : : value ) ;
static_assert ( ro : : is_serializable < char * > : : value ) ;
static_assert ( ro : : is_serializable < uint8_t * > : : value = = false ) ; //false because uint8_t * has no inband terminator
2022-02-28 00:54:21 -05:00
static_assert ( false = = ro : : is_serializable < wxString > : : value & & ! ro : : is_constructible_from_v < hash < 256 > , wxString > , " wxStrings are apt to convert anything to anything, with surprising and unexpected results " ) ;
2022-02-16 00:53:01 -05:00
static_assert ( ro : : is_serializable < decltype ( std : : declval < wxString > ( ) . ToUTF8 ( ) ) > : : value = = true ) ;
static_assert ( ro : : is_constructible_from_all_of < scalar , int , hash < 512 > , std : : array < uint8_t , crypto_core_ristretto255_BYTES > > ) ;
static_assert ( ro : : is_constructible_from_all_of < hash < 256 > , char * , short , unsigned short , hash < 512 > , point , scalar > , " want to be able to hash anything serializable " ) ;
static_assert ( false = = ro : : is_constructible_from_any_of < int , scalar , point , hsh < 512 > , hash < 256 > > ) ;
static_assert ( false = = ro : : is_constructible_from_any_of < scalar , wxString , hash < 256 > , byte * > , " do not want indiscriminate casts " ) ;
static_assert ( false = = ro : : is_constructible_from_any_of < point , wxString , hash < 256 > , byte * > , " do not want indiscriminate casts " ) ;
2022-02-28 00:54:21 -05:00
static_assert ( false = = ro : : is_constructible_from_v < hash < 256 > , float > ) ;
2022-02-16 00:53:01 -05:00
static_assert ( ro : : is_serializable < float > : : value = = false ) ; //Need to convert floats to
// their machine independent representation, possibly through idexp, frexp
// and DBL_MANT_DIG
static_assert ( sizeof ( decltype ( ro : : serialize ( std : : declval < scalar > ( ) ) [ 0 ] ) ) = = 1 ) ;
static_assert ( std : : is_standard_layout < scalar > ( ) , " scalar for some reason is not standard layout " ) ;
static_assert ( std : : is_trivial < scalar > ( ) , " scalar for some reason is not trivial " ) ;
static_assert ( sizeof ( point ) = = 32 , " funny alignment " ) ;
static_assert ( sizeof ( scalar ) = = 32 , " funny alignment " ) ;
class signed_text {
public :
std : : span < char > txt ;
scalar c ;
scalar s ;
point K ;
signed_text (
const scalar & , // Signer's secret key
const point & , // Signer's public key
std : : span < char > // Text to be signed.
) ;
bool verify ( ) ;
} ;
class CMasterSecret : public scalar {
public :
CMasterSecret ( ) = default ;
CMasterSecret ( const scalar & pt ) : scalar ( pt ) { }
CMasterSecret ( const scalar & & pt ) : scalar ( pt ) { }
CMasterSecret ( CMasterSecret & & ) = default ; // Move constructor
CMasterSecret ( const CMasterSecret & ) = default ; // Copy constructor
CMasterSecret & operator = ( CMasterSecret & & ) = default ; // Move assignment.
CMasterSecret & operator = ( const CMasterSecret & ) = default ; // Copy assignment.
template < class T > auto operator ( ) ( T psz ) {
scalar & t ( * this ) ;
return scalar ( hash < 512 > ( t , psz ) ) ;
}
} ;
} //End ristretto255 namespace
// Ristretto255 scalars are defined to be little endian on all hardware
// regardless of the endianess of the underlying hardware.
// though it is entirely possible that sometime in the future, this
2022-02-18 15:59:12 -05:00
// definition will be changed should big endian hardware ever be
2022-02-16 00:53:01 -05:00
// sufficiently popular for anyone to care.
// So, because scalars are in fact integers, displaying them as
// biendian on all hardware when displayed in hex
// or base64. Everything else gets displayed in memory order.
template < > ristretto255 : : scalar ro : : hex2bin < ristretto255 : : scalar > ( const ro : : CompileSizedString < ( 2 * sizeof ( ristretto255 : : scalar ) ) > & ) ;
template < > ro : : CompileSizedString < ( 2 * sizeof ( ristretto255 : : scalar ) ) > ro : : bin2hex < ristretto255 : : scalar > ( const ristretto255 : : scalar & ) ;
template < > ro : : CompileSizedString < ( 8 * sizeof ( ristretto255 : : scalar ) + 5 ) / 6 > ro : : to_base64_string < ristretto255 : : scalar > ( const ristretto255 : : scalar & ) ;