Skip to content

Have wNAF use PrimeField::to_le_repr for scalars#12

Merged
tarcieri merged 1 commit into
mainfrom
wnaf-fix
Mar 31, 2026
Merged

Have wNAF use PrimeField::to_le_repr for scalars#12
tarcieri merged 1 commit into
mainfrom
wnaf-fix

Conversation

@tarcieri
Copy link
Copy Markdown
Member

@tarcieri tarcieri commented Mar 31, 2026

The wNAF implementation assumes a little endian representation for scalars, but PrimeField::to_repr returns an opaque representation which may be big endian and is in the case of our implementations of the NIST P-curves.

RustCrypto/ff#10 added a stopgap API: PrimeField::to_le_repr, which is guaranteed to return a little endian representation. This commit switches (rustcrypto-)group to use it, which should make it compatible with our curves which otherwise use a big endian SEC1 representation.

Thanks to @tob-scott-a for sleuthing this out in #10.

The wNAF implementation assumes a little endian representation for
scalars, but `PrimeField::to_repr` returns an opaque representation
which may be big endian and is in the case of our implementations of the
NIST P-curves.

RustCrypto/ff#10 added a stopgap API: `PrimeField::to_le_repr`, which is
guaranteed to return a little endian representation. This commit
switches `(rustcrypto-)group` to use it, which should make it compatible
with our curves which otherwise use a big endian SEC1 representation.
@tarcieri tarcieri changed the title [WIP] Have wNAF use PrimeField::to_le_repr for scalars Have wNAF use PrimeField::to_le_repr for scalars Mar 31, 2026
@tarcieri tarcieri marked this pull request as ready for review March 31, 2026 15:55
@tarcieri
Copy link
Copy Markdown
Member Author

tarcieri commented Mar 31, 2026

Confirmed this is working against p256 on the wnaf branch of https://github.com/RustCrypto/elliptic-curves, so I'm going to merge

cc @str4d

@tarcieri tarcieri merged commit 0d3091d into main Mar 31, 2026
8 checks passed
@tarcieri tarcieri deleted the wnaf-fix branch March 31, 2026 19:32
tarcieri added a commit to RustCrypto/elliptic-curves that referenced this pull request Apr 8, 2026
RustCrypto/group#12 included a workaround that allows curves with a big
endian `PrimeField::Repr` to be used for wNAF, by defining a separate
`PrimeField::to_le_repr` method which is always guaranteed to be little
endian. This may not be the permanent solution to this problem which
gets upstreamed, but it unblocks work for now.

This commit adds the relevant impls of `to_le_repr`, along with initial
`WnafGroup` impls to `ProjectivePoint` in `k256` and `primeorder`
(currently hardcoded to a fixed constant of `4` for now to unblock
additional work).

This also adds a `ProjectivePoint::wnaf` static method to obtain a
wNAF context for that particular curve group, feature-gated on `alloc`.

Finally, it adds a smoke test to `p256` which checks it against our
scalar multiplication test vectors, however it does not check any other
curves yet and probably should.
tarcieri added a commit to RustCrypto/elliptic-curves that referenced this pull request Apr 8, 2026
RustCrypto/group#12 included a workaround that allows curves with a big
endian `PrimeField::Repr` to be used for wNAF, by defining a separate
`PrimeField::to_le_repr` method which is always guaranteed to be little
endian. This may not be the permanent solution to this problem which
gets upstreamed, but it unblocks work for now.

This commit adds the relevant impls of `to_le_repr`, along with initial
`WnafGroup` impls to `ProjectivePoint` in `k256` and `primeorder`
(currently hardcoded to a fixed constant of `4` for now to unblock
additional work).

This also adds a `ProjectivePoint::wnaf` static method to obtain a
wNAF context for that particular curve group, feature-gated on `alloc`.

Finally, it adds a smoke test to `p256` which checks it against our
scalar multiplication test vectors, however it does not check any other
curves yet and probably should.
tarcieri added a commit to RustCrypto/utils that referenced this pull request May 15, 2026
Adds a crate providing a `&BitSlice`/`&mut BitSlice` type which is
constructable from `&[u8]` but provides slicing at the granularity of
individual bits. The name of the crate is a play on `bitvec`, which
provides a similar type. However, the implementation in this crate is
significantly simpler with a much smaller code surface and minimal use
of `unsafe` code.

The implementation is a generalization of RustCrypto/formats#2300 which
sought to implement a similar data structure as a reference type for
representing ASN.1 BIT STRINGs. However, using this approach was
deferred because the implementation relies on a conversion which is
sound under Tree Borrows (as verified by Miri) but unsound under Stacked
Borrows as it loses provenance. See rust-lang/unsafe-code-guidelines#134

