Skip to content
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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement num_traits::pow for Scalar #340

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from

Conversation

cargodog
Copy link

@cargodog cargodog commented Jan 2, 2021

What:

This PR implements num_traits::Pow for the Scalar type.

Why:

Many cryptographic protocols, especially some more complex ZKP schemes, rely on Scalar exponentiation. Without this trait implementation, using this library in such protocols requires also implementing exponentiation for Scalar types. This leads to inconsistent implementations and suboptimal arithmetic (e.g. fast exponentiation).

In many cases, simple iterative exponentiation is sufficient and easy to implement. In other cases, however, iterative exponentiation is costly and slows down the system. num_traits::Pow provides optimized "fast math" exponentiation for us, providing users an easy and repeatable way to get the most efficient exponentiation in all scenarios.

Implementation notes:

I copied the pow_impl! macro from num_traits::Pow, because they do not export this macro. I feel this provides the simplest/cleanest implementation, but please let me know if you would prefer to have this done some other way (or not at all).

Cheers 馃嵒

P.S. great work on this library! I find myself recommending it to others all the time.

@cargodog
Copy link
Author

cargodog commented Jan 8, 2021

I should point out, I also implemented num_traits::identities::{One, Zero}, which are useful to make Scalars usable with several other math libs.

I just implemented these as wrappers around the existing Scalar::one() and Scalar::zero() methods, since that was the least intrusive, but arguably those methods could instead be removed and replaced in favor of the identity implementations.

@isislovecruft
Copy link
Member

Hi @cargodog, thanks for the PR.

First, I feel extremely hesitant to implement numeric traits from a non-stdlib crate, especially one that is not yet stabilised.

On another note, I took a skim over the arcturus paper and your implementation, and I could definitely be wrong about this but I believe your scalar mu (and field element rho) terms are written multiplicatively, so anything that looks like an exponentiation in those terms is instead a multiplication. It's a little confusing because the author is using additive notation for the group elements and multiplicative for field elements and scalars, but it's (annoyingly) something I've seen in other papers with similar utilisation of polynomial evaluations for secret keys and/or NIZK challenges. Anyway, this is all just to say that unless I'm reading this paper wrong, I'm pretty sure you don't need exponentiation.

Copy link
Member

@isislovecruft isislovecruft left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comment above.

@cargodog
Copy link
Author

cargodog commented Jan 8, 2021

I feel extremely hesitant to implement numeric traits from a non-stdlib crate, especially one that is not yet stabilised.

I understand this concern, but I disagree that the crate is not yet established. The crate was originally part of std, but was removed as part of a broader effort to simplify the standard lib (itertools is another victim of this movement). It is still maintained by core Rust devs, and remains the defacto numeric trait library.

That said, I understand pulling in a non-std crate carries risk, and I understand if that's a deal-breaker 馃槙.

On another note, I took a skim over the arcturus paper and your implementation, and I could definitely be wrong about this but I believe your scalar mu (and field element rho) terms are written multiplicatively, so anything that looks like an exponentiation in those terms is instead a multiplication. It's a little confusing because the author is using additive notation for the group elements and multiplicative for field elements and scalars, but it's (annoyingly) something I've seen in other papers with similar utilisation of polynomial evaluations for secret keys and/or NIZK challenges. Anyway, this is all just to say that unless I'm reading this paper wrong, I'm pretty sure you don't need exponentiation.

I'm now seeing the author has revised his paper since my original implementation, specifically with regard to mu_k computation, so thats fun 馃榿

The mu^k terms are truly exponentiation. I've logged a conversation with the author, where he explains the reason (we were brainstorming approaches to maximize performance). In most cases, mu^k can be computed as an iterative chain of multiplications, with no need for actual exponentiation as you suggest. There is one case, however, where this incurs a significant performance penalty: The prover must compute mu^k for each input she chooses to prove, which may be located at random positions k within the set. Since these are random, they cannot be efficiently computed in the iterator chains, and require expensive "one-off" computation of each exponent. For large anonymity sets, this actually becomes one of the largest performance bottlenecks (oddly, since scalar arithmetic is often overlooked in performance analysis of crypto systems).

An arguably more significant reason for this patch, is broader compatibility with other numeric crates. The One and Zero traits especially open several doors (such as symbolic math libraries, which require these traits to instantiate new identity elements). Using myself as an example, I ended up writing this terrible hack to implement symbolic polynomial evaluation without reliance on the Zero trait, so as to be compatible with the Scalar type. I'll only pick on my own code, but I've seen other instances where common math crates could not be used, and implementers chose to write their own (often questionable) workarounds.

@cargodog
Copy link
Author

cargodog commented Jan 8, 2021

Oof, sorry for the wall of text! If the num-traits dependency is a show stopper, I can close out this PR. Thanks for your time!

@isislovecruft
Copy link
Member

isislovecruft commented Feb 2, 2021

Hi @cargodog,

I missed that鈥攆ive pages into their simulation argument鈥攖hey require DDL, so you're correct that it is actually exponentiation. (On another note, DDL is a rare assumption and it's probably the only actual time I can think of where exponentiation is needed. In any case, I don't think they actually need DDL: they should be able to do the polynomial interpolation as normal requiring only DL, rather than in the exponents, and the resulting protocol would be quite a bit more computationally efficient. Without working through the maths more, I'm not sure what this would do to the size of the proofs.. which might be why they require DDL?)

In any case, I'll think about this a bit more, but since it's really uncommon to need exponentiation and many papers have confusing and/or mixed notation, I'd still be a bit nervous that the API would provide an easy foot-gun to users.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants