diff --git a/.github/workflows/ecdsa.yml b/.github/workflows/ecdsa.yml index 186150eb..36fa3d6b 100644 --- a/.github/workflows/ecdsa.yml +++ b/.github/workflows/ecdsa.yml @@ -24,7 +24,7 @@ jobs: - thumbv7em-none-eabi - wasm32-unknown-unknown rust: - - 1.41.0 # MSRV + - 1.44.0 # MSRV - stable steps: - uses: actions/checkout@v1 @@ -35,15 +35,20 @@ jobs: target: ${{ matrix.target }} override: true - run: cargo build --no-default-features --release --target ${{ matrix.target }} - - run: cargo build --no-default-features --features sign --release --target ${{ matrix.target }} - - run: cargo build --no-default-features --features verify --release --target ${{ matrix.target }} + - run: cargo build --no-default-features --release --target ${{ matrix.target }} --features arithmetic + - run: cargo build --no-default-features --release --target ${{ matrix.target }} --features digest + - run: cargo build --no-default-features --release --target ${{ matrix.target }} --features hazmat + - run: cargo build --no-default-features --release --target ${{ matrix.target }} --features sign + - run: cargo build --no-default-features --release --target ${{ matrix.target }} --features verify + - run: cargo build --no-default-features --release --target ${{ matrix.target }} --features zeroize + - run: cargo build --no-default-features --release --target ${{ matrix.target }} --features arithmetic,digest,hazmat,sign,verify,zeroize test: runs-on: ubuntu-latest strategy: matrix: rust: - - 1.41.0 # MSRV + - 1.44.0 # MSRV - stable steps: - uses: actions/checkout@v1 diff --git a/.github/workflows/workspace.yml b/.github/workflows/workspace.yml index 19faab44..0bd1dfd2 100644 --- a/.github/workflows/workspace.yml +++ b/.github/workflows/workspace.yml @@ -38,7 +38,7 @@ jobs: - uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: stable + toolchain: 1.44.0 # Highest MSRV in repo components: clippy - run: cargo clippy --all-features -- -D warnings diff --git a/Cargo.lock b/Cargo.lock index 4aaf6725..71912947 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,6 +10,17 @@ dependencies = [ "serde", ] +[[package]] +name = "bitvec" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c1f0df4bb4c441080e98d6ea2dc3281fc19bb440e69ce03075e3d705894f1cb" +dependencies = [ + "funty", + "radium", + "wyz", +] + [[package]] name = "block-buffer" version = "0.9.0" @@ -79,8 +90,9 @@ dependencies = [ [[package]] name = "elliptic-curve" version = "0.5.0" -source = "git+https://github.com/RustCrypto/traits#88d462bd5c94a1b1dbf3f2f5375fdfc406b35293" +source = "git+https://github.com/RustCrypto/traits#59e67e05cb30194e1af8aa81a30fd33872d904a6" dependencies = [ + "bitvec", "digest", "ff", "generic-array", @@ -92,15 +104,21 @@ dependencies = [ [[package]] name = "ff" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11efdc125f2647dde5a0f5f88010a5b0f89b700f86052afa1d148c4696047" +checksum = "01646e077d4ebda82b73f1bca002ea1e91561a77df2431a9e79729bcc31950ef" dependencies = [ - "byteorder", + "bitvec", "rand_core", "subtle", ] +[[package]] +name = "funty" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ba62103ce691c2fd80fbae2213dfdda9ce60804973ac6b6e97de818ea7f52c8" + [[package]] name = "generic-array" version = "0.14.4" @@ -113,10 +131,10 @@ dependencies = [ [[package]] name = "group" -version = "0.7.0" -source = "git+https://github.com/zkcrypto/group.git#2942324876cdbb5c94140ad39ae83da642c30374" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc11f9f5fbf1943b48ae7c2bf6846e7d827a512d1be4f23af708f5ca5d01dde1" dependencies = [ - "byteorder", "ff", "rand_core", "subtle", @@ -144,6 +162,12 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "radium" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "def50a86306165861203e7f84ecffbbdfdea79f0e51039b33de1e952358c47ac" + [[package]] name = "rand_core" version = "0.5.1" @@ -197,6 +221,12 @@ version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" +[[package]] +name = "wyz" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" + [[package]] name = "zeroize" version = "1.1.0" diff --git a/Cargo.toml b/Cargo.toml index 9470dcba..8bcb2dda 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,4 +3,3 @@ members = ["ecdsa", "ed25519"] [patch.crates-io] elliptic-curve = { git = "https://github.com/RustCrypto/traits" } -group = { git = "https://github.com/zkcrypto/group.git" } diff --git a/ecdsa/Cargo.toml b/ecdsa/Cargo.toml index cd1874ad..5acef5d6 100644 --- a/ecdsa/Cargo.toml +++ b/ecdsa/Cargo.toml @@ -25,12 +25,13 @@ sha2 = { version = "0.9", default-features = false } [features] default = ["digest"] alloc = [] -dev = ["digest", "zeroize"] +arithmetic = ["elliptic-curve/arithmetic"] +dev = ["arithmetic", "digest", "zeroize"] digest = ["elliptic-curve/digest", "signature/digest-preview"] hazmat = [] -sign = ["digest", "hazmat", "hmac", "zeroize"] +sign = ["arithmetic", "digest", "hazmat", "hmac", "zeroize"] std = ["alloc", "elliptic-curve/std", "signature/std"] -verify = ["digest", "hazmat"] +verify = ["arithmetic", "digest", "hazmat"] zeroize = ["elliptic-curve/zeroize"] [package.metadata.docs.rs] diff --git a/ecdsa/README.md b/ecdsa/README.md index eab4d9c0..46ff5ba5 100644 --- a/ecdsa/README.md +++ b/ecdsa/README.md @@ -26,7 +26,7 @@ ways: ## Minimum Supported Rust Version -- Rust **1.41+** +- Rust **1.44+** ## License @@ -50,7 +50,7 @@ dual licensed as above, without any additional terms or conditions. [docs-image]: https://docs.rs/ecdsa/badge.svg [docs-link]: https://docs.rs/ecdsa/ [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg -[rustc-image]: https://img.shields.io/badge/rustc-1.41+-blue.svg +[rustc-image]: https://img.shields.io/badge/rustc-1.44+-blue.svg [build-image]: https://github.com/RustCrypto/signatures/workflows/ecdsa/badge.svg?branch=master&event=push [build-link]: https://github.com/RustCrypto/signatures/actions?query=workflow%3Aecdsa diff --git a/ecdsa/src/dev/curve.rs b/ecdsa/src/dev/curve.rs index 285f0b90..77da29c2 100644 --- a/ecdsa/src/dev/curve.rs +++ b/ecdsa/src/dev/curve.rs @@ -2,16 +2,23 @@ //! //! Modeled after NIST P-256. -use core::{convert::TryInto, ops::Mul}; +use core::{ + convert::TryInto, + iter::Sum, + ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}, +}; use elliptic_curve::{ consts::U32, digest::Digest, + ff::{Field, PrimeField}, + group, ops::Invert, point::Generator, + rand_core::RngCore, subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}, util::{adc64, sbb64}, zeroize::Zeroize, - FromBytes, FromDigest, + FieldBits, FromBytes, FromDigest, }; /// Example NIST P-256-like elliptic curve. @@ -28,6 +35,7 @@ impl elliptic_curve::weierstrass::Curve for ExampleCurve {} impl elliptic_curve::Arithmetic for ExampleCurve { type Scalar = Scalar; type AffinePoint = AffinePoint; + type ProjectivePoint = ProjectivePoint; } /// Field element bytes. @@ -51,9 +59,82 @@ const MODULUS: U256 = [ ]; /// Example scalar type -#[derive(Clone, Copy, Debug, Default)] +#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] pub struct Scalar([u64; LIMBS]); +impl Field for Scalar { + fn random(_rng: impl RngCore) -> Self { + unimplemented!(); + } + + fn zero() -> Self { + unimplemented!(); + } + + fn one() -> Self { + unimplemented!(); + } + + fn is_zero(&self) -> bool { + unimplemented!(); + } + + #[must_use] + fn square(&self) -> Self { + unimplemented!(); + } + + #[must_use] + fn double(&self) -> Self { + unimplemented!(); + } + + fn invert(&self) -> CtOption { + unimplemented!(); + } + + fn sqrt(&self) -> CtOption { + unimplemented!(); + } +} + +impl PrimeField for Scalar { + type Repr = ElementBytes; + type ReprBits = usize; + + const NUM_BITS: u32 = 256; + const CAPACITY: u32 = 255; + const S: u32 = 4; + + fn from_repr(_repr: ElementBytes) -> Option { + unimplemented!(); + } + + fn to_repr(&self) -> ElementBytes { + unimplemented!(); + } + + fn to_le_bits(&self) -> FieldBits { + unimplemented!(); + } + + fn is_odd(&self) -> bool { + unimplemented!(); + } + + fn char_le_bits() -> FieldBits { + unimplemented!(); + } + + fn multiplicative_generator() -> Self { + unimplemented!(); + } + + fn root_of_unity() -> Self { + unimplemented!(); + } +} + impl ConditionallySelectable for Scalar { fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { Scalar([ @@ -74,6 +155,104 @@ impl ConstantTimeEq for Scalar { } } +impl Add for Scalar { + type Output = Scalar; + + fn add(self, _other: Scalar) -> Scalar { + unimplemented!(); + } +} + +impl Add<&Scalar> for Scalar { + type Output = Scalar; + + fn add(self, _other: &Scalar) -> Scalar { + unimplemented!(); + } +} + +impl AddAssign for Scalar { + fn add_assign(&mut self, _rhs: Scalar) { + unimplemented!(); + } +} + +impl AddAssign<&Scalar> for Scalar { + fn add_assign(&mut self, _rhs: &Scalar) { + unimplemented!(); + } +} + +impl Sub for Scalar { + type Output = Scalar; + + fn sub(self, _other: Scalar) -> Scalar { + unimplemented!(); + } +} + +impl Sub<&Scalar> for Scalar { + type Output = Scalar; + + fn sub(self, _other: &Scalar) -> Scalar { + unimplemented!(); + } +} + +impl SubAssign for Scalar { + fn sub_assign(&mut self, _rhs: Scalar) { + unimplemented!(); + } +} + +impl SubAssign<&Scalar> for Scalar { + fn sub_assign(&mut self, _rhs: &Scalar) { + unimplemented!(); + } +} + +impl Mul for Scalar { + type Output = Scalar; + + fn mul(self, _other: Scalar) -> Scalar { + unimplemented!(); + } +} + +impl Mul<&Scalar> for Scalar { + type Output = Scalar; + + fn mul(self, _other: &Scalar) -> Scalar { + unimplemented!(); + } +} + +impl MulAssign for Scalar { + fn mul_assign(&mut self, _rhs: Scalar) { + unimplemented!(); + } +} + +impl MulAssign<&Scalar> for Scalar { + fn mul_assign(&mut self, _rhs: &Scalar) { + unimplemented!(); + } +} + +impl Neg for Scalar { + type Output = Scalar; + + fn neg(self) -> Scalar { + unimplemented!(); + } +} + +impl From for Scalar { + fn from(_: u64) -> Scalar { + unimplemented!(); + } +} + impl FromBytes for Scalar { type Size = U32; @@ -100,6 +279,12 @@ impl FromBytes for Scalar { impl From for ElementBytes { fn from(scalar: Scalar) -> Self { + Self::from(&scalar) + } +} + +impl From<&Scalar> for ElementBytes { + fn from(scalar: &Scalar) -> Self { let mut ret = ElementBytes::default(); ret[0..8].copy_from_slice(&scalar.0[3].to_be_bytes()); ret[8..16].copy_from_slice(&scalar.0[2].to_be_bytes()); @@ -197,3 +382,200 @@ impl Generator for AffinePoint { unimplemented!(); } } + +/// Example projective point type +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct ProjectivePoint {} + +impl group::Group for ProjectivePoint { + type Scalar = Scalar; + + fn random(_rng: impl RngCore) -> Self { + unimplemented!(); + } + + fn identity() -> Self { + unimplemented!(); + } + + fn generator() -> Self { + unimplemented!(); + } + + fn is_identity(&self) -> Choice { + unimplemented!(); + } + + #[must_use] + fn double(&self) -> Self { + unimplemented!(); + } +} + +impl group::Curve for ProjectivePoint { + type AffineRepr = AffinePoint; + + fn to_affine(&self) -> AffinePoint { + unimplemented!(); + } +} + +impl Add for ProjectivePoint { + type Output = ProjectivePoint; + + fn add(self, _other: ProjectivePoint) -> ProjectivePoint { + unimplemented!(); + } +} + +impl Add<&ProjectivePoint> for ProjectivePoint { + type Output = ProjectivePoint; + + fn add(self, _other: &ProjectivePoint) -> ProjectivePoint { + unimplemented!(); + } +} + +impl AddAssign for ProjectivePoint { + fn add_assign(&mut self, _rhs: ProjectivePoint) { + unimplemented!(); + } +} + +impl AddAssign<&ProjectivePoint> for ProjectivePoint { + fn add_assign(&mut self, _rhs: &ProjectivePoint) { + unimplemented!(); + } +} + +impl Sub for ProjectivePoint { + type Output = ProjectivePoint; + + fn sub(self, _other: ProjectivePoint) -> ProjectivePoint { + unimplemented!(); + } +} + +impl Sub<&ProjectivePoint> for ProjectivePoint { + type Output = ProjectivePoint; + + fn sub(self, _other: &ProjectivePoint) -> ProjectivePoint { + unimplemented!(); + } +} + +impl SubAssign for ProjectivePoint { + fn sub_assign(&mut self, _rhs: ProjectivePoint) { + unimplemented!(); + } +} + +impl SubAssign<&ProjectivePoint> for ProjectivePoint { + fn sub_assign(&mut self, _rhs: &ProjectivePoint) { + unimplemented!(); + } +} + +impl Add for ProjectivePoint { + type Output = ProjectivePoint; + + fn add(self, _other: AffinePoint) -> ProjectivePoint { + unimplemented!(); + } +} + +impl Add<&AffinePoint> for ProjectivePoint { + type Output = ProjectivePoint; + + fn add(self, _other: &AffinePoint) -> ProjectivePoint { + unimplemented!(); + } +} + +impl AddAssign for ProjectivePoint { + fn add_assign(&mut self, _rhs: AffinePoint) { + unimplemented!(); + } +} + +impl AddAssign<&AffinePoint> for ProjectivePoint { + fn add_assign(&mut self, _rhs: &AffinePoint) { + unimplemented!(); + } +} + +impl Sum for ProjectivePoint { + fn sum>(_iter: I) -> Self { + unimplemented!(); + } +} + +impl<'a> Sum<&'a ProjectivePoint> for ProjectivePoint { + fn sum>(_iter: I) -> Self { + unimplemented!(); + } +} + +impl Sub for ProjectivePoint { + type Output = ProjectivePoint; + + fn sub(self, _other: AffinePoint) -> ProjectivePoint { + unimplemented!(); + } +} + +impl Sub<&AffinePoint> for ProjectivePoint { + type Output = ProjectivePoint; + + fn sub(self, _other: &AffinePoint) -> ProjectivePoint { + unimplemented!(); + } +} + +impl SubAssign for ProjectivePoint { + fn sub_assign(&mut self, _rhs: AffinePoint) { + unimplemented!(); + } +} + +impl SubAssign<&AffinePoint> for ProjectivePoint { + fn sub_assign(&mut self, _rhs: &AffinePoint) { + unimplemented!(); + } +} + +impl Mul for ProjectivePoint { + type Output = ProjectivePoint; + + fn mul(self, _other: Scalar) -> ProjectivePoint { + unimplemented!(); + } +} + +impl Mul<&Scalar> for ProjectivePoint { + type Output = ProjectivePoint; + + fn mul(self, _other: &Scalar) -> ProjectivePoint { + unimplemented!(); + } +} + +impl MulAssign for ProjectivePoint { + fn mul_assign(&mut self, _rhs: Scalar) { + unimplemented!(); + } +} + +impl MulAssign<&Scalar> for ProjectivePoint { + fn mul_assign(&mut self, _rhs: &Scalar) { + unimplemented!(); + } +} + +impl Neg for ProjectivePoint { + type Output = ProjectivePoint; + + fn neg(self) -> ProjectivePoint { + unimplemented!(); + } +} diff --git a/ecdsa/src/hazmat.rs b/ecdsa/src/hazmat.rs index da9713f0..c481db0f 100644 --- a/ecdsa/src/hazmat.rs +++ b/ecdsa/src/hazmat.rs @@ -11,19 +11,32 @@ //! Failure to use them correctly can lead to catastrophic failures including //! FULL PRIVATE KEY RECOVERY! -use crate::{CheckSignatureBytes, Signature, SignatureSize}; +#[cfg(feature = "arithmetic")] +use crate::SignatureSize; +#[cfg(feature = "arithmetic")] use core::borrow::Borrow; -use elliptic_curve::{generic_array::ArrayLength, ops::Invert, weierstrass::Curve, Arithmetic}; +#[cfg(feature = "arithmetic")] +use elliptic_curve::{ops::Invert, Arithmetic}; +#[cfg(feature = "arithmetic")] use signature::Error; +#[cfg(feature = "digest")] +use crate::CheckSignatureBytes; #[cfg(feature = "digest")] use signature::{digest::Digest, PrehashSignature}; +#[cfg(any(feature = "arithmetic", feature = "digest"))] +use crate::Signature; +#[cfg(any(feature = "arithmetic", feature = "digest"))] +use elliptic_curve::{generic_array::ArrayLength, weierstrass::Curve}; + /// Try to sign the given prehashed message using ECDSA. /// /// This trait is intended to be implemented on a type with access /// to the secret scalar via `&self`, such as particular curve's `Scalar` type, /// or potentially a key handle to a hardware device. +#[cfg(feature = "arithmetic")] +#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] pub trait SignPrimitive where C: Curve + Arithmetic, @@ -48,6 +61,8 @@ where /// This trait is intended to be implemented on type which can access /// the affine point represeting the public key via `&self`, such as a /// particular curve's `AffinePoint` type. +#[cfg(feature = "arithmetic")] +#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] pub trait VerifyPrimitive where C: Curve + Arithmetic, diff --git a/ecdsa/src/lib.rs b/ecdsa/src/lib.rs index 25e5d43f..dd9b6b20 100644 --- a/ecdsa/src/lib.rs +++ b/ecdsa/src/lib.rs @@ -69,9 +69,12 @@ use core::{ fmt::{self, Debug}, ops::Add, }; -use elliptic_curve::{scalar::NonZeroScalar, Arithmetic, ElementBytes, FromBytes}; +use elliptic_curve::ElementBytes; use generic_array::{sequence::Concat, typenum::Unsigned, ArrayLength, GenericArray}; +#[cfg(feature = "arithmetic")] +use elliptic_curve::{scalar::NonZeroScalar, Arithmetic, FromBytes}; + /// Size of a fixed sized signature for the given elliptic curve. pub type SignatureSize = <::FieldSize as Add>::Output; @@ -136,37 +139,35 @@ where let (r, s) = self.bytes.split_at(C::FieldSize::to_usize()); asn1::Signature::from_scalar_bytes(r, s) } +} +#[cfg(feature = "arithmetic")] +#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] +impl Signature +where + C: Curve + Arithmetic, + SignatureSize: ArrayLength, +{ /// Get the `r` component of this signature - pub fn r(&self) -> NonZeroScalar - where - C: Arithmetic, - { + pub fn r(&self) -> NonZeroScalar { let r_bytes = ElementBytes::::from_slice(&self.bytes[..C::FieldSize::to_usize()]); NonZeroScalar::from_bytes(&r_bytes).unwrap() } /// Get the `s` component of this signature - pub fn s(&self) -> NonZeroScalar - where - C: Arithmetic, - { + pub fn s(&self) -> NonZeroScalar { let s_bytes = ElementBytes::::from_slice(&self.bytes[C::FieldSize::to_usize()..]); NonZeroScalar::from_bytes(&s_bytes).unwrap() } -} -impl Signature -where - C: Curve + Arithmetic, - C::Scalar: NormalizeLow, - SignatureSize: ArrayLength, -{ /// Normalize signature into "low S" form as described in /// [BIP 0062: Dealing with Malleability][1]. /// /// [1]: https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki - pub fn normalize_s(&mut self) -> Result { + pub fn normalize_s(&mut self) -> Result + where + C::Scalar: NormalizeLow, + { let s_bytes = GenericArray::from_mut_slice(&mut self.bytes[C::FieldSize::to_usize()..]); let s_option = C::Scalar::from_bytes(s_bytes); @@ -298,6 +299,8 @@ where } } +#[cfg(feature = "arithmetic")] +#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))] impl CheckSignatureBytes for C where C: Curve + Arithmetic,