There are several places such a data structure is potentially useful for
RustCrypto projects. Beyond the previously mentioned ASN.1 BIT STRING
use case, being able to iterate over bits is useful in many numerical
algorithms with applications in cryptography, notably in `crypto-bigint`
and for elliptic curves.

Elliptic curve scalar multiplication is generally implemented as a loop
over the bits of a scalar. Having an iterator type for this purpose
avoids problems relating to the endianness of how scalars are serialized
when implementing generic scalar multiplication algorithms, e.g. wNAF
(see RustCrypto/group#12).

Given the current open soundness story, I'm not rushing to use this in
`crypto-bigint` until that changes. Where we could use it today though
is as an optional dependency to `der`, where it can act as an ASN.1
BIT STRING type, but implement `ToOwned` producing a
`der::asn1::BitString` (which, to make `ToOwned` work, needs to impl
`Borrow<BitSlice>`).

This would make it optionally possible to use `Cow` for copy-on-write
BIT STRINGs today with `BitSlice` as the borrowed form, but leaving the
preferred default data structure for that purpose as
`der::asn1::BitStringRef`, which is a lifetime-parameterized struct
that avoids the open soundness questions around `BitSlice`.

From there we can see what develops around the soundness story and SB/TB
discrepancy, and beyond that new Rust features like custom DSTs which
may make expressing structures like this less of a hack.
tarcieri added a commit to RustCrypto/utils that referenced this pull request May 15, 2026
Adds a crate providing a `&BitSlice`/`&mut BitSlice` type which is
constructable from `&[u8]` but provides slicing at the granularity of
individual bits. The name of the crate is a play on `bitvec`, which
provides a similar type. However, the implementation in this crate is
significantly simpler with a much smaller code surface and minimal use
of `unsafe` code.

The implementation is a generalization of RustCrypto/formats#2300 which
sought to implement a similar data structure as a reference type for
representing ASN.1 BIT STRINGs. However, using this approach was
deferred because the implementation relies on a conversion which is
sound under Tree Borrows (as verified by Miri) but unsound under Stacked
Borrows as it loses provenance. See rust-lang/unsafe-code-guidelines#134

There are several places such a data structure is potentially useful for
RustCrypto projects. Beyond the previously mentioned ASN.1 BIT STRING
use case, being able to iterate over bits is useful in many numerical
algorithms with applications in cryptography, notably in `crypto-bigint`
and for elliptic curves.

Elliptic curve scalar multiplication is generally implemented as a loop
over the bits of a scalar. Having an iterator type for this purpose
avoids problems relating to the endianness of how scalars are serialized
when implementing generic scalar multiplication algorithms, e.g. wNAF
(see RustCrypto/group#12).

Given the current open soundness story, I'm not rushing to use this in
`crypto-bigint` until that changes. Where we could use it today though
is as an optional dependency to `der`, where it can act as an ASN.1
BIT STRING type, but implement `ToOwned` producing a
`der::asn1::BitString` (which, to make `ToOwned` work, needs to impl
`Borrow<BitSlice>`).

This would make it optionally possible to use `Cow` for copy-on-write
BIT STRINGs today with `BitSlice` as the borrowed form, but leaving the
preferred default data structure for that purpose as
`der::asn1::BitStringRef`, which is a lifetime-parameterized struct
that avoids the open soundness questions around `BitSlice`.

From there we can see what develops around the soundness story and SB/TB
discrepancy, and beyond that new Rust features like custom DSTs which
may make expressing structures like this less of a hack.
tarcieri added a commit to RustCrypto/utils that referenced this pull request May 15, 2026
Adds a crate providing a `&BitSlice`/`&mut BitSlice` type which is
constructable from `&[u8]` but provides slicing at the granularity of
individual bits. The name of the crate is a play on `bitvec`, which
provides a similar type. However, the implementation in this crate is
significantly simpler with a much smaller code surface and minimal use
of `unsafe` code.

The implementation is a generalization of RustCrypto/formats#2300 which
sought to implement a similar data structure as a reference type for
representing ASN.1 BIT STRINGs. However, using this approach was
deferred because the implementation relies on a conversion which is
sound under Tree Borrows (as verified by Miri) but unsound under Stacked
Borrows as it loses provenance. See rust-lang/unsafe-code-guidelines#134

There are several places such a data structure is potentially useful for
RustCrypto projects. Beyond the previously mentioned ASN.1 BIT STRING
use case, being able to iterate over bits is useful in many numerical
algorithms with applications in cryptography, notably in `crypto-bigint`
and for elliptic curves.

Elliptic curve scalar multiplication is generally implemented as a loop
over the bits of a scalar. Having an iterator type for this purpose
avoids problems relating to the endianness of how scalars are serialized
when implementing generic scalar multiplication algorithms, e.g. wNAF
(see RustCrypto/group#12).

Given the current open soundness story, I'm not rushing to use this in
`crypto-bigint` until that changes. Where we could use it today though
is as an optional dependency to `der`, where it can act as an ASN.1
BIT STRING type, but implement `ToOwned` producing a
`der::asn1::BitString` (which, to make `ToOwned` work, needs to impl
`Borrow<BitSlice>`).

This would make it optionally possible to use `Cow` for copy-on-write
BIT STRINGs today with `BitSlice` as the borrowed form, but leaving the
preferred default data structure for that purpose as
`der::asn1::BitStringRef`, which is a lifetime-parameterized struct
that avoids the open soundness questions around `BitSlice`.

From there we can see what develops around the soundness story and SB/TB
discrepancy, and beyond that new Rust features like custom DSTs which
may make expressing structures like this less of a hack.
tarcieri added a commit to RustCrypto/utils that referenced this pull request May 15, 2026
Adds a crate providing a `&BitSlice`/`&mut BitSlice` type which is
constructable from `&[u8]` but provides slicing at the granularity of
individual bits. The name of the crate is a play on `bitvec`, which
provides a similar type. However, the implementation in this crate is
significantly simpler with a much smaller code surface and minimal use
of `unsafe` code.

The implementation is a generalization of RustCrypto/formats#2300 which
sought to implement a similar data structure as a reference type for
representing ASN.1 BIT STRINGs. However, using this approach was
deferred because the implementation relies on a conversion which is
sound under Tree Borrows (as verified by Miri) but unsound under Stacked
Borrows as it loses provenance. See rust-lang/unsafe-code-guidelines#134

There are several places such a data structure is potentially useful for
RustCrypto projects. Beyond the previously mentioned ASN.1 BIT STRING
use case, being able to iterate over bits is useful in many numerical
algorithms with applications in cryptography, notably in `crypto-bigint`
and for elliptic curves.

Elliptic curve scalar multiplication is generally implemented as a loop
over the bits of a scalar. Having an iterator type for this purpose
avoids problems relating to the endianness of how scalars are serialized
when implementing generic scalar multiplication algorithms, e.g. wNAF
(see RustCrypto/group#12).

Given the current open soundness story, I'm not rushing to use this in
`crypto-bigint` until that changes. Where we could use it today though
is as an optional dependency to `der`, where it can act as an ASN.1
BIT STRING type, but implement `ToOwned` producing a
`der::asn1::BitString` (which, to make `ToOwned` work, needs to impl
`Borrow<BitSlice>`).

This would make it optionally possible to use `Cow` for copy-on-write
BIT STRINGs today with `BitSlice` as the borrowed form, but leaving the
preferred default data structure for that purpose as
`der::asn1::BitStringRef`, which is a lifetime-parameterized struct
that avoids the open soundness questions around `BitSlice`.

From there we can see what develops around the soundness story and SB/TB
discrepancy, and beyond that new Rust features like custom DSTs which
may make expressing structures like this less of a hack.
tarcieri added a commit to RustCrypto/utils that referenced this pull request May 15, 2026
Adds a crate providing a `&BitSlice`/`&mut BitSlice` type which is
constructable from `&[u8]` but provides slicing at the granularity of
individual bits. The name of the crate is a play on `bitvec`, which
provides a similar type. However, the implementation in this crate is
significantly simpler with a much smaller code surface and minimal use
of `unsafe` code.

The implementation is a generalization of RustCrypto/formats#2300 which
sought to implement a similar data structure as a reference type for
representing ASN.1 BIT STRINGs. However, using this approach was
deferred because the implementation relies on a conversion which is
sound under Tree Borrows (as verified by Miri) but unsound under Stacked
Borrows as it loses provenance. See rust-lang/unsafe-code-guidelines#134

There are several places such a data structure is potentially useful for
RustCrypto projects. Beyond the previously mentioned ASN.1 BIT STRING
use case, being able to iterate over bits is useful in many numerical
algorithms with applications in cryptography, notably in `crypto-bigint`
and for elliptic curves.

Elliptic curve scalar multiplication is generally implemented as a loop
over the bits of a scalar. Having an iterator type for this purpose
avoids problems relating to the endianness of how scalars are serialized
when implementing generic scalar multiplication algorithms, e.g. wNAF
(see RustCrypto/group#12).

Given the current open soundness story, I'm not rushing to use this in
`crypto-bigint` until that changes. Where we could use it today though
is as an optional dependency to `der`, where it can act as an ASN.1
BIT STRING type, but implement `ToOwned` producing a
`der::asn1::BitString` (which, to make `ToOwned` work, needs to impl
`Borrow<BitSlice>`).

This would make it optionally possible to use `Cow` for copy-on-write
BIT STRINGs today with `BitSlice` as the borrowed form, but leaving the
preferred default data structure for that purpose as
`der::asn1::BitStringRef`, which is a lifetime-parameterized struct
that avoids the open soundness questions around `BitSlice`.

From there we can see what develops around the soundness story and SB/TB
discrepancy, and beyond that new Rust features like custom DSTs which
may make expressing structures like this less of a hack.
tarcieri added a commit to RustCrypto/utils that referenced this pull request May 15, 2026
Adds a crate providing a `&BitSlice`/`&mut BitSlice` type which is
constructable from `&[u8]` but provides slicing at the granularity of
individual bits. The name of the crate is a play on `bitvec`, which
provides a similar type. However, the implementation in this crate is
significantly simpler with a much smaller code surface and minimal use
of `unsafe` code.

The implementation is a generalization of RustCrypto/formats#2300 which
sought to implement a similar data structure as a reference type for
representing ASN.1 BIT STRINGs. However, using this approach was
deferred because the implementation relies on a conversion which is
sound under Tree Borrows (as verified by Miri) but unsound under Stacked
Borrows as it loses provenance. See rust-lang/unsafe-code-guidelines#134

There are several places such a data structure is potentially useful for
RustCrypto projects. Beyond the previously mentioned ASN.1 BIT STRING
use case, being able to iterate over bits is useful in many numerical
algorithms with applications in cryptography, notably in `crypto-bigint`
and for elliptic curves.

Elliptic curve scalar multiplication is generally implemented as a loop
over the bits of a scalar. Having an iterator type for this purpose
avoids problems relating to the endianness of how scalars are serialized
when implementing generic scalar multiplication algorithms, e.g. wNAF
(see RustCrypto/group#12).

Given the current open soundness story, I'm not rushing to use this in
`crypto-bigint` until that changes. Where we could use it today though
is as an optional dependency to `der`, where it can act as an ASN.1
BIT STRING type, but implement `ToOwned` producing a
`der::asn1::BitString` (which, to make `ToOwned` work, needs to impl
`Borrow<BitSlice>`).

This would make it optionally possible to use `Cow` for copy-on-write
BIT STRINGs today with `BitSlice` as the borrowed form, but leaving the
preferred default data structure for that purpose as
`der::asn1::BitStringRef`, which is a lifetime-parameterized struct
that avoids the open soundness questions around `BitSlice`.

From there we can see what develops around the soundness story and SB/TB
discrepancy, and beyond that new Rust features like custom DSTs which
may make expressing structures like this less of a hack.
tarcieri added a commit to RustCrypto/utils that referenced this pull request May 15, 2026
Adds a crate providing a `&BitSlice`/`&mut BitSlice` type which is
constructable from `&[u8]` but provides slicing at the granularity of
individual bits. The name of the crate is a play on `bitvec`, which
provides a similar type. However, the implementation in this crate is
significantly simpler with a much smaller code surface and minimal use
of `unsafe` code.

The implementation is a generalization of RustCrypto/formats#2300 which
sought to implement a similar data structure as a reference type for
representing ASN.1 BIT STRINGs. However, using this approach was
deferred because the implementation relies on a conversion which is
sound under Tree Borrows (as verified by Miri) but unsound under Stacked
Borrows as it loses provenance. See rust-lang/unsafe-code-guidelines#134

There are several places such a data structure is potentially useful for
RustCrypto projects. Beyond the previously mentioned ASN.1 BIT STRING
use case, being able to iterate over bits is useful in many numerical
algorithms with applications in cryptography, notably in `crypto-bigint`
and for elliptic curves.

Elliptic curve scalar multiplication is generally implemented as a loop
over the bits of a scalar. Having an iterator type for this purpose
avoids problems relating to the endianness of how scalars are serialized
when implementing generic scalar multiplication algorithms, e.g. wNAF
(see RustCrypto/group#12).

Given the current open soundness story, I'm not rushing to use this in
`crypto-bigint` until that changes. Where we could use it today though
is as an optional dependency to `der`, where it can act as an ASN.1
BIT STRING type, but implement `ToOwned` producing a
`der::asn1::BitString` (which, to make `ToOwned` work, needs to impl
`Borrow<BitSlice>`).

This would make it optionally possible to use `Cow` for copy-on-write
BIT STRINGs today with `BitSlice` as the borrowed form, but leaving the
preferred default data structure for that purpose as
`der::asn1::BitStringRef`, which is a lifetime-parameterized struct
that avoids the open soundness questions around `BitSlice`.

From there we can see what develops around the soundness story and SB/TB
discrepancy, and beyond that new Rust features like custom DSTs which
may make expressing structures like this less of a hack.
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

Successfully merging this pull request may close these issues.

1 participant