-
Notifications
You must be signed in to change notification settings - Fork 129
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
Think about Rustls #1531
Comments
The It seems the Maybe someone in the Rust community can be convinced to add a crate that does it, at least for |
crrl library looks interesting.
I'm curious what |
One application that comes to mind is Bitcoinolog, which uses It is true: If you need only an encrypted network connection, you can simply use the predicates from
|
I do not know cryptography very well but maybe this could work |
Thank you, well spotted! I took a look specifically at RustCrypto's k256 crate since it implements It seems the crate almost provides the intended functionality, but again lacks elementary functionality, such as getting not only the X but also the Y coordinate of an affine point. The operation I need is the most frequently needed and most basic operation on elliptic curves: Given a scalar s and a point P on the elliptic curve, I need to compute s·P and obtain the coordinates X and Y of the result. The let mut point = AffinePoint::from_bytes(&qbytes).unwrap(); let s = Scalar::from_str_vartime(&scalar.to_string()).unwrap(); let result = point.mul(s); So we have It would be great to have an actual Rust-based cryptographic library, which uses the built-in Rust data structures to represent integers, points etc. All these redundant, badly documented, and error-prone conversions between bytes, strings and cryptic formats are extremely frustrating to use. An ideal Rust crate would provide s·P as a multiplication of a Rust integer s and a point P and result whose coordinates are easy to reason about within Rust. |
RustCrypto/elliptic-curves#621 appear to implement a trait/method with the missing conversion |
I think there are reasonable objections to exposing raw cryptographic primitives to userspace in general. Secrecy breaking operations are littered left and right. For example, an implementation using pure Rust would have no way to ensure the absence of optimizations that are conditional on the contents of the encrypted payload, exposing all users to timing-based attacks depending on arbitrary compiler optimizations that are present now or any time in the future. Thus assembly-based implementations (e.g. These concerns are not theoretical and such attacks are surprisingly simple to pull off. Cryptopals publishes a great self-learning course in the form of progressive challenges that teach you how to break many cryptographic designs that were in public use at some point in the past. What I learned working through these challenges is that designing a cryptographic system directly on top of primitives that is suitable for a specific application and is not vulnerable is shockingly subtle. That said, I haven't studied this implementation in depth so I'm not comfortable commenting on it directly. Besides RustCrypto/elliptic-curves#621 : p256: Allow converting affine points to coordinates and back mentioned by Skgland, there is also a related discussion: zkcrypto/group: Add traits and APIs for dealing with curve coordinates #30. |
Well, to use these cryptographic APIs, I have to perform a very basic operation: Translate an integer I have available in Rust to one of the formats that these crates require. This basic operation will always be needed, no matter how obscure and hard it is for application programmers. I have now tried, and failed, to perform this basic operation, and did not succeed. What I currently have for pub(crate) fn crypto_curve_scalar_mult(&mut self) { let curve = cell_as_atom!(self.machine_st.registers[1]); match curve { atom!("secp256k1") => { } _ => { unreachable!() } }; let stub_gen = || functor_stub(atom!("crypto_curve_scalar_mult"), 5); let sbytes = self.machine_st.integers_to_bytevec(self.machine_st.registers[2], stub_gen); let s = Scalar::from_repr(sbytes).unwrap(); let qbytes = self.machine_st.integers_to_bytevec(self.machine_st.registers[3], stub_gen); let mut q = AffinePoint::from_bytes(&qbytes).unwrap(); let result = q.mul(s); let enc = result.to_encoded_point(false); let x = enc.x().unwrap(); let y = enc.y().unwrap(); let sx = { let buffer = String::from_iter(x.as_ref().iter().map(|b| *b as char)); if buffer.len() == 0 { empty_list_as_cell!() } else { atom_as_cstr_cell!(self.machine_st.atom_tbl.build_with(&buffer)) } }; let sy = { let buffer = String::from_iter(y.as_ref().iter().map(|b| *b as char)); if buffer.len() == 0 { empty_list_as_cell!() } else { atom_as_cstr_cell!(self.machine_st.atom_tbl.build_with(&buffer)) } }; unify!(self.machine_st, self.machine_st.registers[4], sx); unify!(self.machine_st, self.machine_st.registers[5], sy); } This fails to compile with 2 errors: error[E0599]: no function or associated item named `from_repr` found for struct `k256::Scalar` in the current scope --> src/machine/system_calls.rs:6128:25 | 6128 | let s = Scalar::from_repr(sbytes).unwrap(); | ^^^^^^^^^ function or associated item not found in `k256::Scalar` and also: 6132 | let mut q = AffinePoint::from_bytes(&qbytes).unwrap(); | ^^^^^^^^^^ function or associated item not found in `AffinePoint` I do not know why these occur. I see My impression of this crate is that essential functionality is either not available or not sufficiently documented at the moment: Essential functions are either not available, or require translations between several cryptic formats. I hope someone is interested to help in this area. The overall functionality that is required here is pretty basic: Multiply a point on the curve by an integer, and get the result to Prolog. |
The decision not to expose the y-coordinate is very much deliberate, as y-coordinate access is implicated in the most common attack against elliptic curve libraries: invalid curve attacks. There is some ongoing discussion here as to how to safely expose raw coordinate access: zkcrypto/group#30 In the meantime, as a workaround you can obtain an uncompressed SEC1-encoded point and access its y-coordinate if you pass |
Thank you a lot! Quoting from https://safecurves.cr.yp.to/twist.html regarding invalid curve attacks: An ECC implementor can stop an invalid-curve attack by checking whether the input point Q satisfies the correct curve equation; this does not take much time, and it guarantees that Q is on the original curve. Such a check seems to be a much more reliable safety measure than not exposing the Y coordinate, which, it turns out, can be obtained after all in another way. Later in the document, we find: A protocol designer can help protect against this attack by specifying point compression. This again seems to be a much better choice: Specify point compression in the protocol. I do not regard this a a good argument for obscuring such basic functionality as obtaining (not even: specifying) the coordinates of a point. |
We of course check that any inputs satisfy the curve equation. The issue is less our implementation, which uses modern complete addition formulas, and rather other legacy implementations which don't. And in fact, if you can solve the curve equation, you don't need the full y-coordinate and can solve for it instead: that's how point decompression works, which is a strategic approach to eliminating invalid curves as a bugclass. Just a general note: the SafeCurves site is very much out-of-date and does not represent the state-of-the-art, especially when it comes to prime order curves. There have been several developments in the past decade which that site does not mention or adequately provide context for. Anyway, this is one of the biggest hot-button issues in all of our crates. There is a tradeoff between providing misuse-resistant APIs and "power user APIs" which we are trying to walk delicately. There's already been ample discussion about it I suggest you familiarize yourself with. Please see this issue and leave any relevant comments there: zkcrypto/group#30 To quote that issue:
|
We currently already have this functionality, so I am not particularly interested in ample discussion about how to obtain the coordinate of a point. If a crate appears that readily provides this elementary operation, I will immediately use it, so that we can get rid of the current dependency on OpenSSL. |
The OpenSSL example appears to be using the SEC1 encoding. As I already noted, that's fully supported by Passing The default encoding is compressed (which omits the full y-coordinate), as the secp256k1 ecosystem uses compressed points almost exclusively. |
I have published what I have so far in the https://github.com/triska/scryer-prolog/tree/rust-crypto In particular, the following commit attempts to use I get the mentioned compilation errors. I have looked at the diagrams in zkcrypto/group#30 (comment), and I have looked at the source of the crate, and I am at a loss on how to perform this basic operation: Given a Prolog integer and a point on the elliptic curve (specified in affine coordinates, using Prolog integers), obtain the Prolog and Rust interact with this internal predicate: https://github.com/triska/scryer-prolog/blob/98f1efd214860cec1a964cf5950b4415e2c7dcd6/src/lib/crypto.pl#L767 Please note that not all use cases of elliptic curves are cryptographic: Someone may want to perform the scalar multiplication and look at the resulting point for reasons that are completely unrelated to cryptography. I would dearly appreciate help from other contributors to make this work. Thank you a lot! |
You need to import the For The |
I tried to import this trait in triska@766ffa6, and now the entire compilation crashes: $ cargo build --release Compiling scryer-prolog v0.9.0 (/Users/triska/scryer-prolog) error: failed to run custom build command for `scryer-prolog v0.9.0 (/Users/triska/scryer-prolog)` Caused by: process didn't exit successfully: `/Users/triska/scryer-prolog/target/release/build/scryer-prolog-4c9b496aa1684afc/build-script-main` (exit status: 101) --- stdout rustfmt 1.4.38-stable (e092d0b6 2022-07-16) --- stderr thread 'main' panicked at 'parse error: expected `,` in file "src/machine/system_calls.rs"', build/static_string_indexing.rs:124:17 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace make: *** [all] Error 101 Maybe the import was not done correctly? |
I am very concerned by these lines of the predicate: It appears that what is going on here is:
It seems to me like this has a problematic abstraction mismatch. The underlying |
@triska you've imported the trait correctly. This seems more like a bug in |
@str4d: Our goal in this issue is to replace the way this is currently done with a method that does not depend on OpenSSL, and ideally also uses a much better API. All crates currently under discussion in this issue suffer from this dramatic abstraction mismatch: As a Rust programmer, I would like to use Rust integers to represent integers. Yet, I am forced to use completely different encodings by these crates. I prefer to write any necessary conversions to the greatest possible extent in Prolog, because I want to keep as much as possible of the implementation in Prolog. |
Regarding the point representation: In Scalar multiplication only works for points that are on the curve, |
Then you will be left wanting. There are no Rust integers that can represent cryptographically-relevant fields, as Rust does not have native big integer support like e.g. Python (or I presume Prolog), and the largest native integer size is a The point encodings provided by the Rust crates in question are developed for the specific use case of safe production usage in cryptographic protocols; it is therefore natural and expected that they will bake in security precautions that a library solely interested in "reasons unrelated to cryptography" (as you put it) may not require.
Then indeed, there is no need for the Rust code to deal directly in coordinates at all, as you say you want the conversions to be implemented in Prolog. @tarcieri has already specified above how you should go about this. To re-iterate:
|
Scryer Prolog uses the If someone is interested in writing these conversion functions, please do, thank you a lot. |
This change is now available in |
Compiling this crate from source is not a good experience, mainly because of OpenSSL and it's silly Perl building requiment. I would at least think about using Rustls so it is more easily portable. Looking at the source it is mainly limited to one function it seems so this may be doable, but I am no expert.
The text was updated successfully, but these errors were encountered: