Skip to content

Move away from traits implemented for specific Uint sizes? #793

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

Open
fjarri opened this issue Mar 13, 2025 · 1 comment
Open

Move away from traits implemented for specific Uint sizes? #793

fjarri opened this issue Mar 13, 2025 · 1 comment

Comments

@fjarri
Copy link
Contributor

fjarri commented Mar 13, 2025

Some traits are currently only implemented for specific Uint sizes, like Encoding, ConcatMixed/SplitMixed, WideningMul, and some others. This creates problems when working with big Uints of non-standard sizes, and increases compilation time because of all the macros creating the implementations.

I wonder if there's any desire to try and make these traits implementable generically, or make analogous traits that can be implemented generically, to exist side by side?

E.g. in my library I would like to use ConcatMixed, but can't, since it's only implemented up to U1024. So I have a trait Extendable, such that

pub trait Extendable<Wide: Sized>: Sized {
    fn to_wide(&self) -> Wide;
    fn try_from_wide(value: &Wide) -> Option<Self>;
}

impl<const L: usize, const W: usize> Extendable<Uint<W>> for Uint<L> {
    fn to_wide(&self) -> Uint<W> {
        const {
            if W < L {
                panic!("Inconsistent widths in `Extendable::to_wide()`");
            }
        }
        ...
    }
    ...
}

That is, the output length has to be provided explicitly, and if it is not consistent with the Uint length, a compile-time error is raised. Arguably, it is a clearer compile-time error compared to what you get if you try to use ConcatMixed with a type for which it is not implemented. Although, of course, in order to get it, you need to actually use to_wide() somewhere in your code, which is a downside.

I have a similar trait for the widening multiplication, where there's a compile-time check that the sum of the lengths of two arguments is equal to the output length.

For serialization, I have

pub trait BoxedEncoding: Sized {
    fn to_be_bytes(&self) -> Box<[u8]>;
    fn try_from_be_bytes(bytes: &[u8]) -> Result<Self, String>;
}

The problem with having it defined locally is that I have to wrap Uints in a newtype in order to use it.

Alternatively, it is possible to implement generic non-allocating Serialize/Deserialize for Uint (without it having to depend on Encoding), but it requires the use of zerocopy or bytemuck to transmute between &[Limb] and &[u8].

Any interest of bringing any of that into crypto-bigint?

@tarcieri
Copy link
Member

Ideally I think all traits would be implemented for all sizes, yes. If you can remove the hardcoded size limitations and implement things for all sizes, that'd be great. The const comparison is a nice hack.

Where this is very difficult currently is safegcd which uses precalculated conversions between the sizes needed for an integer and its unsaturated 62-bit representation used for safegcd, but hopefully #755 could help address that.

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

No branches or pull requests

2 participants