-
Notifications
You must be signed in to change notification settings - Fork 295
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
[zk-token-sdk] Implement FromStr
for ElGamalPubkey
, ElGamalCiphertext
, and AeCiphertext
#130
[zk-token-sdk] Implement FromStr
for ElGamalPubkey
, ElGamalCiphertext
, and AeCiphertext
#130
Conversation
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.
Looks good for the most part! mostly nits.
Since the implementations look pretty much the same in every case, how about creating a macro in the crate to derive FromStr
for all of them? It looks like you just need the type, base64 length, and byte length
if s.len() > AE_CIPHERTEXT_MAX_BASE64_LEN { | ||
return Err(ParseError::WrongSize); | ||
} | ||
let ciphertext_vec = BASE64_STANDARD.decode(s).map_err(|_| ParseError::Invalid)?; |
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.
How about decoding directly into an array of [u8; AE_CIPHERTEXT_LEN]
with decode_slice
https://docs.rs/base64/latest/base64/engine/trait.Engine.html#method.decode_slice? Then you can check that the length is correct and return that directly, no allocations required!
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 good idea, but one issue that I had is that something like this does not work
let mut array = [0u8; AE_CIPHERTEXT_LEN]; // 64 byte array
let decoded_length = BASE64_STANDARD.decode_slice(s, &mut array).unwrap();
because it seems like for the base64 encoding, you need extra space for the additional zeroes during decoding. So decoded_length
is still 64, but array
must be at least of size 66
for this to not panic. This seems to make directly decoding into an array pointless since we would need to eventually allocate to an array length 64. What do you think?
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.
Sorry, I think I'm missing something, do you have an example that shows this? I just tried this with a few examples of valid of 64-byte encoded strings, ie:
let s = "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIDFUaGUgcXVpY2sgYnJvd24gZm94IGp1bXBzIG92ZXIgMQ==";
let mut array = [0u8; 64];
let decoded_length = BASE64_STANDARD.decode_slice(&s, &mut array).unwrap();
println!("decoded: {decoded_length}, array: {array:?}");
And it worked as expected with a decoded length of 64.
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.
Hm, weird... I just copy pasted the exact lines into a temporary test and it seems to give the following output for me:
thread 'zk_token_elgamal::pod::elgamal::tests::temp_test' panicked at zk-token-sdk/src/zk_token_elgamal/pod/elgamal.rs:186:75:
called `Result::unwrap()` on an `Err` value: OutputSliceTooSmall
If you add the following test
#[test]
fn temp_test() {
let s = "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIDFUaGUgcXVpY2sgYnJvd24gZm94IGp1bXBzIG92ZXIgMQ==";
let mut array = [0u8; 64];
let decoded_length = BASE64_STANDARD.decode_slice(&s, &mut array).unwrap();
println!("decoded: {decoded_length}, array: {array:?}");
}
does it pass in your local machine? Both my local and dev server seems to produce OutputSliceTooSmall
.
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! Looks like this was fixed in version 0.22, which is the version I was testing with
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.
https://github.com/marshallpierce/rust-base64/blob/master/RELEASE-NOTES.md#0220 literally the exact situation we're discussing 😅
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.
Ah makes sense! This was released two weeks ago. I guess then it would make sense to update the base64 crate version for the monorepo in a separate PR and then rebase this PR after that?
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.
#225 on it!
if s.len() > ELGAMAL_CIPHERTEXT_MAX_BASE64_LEN { | ||
return Err(ParseError::WrongSize); | ||
} | ||
let ciphertext_vec = BASE64_STANDARD.decode(s).map_err(|_| ParseError::Invalid)?; |
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 note here: decode into an array?
@@ -82,3 +82,27 @@ impl TryFrom<PodProofType> for ProofType { | |||
#[derive(Clone, Copy, Pod, Zeroable, PartialEq, Eq)] | |||
#[repr(transparent)] | |||
pub struct CompressedRistretto(pub [u8; 32]); | |||
|
|||
#[macro_export] |
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.
nit: since #[macro_export]
makes this pub by default, how about exporting as only pub(crate)
like here https://stackoverflow.com/a/67140319/16310679 ?
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 yes, I completely forgot about this. I removed it.
3ecebdc
to
1cd90bf
Compare
1cd90bf
to
9c13720
Compare
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #130 +/- ##
========================================
Coverage 81.9% 81.9%
========================================
Files 836 836
Lines 226643 226675 +32
========================================
+ Hits 185636 185744 +108
+ Misses 41007 40931 -76 |
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.
It's pretty much there! Just two last little nits, then this is all good for me
Co-authored-by: Jon C <[email protected]>
|
||
fn from_str(s: &str) -> Result<Self, Self::Err> { | ||
if s.len() > $base64_len { | ||
return Err(ParseError::WrongSize); |
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.
Sorry one last bit: it seems like these usages here still require implementations to import ParseError
, could you fully qualify these with Self::Err
or crate::zk_token_elgamal::pod::ParseError
so the import isn't required?
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 yes I should have caught this before. I removed the need for the dependency!
…rtext`, and `AeCiphertext` (anza-xyz#130) * add `ParseError` in `zk-token-elgamal` * implement `FromStr` for `ElGamalPubkey` and `ElGamalCiphertext` * implement `FromStr` for `AeCiphertext` * fix target * cargo fmt * use constants for byte length check * make `FromStr` functions available on chain * use macros for the `FromStr` implementations * restrict `from_str` macro to `pub(crate)` * decode directly into array * cargo fmt * Apply suggestions from code review Co-authored-by: Jon C <[email protected]> * remove unnecessary imports * remove the need for `ParseError` dependency --------- Co-authored-by: Jon C <[email protected]>
Problem
Currently,
ElGamalPubkey
,ElGamalCiphertext
andAeCiphertext
types implement theDisplay
trait, but notFromStr
. It would be nice to implementFromStr
for these types since clap-v3 can automatically validate and parse string encodings of any type that implementsFromStr
. Also,FromStr
makes life much easier when exposing these types in wasm binaries.Summary of Changes
Implement
FromStr
for typesElGamalPubkey
,ElGamalCiphertext
, andAeCiphertext
.Fixes #