-
Notifications
You must be signed in to change notification settings - Fork 32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[main] Crypto extension wrappers and data types for C++ #52
Conversation
* @param x_ - The x coordinate, a vector of chars | ||
* @param y_ - The y coordinate, a vector of chars | ||
*/ | ||
g1_view(std::vector<char>& x_, std::vector<char>& y_) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would suggest using std::span<char>
instead of std::vector<char>
so other containers can be used (e.g. compile-time defined std::array<char>
) or offsets into binary data.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your suggestion here and in the associated issue. std::span
is in C++20 while we still need to support C++17 at the moment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh sorry I didn't realize support for C++17 is still required.
Ok I guess this would be proper for separate issue/PR, but how about creating a new span like type for C++17 (internal namespace) and exposing only 'bytes view' like span alias to cdt? When support for C++17 is dropped in the future only this internal span implementation has to be removed but the alias would stay intact without breaking api.
Just for reference, I made one simple type imitating span for such cases: https://github.com/ZeroPass/antelope.ck/blob/1bf203db28d053e9d5b171fb92f27c44b94acdc4/include/eosiock/span.hpp
struct bigint { | ||
/** | ||
* Construct a bigint given a vector of chars (bytes) | ||
* | ||
* @param s - The source bytes | ||
*/ | ||
bigint(std::vector<char>& s) | ||
:data(s.data()), size(s.size()) | ||
{ | ||
}; | ||
|
||
char* data; | ||
uint32_t size; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of introducing new type I suggest making an alias for std::span<char>
aka bytes_view
.
* @param result - the result of the compression | ||
* @return -1 if there is an error otherwise 0 | ||
*/ | ||
int32_t blake2_f( uint32_t rounds, const std::vector<char>& state, const std::vector<char>& msg, const std::vector<char>& t0_offset, const std::vector<char>& t1_offset, bool final, std::vector<char>& result) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest using std::span
based 'bytes view' type here as well for the inputs instead of const std::vector<char>
.
tests/integration/crypto_tests.cpp
Outdated
|
||
produce_blocks(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest to also add additional test with smaller exponent and larger base number, same size as modulus (to emulate RSA crypto).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. Will add more tests for this.
/** | ||
* Returns packed x and y | ||
*/ | ||
std::vector<char> packed() const { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unless there are some recent changes that I'm not aware of, we are using non-class member functions like:
eosio::pack
and eosio::unpack
all over the code. So I suggest to adhere to those standards.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The name here is misleading. The intention was to provide a way to serialize x
and y
only, and populate a G1
or G2
point from a serialized form. Will change the names.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, got you. Anyway it looks like some non-standard approach for serialization. There is CDT_REFLECT
macro in the eosiolib
, have you considered it? it looks like a good approach for your purpose. it could be a bit tricky to use in your case but that way we can stick to standard approach. please let me know what do you think.
/** | ||
* Pointer to the x coordinate | ||
*/ | ||
char* x; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this a view, we should make these const char*
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because you need to be able to return a point_view in some of the functions, I suggest that we have point_view and point. Where point holds std::vectors for x and y so we don't need to worry about memory issues.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your suggestions! I was struggling on how to mutate point_view to return a result.
* | ||
* @ingroup crypto | ||
*/ | ||
struct g1_view : public point_view { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would just make these templated and add a typedefs.
So, something like
template <std::size_t Size = 32>
struct point_view {
point_view(const std::vector<char>& x, const std::vector<char>& y) {
>> The other constructor code here from above <<
eosio::check ( size == Size, "point size must match");
}
.
.
.
using g1_view = point_view<g1_coordinate_size>;
using g2_view = point_view<g2_coordinate_size>;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will change. Thanks.
* @param x_ - The x coordinate, a vector of chars | ||
* @param y_ - The y coordinate, a vector of chars | ||
*/ | ||
g1_view(std::vector<char>& x_, std::vector<char>& y_) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of the 3 separate types these can be collapsed in to point_view and have point_view become templates.
template <std::size_t Size = 32>
struct point_view
Then,
using g1_view = point_view<g1_coordinate_size>;
using g2_view = point_view<g2_coordinate_size>;
struct bigint { | ||
/** | ||
* Construct a bigint given a vector of chars (bytes) | ||
* |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given our uses of bigint at this point, I would suggest we just go with an std::vector or a typedef.
So,
using bigint = std::vector<char>;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think std::vector<char>
would be better aliased as bytes
since it could be used in other non-crypto related cases. Also, since ABI already defines bytes
type for std::vector<char>
I believe such alias would also improve code readability.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you mean
using bytes = std::vector<char>;
using bigint = bytes;
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess you could abstract it that way. Tho in this case, the bigint
alias just brings another abstraction layer with no additional functionality and I don't know if such abstraction is ok in terms of code readability and usage (i.e. 2 layers bigint
-> bytes
to know it's an alias for std::vector<char>
). If it were up to me I'd avoid bigint
alias.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed. Two layers of abstraction is not good. Keep bigint
as is for future extensions.
* @param source - The source to be copied from | ||
*/ | ||
void copy_from(const std::vector<char>& source) { | ||
eosio::check( source.size() == 2 * size, "size of souce buffer must be size of x + y" ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo 'souce'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh my bad. Thanks for spotting this.
* | ||
* @param source - The source to be copied from | ||
*/ | ||
void copy_from(const std::vector<char>& source) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a view, I don't think it should have a function to mutate.
* @param result - result of the addition operation | ||
* @return -1 if there is an error otherwise 0 | ||
*/ | ||
inline int32_t alt_bn128_add( const g1_view& op1, const g1_view& op2, g1_view& result) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For these we can check
the internal return value and assert. And return a "result" from this instead of making it an in/out param.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will change.
/** | ||
* Pointer to the x coordinate | ||
*/ | ||
char* x; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because you need to be able to return a point_view in some of the functions, I suggest that we have point_view and point. Where point holds std::vectors for x and y so we don't need to worry about memory issues.
…porate other review comments
* @param p - The serialized point | ||
*/ | ||
ec_point(std::vector<char>& p) | ||
:x(p.data(), p.data() + p.size()/2), y(p.data() + p.size()/2, p.data() + p.size()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
p.size()/2
can just be Size
as we check that p.size() == Size*2
later.
* @param x_ - The x coordinate, a vector of chars | ||
* @param y_ - The y coordinate, a vector of chars | ||
*/ | ||
ec_point_view(std::vector<char>& x_, std::vector<char>& y_) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should have a constructor that accepts a ec_point
with ec_point_view::Size ==
ec_point::Size` via static assertion.
* @param x_ - The x coordinate, a vector of chars | ||
* @param y_ - The y coordinate, a vector of chars | ||
*/ | ||
ec_point_view(std::vector<char>& x_, std::vector<char>& y_) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This shouldn't take an std::vector<char>&
but a const char*
.
* | ||
* @param p - The serialized point | ||
*/ | ||
ec_point_view(std::vector<char>& p) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above constructor.
…an existing ec_point_view constructor to take char* as an input
Change Description
Resolve #45.
API Changes
Documentation Additions