├── .cargo └── audit.toml ├── .github ├── dependabot.yml └── workflows │ ├── bign256.yml │ ├── bp256.yml │ ├── bp384.yml │ ├── ed448-goldilocks.yml │ ├── k256.yml │ ├── p192.yml │ ├── p224.yml │ ├── p256.yml │ ├── p384.yml │ ├── p521.yml │ ├── primefield.yml │ ├── primeorder.yml │ ├── security-audit.yml │ ├── sm2.yml │ └── workspace.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── README.md ├── SECURITY.md ├── bign256 ├── .gitignore ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── benches │ ├── field.rs │ └── scalar.rs ├── src │ ├── arithmetic.rs │ ├── arithmetic │ │ ├── field.rs │ │ ├── field │ │ │ ├── bign256_32.rs │ │ │ └── bign256_64.rs │ │ ├── scalar.rs │ │ └── scalar │ │ │ ├── bign256_scalar_32.rs │ │ │ └── bign256_scalar_64.rs │ ├── ecdh.rs │ ├── ecdsa.rs │ ├── ecdsa │ │ ├── signing.rs │ │ └── verifying.rs │ ├── lib.rs │ ├── public_key.rs │ ├── secret_key.rs │ ├── test_vectors.rs │ └── test_vectors │ │ ├── field.rs │ │ └── group.rs └── tests │ ├── dsa.rs │ ├── ecdh.rs │ ├── examples │ ├── pkcs8-private.der │ ├── pkcs8-private.pem │ ├── pkcs8-public.der │ └── pkcs8-public.pem │ ├── pkcs8.rs │ ├── projective.rs │ └── scalar.rs ├── bp256 ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md └── src │ ├── arithmetic.rs │ ├── arithmetic │ ├── field.rs │ ├── field │ │ ├── bp256_32.rs │ │ └── bp256_64.rs │ ├── scalar.rs │ └── scalar │ │ ├── bp256_scalar_32.rs │ │ └── bp256_scalar_64.rs │ ├── lib.rs │ ├── r1.rs │ ├── r1 │ ├── arithmetic.rs │ └── ecdsa.rs │ ├── t1.rs │ └── t1 │ ├── arithmetic.rs │ └── ecdsa.rs ├── bp384 ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md └── src │ ├── arithmetic.rs │ ├── arithmetic │ ├── field.rs │ ├── field │ │ ├── bp384_32.rs │ │ └── bp384_64.rs │ ├── scalar.rs │ └── scalar │ │ ├── bp384_scalar_32.rs │ │ └── bp384_scalar_64.rs │ ├── lib.rs │ ├── r1.rs │ ├── r1 │ ├── arithmetic.rs │ └── ecdsa.rs │ ├── t1.rs │ └── t1 │ ├── arithmetic.rs │ └── ecdsa.rs ├── clippy.toml ├── codecov.yml ├── ed448-goldilocks ├── Cargo.toml ├── README.md ├── resources │ └── bear.png └── src │ ├── constants.rs │ ├── curve.rs │ ├── curve │ ├── edwards.rs │ ├── edwards │ │ ├── affine.rs │ │ └── extended.rs │ ├── montgomery.rs │ ├── scalar_mul.rs │ ├── scalar_mul │ │ ├── double_and_add.rs │ │ ├── double_base.rs │ │ ├── variable_base.rs │ │ ├── window.rs │ │ └── window │ │ │ └── wnaf.rs │ ├── twedwards.rs │ └── twedwards │ │ ├── affine.rs │ │ ├── extended.rs │ │ ├── extensible.rs │ │ └── projective.rs │ ├── decaf.rs │ ├── decaf │ ├── affine.rs │ ├── ops.rs │ └── points.rs │ ├── field.rs │ ├── field │ ├── element.rs │ └── scalar.rs │ ├── lib.rs │ ├── macros.rs │ ├── ristretto.rs │ ├── ristretto │ ├── constants.rs │ └── points.rs │ ├── sign.rs │ └── sign │ ├── context.rs │ ├── error.rs │ ├── expanded.rs │ ├── signature.rs │ ├── signing_key.rs │ └── verifying_key.rs ├── k256 ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── benches │ ├── ecdsa.rs │ ├── field.rs │ └── scalar.rs ├── proptest-regressions │ └── arithmetic │ │ └── scalar.txt └── src │ ├── arithmetic.rs │ ├── arithmetic │ ├── affine.rs │ ├── dev.rs │ ├── field.rs │ ├── field │ │ ├── field_10x26.rs │ │ ├── field_5x52.rs │ │ └── field_impl.rs │ ├── hash2curve.rs │ ├── mul.rs │ ├── projective.rs │ ├── scalar.rs │ └── scalar │ │ ├── wide32.rs │ │ └── wide64.rs │ ├── ecdh.rs │ ├── ecdsa.rs │ ├── lib.rs │ ├── schnorr.rs │ ├── schnorr │ ├── signing.rs │ └── verifying.rs │ ├── test_vectors.rs │ └── test_vectors │ ├── data │ ├── wycheproof-p1316.blb │ └── wycheproof.blb │ ├── ecdsa.rs │ ├── field.rs │ └── group.rs ├── p192 ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── src │ ├── arithmetic.rs │ ├── arithmetic │ │ ├── field.rs │ │ ├── field │ │ │ ├── p192_32.rs │ │ │ └── p192_64.rs │ │ ├── scalar.rs │ │ └── scalar │ │ │ ├── p192_scalar_32.rs │ │ │ └── p192_scalar_64.rs │ ├── ecdsa.rs │ ├── lib.rs │ ├── test_vectors.rs │ └── test_vectors │ │ ├── ecdsa.rs │ │ └── group.rs └── tests │ └── projective.rs ├── p224 ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── src │ ├── arithmetic.rs │ ├── arithmetic │ │ ├── field.rs │ │ ├── field │ │ │ ├── p224_32.rs │ │ │ └── p224_64.rs │ │ ├── scalar.rs │ │ └── scalar │ │ │ ├── p224_scalar_32.rs │ │ │ └── p224_scalar_64.rs │ ├── ecdh.rs │ ├── ecdsa.rs │ ├── lib.rs │ ├── test_vectors.rs │ └── test_vectors │ │ ├── data │ │ └── wycheproof.blb │ │ ├── ecdsa.rs │ │ └── group.rs └── tests │ └── projective.rs ├── p256 ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── benches │ ├── field.rs │ └── scalar.rs ├── src │ ├── arithmetic.rs │ ├── arithmetic │ │ ├── field.rs │ │ ├── field │ │ │ ├── field32.rs │ │ │ └── field64.rs │ │ ├── hash2curve.rs │ │ ├── scalar.rs │ │ └── scalar │ │ │ ├── scalar32.rs │ │ │ └── scalar64.rs │ ├── ecdh.rs │ ├── ecdsa.rs │ ├── lib.rs │ ├── test_vectors.rs │ └── test_vectors │ │ ├── data │ │ └── wycheproof.blb │ │ ├── ecdsa.rs │ │ ├── field.rs │ │ └── group.rs └── tests │ ├── affine.rs │ ├── ecdsa.rs │ ├── examples │ ├── pkcs8-private-key.der │ ├── pkcs8-private-key.pem │ ├── pkcs8-public-key.der │ └── pkcs8-public-key.pem │ ├── pkcs8.rs │ ├── projective.rs │ └── scalar.rs ├── p384 ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── benches │ ├── field.rs │ └── scalar.rs ├── src │ ├── arithmetic.rs │ ├── arithmetic │ │ ├── field.rs │ │ ├── field │ │ │ ├── p384_32.rs │ │ │ └── p384_64.rs │ │ ├── hash2curve.rs │ │ ├── scalar.rs │ │ └── scalar │ │ │ ├── p384_scalar_32.rs │ │ │ └── p384_scalar_64.rs │ ├── ecdh.rs │ ├── ecdsa.rs │ ├── lib.rs │ ├── test_vectors.rs │ └── test_vectors │ │ ├── data │ │ └── wycheproof.blb │ │ ├── ecdsa.rs │ │ └── group.rs └── tests │ ├── affine.rs │ └── projective.rs ├── p521 ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── benches │ ├── field.rs │ └── scalar.rs ├── src │ ├── arithmetic.rs │ ├── arithmetic │ │ ├── field.rs │ │ ├── field │ │ │ ├── loose.rs │ │ │ └── p521_64.rs │ │ ├── hash2curve.rs │ │ ├── scalar.rs │ │ ├── scalar │ │ │ └── p521_scalar_64.rs │ │ └── util.rs │ ├── ecdh.rs │ ├── ecdsa.rs │ ├── lib.rs │ ├── test_vectors.rs │ └── test_vectors │ │ ├── data │ │ └── wycheproof.blb │ │ ├── ecdsa.rs │ │ └── group.rs └── tests │ └── projective.rs ├── primefield ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md └── src │ ├── fiat.rs │ └── lib.rs ├── primeorder ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md └── src │ ├── affine.rs │ ├── dev.rs │ ├── lib.rs │ ├── point_arithmetic.rs │ └── projective.rs └── sm2 ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── src ├── arithmetic.rs ├── arithmetic │ ├── field.rs │ ├── field │ │ ├── sm2_32.rs │ │ └── sm2_64.rs │ ├── scalar.rs │ └── scalar │ │ ├── sm2_scalar_32.rs │ │ └── sm2_scalar_64.rs ├── distid.rs ├── dsa.rs ├── dsa │ ├── signing.rs │ └── verifying.rs ├── lib.rs ├── pke.rs └── pke │ ├── decrypting.rs │ └── encrypting.rs └── tests ├── dsa_extended.rs ├── examples ├── pkcs8-private-key.der ├── pkcs8-private-key.pem ├── pkcs8-public-key.der └── pkcs8-public-key.pem ├── pkcs8.rs ├── sm2dsa.rs └── sm2pke.rs /.cargo/audit.toml: -------------------------------------------------------------------------------- 1 | [advisories] 2 | ignore = [ 3 | "RUSTSEC-2021-0127", # serde_cbor is unmaintained 4 | ] 5 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: cargo 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | open-pull-requests-limit: 10 8 | - package-ecosystem: github-actions 9 | directory: "/" 10 | schedule: 11 | interval: weekly 12 | open-pull-requests-limit: 10 13 | -------------------------------------------------------------------------------- /.github/workflows/bp256.yml: -------------------------------------------------------------------------------- 1 | name: bp256 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - ".github/workflows/bp256.yml" 7 | - "bp256/**" 8 | - "Cargo.*" 9 | push: 10 | branches: master 11 | 12 | defaults: 13 | run: 14 | working-directory: bp256 15 | 16 | env: 17 | CARGO_INCREMENTAL: 0 18 | RUSTFLAGS: "-Dwarnings" 19 | RUSTDOCFLAGS: "-Dwarnings" 20 | 21 | jobs: 22 | build: 23 | runs-on: ubuntu-latest 24 | strategy: 25 | matrix: 26 | rust: 27 | - 1.85.0 # MSRV 28 | - stable 29 | target: 30 | - thumbv7em-none-eabi 31 | - wasm32-unknown-unknown 32 | steps: 33 | - uses: actions/checkout@v4 34 | - uses: dtolnay/rust-toolchain@master 35 | with: 36 | toolchain: ${{ matrix.rust }} 37 | targets: ${{ matrix.target }} 38 | - run: cargo build --target ${{ matrix.target }} --release --no-default-features 39 | - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features alloc 40 | - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features arithmetic 41 | - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features ecdsa 42 | - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features pem 43 | - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features pkcs8 44 | - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features serde 45 | - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features sha256 46 | - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features ecdsa,pem,pkcs8,serde,sha256 47 | 48 | test: 49 | runs-on: ubuntu-latest 50 | strategy: 51 | matrix: 52 | rust: 53 | - 1.85.0 # MSRV 54 | - stable 55 | steps: 56 | - uses: actions/checkout@v4 57 | - uses: dtolnay/rust-toolchain@master 58 | with: 59 | toolchain: ${{ matrix.rust }} 60 | - run: cargo check --all-features 61 | - run: cargo test --no-default-features 62 | - run: cargo test 63 | - run: cargo test --all-features 64 | 65 | doc: 66 | runs-on: ubuntu-latest 67 | steps: 68 | - uses: actions/checkout@v4 69 | - uses: RustCrypto/actions/cargo-cache@master 70 | - uses: dtolnay/rust-toolchain@master 71 | with: 72 | toolchain: stable 73 | - run: cargo doc --all-features 74 | -------------------------------------------------------------------------------- /.github/workflows/bp384.yml: -------------------------------------------------------------------------------- 1 | name: bp384 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - ".github/workflows/bp384.yml" 7 | - "bp384/**" 8 | - "Cargo.*" 9 | push: 10 | branches: master 11 | 12 | defaults: 13 | run: 14 | working-directory: bp384 15 | 16 | env: 17 | CARGO_INCREMENTAL: 0 18 | RUSTFLAGS: "-Dwarnings" 19 | RUSTDOCFLAGS: "-Dwarnings" 20 | 21 | jobs: 22 | build: 23 | runs-on: ubuntu-latest 24 | strategy: 25 | matrix: 26 | rust: 27 | - 1.85.0 # MSRV 28 | - stable 29 | target: 30 | - thumbv7em-none-eabi 31 | - wasm32-unknown-unknown 32 | steps: 33 | - uses: actions/checkout@v4 34 | - uses: dtolnay/rust-toolchain@master 35 | with: 36 | toolchain: ${{ matrix.rust }} 37 | targets: ${{ matrix.target }} 38 | - run: cargo build --target ${{ matrix.target }} --release --no-default-features 39 | - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features alloc 40 | - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features arithmetic 41 | - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features ecdsa 42 | - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features pem 43 | - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features pkcs8 44 | - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features serde 45 | - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features sha384 46 | - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features ecdsa,pem,pkcs8,serde,sha384 47 | 48 | test: 49 | runs-on: ubuntu-latest 50 | strategy: 51 | matrix: 52 | rust: 53 | - 1.85.0 # MSRV 54 | - stable 55 | steps: 56 | - uses: actions/checkout@v4 57 | - uses: dtolnay/rust-toolchain@master 58 | with: 59 | toolchain: ${{ matrix.rust }} 60 | - run: cargo check --all-features 61 | - run: cargo test --no-default-features 62 | - run: cargo test 63 | - run: cargo test --all-features 64 | 65 | doc: 66 | runs-on: ubuntu-latest 67 | steps: 68 | - uses: actions/checkout@v4 69 | - uses: RustCrypto/actions/cargo-cache@master 70 | - uses: dtolnay/rust-toolchain@master 71 | with: 72 | toolchain: stable 73 | - run: cargo doc --all-features 74 | -------------------------------------------------------------------------------- /.github/workflows/p192.yml: -------------------------------------------------------------------------------- 1 | name: p192 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - ".github/workflows/p192.yml" 7 | - "p192/**" 8 | - "Cargo.*" 9 | push: 10 | branches: master 11 | 12 | defaults: 13 | run: 14 | working-directory: p192 15 | 16 | env: 17 | CARGO_INCREMENTAL: 0 18 | RUSTFLAGS: "-Dwarnings" 19 | RUSTDOCFLAGS: "-Dwarnings" 20 | 21 | jobs: 22 | build: 23 | runs-on: ubuntu-latest 24 | strategy: 25 | matrix: 26 | rust: 27 | - 1.85.0 # MSRV 28 | - stable 29 | target: 30 | - thumbv7em-none-eabi 31 | - wasm32-unknown-unknown 32 | steps: 33 | - uses: actions/checkout@v4 34 | - uses: dtolnay/rust-toolchain@master 35 | with: 36 | toolchain: ${{ matrix.rust }} 37 | targets: ${{ matrix.target }} 38 | - run: cargo build --target ${{ matrix.target }} --release --no-default-features 39 | - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features alloc 40 | - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features arithmetic 41 | - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features pkcs8 42 | - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features serde 43 | - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features alloc,arithmetic,pkcs8,serde 44 | 45 | test: 46 | runs-on: ubuntu-latest 47 | strategy: 48 | matrix: 49 | include: 50 | # 32-bit Linux 51 | - target: i686-unknown-linux-gnu 52 | rust: 1.85.0 # MSRV 53 | deps: sudo apt update && sudo apt install gcc-multilib 54 | - target: i686-unknown-linux-gnu 55 | rust: stable 56 | deps: sudo apt update && sudo apt install gcc-multilib 57 | 58 | # 64-bit Linux 59 | - target: x86_64-unknown-linux-gnu 60 | rust: 1.85.0 # MSRV 61 | - target: x86_64-unknown-linux-gnu 62 | rust: stable 63 | 64 | steps: 65 | - uses: actions/checkout@v4 66 | - uses: dtolnay/rust-toolchain@master 67 | with: 68 | toolchain: ${{ matrix.rust }} 69 | targets: ${{ matrix.target }} 70 | - run: ${{ matrix.deps }} 71 | - run: cargo check --target ${{ matrix.target }} --all-features 72 | - run: cargo test --release --target ${{ matrix.target }} --no-default-features 73 | - run: cargo test --release --target ${{ matrix.target }} 74 | - run: cargo test --release --target ${{ matrix.target }} --all-features 75 | 76 | doc: 77 | runs-on: ubuntu-latest 78 | steps: 79 | - uses: actions/checkout@v4 80 | - uses: RustCrypto/actions/cargo-cache@master 81 | - uses: dtolnay/rust-toolchain@master 82 | with: 83 | toolchain: stable 84 | - run: cargo doc --all-features 85 | -------------------------------------------------------------------------------- /.github/workflows/p521.yml: -------------------------------------------------------------------------------- 1 | name: p521 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - ".github/workflows/p521.yml" 7 | - "p521/**" 8 | - "Cargo.*" 9 | push: 10 | branches: master 11 | 12 | defaults: 13 | run: 14 | working-directory: p521 15 | 16 | env: 17 | CARGO_INCREMENTAL: 0 18 | RUSTFLAGS: "-Dwarnings" 19 | RUSTDOCFLAGS: "-Dwarnings" 20 | 21 | jobs: 22 | build: 23 | runs-on: ubuntu-latest 24 | strategy: 25 | matrix: 26 | rust: 27 | - 1.85.0 # MSRV 28 | - stable 29 | target: 30 | - thumbv7em-none-eabi 31 | - wasm32-unknown-unknown 32 | steps: 33 | - uses: actions/checkout@v4 34 | - uses: dtolnay/rust-toolchain@master 35 | with: 36 | toolchain: ${{ matrix.rust }} 37 | targets: ${{ matrix.target }} 38 | - run: cargo build --target ${{ matrix.target }} --release --no-default-features 39 | - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features alloc 40 | 41 | benches: 42 | runs-on: ubuntu-latest 43 | strategy: 44 | matrix: 45 | rust: 46 | - stable 47 | steps: 48 | - uses: actions/checkout@v4 49 | - uses: dtolnay/rust-toolchain@master 50 | with: 51 | toolchain: ${{ matrix.rust }} 52 | - run: cargo build --all-features --benches 53 | 54 | test: 55 | runs-on: ubuntu-latest 56 | strategy: 57 | matrix: 58 | include: 59 | # 32-bit Linux 60 | - target: i686-unknown-linux-gnu 61 | rust: 1.85.0 # MSRV 62 | deps: sudo apt update && sudo apt install gcc-multilib 63 | - target: i686-unknown-linux-gnu 64 | rust: stable 65 | deps: sudo apt update && sudo apt install gcc-multilib 66 | 67 | # 64-bit Linux 68 | - target: x86_64-unknown-linux-gnu 69 | rust: 1.85.0 # MSRV 70 | - target: x86_64-unknown-linux-gnu 71 | rust: stable 72 | 73 | steps: 74 | - uses: actions/checkout@v4 75 | - uses: dtolnay/rust-toolchain@master 76 | with: 77 | toolchain: ${{ matrix.rust }} 78 | targets: ${{ matrix.target }} 79 | - run: ${{ matrix.deps }} 80 | - run: cargo check --target ${{ matrix.target }} --all-features 81 | - run: cargo test --release --target ${{ matrix.target }} --no-default-features 82 | - run: cargo test --release --target ${{ matrix.target }} 83 | - run: cargo test --release --target ${{ matrix.target }} --all-features 84 | 85 | doc: 86 | runs-on: ubuntu-latest 87 | steps: 88 | - uses: actions/checkout@v4 89 | - uses: RustCrypto/actions/cargo-cache@master 90 | - uses: dtolnay/rust-toolchain@master 91 | with: 92 | toolchain: stable 93 | - run: cargo doc --all-features 94 | -------------------------------------------------------------------------------- /.github/workflows/primefield.yml: -------------------------------------------------------------------------------- 1 | name: primefield 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - ".github/workflows/primefield.yml" 7 | - "primefield/**" 8 | - "Cargo.*" 9 | push: 10 | branches: master 11 | 12 | defaults: 13 | run: 14 | working-directory: primefield 15 | 16 | env: 17 | CARGO_INCREMENTAL: 0 18 | RUSTFLAGS: "-Dwarnings" 19 | RUSTDOCFLAGS: "-Dwarnings" 20 | 21 | jobs: 22 | build: 23 | runs-on: ubuntu-latest 24 | strategy: 25 | matrix: 26 | rust: 27 | - 1.85.0 # MSRV 28 | - stable 29 | target: 30 | - thumbv7em-none-eabi 31 | - wasm32-unknown-unknown 32 | steps: 33 | - uses: actions/checkout@v4 34 | - uses: dtolnay/rust-toolchain@master 35 | with: 36 | toolchain: ${{ matrix.rust }} 37 | targets: ${{ matrix.target }} 38 | - run: cargo build --target ${{ matrix.target }} --release 39 | 40 | test: 41 | runs-on: ubuntu-latest 42 | strategy: 43 | matrix: 44 | rust: 45 | - 1.85.0 # MSRV 46 | - stable 47 | steps: 48 | - uses: actions/checkout@v4 49 | - uses: dtolnay/rust-toolchain@master 50 | with: 51 | toolchain: ${{ matrix.rust }} 52 | - run: cargo test 53 | 54 | doc: 55 | runs-on: ubuntu-latest 56 | steps: 57 | - uses: actions/checkout@v4 58 | - uses: RustCrypto/actions/cargo-cache@master 59 | - uses: dtolnay/rust-toolchain@master 60 | with: 61 | toolchain: stable 62 | - run: cargo doc --all-features 63 | -------------------------------------------------------------------------------- /.github/workflows/primeorder.yml: -------------------------------------------------------------------------------- 1 | name: primeorder 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - ".github/workflows/primeorder.yml" 7 | - "primeorder/**" 8 | - "Cargo.*" 9 | push: 10 | branches: master 11 | 12 | defaults: 13 | run: 14 | working-directory: primeorder 15 | 16 | env: 17 | CARGO_INCREMENTAL: 0 18 | RUSTFLAGS: "-Dwarnings" 19 | RUSTDOCFLAGS: "-Dwarnings" 20 | 21 | jobs: 22 | build: 23 | runs-on: ubuntu-latest 24 | strategy: 25 | matrix: 26 | rust: 27 | - 1.85.0 # MSRV 28 | - stable 29 | target: 30 | - thumbv7em-none-eabi 31 | - wasm32-unknown-unknown 32 | steps: 33 | - uses: actions/checkout@v4 34 | - uses: dtolnay/rust-toolchain@master 35 | with: 36 | toolchain: ${{ matrix.rust }} 37 | targets: ${{ matrix.target }} 38 | - run: cargo build --target ${{ matrix.target }} --release --no-default-features 39 | - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features alloc 40 | 41 | test: 42 | runs-on: ubuntu-latest 43 | strategy: 44 | matrix: 45 | rust: 46 | - 1.85.0 # MSRV 47 | - stable 48 | steps: 49 | - uses: actions/checkout@v4 50 | - uses: dtolnay/rust-toolchain@master 51 | with: 52 | toolchain: ${{ matrix.rust }} 53 | - run: cargo check --all-features 54 | - run: cargo test --no-default-features 55 | - run: cargo test 56 | - run: cargo test --all-features 57 | 58 | doc: 59 | runs-on: ubuntu-latest 60 | steps: 61 | - uses: actions/checkout@v4 62 | - uses: RustCrypto/actions/cargo-cache@master 63 | - uses: dtolnay/rust-toolchain@master 64 | with: 65 | toolchain: stable 66 | - run: cargo doc --all-features 67 | -------------------------------------------------------------------------------- /.github/workflows/security-audit.yml: -------------------------------------------------------------------------------- 1 | name: Security Audit 2 | on: 3 | pull_request: 4 | paths: 5 | - .github/workflows/security-audit.yml 6 | - Cargo.lock 7 | push: 8 | branches: master 9 | paths: Cargo.lock 10 | schedule: 11 | - cron: "0 0 * * *" 12 | 13 | jobs: 14 | security_audit: 15 | name: Security Audit 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/checkout@v4 19 | - uses: dtolnay/rust-toolchain@master 20 | with: 21 | toolchain: stable 22 | - uses: actions/cache@v4 23 | with: 24 | path: ~/.cargo/bin 25 | key: ${{ runner.os }}-cargo-audit-v0.20.1 26 | - uses: rustsec/audit-check@v2 27 | with: 28 | token: ${{ secrets.GITHUB_TOKEN }} 29 | -------------------------------------------------------------------------------- /.github/workflows/sm2.yml: -------------------------------------------------------------------------------- 1 | name: sm2 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - ".github/workflows/sm2.yml" 7 | - "sm2/**" 8 | - "Cargo.*" 9 | push: 10 | branches: master 11 | 12 | defaults: 13 | run: 14 | working-directory: sm2 15 | 16 | env: 17 | CARGO_INCREMENTAL: 0 18 | RUSTFLAGS: "-Dwarnings" 19 | RUSTDOCFLAGS: "-Dwarnings" 20 | 21 | jobs: 22 | build: 23 | runs-on: ubuntu-latest 24 | strategy: 25 | matrix: 26 | rust: 27 | - 1.85.0 # MSRV 28 | - stable 29 | target: 30 | - thumbv7em-none-eabi 31 | - wasm32-unknown-unknown 32 | steps: 33 | - uses: actions/checkout@v4 34 | - uses: dtolnay/rust-toolchain@master 35 | with: 36 | toolchain: ${{ matrix.rust }} 37 | targets: ${{ matrix.target }} 38 | - run: cargo build --target ${{ matrix.target }} --release --no-default-features 39 | - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features alloc 40 | - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features arithmetic 41 | - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features pkcs8 42 | - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features alloc,arithmetic,pkcs8 43 | 44 | test: 45 | runs-on: ubuntu-latest 46 | strategy: 47 | matrix: 48 | include: 49 | # 32-bit Linux 50 | - target: i686-unknown-linux-gnu 51 | rust: 1.85.0 # MSRV 52 | deps: sudo apt update && sudo apt install gcc-multilib 53 | - target: i686-unknown-linux-gnu 54 | rust: stable 55 | deps: sudo apt update && sudo apt install gcc-multilib 56 | 57 | # 64-bit Linux 58 | - target: x86_64-unknown-linux-gnu 59 | rust: 1.85.0 # MSRV 60 | - target: x86_64-unknown-linux-gnu 61 | rust: stable 62 | 63 | steps: 64 | - uses: actions/checkout@v4 65 | - uses: dtolnay/rust-toolchain@master 66 | with: 67 | toolchain: ${{ matrix.rust }} 68 | targets: ${{ matrix.target }} 69 | - run: ${{ matrix.deps }} 70 | - run: cargo check --target ${{ matrix.target }} --all-features 71 | - run: cargo test --release --target ${{ matrix.target }} --no-default-features 72 | - run: cargo test --release --target ${{ matrix.target }} 73 | - run: cargo test --release --target ${{ matrix.target }} --all-features 74 | 75 | doc: 76 | runs-on: ubuntu-latest 77 | steps: 78 | - uses: actions/checkout@v4 79 | - uses: RustCrypto/actions/cargo-cache@master 80 | - uses: dtolnay/rust-toolchain@master 81 | with: 82 | toolchain: stable 83 | - run: cargo doc --all-features 84 | -------------------------------------------------------------------------------- /.github/workflows/workspace.yml: -------------------------------------------------------------------------------- 1 | name: Workspace 2 | 3 | on: 4 | pull_request: 5 | paths-ignore: 6 | - README.md 7 | push: 8 | branches: master 9 | paths-ignore: 10 | - README.md 11 | 12 | env: 13 | CARGO_INCREMENTAL: 0 14 | RUSTFLAGS: "-Dwarnings" 15 | 16 | jobs: 17 | clippy: 18 | runs-on: ubuntu-latest 19 | steps: 20 | - uses: actions/checkout@v4 21 | - uses: dtolnay/rust-toolchain@master 22 | with: 23 | toolchain: 1.85.0 24 | components: clippy 25 | - run: cargo clippy --all --all-features -- -D warnings 26 | 27 | rustfmt: 28 | runs-on: ubuntu-latest 29 | steps: 30 | - uses: actions/checkout@v4 31 | - uses: dtolnay/rust-toolchain@master 32 | with: 33 | toolchain: stable 34 | components: rustfmt 35 | - run: cargo fmt --all -- --check 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | *.sw* 3 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | members = [ 4 | "bign256", 5 | "bp256", 6 | "bp384", 7 | "ed448-goldilocks", 8 | "k256", 9 | "p192", 10 | "p224", 11 | "p256", 12 | "p384", 13 | "p521", 14 | "primefield", 15 | "primeorder", 16 | "sm2" 17 | ] 18 | 19 | [profile.dev] 20 | opt-level = 2 21 | 22 | [patch.crates-io] 23 | primefield = { path = "primefield" } 24 | primeorder = { path = "primeorder" } 25 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Security updates are applied only to the most recent release. 6 | 7 | ## Reporting a Vulnerability 8 | 9 | If you have discovered a security vulnerability in this project, please report 10 | it privately. **Do not disclose it as a public issue.** This gives us time to 11 | work with you to fix the issue before public exposure, reducing the chance that 12 | the exploit will be used before a patch is released. 13 | 14 | Please disclose it at [security advisory](https://github.com/RustCrypto/elliptic-curves/security/advisories/new). 15 | 16 | This project is maintained by a team of volunteers on a reasonable-effort basis. 17 | As such, please give us at least 90 days to work on a fix before public exposure. 18 | -------------------------------------------------------------------------------- /bign256/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /Cargo.lock 3 | -------------------------------------------------------------------------------- /bign256/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## 0.14.0 (UNRELEASED) 8 | ### Added 9 | - ECDH and PKCS8 support ([#1046]) 10 | - `bits`, `serde`, and `test-vectors` features ([#1062]) 11 | 12 | ## Changed 13 | - Update to `digest` v0.11 ([#1011]) 14 | - Update to `pkcs8` v0.11 ([#1011]) 15 | - Update to `sec1` v0.8 ([#1011]) 16 | - Update to `rand_core` v0.9 ([#1125]) 17 | - Update to `hybrid-array` v0.3 ([#1125]) 18 | - Edition changed to 2024 and MSRV bumped to 1.85 ([#1125]) 19 | - Relax MSRV policy and allow MSRV bumps in patch releases 20 | 21 | [#1011]: https://github.com/RustCrypto/elliptic-curves/pull/1011 22 | [#1046]: https://github.com/RustCrypto/elliptic-curves/pull/1046 23 | [#1062]: https://github.com/RustCrypto/elliptic-curves/pull/1062 24 | [#1125]: https://github.com/RustCrypto/elliptic-curves/pull/1125 25 | 26 | ## 0.13.1 (2024-01-05) 27 | ### Added 28 | - Digital signature algorithm ([#935]) 29 | 30 | [#935]: https://github.com/RustCrypto/elliptic-curves/pull/935 31 | 32 | ## 0.13.0 (2023-06-27) 33 | - Initial release 34 | -------------------------------------------------------------------------------- /bign256/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bign256" 3 | version = "0.14.0-pre" 4 | description = """ 5 | Pure Rust implementation of the Bign P-256 (a.k.a. bign-curve256v1) 6 | elliptic curve as defined in STB 34.101.45-2013, with 7 | general purpose curve arithmetic 8 | """ 9 | authors = ["RustCrypto Developers"] 10 | license = "Apache-2.0 OR MIT" 11 | documentation = "https://docs.rs/bign256" 12 | homepage = "https://github.com/RustCrypto/elliptic-curves/tree/master/bign256" 13 | repository = "https://github.com/RustCrypto/elliptic-curves" 14 | readme = "README.md" 15 | categories = ["cryptography", "no-std"] 16 | keywords = ["crypto", "ecc", "stb", "bign-curve256v1", "bignp256"] 17 | edition = "2024" 18 | rust-version = "1.85" 19 | 20 | [dependencies] 21 | elliptic-curve = { version = "0.14.0-rc.5", features = ["sec1"] } 22 | 23 | # optional dependencies 24 | belt-hash = { version = "0.2.0-rc.0", optional = true, default-features = false } 25 | der = { version = "0.8.0-rc.0" } 26 | digest = { version = "0.11.0-rc.0", optional = true } 27 | hex-literal = { version = "1", optional = true } 28 | hkdf = { version = "0.13.0-rc.0", optional = true } 29 | hmac = { version = "0.13.0-rc.0", optional = true } 30 | rand_core = "0.9" 31 | rfc6979 = { version = "0.5.0-rc.0", optional = true } 32 | pkcs8 = { version = "0.11.0-rc.3", optional = true } 33 | primefield = { version = "=0.14.0-pre.2", optional = true } 34 | primeorder = { version = "=0.14.0-pre.4", optional = true } 35 | sec1 = { version = "0.8.0-rc.1", optional = true } 36 | signature = { version = "3.0.0-pre.1", optional = true } 37 | 38 | [dev-dependencies] 39 | criterion = "0.6" 40 | hex-literal = "1" 41 | primeorder = { version = "=0.14.0-pre.4", features = ["dev"] } 42 | proptest = "1" 43 | rand_core = { version = "0.9", features = ["os_rng"] } 44 | hex = { version = "0.4" } 45 | 46 | [features] 47 | default = ["arithmetic", "pkcs8", "std", "ecdsa", "pem", "ecdh"] 48 | alloc = ["elliptic-curve/alloc", "primeorder?/alloc"] 49 | std = ["alloc", "elliptic-curve/std"] 50 | 51 | arithmetic = ["dep:primefield", "dep:primeorder", "elliptic-curve/arithmetic"] 52 | bits = ["arithmetic", "elliptic-curve/bits"] 53 | ecdsa = ["arithmetic", "dep:rfc6979", "dep:signature", "dep:belt-hash"] 54 | pem = ["pkcs8", "sec1/pem"] 55 | pkcs8 = ["dep:pkcs8"] 56 | ecdh = ["arithmetic", "elliptic-curve/ecdh", "dep:digest", "dep:hkdf", "dep:hmac", "dep:belt-hash", "alloc"] 57 | serde = ["elliptic-curve/serde", "primeorder?/serde"] 58 | test-vectors = ["dep:hex-literal"] 59 | 60 | [[bench]] 61 | name = "field" 62 | harness = false 63 | 64 | [[bench]] 65 | name = "scalar" 66 | harness = false 67 | -------------------------------------------------------------------------------- /bign256/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2023 RustCrypto Developers 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /bign256/README.md: -------------------------------------------------------------------------------- 1 | # [RustCrypto]: BIGN P-256 (bign-curve256v1) elliptic curve 2 | 3 | [![crate][crate-image]][crate-link] 4 | [![Docs][docs-image]][docs-link] 5 | [![Build Status][build-image]][build-link] 6 | ![Apache2/MIT licensed][license-image] 7 | ![Rust Version][rustc-image] 8 | [![Project Chat][chat-image]][chat-link] 9 | 10 | Pure Rust implementation of the BIGN P-256 (a.k.a. bign-curve256v1) elliptic curve 11 | with support for ECDSA signing/verification, and general purpose curve 12 | arithmetic support implemented in terms of traits from the [`elliptic-curve`] 13 | crate. 14 | 15 | [Documentation][docs-link] 16 | 17 | ## ⚠️ Security Warning 18 | 19 | The elliptic curve arithmetic contained in this crate has never been 20 | independently audited! 21 | 22 | This crate has been designed with the goal of ensuring that secret-dependent 23 | operations are performed in constant time (using the `subtle` crate and 24 | constant-time formulas). However, it has not been thoroughly assessed to ensure 25 | that generated assembly is constant time on common CPU architectures. 26 | 27 | USE AT YOUR OWN RISK! 28 | 29 | ## Supported Algorithms 30 | 31 | ## About BIGN P-256 32 | 33 | BIGN P-256 is a Weierstrass curve specified in [STB 34.101.45-2013]. 34 | Also known as bign-curve256v1. 35 | 36 | ## License 37 | 38 | All crates licensed under either of 39 | 40 | * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) 41 | * [MIT license](http://opensource.org/licenses/MIT) 42 | 43 | at your option. 44 | 45 | ### Contribution 46 | 47 | Unless you explicitly state otherwise, any contribution intentionally submitted 48 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall be 49 | dual licensed as above, without any additional terms or conditions. 50 | 51 | [//]: # (badges) 52 | 53 | [crate-image]: https://img.shields.io/crates/v/bign256?logo=rust 54 | [crate-link]: https://crates.io/crates/bign256 55 | [docs-image]: https://docs.rs/bign256/badge.svg 56 | [docs-link]: https://docs.rs/bign256/ 57 | [build-image]: https://github.com/RustCrypto/elliptic-curves/actions/workflows/bign256.yml/badge.svg 58 | [build-link]: https://github.com/RustCrypto/elliptic-curves/actions/workflows/bign256.yml 59 | [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg 60 | [rustc-image]: https://img.shields.io/badge/rustc-1.85+-blue.svg 61 | [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg 62 | [chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/260040-elliptic-curves 63 | 64 | [//]: # (links) 65 | 66 | [RustCrypto]: https://github.com/rustcrypto/ 67 | [`elliptic-curve`]: https://github.com/RustCrypto/traits/tree/master/elliptic-curve 68 | [ECDH]: https://en.wikipedia.org/wiki/Elliptic-curve_Diffie-Hellman 69 | [ECDSA]: https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm 70 | [STB 34.101.45-2013]: https://apmi.bsu.by/assets/files/std/bign-spec294.pdf 71 | -------------------------------------------------------------------------------- /bign256/benches/field.rs: -------------------------------------------------------------------------------- 1 | //! bign-curve256v1 field element benchmarks 2 | 3 | use bign256::arithmetic::FieldElement; 4 | use criterion::{ 5 | BenchmarkGroup, Criterion, criterion_group, criterion_main, measurement::Measurement, 6 | }; 7 | use hex_literal::hex; 8 | 9 | fn test_field_element_x() -> FieldElement { 10 | FieldElement::from_bytes( 11 | &hex!("1ccbe91c075fc7f4f033bfa248db8fccd3565de94bbfb12f3c59ff46c271bf83").into(), 12 | ) 13 | .unwrap() 14 | } 15 | 16 | fn test_field_element_y() -> FieldElement { 17 | FieldElement::from_bytes( 18 | &hex!("ce4014c68811f9a21a1fdb2c0e6113e06db7ca93b7404e78dc7ccd5ca89a4ca9").into(), 19 | ) 20 | .unwrap() 21 | } 22 | 23 | fn bench_field_element_mul(group: &mut BenchmarkGroup) { 24 | let x = test_field_element_x(); 25 | let y = test_field_element_y(); 26 | group.bench_function("mul", |b| b.iter(|| x * y)); 27 | } 28 | 29 | fn bench_field_element_square(group: &mut BenchmarkGroup) { 30 | let x = test_field_element_x(); 31 | group.bench_function("square", |b| b.iter(|| x.square())); 32 | } 33 | 34 | fn bench_field_element_sqrt(group: &mut BenchmarkGroup) { 35 | let x = test_field_element_x(); 36 | group.bench_function("sqrt", |b| b.iter(|| x.sqrt())); 37 | } 38 | 39 | fn bench_field_element_invert(group: &mut BenchmarkGroup) { 40 | let x = test_field_element_x(); 41 | group.bench_function("invert", |b| b.iter(|| x.invert())); 42 | } 43 | 44 | fn bench_field_element(c: &mut Criterion) { 45 | let mut group = c.benchmark_group("field element operations"); 46 | bench_field_element_mul(&mut group); 47 | bench_field_element_square(&mut group); 48 | bench_field_element_invert(&mut group); 49 | bench_field_element_sqrt(&mut group); 50 | group.finish(); 51 | } 52 | 53 | criterion_group!(benches, bench_field_element); 54 | criterion_main!(benches); 55 | -------------------------------------------------------------------------------- /bign256/benches/scalar.rs: -------------------------------------------------------------------------------- 1 | //! bign-curve256v1 scalar arithmetic benchmarks 2 | 3 | use bign256::{ProjectivePoint, Scalar, elliptic_curve::group::ff::PrimeField}; 4 | use criterion::{ 5 | BenchmarkGroup, Criterion, criterion_group, criterion_main, measurement::Measurement, 6 | }; 7 | use hex_literal::hex; 8 | 9 | fn test_scalar_x() -> Scalar { 10 | Scalar::from_repr( 11 | hex!("519b423d715f8b581f4fa8ee59f4771a5b44c8130b4e3eacca54a56dda72b464").into(), 12 | ) 13 | .unwrap() 14 | } 15 | 16 | fn test_scalar_y() -> Scalar { 17 | Scalar::from_repr( 18 | hex!("0f56db78ca460b055c500064824bed999a25aaf48ebb519ac201537b85479813").into(), 19 | ) 20 | .unwrap() 21 | } 22 | 23 | fn bench_point_mul(group: &mut BenchmarkGroup) { 24 | let p = ProjectivePoint::GENERATOR; 25 | let m = test_scalar_x(); 26 | let s = Scalar::from_repr(m.into()).unwrap(); 27 | group.bench_function("point-scalar mul", |b| b.iter(|| p * s)); 28 | } 29 | 30 | fn bench_scalar_sub(group: &mut BenchmarkGroup) { 31 | let x = test_scalar_x(); 32 | let y = test_scalar_y(); 33 | group.bench_function("sub", |b| b.iter(|| x - y)); 34 | } 35 | 36 | fn bench_scalar_add(group: &mut BenchmarkGroup) { 37 | let x = test_scalar_x(); 38 | let y = test_scalar_y(); 39 | group.bench_function("add", |b| b.iter(|| x + y)); 40 | } 41 | 42 | fn bench_scalar_mul(group: &mut BenchmarkGroup) { 43 | let x = test_scalar_x(); 44 | let y = test_scalar_y(); 45 | group.bench_function("mul", |b| b.iter(|| x * y)); 46 | } 47 | 48 | fn bench_scalar_negate(group: &mut BenchmarkGroup) { 49 | let x = test_scalar_x(); 50 | group.bench_function("negate", |b| b.iter(|| -x)); 51 | } 52 | 53 | fn bench_scalar_invert(group: &mut BenchmarkGroup) { 54 | let x = test_scalar_x(); 55 | group.bench_function("invert", |b| b.iter(|| x.invert())); 56 | } 57 | 58 | fn bench_point(c: &mut Criterion) { 59 | let mut group = c.benchmark_group("point operations"); 60 | bench_point_mul(&mut group); 61 | group.finish(); 62 | } 63 | 64 | fn bench_scalar(c: &mut Criterion) { 65 | let mut group = c.benchmark_group("scalar operations"); 66 | bench_scalar_sub(&mut group); 67 | bench_scalar_add(&mut group); 68 | bench_scalar_mul(&mut group); 69 | bench_scalar_negate(&mut group); 70 | bench_scalar_invert(&mut group); 71 | group.finish(); 72 | } 73 | 74 | criterion_group!(benches, bench_point, bench_scalar); 75 | criterion_main!(benches); 76 | -------------------------------------------------------------------------------- /bign256/src/arithmetic.rs: -------------------------------------------------------------------------------- 1 | //! Pure Rust implementation of group operations on bign-curve256v1. 2 | //! 3 | //! Curve parameters can be found in STB 34.101.45-2013 4 | //! 5 | //! 6 | //! See table B.1: l = 128. 7 | 8 | pub(crate) mod field; 9 | pub(crate) mod scalar; 10 | 11 | pub use self::scalar::Scalar; 12 | 13 | pub use self::field::FieldElement; 14 | use crate::BignP256; 15 | pub use elliptic_curve::{CurveArithmetic, PrimeCurveArithmetic}; 16 | pub use primeorder::{PrimeCurveParams, point_arithmetic}; 17 | 18 | /// Elliptic curve point in affine coordinates. 19 | pub type AffinePoint = primeorder::AffinePoint; 20 | 21 | /// Elliptic curve point in projective coordinates. 22 | pub type ProjectivePoint = primeorder::ProjectivePoint; 23 | 24 | impl CurveArithmetic for BignP256 { 25 | type AffinePoint = AffinePoint; 26 | type ProjectivePoint = ProjectivePoint; 27 | type Scalar = Scalar; 28 | } 29 | 30 | impl PrimeCurveArithmetic for BignP256 { 31 | type CurveGroup = ProjectivePoint; 32 | } 33 | 34 | impl PrimeCurveParams for BignP256 { 35 | type FieldElement = FieldElement; 36 | type PointArithmetic = point_arithmetic::EquationAIsGeneric; 37 | const EQUATION_A: Self::FieldElement = 38 | FieldElement::from_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF40"); 39 | const EQUATION_B: Self::FieldElement = 40 | FieldElement::from_hex("77CE6C1515F3A8EDD2C13AABE4D8FBBE4CF55069978B9253B22E7D6BD69C03F1"); 41 | const GENERATOR: (Self::FieldElement, Self::FieldElement) = ( 42 | FieldElement::ZERO, 43 | FieldElement::from_hex("6BF7FC3CFB16D69F5CE4C9A351D6835D78913966C408F6521E29CF1804516A93"), 44 | ); 45 | } 46 | -------------------------------------------------------------------------------- /bign256/src/test_vectors.rs: -------------------------------------------------------------------------------- 1 | //! secp256r1 test vectors. 2 | 3 | #[cfg(test)] 4 | pub mod field; 5 | pub mod group; 6 | -------------------------------------------------------------------------------- /bign256/tests/dsa.rs: -------------------------------------------------------------------------------- 1 | //! bign256 DSA Tests 2 | 3 | #![cfg(feature = "ecdsa")] 4 | 5 | use elliptic_curve::ops::Reduce; 6 | use hex_literal::hex; 7 | use proptest::prelude::*; 8 | 9 | use bign256::{ 10 | NonZeroScalar, Scalar, U256, 11 | ecdsa::{ 12 | Signature, SigningKey, VerifyingKey, 13 | signature::{Signer, Verifier}, 14 | }, 15 | }; 16 | 17 | const PUBLIC_KEY: [u8; 64] = hex!( 18 | "BD1A5650 179D79E0 3FCEE49D 4C2BD5DD F54CE46D 0CF11E4F F87BF7A8 90857FD0" 19 | "7AC6A603 61E8C817 3491686D 461B2826 190C2EDA 5909054A 9AB84D2A B9D99A90" 20 | ); 21 | 22 | const MSG: &[u8] = b"testing"; 23 | const SIG: [u8; 48] = hex!( 24 | "63F59C523FF1780851143114FFBC5C13" 25 | "9BE81FF88F9D7F7FE209A6914198044C2A41D37B8439AAB42983FDB04AC2C326" 26 | ); 27 | 28 | #[test] 29 | fn verify_test_vector() { 30 | let vk = VerifyingKey::from_bytes(&PUBLIC_KEY).unwrap(); 31 | let sig = Signature::try_from(&SIG).unwrap(); 32 | assert!(vk.verify(MSG, &sig).is_ok()); 33 | } 34 | 35 | prop_compose! { 36 | fn signing_key()(bytes in any::<[u8; 32]>()) -> SigningKey { 37 | loop { 38 | let scalar = >::reduce_bytes(&bytes.into()); 39 | if let Some(scalar) = Option::from(NonZeroScalar::new(scalar)) { 40 | return SigningKey::from_nonzero_scalar(scalar).unwrap(); 41 | } 42 | } 43 | } 44 | } 45 | 46 | proptest! { 47 | #[test] 48 | fn sign_and_verify(sk in signing_key()) { 49 | let signature = sk.sign(MSG); 50 | prop_assert!(sk.verifying_key().verify(MSG, &signature).is_ok()); 51 | } 52 | 53 | #[test] 54 | fn reject_invalid_signature(sk in signing_key(), byte in 0usize..32, bit in 0usize..8) { 55 | let mut signature_bytes = sk.sign(MSG).to_bytes(); 56 | 57 | // tweak signature to make it invalid 58 | signature_bytes[byte] ^= 1 << bit; 59 | 60 | let signature = Signature::from_bytes(&signature_bytes).unwrap(); 61 | prop_assert!(sk.verifying_key().verify(MSG, &signature).is_err()); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /bign256/tests/ecdh.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "ecdh")] 2 | #[test] 3 | fn ecdh() { 4 | use bign256::{EncodedPoint, PublicKey, ecdh::EphemeralSecret}; 5 | use rand_core::{OsRng, TryRngCore}; // requires 'os_rng' feature 6 | 7 | // Alice 8 | let alice_secret = EphemeralSecret::random(&mut OsRng.unwrap_mut()); 9 | let alice_pk_bytes = EncodedPoint::from(alice_secret.public_key()); 10 | 11 | // Bob 12 | let bob_secret = EphemeralSecret::random(&mut OsRng.unwrap_mut()); 13 | let bob_pk_bytes = EncodedPoint::from(bob_secret.public_key()); 14 | 15 | // Alice decodes Bob's serialized public key and computes a shared secret from it 16 | let bob_public = 17 | PublicKey::from_encoded_point(bob_pk_bytes).expect("bob's public key is invalid!"); // In real usage, don't panic, handle this! 18 | 19 | let alice_shared = alice_secret.diffie_hellman(&bob_public); 20 | 21 | // Bob decodes Alice's serialized public key and computes the same shared secret 22 | let alice_public = 23 | PublicKey::from_encoded_point(alice_pk_bytes).expect("alice's public key is invalid!"); // In real usage, don't panic, handle this! 24 | 25 | let bob_shared = bob_secret.diffie_hellman(&alice_public); 26 | 27 | // Both participants arrive on the same shared secret 28 | assert_eq!( 29 | alice_shared.raw_secret_bytes(), 30 | bob_shared.raw_secret_bytes() 31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /bign256/tests/examples/pkcs8-private.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RustCrypto/elliptic-curves/d317ce8100dc09416901d50b223ba45f39549568/bign256/tests/examples/pkcs8-private.der -------------------------------------------------------------------------------- /bign256/tests/examples/pkcs8-private.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MD8CAQAwGAYKKnAAAgAiZS0CAQYKKnAAAgAiZS0DAQQgH2a1uEtzOWdFM/AynHTy 3 | GDQoH+0HMkKeDHkjX8Jz4mk= 4 | -----END PRIVATE KEY----- 5 | -------------------------------------------------------------------------------- /bign256/tests/examples/pkcs8-public.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RustCrypto/elliptic-curves/d317ce8100dc09416901d50b223ba45f39549568/bign256/tests/examples/pkcs8-public.der -------------------------------------------------------------------------------- /bign256/tests/examples/pkcs8-public.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MF0wGAYKKnAAAgAiZS0CAQYKKnAAAgAiZS0DAQNBALLYmXRs6y04kBzvQkY56jD9 3 | onIL58G6PwS8MV3yQSupOA6o7OD3p7p+qWUtusU7gnvSwvtZhIaY3i6mdZYF65Y= 4 | -----END PUBLIC KEY----- 5 | -------------------------------------------------------------------------------- /bign256/tests/projective.rs: -------------------------------------------------------------------------------- 1 | //! Projective arithmetic tests. 2 | 3 | #![cfg(all(feature = "arithmetic", feature = "test-vectors"))] 4 | 5 | use bign256::{ 6 | AffinePoint, ProjectivePoint, Scalar, 7 | test_vectors::group::{ADD_TEST_VECTORS, MUL_TEST_VECTORS}, 8 | }; 9 | use elliptic_curve::{ 10 | group::{GroupEncoding, ff::PrimeField}, 11 | sec1::{self, ToEncodedPoint}, 12 | }; 13 | use primeorder::{Double, test_projective_arithmetic}; 14 | 15 | test_projective_arithmetic!( 16 | AffinePoint, 17 | ProjectivePoint, 18 | Scalar, 19 | ADD_TEST_VECTORS, 20 | MUL_TEST_VECTORS 21 | ); 22 | 23 | #[test] 24 | fn projective_identity_to_bytes() { 25 | // This is technically an invalid SEC1 encoding, but is preferable to panicking. 26 | assert_eq!([0; 33], ProjectivePoint::IDENTITY.to_bytes().as_slice()); 27 | } 28 | -------------------------------------------------------------------------------- /bign256/tests/scalar.rs: -------------------------------------------------------------------------------- 1 | //! Scalar arithmetic tests. 2 | 3 | #![cfg(feature = "arithmetic")] 4 | 5 | use bign256::{Scalar, U256}; 6 | use elliptic_curve::ops::{Invert, Reduce}; 7 | use proptest::prelude::*; 8 | 9 | prop_compose! { 10 | fn scalar()(bytes in any::<[u8; 32]>()) -> Scalar { 11 | >::reduce_bytes(&bytes.into()) 12 | } 13 | } 14 | 15 | proptest! { 16 | #[test] 17 | fn invert_and_invert_vartime_are_equivalent(w in scalar()) { 18 | let inv: Option = w.invert().into(); 19 | let inv_vartime: Option = w.invert_vartime().into(); 20 | prop_assert_eq!(inv, inv_vartime); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /bp256/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bp256" 3 | version = "0.7.0-pre" 4 | description = "Brainpool P-256 (brainpoolP256r1 and brainpoolP256t1) elliptic curves" 5 | authors = ["RustCrypto Developers"] 6 | license = "Apache-2.0 OR MIT" 7 | documentation = "https://docs.rs/bp256" 8 | homepage = "https://github.com/RustCrypto/elliptic-curves/tree/master/bp256" 9 | repository = "https://github.com/RustCrypto/elliptic-curves" 10 | readme = "README.md" 11 | categories = ["cryptography", "no-std"] 12 | keywords = ["brainpool", "crypto", "ecc"] 13 | edition = "2024" 14 | rust-version = "1.85" 15 | 16 | [dependencies] 17 | elliptic-curve = { version = "0.14.0-rc.5", default-features = false, features = ["sec1"] } 18 | 19 | # optional dependencies 20 | ecdsa = { version = "0.17.0-rc.0", optional = true, default-features = false, features = ["der"] } 21 | primefield = { version = "=0.14.0-pre.2", optional = true } 22 | primeorder = { version = "=0.14.0-pre.4", optional = true } 23 | sha2 = { version = "0.11.0-rc.0", optional = true, default-features = false } 24 | 25 | [features] 26 | default = ["pkcs8", "std"] 27 | alloc = ["ecdsa?/alloc", "elliptic-curve/alloc", "primeorder?/alloc"] 28 | std = ["alloc", "ecdsa?/std", "elliptic-curve/std"] 29 | 30 | pem = ["elliptic-curve/pem", "pkcs8"] 31 | pkcs8 = ["ecdsa/pkcs8", "elliptic-curve/pkcs8"] 32 | serde = ["ecdsa/serde", "elliptic-curve/serde"] 33 | sha256 = ["ecdsa/digest", "ecdsa/hazmat", "sha2"] 34 | arithmetic = ["dep:primefield", "dep:primeorder"] 35 | 36 | [package.metadata.docs.rs] 37 | all-features = true 38 | rustdoc-args = ["--cfg", "docsrs"] 39 | -------------------------------------------------------------------------------- /bp256/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2021-2023 RustCrypto Developers 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /bp256/README.md: -------------------------------------------------------------------------------- 1 | # [RustCrypto]: Brainpool P-256 elliptic curves 2 | 3 | [![crate][crate-image]][crate-link] 4 | [![Docs][docs-image]][docs-link] 5 | [![Build Status][build-image]][build-link] 6 | ![Apache2/MIT licensed][license-image] 7 | ![Rust Version][rustc-image] 8 | [![Project Chat][chat-image]][chat-link] 9 | 10 | Brainpool P-256 (brainpoolP256r1 and brainpoolP256t1) elliptic curve types 11 | implemented in terms of traits from the [`elliptic-curve`] crate. 12 | 13 | [Documentation][docs-link] 14 | 15 | ## License 16 | 17 | All crates licensed under either of 18 | 19 | * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) 20 | * [MIT license](http://opensource.org/licenses/MIT) 21 | 22 | at your option. 23 | 24 | ### Contribution 25 | 26 | Unless you explicitly state otherwise, any contribution intentionally submitted 27 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall be 28 | dual licensed as above, without any additional terms or conditions. 29 | 30 | [//]: # (badges) 31 | 32 | [crate-image]: https://img.shields.io/crates/v/bp256?logo=rust 33 | [crate-link]: https://crates.io/crates/bp256 34 | [docs-image]: https://docs.rs/bp256/badge.svg 35 | [docs-link]: https://docs.rs/bp256/ 36 | [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg 37 | [rustc-image]: https://img.shields.io/badge/rustc-1.85+-blue.svg 38 | [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg 39 | [chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/260040-elliptic-curves 40 | [build-image]: https://github.com/RustCrypto/elliptic-curves/actions/workflows/bp256.yml/badge.svg 41 | [build-link]: https://github.com/RustCrypto/elliptic-curves/actions/workflows/bp256.yml 42 | 43 | [//]: # (links) 44 | 45 | [RustCrypto]: https://github.com/rustcrypto/ 46 | [`elliptic-curve`]: https://github.com/RustCrypto/traits/tree/master/elliptic-curve 47 | -------------------------------------------------------------------------------- /bp256/src/arithmetic.rs: -------------------------------------------------------------------------------- 1 | //! Field arithmetic for the brainpoolP256 elliptic curve. 2 | 3 | pub(crate) mod field; 4 | pub(crate) mod scalar; 5 | -------------------------------------------------------------------------------- /bp256/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![cfg_attr(docsrs, feature(doc_auto_cfg))] 3 | #![doc = include_str!("../README.md")] 4 | #![doc( 5 | html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg", 6 | html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg" 7 | )] 8 | #![forbid(unsafe_code)] 9 | #![warn( 10 | clippy::mod_module_files, 11 | clippy::unwrap_used, 12 | missing_docs, 13 | rust_2018_idioms, 14 | unused_lifetimes, 15 | unused_qualifications 16 | )] 17 | 18 | pub mod r1; 19 | pub mod t1; 20 | 21 | #[cfg(feature = "arithmetic")] 22 | mod arithmetic; 23 | 24 | pub use crate::{r1::BrainpoolP256r1, t1::BrainpoolP256t1}; 25 | pub use elliptic_curve::{self, bigint::U256}; 26 | 27 | #[cfg(feature = "arithmetic")] 28 | pub use crate::arithmetic::scalar::Scalar; 29 | 30 | #[cfg(feature = "pkcs8")] 31 | pub use elliptic_curve::pkcs8; 32 | 33 | #[cfg(feature = "arithmetic")] 34 | pub(crate) use crate::arithmetic::field::FieldElement; 35 | use elliptic_curve::array::{Array, typenum::U32}; 36 | use elliptic_curve::bigint::ArrayEncoding; 37 | 38 | /// Byte representation of a base/scalar field element of a given curve. 39 | pub type FieldBytes = Array; 40 | 41 | const ORDER_HEX: &str = "a9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974856a7"; 42 | const ORDER: U256 = U256::from_be_hex(ORDER_HEX); 43 | 44 | fn decode_field_bytes(field_bytes: &FieldBytes) -> U256 { 45 | U256::from_be_byte_array(*field_bytes) 46 | } 47 | 48 | fn encode_field_bytes(uint: &U256) -> FieldBytes { 49 | uint.to_be_byte_array() 50 | } 51 | -------------------------------------------------------------------------------- /bp256/src/r1.rs: -------------------------------------------------------------------------------- 1 | //! brainpoolP256r1 elliptic curve: verifiably pseudo-random variant 2 | 3 | #[cfg(feature = "ecdsa")] 4 | pub mod ecdsa; 5 | 6 | #[cfg(feature = "arithmetic")] 7 | mod arithmetic; 8 | 9 | #[cfg(feature = "arithmetic")] 10 | pub use { 11 | self::arithmetic::{AffinePoint, NonZeroScalar, ProjectivePoint, ScalarPrimitive}, 12 | crate::Scalar, 13 | }; 14 | 15 | use crate::ORDER; 16 | use elliptic_curve::{FieldBytesEncoding, bigint::U256, consts::U32}; 17 | 18 | #[cfg(feature = "pkcs8")] 19 | use crate::pkcs8; 20 | 21 | /// brainpoolP256r1 elliptic curve: verifiably pseudo-random variant 22 | #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord)] 23 | pub struct BrainpoolP256r1; 24 | 25 | impl elliptic_curve::Curve for BrainpoolP256r1 { 26 | /// 32-byte serialized field elements. 27 | type FieldBytesSize = U32; 28 | 29 | /// 256-bit field modulus. 30 | type Uint = U256; 31 | 32 | /// Curve order 33 | const ORDER: U256 = ORDER; 34 | } 35 | 36 | impl elliptic_curve::PrimeCurve for BrainpoolP256r1 {} 37 | 38 | impl elliptic_curve::point::PointCompression for BrainpoolP256r1 { 39 | const COMPRESS_POINTS: bool = false; 40 | } 41 | 42 | #[cfg(feature = "pkcs8")] 43 | impl pkcs8::AssociatedOid for BrainpoolP256r1 { 44 | const OID: pkcs8::ObjectIdentifier = 45 | pkcs8::ObjectIdentifier::new_unwrap("1.3.36.3.3.2.8.1.1.7"); 46 | } 47 | 48 | /// brainpoolP256r1 SEC1 encoded point. 49 | pub type EncodedPoint = elliptic_curve::sec1::EncodedPoint; 50 | 51 | /// brainpoolP256r1 field element serialized as bytes. 52 | /// 53 | /// Byte array containing a serialized field element value (base field or scalar). 54 | pub type FieldBytes = elliptic_curve::FieldBytes; 55 | 56 | impl FieldBytesEncoding for U256 { 57 | fn decode_field_bytes(field_bytes: &FieldBytes) -> Self { 58 | crate::decode_field_bytes(field_bytes) 59 | } 60 | 61 | fn encode_field_bytes(&self) -> FieldBytes { 62 | crate::encode_field_bytes(self) 63 | } 64 | } 65 | 66 | /// brainpoolP256r1 secret key. 67 | pub type SecretKey = elliptic_curve::SecretKey; 68 | 69 | #[cfg(not(feature = "arithmetic"))] 70 | impl elliptic_curve::sec1::ValidatePublicKey for BrainpoolP256r1 {} 71 | -------------------------------------------------------------------------------- /bp256/src/r1/arithmetic.rs: -------------------------------------------------------------------------------- 1 | //! brainpoolP256r1 curve arithmetic implementation. 2 | 3 | use super::BrainpoolP256r1; 4 | use crate::{FieldElement, Scalar}; 5 | use elliptic_curve::{CurveArithmetic, PrimeCurveArithmetic}; 6 | use primeorder::{PrimeCurveParams, point_arithmetic}; 7 | 8 | /// Elliptic curve point in affine coordinates. 9 | pub type AffinePoint = primeorder::AffinePoint; 10 | 11 | /// Elliptic curve point in projective coordinates. 12 | pub type ProjectivePoint = primeorder::ProjectivePoint; 13 | 14 | /// Primitive scalar type. 15 | pub type ScalarPrimitive = elliptic_curve::ScalarPrimitive; 16 | 17 | /// Non-zero scalar field element. 18 | pub type NonZeroScalar = elliptic_curve::NonZeroScalar; 19 | 20 | impl CurveArithmetic for BrainpoolP256r1 { 21 | type AffinePoint = AffinePoint; 22 | type ProjectivePoint = ProjectivePoint; 23 | type Scalar = Scalar; 24 | } 25 | 26 | impl PrimeCurveArithmetic for BrainpoolP256r1 { 27 | type CurveGroup = ProjectivePoint; 28 | } 29 | 30 | impl PrimeCurveParams for BrainpoolP256r1 { 31 | type FieldElement = FieldElement; 32 | type PointArithmetic = point_arithmetic::EquationAIsGeneric; 33 | 34 | const EQUATION_A: FieldElement = 35 | FieldElement::from_hex("7d5a0975fc2c3057eef67530417affe7fb8055c126dc5c6ce94a4b44f330b5d9"); 36 | const EQUATION_B: FieldElement = 37 | FieldElement::from_hex("26dc5c6ce94a4b44f330b5d9bbd77cbf958416295cf7e1ce6bccdc18ff8c07b6"); 38 | const GENERATOR: (FieldElement, FieldElement) = ( 39 | FieldElement::from_hex("8bd2aeb9cb7e57cb2c4b482ffc81b7afb9de27e1e3bd23c23a4453bd9ace3262"), 40 | FieldElement::from_hex("547ef835c3dac4fd97f8461a14611dc9c27745132ded8e545c1d54c72f046997"), 41 | ); 42 | } 43 | -------------------------------------------------------------------------------- /bp256/src/r1/ecdsa.rs: -------------------------------------------------------------------------------- 1 | //! Elliptic Curve Digital Signature Algorithm (ECDSA) 2 | 3 | pub use super::BrainpoolP256r1; 4 | 5 | /// ECDSA/brainpoolP256r1 signature (fixed-size) 6 | pub type Signature = ecdsa::Signature; 7 | 8 | /// ECDSA/brainpoolP256r1 signature (ASN.1 DER encoded) 9 | pub type DerSignature = ecdsa::der::Signature; 10 | 11 | impl ecdsa::EcdsaCurve for BrainpoolP256r1 { 12 | const NORMALIZE_S: bool = false; 13 | } 14 | 15 | #[cfg(feature = "sha256")] 16 | impl ecdsa::hazmat::DigestPrimitive for BrainpoolP256r1 { 17 | type Digest = sha2::Sha256; 18 | } 19 | -------------------------------------------------------------------------------- /bp256/src/t1.rs: -------------------------------------------------------------------------------- 1 | //! brainpoolP256t1 elliptic curve: twisted variant 2 | 3 | #[cfg(feature = "ecdsa")] 4 | pub mod ecdsa; 5 | 6 | #[cfg(feature = "arithmetic")] 7 | mod arithmetic; 8 | 9 | #[cfg(feature = "arithmetic")] 10 | pub use { 11 | self::arithmetic::{AffinePoint, NonZeroScalar, ProjectivePoint, ScalarPrimitive}, 12 | crate::Scalar, 13 | }; 14 | 15 | use crate::ORDER; 16 | use elliptic_curve::{FieldBytesEncoding, bigint::U256, consts::U32}; 17 | 18 | #[cfg(feature = "pkcs8")] 19 | use crate::pkcs8; 20 | 21 | /// brainpoolP256t1 elliptic curve: twisted variant 22 | #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord)] 23 | pub struct BrainpoolP256t1; 24 | 25 | impl elliptic_curve::Curve for BrainpoolP256t1 { 26 | /// 32-byte serialized field elements. 27 | type FieldBytesSize = U32; 28 | 29 | /// 256-bit field modulus. 30 | type Uint = U256; 31 | 32 | /// Curve order 33 | const ORDER: U256 = ORDER; 34 | } 35 | 36 | impl elliptic_curve::PrimeCurve for BrainpoolP256t1 {} 37 | 38 | impl elliptic_curve::point::PointCompression for BrainpoolP256t1 { 39 | const COMPRESS_POINTS: bool = false; 40 | } 41 | 42 | #[cfg(feature = "pkcs8")] 43 | impl pkcs8::AssociatedOid for BrainpoolP256t1 { 44 | const OID: pkcs8::ObjectIdentifier = 45 | pkcs8::ObjectIdentifier::new_unwrap("1.3.36.3.3.2.8.1.1.8"); 46 | } 47 | 48 | /// brainpoolP256t1 SEC1 encoded point. 49 | pub type EncodedPoint = elliptic_curve::sec1::EncodedPoint; 50 | 51 | /// brainpoolP256t1 field element serialized as bytes. 52 | /// 53 | /// Byte array containing a serialized field element value (base field or scalar). 54 | pub type FieldBytes = elliptic_curve::FieldBytes; 55 | 56 | impl FieldBytesEncoding for U256 { 57 | fn decode_field_bytes(field_bytes: &crate::r1::FieldBytes) -> Self { 58 | crate::decode_field_bytes(field_bytes) 59 | } 60 | 61 | fn encode_field_bytes(&self) -> crate::r1::FieldBytes { 62 | crate::encode_field_bytes(self) 63 | } 64 | } 65 | 66 | /// brainpoolP256t1 secret key. 67 | pub type SecretKey = elliptic_curve::SecretKey; 68 | 69 | #[cfg(not(feature = "arithmetic"))] 70 | impl elliptic_curve::sec1::ValidatePublicKey for BrainpoolP256t1 {} 71 | -------------------------------------------------------------------------------- /bp256/src/t1/arithmetic.rs: -------------------------------------------------------------------------------- 1 | //! brainpoolP256t1 curve arithmetic implementation. 2 | 3 | use super::BrainpoolP256t1; 4 | use crate::{FieldElement, Scalar}; 5 | use elliptic_curve::{CurveArithmetic, PrimeCurveArithmetic}; 6 | use primeorder::{PrimeCurveParams, point_arithmetic}; 7 | 8 | /// Elliptic curve point in affine coordinates. 9 | pub type AffinePoint = primeorder::AffinePoint; 10 | 11 | /// Elliptic curve point in projective coordinates. 12 | pub type ProjectivePoint = primeorder::ProjectivePoint; 13 | 14 | /// Primitive scalar type. 15 | pub type ScalarPrimitive = elliptic_curve::ScalarPrimitive; 16 | 17 | /// Non-zero scalar field element. 18 | pub type NonZeroScalar = elliptic_curve::NonZeroScalar; 19 | 20 | impl CurveArithmetic for BrainpoolP256t1 { 21 | type AffinePoint = AffinePoint; 22 | type ProjectivePoint = ProjectivePoint; 23 | type Scalar = Scalar; 24 | } 25 | 26 | impl PrimeCurveArithmetic for BrainpoolP256t1 { 27 | type CurveGroup = ProjectivePoint; 28 | } 29 | 30 | impl PrimeCurveParams for BrainpoolP256t1 { 31 | type FieldElement = FieldElement; 32 | type PointArithmetic = point_arithmetic::EquationAIsGeneric; 33 | 34 | const EQUATION_A: FieldElement = 35 | FieldElement::from_hex("a9fb57dba1eea9bc3e660a909d838d726e3bf623d52620282013481d1f6e5374"); 36 | const EQUATION_B: FieldElement = 37 | FieldElement::from_hex("662c61c430d84ea4fe66a7733d0b76b7bf93ebc4af2f49256ae58101fee92b04"); 38 | const GENERATOR: (FieldElement, FieldElement) = ( 39 | FieldElement::from_hex("a3e8eb3cc1cfe7b7732213b23a656149afa142c47aafbc2b79a191562e1305f4"), 40 | FieldElement::from_hex("2d996c823439c56d7f7b22e14644417e69bcb6de39d027001dabe8f35b25c9be"), 41 | ); 42 | } 43 | -------------------------------------------------------------------------------- /bp256/src/t1/ecdsa.rs: -------------------------------------------------------------------------------- 1 | //! Elliptic Curve Digital Signature Algorithm (ECDSA) 2 | 3 | pub use super::BrainpoolP256t1; 4 | 5 | /// ECDSA/brainpoolP256t1 signature (fixed-size) 6 | pub type Signature = ecdsa::Signature; 7 | 8 | /// ECDSA/brainpoolP256t1 signature (ASN.1 DER encoded) 9 | pub type DerSignature = ecdsa::der::Signature; 10 | 11 | impl ecdsa::EcdsaCurve for BrainpoolP256t1 { 12 | const NORMALIZE_S: bool = false; 13 | } 14 | 15 | #[cfg(feature = "sha256")] 16 | impl ecdsa::hazmat::DigestPrimitive for BrainpoolP256t1 { 17 | type Digest = sha2::Sha256; 18 | } 19 | -------------------------------------------------------------------------------- /bp384/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bp384" 3 | version = "0.7.0-pre" 4 | description = "Brainpool P-384 (brainpoolP384r1 and brainpoolP384t1) elliptic curves" 5 | authors = ["RustCrypto Developers"] 6 | license = "Apache-2.0 OR MIT" 7 | documentation = "https://docs.rs/bp384" 8 | homepage = "https://github.com/RustCrypto/elliptic-curves/tree/master/bp384" 9 | repository = "https://github.com/RustCrypto/elliptic-curves" 10 | readme = "README.md" 11 | categories = ["cryptography", "no-std"] 12 | keywords = ["brainpool", "crypto", "ecc"] 13 | edition = "2024" 14 | rust-version = "1.85" 15 | 16 | [dependencies] 17 | elliptic-curve = { version = "0.14.0-rc.5", default-features = false, features = ["sec1"] } 18 | 19 | # optional dependencies 20 | ecdsa = { version = "0.17.0-rc.0", optional = true, default-features = false, features = ["der"] } 21 | primefield = { version = "=0.14.0-pre.2", optional = true } 22 | primeorder = { version = "=0.14.0-pre.4", optional = true } 23 | sha2 = { version = "0.11.0-rc.0", optional = true, default-features = false } 24 | 25 | [features] 26 | default = ["pkcs8", "std"] 27 | alloc = ["ecdsa?/alloc", "elliptic-curve/alloc", "primeorder?/alloc"] 28 | std = ["alloc", "ecdsa?/std", "elliptic-curve/std"] 29 | 30 | pem = ["elliptic-curve/pem", "pkcs8"] 31 | pkcs8 = ["ecdsa/pkcs8", "elliptic-curve/pkcs8"] 32 | serde = ["ecdsa/serde", "elliptic-curve/serde"] 33 | sha384 = ["ecdsa/digest", "ecdsa/hazmat", "sha2"] 34 | arithmetic = ["dep:primefield", "dep:primeorder"] 35 | 36 | [package.metadata.docs.rs] 37 | all-features = true 38 | rustdoc-args = ["--cfg", "docsrs"] 39 | -------------------------------------------------------------------------------- /bp384/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2021-2023 RustCrypto Developers 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /bp384/README.md: -------------------------------------------------------------------------------- 1 | # [RustCrypto]: Brainpool P-384 elliptic curves 2 | 3 | [![crate][crate-image]][crate-link] 4 | [![Docs][docs-image]][docs-link] 5 | [![Build Status][build-image]][build-link] 6 | ![Apache2/MIT licensed][license-image] 7 | ![Rust Version][rustc-image] 8 | [![Project Chat][chat-image]][chat-link] 9 | 10 | Brainpool P-384 (brainpoolP384r1 and brainpoolP384t1) elliptic curve types 11 | implemented in terms of traits from the [`elliptic-curve`] crate. 12 | 13 | [Documentation][docs-link] 14 | 15 | ## License 16 | 17 | All crates licensed under either of 18 | 19 | * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) 20 | * [MIT license](http://opensource.org/licenses/MIT) 21 | 22 | at your option. 23 | 24 | ### Contribution 25 | 26 | Unless you explicitly state otherwise, any contribution intentionally submitted 27 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall be 28 | dual licensed as above, without any additional terms or conditions. 29 | 30 | [//]: # (badges) 31 | 32 | [crate-image]: https://img.shields.io/crates/v/bp384?logo=rust 33 | [crate-link]: https://crates.io/crates/bp384 34 | [docs-image]: https://docs.rs/bp384/badge.svg 35 | [docs-link]: https://docs.rs/bp384/ 36 | [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg 37 | [rustc-image]: https://img.shields.io/badge/rustc-1.85+-blue.svg 38 | [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg 39 | [chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/260040-elliptic-curves 40 | [build-image]: https://github.com/RustCrypto/elliptic-curves/actions/workflows/bp384.yml/badge.svg 41 | [build-link]: https://github.com/RustCrypto/elliptic-curves/actions/workflows/bp384.yml 42 | 43 | [//]: # (links) 44 | 45 | [RustCrypto]: https://github.com/rustcrypto/ 46 | [`elliptic-curve`]: https://github.com/RustCrypto/traits/tree/master/elliptic-curve 47 | -------------------------------------------------------------------------------- /bp384/src/arithmetic.rs: -------------------------------------------------------------------------------- 1 | //! Field arithmetic for the brainpoolP384 elliptic curve. 2 | 3 | pub(crate) mod field; 4 | pub(crate) mod scalar; 5 | -------------------------------------------------------------------------------- /bp384/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![cfg_attr(docsrs, feature(doc_auto_cfg))] 3 | #![doc = include_str!("../README.md")] 4 | #![doc( 5 | html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg", 6 | html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg" 7 | )] 8 | #![forbid(unsafe_code)] 9 | #![warn( 10 | clippy::mod_module_files, 11 | clippy::unwrap_used, 12 | missing_docs, 13 | rust_2018_idioms, 14 | unused_lifetimes, 15 | unused_qualifications 16 | )] 17 | 18 | pub mod r1; 19 | pub mod t1; 20 | 21 | #[cfg(feature = "arithmetic")] 22 | mod arithmetic; 23 | 24 | pub use crate::{r1::BrainpoolP384r1, t1::BrainpoolP384t1}; 25 | pub use elliptic_curve::{ 26 | self, 27 | bigint::{ArrayEncoding, U384}, 28 | }; 29 | 30 | #[cfg(feature = "arithmetic")] 31 | pub use crate::arithmetic::scalar::Scalar; 32 | 33 | #[cfg(feature = "pkcs8")] 34 | pub use elliptic_curve::pkcs8; 35 | 36 | #[cfg(feature = "arithmetic")] 37 | pub(crate) use crate::arithmetic::field::FieldElement; 38 | use elliptic_curve::array::{Array, typenum::U48}; 39 | 40 | /// Byte representation of a base/scalar field element of a given curve. 41 | pub type FieldBytes = Array; 42 | 43 | const ORDER_HEX: &str = "8cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b31f166e6cac0425a7cf3ab6af6b7fc3103b883202e9046565"; 44 | const ORDER: U384 = U384::from_be_hex(ORDER_HEX); 45 | 46 | fn decode_field_bytes(field_bytes: &FieldBytes) -> U384 { 47 | U384::from_be_byte_array(*field_bytes) 48 | } 49 | 50 | fn encode_field_bytes(uint: &U384) -> FieldBytes { 51 | uint.to_be_byte_array() 52 | } 53 | -------------------------------------------------------------------------------- /bp384/src/r1.rs: -------------------------------------------------------------------------------- 1 | //! brainpoolP384r1 elliptic curve: verifiably pseudo-random variant 2 | 3 | #[cfg(feature = "ecdsa")] 4 | pub mod ecdsa; 5 | 6 | #[cfg(feature = "arithmetic")] 7 | mod arithmetic; 8 | 9 | #[cfg(feature = "arithmetic")] 10 | pub use { 11 | self::arithmetic::{AffinePoint, NonZeroScalar, ProjectivePoint, ScalarPrimitive}, 12 | crate::Scalar, 13 | }; 14 | 15 | use crate::ORDER; 16 | use elliptic_curve::{FieldBytesEncoding, bigint::U384, consts::U48}; 17 | 18 | #[cfg(feature = "pkcs8")] 19 | use crate::pkcs8; 20 | 21 | /// brainpoolP384r1 elliptic curve: verifiably pseudo-random variant 22 | #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord)] 23 | pub struct BrainpoolP384r1; 24 | 25 | impl elliptic_curve::Curve for BrainpoolP384r1 { 26 | /// 48-byte serialized field elements. 27 | type FieldBytesSize = U48; 28 | 29 | /// 384-bit field modulus. 30 | type Uint = U384; 31 | 32 | /// Curve order. 33 | const ORDER: U384 = ORDER; 34 | } 35 | 36 | impl elliptic_curve::PrimeCurve for BrainpoolP384r1 {} 37 | 38 | impl elliptic_curve::point::PointCompression for BrainpoolP384r1 { 39 | const COMPRESS_POINTS: bool = false; 40 | } 41 | 42 | #[cfg(feature = "pkcs8")] 43 | impl pkcs8::AssociatedOid for BrainpoolP384r1 { 44 | const OID: pkcs8::ObjectIdentifier = 45 | pkcs8::ObjectIdentifier::new_unwrap("1.3.36.3.3.2.8.1.1.11"); 46 | } 47 | 48 | /// brainpoolP384r1 SEC1 encoded point. 49 | pub type EncodedPoint = elliptic_curve::sec1::EncodedPoint; 50 | 51 | /// brainpoolP384r1 field element serialized as bytes. 52 | /// 53 | /// Byte array containing a serialized field element value (base field or scalar). 54 | pub type FieldBytes = elliptic_curve::FieldBytes; 55 | 56 | impl FieldBytesEncoding for U384 { 57 | fn decode_field_bytes(field_bytes: &FieldBytes) -> Self { 58 | crate::decode_field_bytes(field_bytes) 59 | } 60 | 61 | fn encode_field_bytes(&self) -> FieldBytes { 62 | crate::encode_field_bytes(self) 63 | } 64 | } 65 | 66 | /// brainpoolP384r1 secret key. 67 | pub type SecretKey = elliptic_curve::SecretKey; 68 | 69 | #[cfg(not(feature = "arithmetic"))] 70 | impl elliptic_curve::sec1::ValidatePublicKey for BrainpoolP384r1 {} 71 | -------------------------------------------------------------------------------- /bp384/src/r1/arithmetic.rs: -------------------------------------------------------------------------------- 1 | //! brainpoolP384r1 curve arithmetic implementation. 2 | 3 | use super::BrainpoolP384r1; 4 | use crate::{FieldElement, Scalar}; 5 | use elliptic_curve::{CurveArithmetic, PrimeCurveArithmetic}; 6 | use primeorder::{PrimeCurveParams, point_arithmetic}; 7 | 8 | /// Elliptic curve point in affine coordinates. 9 | pub type AffinePoint = primeorder::AffinePoint; 10 | 11 | /// Elliptic curve point in projective coordinates. 12 | pub type ProjectivePoint = primeorder::ProjectivePoint; 13 | 14 | /// Primitive scalar type. 15 | pub type ScalarPrimitive = elliptic_curve::ScalarPrimitive; 16 | 17 | /// Non-zero scalar field element. 18 | pub type NonZeroScalar = elliptic_curve::NonZeroScalar; 19 | 20 | impl CurveArithmetic for BrainpoolP384r1 { 21 | type AffinePoint = AffinePoint; 22 | type ProjectivePoint = ProjectivePoint; 23 | type Scalar = Scalar; 24 | } 25 | 26 | impl PrimeCurveArithmetic for BrainpoolP384r1 { 27 | type CurveGroup = ProjectivePoint; 28 | } 29 | 30 | impl PrimeCurveParams for BrainpoolP384r1 { 31 | type FieldElement = FieldElement; 32 | type PointArithmetic = point_arithmetic::EquationAIsGeneric; 33 | 34 | const EQUATION_A: FieldElement = FieldElement::from_hex( 35 | "7bc382c63d8c150c3c72080ace05afa0c2bea28e4fb22787139165efba91f90f8aa5814a503ad4eb04a8c7dd22ce2826", 36 | ); 37 | const EQUATION_B: FieldElement = FieldElement::from_hex( 38 | "04a8c7dd22ce28268b39b55416f0447c2fb77de107dcd2a62e880ea53eeb62d57cb4390295dbc9943ab78696fa504c11", 39 | ); 40 | const GENERATOR: (FieldElement, FieldElement) = ( 41 | FieldElement::from_hex( 42 | "1d1c64f068cf45ffa2a63a81b7c13f6b8847a3e77ef14fe3db7fcafe0cbd10e8e826e03436d646aaef87b2e247d4af1e", 43 | ), 44 | FieldElement::from_hex( 45 | "8abe1d7520f9c2a45cb1eb8e95cfd55262b70b29feec5864e19c054ff99129280e4646217791811142820341263c5315", 46 | ), 47 | ); 48 | } 49 | -------------------------------------------------------------------------------- /bp384/src/r1/ecdsa.rs: -------------------------------------------------------------------------------- 1 | //! Elliptic Curve Digital Signature Algorithm (ECDSA) 2 | 3 | pub use super::BrainpoolP384r1; 4 | 5 | /// ECDSA/brainpoolP384r1 signature (fixed-size) 6 | pub type Signature = ecdsa::Signature; 7 | 8 | /// ECDSA/brainpoolP384r1 signature (ASN.1 DER encoded) 9 | pub type DerSignature = ecdsa::der::Signature; 10 | 11 | impl ecdsa::EcdsaCurve for BrainpoolP384r1 { 12 | const NORMALIZE_S: bool = false; 13 | } 14 | 15 | #[cfg(feature = "sha384")] 16 | impl ecdsa::hazmat::DigestPrimitive for BrainpoolP384r1 { 17 | type Digest = sha2::Sha384; 18 | } 19 | -------------------------------------------------------------------------------- /bp384/src/t1.rs: -------------------------------------------------------------------------------- 1 | //! brainpoolP384t1 elliptic curve: twisted variant 2 | 3 | #[cfg(feature = "ecdsa")] 4 | pub mod ecdsa; 5 | 6 | #[cfg(feature = "arithmetic")] 7 | mod arithmetic; 8 | 9 | #[cfg(feature = "arithmetic")] 10 | pub use { 11 | self::arithmetic::{AffinePoint, NonZeroScalar, ProjectivePoint, ScalarPrimitive}, 12 | crate::Scalar, 13 | }; 14 | 15 | use crate::ORDER; 16 | use elliptic_curve::{FieldBytesEncoding, bigint::U384, consts::U48}; 17 | 18 | #[cfg(feature = "pkcs8")] 19 | use crate::pkcs8; 20 | 21 | /// brainpoolP384t1 elliptic curve: twisted variant 22 | #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord)] 23 | pub struct BrainpoolP384t1; 24 | 25 | impl elliptic_curve::Curve for BrainpoolP384t1 { 26 | /// 48-byte serialized field elements. 27 | type FieldBytesSize = U48; 28 | 29 | /// 384-bit field modulus. 30 | type Uint = U384; 31 | 32 | /// Curve order. 33 | const ORDER: U384 = ORDER; 34 | } 35 | 36 | impl elliptic_curve::PrimeCurve for BrainpoolP384t1 {} 37 | 38 | impl elliptic_curve::point::PointCompression for BrainpoolP384t1 { 39 | const COMPRESS_POINTS: bool = false; 40 | } 41 | 42 | #[cfg(feature = "pkcs8")] 43 | impl pkcs8::AssociatedOid for BrainpoolP384t1 { 44 | const OID: pkcs8::ObjectIdentifier = 45 | pkcs8::ObjectIdentifier::new_unwrap("1.3.36.3.3.2.8.1.1.12"); 46 | } 47 | 48 | /// brainpoolP384t1 SEC1 encoded point. 49 | pub type EncodedPoint = elliptic_curve::sec1::EncodedPoint; 50 | 51 | /// brainpoolP384t1 field element serialized as bytes. 52 | /// 53 | /// Byte array containing a serialized field element value (base field or scalar). 54 | pub type FieldBytes = elliptic_curve::FieldBytes; 55 | 56 | impl FieldBytesEncoding for U384 { 57 | fn decode_field_bytes(field_bytes: &FieldBytes) -> Self { 58 | crate::decode_field_bytes(field_bytes) 59 | } 60 | 61 | fn encode_field_bytes(&self) -> FieldBytes { 62 | crate::encode_field_bytes(self) 63 | } 64 | } 65 | 66 | /// brainpoolP384t1 secret key. 67 | pub type SecretKey = elliptic_curve::SecretKey; 68 | 69 | #[cfg(not(feature = "arithmetic"))] 70 | impl elliptic_curve::sec1::ValidatePublicKey for BrainpoolP384t1 {} 71 | -------------------------------------------------------------------------------- /bp384/src/t1/arithmetic.rs: -------------------------------------------------------------------------------- 1 | //! brainpoolP384t1 curve arithmetic implementation. 2 | 3 | use super::BrainpoolP384t1; 4 | use crate::{FieldElement, Scalar}; 5 | use elliptic_curve::{CurveArithmetic, PrimeCurveArithmetic}; 6 | use primeorder::{PrimeCurveParams, point_arithmetic}; 7 | 8 | /// Elliptic curve point in affine coordinates. 9 | pub type AffinePoint = primeorder::AffinePoint; 10 | 11 | /// Elliptic curve point in projective coordinates. 12 | pub type ProjectivePoint = primeorder::ProjectivePoint; 13 | 14 | /// Primitive scalar type. 15 | pub type ScalarPrimitive = elliptic_curve::ScalarPrimitive; 16 | 17 | /// Non-zero scalar field element. 18 | pub type NonZeroScalar = elliptic_curve::NonZeroScalar; 19 | 20 | impl CurveArithmetic for BrainpoolP384t1 { 21 | type AffinePoint = AffinePoint; 22 | type ProjectivePoint = ProjectivePoint; 23 | type Scalar = Scalar; 24 | } 25 | 26 | impl PrimeCurveArithmetic for BrainpoolP384t1 { 27 | type CurveGroup = ProjectivePoint; 28 | } 29 | 30 | impl PrimeCurveParams for BrainpoolP384t1 { 31 | type FieldElement = FieldElement; 32 | type PointArithmetic = point_arithmetic::EquationAIsGeneric; 33 | 34 | const EQUATION_A: FieldElement = FieldElement::from_hex( 35 | "8cb91e82a3386d280f5d6f7e50e641df152f7109ed5456b412b1da197fb71123acd3a729901d1a71874700133107ec50", 36 | ); 37 | const EQUATION_B: FieldElement = FieldElement::from_hex( 38 | "7f519eada7bda81bd826dba647910f8c4b9346ed8ccdc64e4b1abd11756dce1d2074aa263b88805ced70355a33b471ee", 39 | ); 40 | const GENERATOR: (FieldElement, FieldElement) = ( 41 | FieldElement::from_hex( 42 | "18de98b02db9a306f2afcd7235f72a819b80ab12ebd653172476fecd462aabffc4ff191b946a5f54d8d0aa2f418808cc", 43 | ), 44 | FieldElement::from_hex( 45 | "25ab056962d30651a114afd2755ad336747f93475b7a1fca3b88f2b6a208ccfe469408584dc2b2912675bf5b9e582928", 46 | ), 47 | ); 48 | } 49 | -------------------------------------------------------------------------------- /bp384/src/t1/ecdsa.rs: -------------------------------------------------------------------------------- 1 | //! Elliptic Curve Digital Signature Algorithm (ECDSA) 2 | 3 | pub use super::BrainpoolP384t1; 4 | 5 | /// ECDSA/brainpoolP384t1 signature (fixed-size) 6 | pub type Signature = ecdsa::Signature; 7 | 8 | /// ECDSA/brainpoolP384t1 signature (ASN.1 DER encoded) 9 | pub type DerSignature = ecdsa::der::Signature; 10 | 11 | impl ecdsa::EcdsaCurve for BrainpoolP384t1 { 12 | const NORMALIZE_S: bool = false; 13 | } 14 | 15 | #[cfg(feature = "sha384")] 16 | impl ecdsa::hazmat::DigestPrimitive for BrainpoolP384t1 { 17 | type Digest = sha2::Sha384; 18 | } 19 | -------------------------------------------------------------------------------- /clippy.toml: -------------------------------------------------------------------------------- 1 | allow-unwrap-in-tests = true 2 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | status: 3 | patch: off 4 | project: off 5 | -------------------------------------------------------------------------------- /ed448-goldilocks/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ed448-goldilocks" 3 | version = "0.14.0-pre.0" 4 | authors = ["RustCrypto Developers"] 5 | categories = ["cryptography"] 6 | keywords = ["cryptography", "decaf", "ed448", "ed448-goldilocks"] 7 | homepage = "https://docs.rs/ed448-goldilocks/" 8 | repository = "https://github.com/RustCrypto/elliptic-curves/tree/master/ed448" 9 | documentation = "https://docs.rs/ed448-goldilocks" 10 | license = "BSD-3-Clause" 11 | edition = "2024" 12 | rust-version = "1.85" 13 | readme = "README.md" 14 | description = """A pure-Rust implementation of Ed448 and Curve448 and Decaf. 15 | This crate also includes signing and verifying of Ed448 signatures. 16 | """ 17 | 18 | [dependencies] 19 | crypto_signature = { version = "3.0.0-rc.0", default-features = false, features = ["digest", "rand_core"], optional = true, package = "signature" } 20 | elliptic-curve = { version = "0.14.0-rc.5", features = ["arithmetic", "hash2curve", "pkcs8"] } 21 | ed448 = { version = "=0.5.0-pre.0", default-features = false, optional = true } 22 | rand_core = { version = "0.9", default-features = false } 23 | serdect = { version = "0.3.0", optional = true } 24 | sha3 = { version = "0.11.0-rc.0", default-features = false } 25 | subtle = { version = "2.6", default-features = false } 26 | 27 | [features] 28 | default = ["std", "signing", "pkcs8"] 29 | alloc = ["crypto_signature/alloc", "ed448?/alloc", "elliptic-curve/alloc", "serdect/alloc"] 30 | std = ["alloc"] 31 | bits = ["elliptic-curve/bits"] 32 | pkcs8 = ["ed448?/pkcs8", "elliptic-curve/pkcs8"] 33 | signing = ["dep:crypto_signature", "ed448"] 34 | serde = ["dep:serdect", "ed448?/serde_bytes"] 35 | 36 | [dev-dependencies] 37 | hex-literal = "1" 38 | hex = "0.4" 39 | rand_core = { version = "0.9", features = ["os_rng"] } 40 | rand_chacha = "0.9" 41 | serde_bare = "0.5" 42 | serde_json = "1.0" 43 | -------------------------------------------------------------------------------- /ed448-goldilocks/resources/bear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RustCrypto/elliptic-curves/d317ce8100dc09416901d50b223ba45f39549568/ed448-goldilocks/resources/bear.png -------------------------------------------------------------------------------- /ed448-goldilocks/src/constants.rs: -------------------------------------------------------------------------------- 1 | use crate::*; 2 | use crate::{Scalar, decaf::DecafPoint}; 3 | 4 | pub const DECAF_BASEPOINT: DecafPoint = DecafPoint(curve::twedwards::extended::ExtendedPoint { 5 | X: TWISTED_EDWARDS_BASE_POINT.X, 6 | Y: TWISTED_EDWARDS_BASE_POINT.Y, 7 | Z: TWISTED_EDWARDS_BASE_POINT.Z, 8 | T: TWISTED_EDWARDS_BASE_POINT.T, 9 | }); 10 | 11 | /// `BASEPOINT_ORDER` is the order of the Ed448 basepoint, i.e., 12 | /// $$ 13 | /// \ell = 2^\{446\} + 0x8335dc163bb124b65129c96fde933d8d723a70aadc873d6d54a7bb0d. 14 | /// $$ 15 | pub const BASEPOINT_ORDER: Scalar = Scalar(ORDER); 16 | -------------------------------------------------------------------------------- /ed448-goldilocks/src/curve.rs: -------------------------------------------------------------------------------- 1 | pub mod edwards; 2 | pub mod montgomery; 3 | pub(crate) mod scalar_mul; 4 | pub(crate) mod twedwards; 5 | 6 | pub use edwards::{AffinePoint, CompressedEdwardsY, EdwardsPoint}; 7 | pub use montgomery::{MontgomeryPoint, ProjectiveMontgomeryPoint}; 8 | -------------------------------------------------------------------------------- /ed448-goldilocks/src/curve/edwards.rs: -------------------------------------------------------------------------------- 1 | /// This module contains the code for the Goldilocks curve. 2 | /// The goldilocks curve is the (untwisted) Edwards curve with affine equation x^2 + y^2 = 1 - 39081x^2y^2 3 | /// Scalar Multiplication for this curve is pre-dominantly delegated to the Twisted Edwards variation using a (doubling) isogeny 4 | /// Passing the point back to the Goldilocks curve using the dual-isogeny clears the cofactor. 5 | /// The small remainder of the Scalar Multiplication is computed on the untwisted curve. 6 | /// See for details 7 | /// 8 | /// This isogeny strategy does not clear the cofactor on the Goldilocks curve unless the Scalar is a multiple of 4. 9 | /// or the point is known to be in the q-torsion subgroup. 10 | /// Hence, one will need to multiply by the cofactor to ensure it is cleared when using the Goldilocks curve. 11 | /// If this is a problem, one can use a different isogeny strategy (Decaf/Ristretto) 12 | pub(crate) mod affine; 13 | pub(crate) mod extended; 14 | pub use affine::AffinePoint; 15 | pub use extended::{CompressedEdwardsY, EdwardsPoint}; 16 | -------------------------------------------------------------------------------- /ed448-goldilocks/src/curve/scalar_mul.rs: -------------------------------------------------------------------------------- 1 | pub(crate) mod double_and_add; 2 | // pub(crate) mod double_base; 3 | pub(crate) mod variable_base; 4 | pub(crate) mod window; 5 | 6 | pub(crate) use double_and_add::double_and_add; 7 | pub(crate) use variable_base::variable_base; 8 | -------------------------------------------------------------------------------- /ed448-goldilocks/src/curve/scalar_mul/double_and_add.rs: -------------------------------------------------------------------------------- 1 | use crate::curve::twedwards::extended::ExtendedPoint; 2 | use crate::field::Scalar; 3 | use subtle::{Choice, ConditionallySelectable}; 4 | 5 | /// Traditional double and add algorithm 6 | pub(crate) fn double_and_add(point: &ExtendedPoint, s: &Scalar) -> ExtendedPoint { 7 | let mut result = ExtendedPoint::IDENTITY; 8 | 9 | // NB, we reverse here, so we are going from MSB to LSB 10 | // XXX: Would be great if subtle had a From for Choice. But maybe that is not it's purpose? 11 | for bit in s.bits().into_iter().rev() { 12 | result = result.double(); 13 | 14 | let mut p = ExtendedPoint::IDENTITY; 15 | p.conditional_assign(point, Choice::from(bit as u8)); 16 | result = result.add(&p); 17 | } 18 | 19 | result 20 | } 21 | -------------------------------------------------------------------------------- /ed448-goldilocks/src/curve/scalar_mul/double_base.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | 3 | use super::double_and_add; 4 | use crate::curve::twedwards::extended::ExtendedPoint; 5 | use crate::field::Scalar; 6 | /// XXX: Really in-efficient way to do double base scala mul 7 | /// Replace it with endomorphism from pornin or use naf form 8 | /// Computes aA + bB where B is the TwistedEdwards basepoint 9 | pub(crate) fn double_base_scalar_mul(a: &Scalar, A: &ExtendedPoint, b: &Scalar) -> ExtendedPoint { 10 | let part_a = double_and_add(A, a); 11 | let part_b = double_and_add(&ExtendedPoint::GENERATOR, b); 12 | part_a.add(&part_b) 13 | } 14 | -------------------------------------------------------------------------------- /ed448-goldilocks/src/curve/scalar_mul/variable_base.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | 3 | use super::window::wnaf::LookupTable; 4 | use crate::curve::twedwards::{extended::ExtendedPoint, extensible::ExtensiblePoint}; 5 | use crate::field::Scalar; 6 | use subtle::{Choice, ConditionallyNegatable}; 7 | 8 | pub fn variable_base(point: &ExtendedPoint, s: &Scalar) -> ExtendedPoint { 9 | let mut result = ExtensiblePoint::IDENTITY; 10 | 11 | // Recode Scalar 12 | let scalar = s.to_radix_16(); 13 | 14 | let lookup = LookupTable::from(point); 15 | 16 | for i in (0..113).rev() { 17 | result = result.double(); 18 | result = result.double(); 19 | result = result.double(); 20 | result = result.double(); 21 | 22 | // The mask is the top bit, will be 1 for negative numbers, 0 for positive numbers 23 | let mask = scalar[i] >> 7; 24 | let sign = mask & 0x1; 25 | // Use the mask to get the absolute value of scalar 26 | let abs_value = ((scalar[i] + mask) ^ mask) as u32; 27 | 28 | let mut neg_P = lookup.select(abs_value); 29 | neg_P.conditional_negate(Choice::from((sign) as u8)); 30 | 31 | result = result.add_projective_niels(&neg_P); 32 | } 33 | 34 | result.to_extended() 35 | } 36 | 37 | #[cfg(test)] 38 | mod test { 39 | use super::*; 40 | use crate::TWISTED_EDWARDS_BASE_POINT; 41 | use crate::curve::scalar_mul::double_and_add; 42 | use elliptic_curve::bigint::U448; 43 | 44 | #[test] 45 | fn test_scalar_mul() { 46 | // XXX: In the future use known multiples from Sage in bytes form? 47 | let twisted_point = TWISTED_EDWARDS_BASE_POINT; 48 | let scalar = Scalar(U448::from_be_hex( 49 | "05ca185aee2e1b73def437f63c003777083f83043fe5bf1aab454c66b64629d1de8026c1307f665ead0b70151533427ce128ae786ee372b7", 50 | )); 51 | 52 | let got = variable_base(&twisted_point, &scalar); 53 | 54 | let got2 = double_and_add(&twisted_point, &scalar); 55 | assert_eq!(got, got2); 56 | 57 | // Lets see if this is conserved over the isogenies 58 | let edwards_point = twisted_point.to_untwisted(); 59 | let got_untwisted_point = edwards_point.scalar_mul(&scalar); 60 | let expected_untwisted_point = got.to_untwisted(); 61 | assert_eq!(got_untwisted_point, expected_untwisted_point); 62 | } 63 | 64 | #[test] 65 | fn test_simple_scalar_mul_identities() { 66 | let x = TWISTED_EDWARDS_BASE_POINT; 67 | 68 | // Test that 1 * P = P 69 | let exp = variable_base(&x, &Scalar::from(1u8)); 70 | assert!(x == exp); 71 | // Test that 2 * (P + P) = 4 * P 72 | let x_ext = x.to_extensible(); 73 | let expected_two_x = x_ext.add_extensible(&x_ext).double(); 74 | let got = variable_base(&x, &Scalar::from(4u8)); 75 | assert!(expected_two_x.to_extended() == got); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /ed448-goldilocks/src/curve/scalar_mul/window.rs: -------------------------------------------------------------------------------- 1 | pub mod wnaf; 2 | -------------------------------------------------------------------------------- /ed448-goldilocks/src/curve/scalar_mul/window/wnaf.rs: -------------------------------------------------------------------------------- 1 | use crate::curve::twedwards::extended::ExtendedPoint; 2 | use crate::curve::twedwards::projective::ProjectiveNielsPoint; 3 | use subtle::{ConditionallySelectable, ConstantTimeEq}; 4 | 5 | pub struct LookupTable([ProjectiveNielsPoint; 8]); 6 | 7 | /// Precomputes odd multiples of the point passed in 8 | impl From<&ExtendedPoint> for LookupTable { 9 | fn from(point: &ExtendedPoint) -> LookupTable { 10 | let P = point.to_extensible(); 11 | 12 | let mut table = [P.to_projective_niels(); 8]; 13 | 14 | for i in 1..8 { 15 | table[i] = P.add_projective_niels(&table[i - 1]).to_projective_niels(); 16 | } 17 | 18 | LookupTable(table) 19 | } 20 | } 21 | 22 | impl LookupTable { 23 | /// Selects a projective niels point from a lookup table in constant time 24 | pub fn select(&self, index: u32) -> ProjectiveNielsPoint { 25 | let mut result = ProjectiveNielsPoint::identity(); 26 | 27 | for i in 1..9 { 28 | let swap = index.ct_eq(&(i as u32)); 29 | result.conditional_assign(&self.0[i - 1], swap); 30 | } 31 | result 32 | } 33 | } 34 | 35 | // XXX: Add back tests to ensure that select works correctly 36 | 37 | #[test] 38 | fn test_lookup() { 39 | let p = ExtendedPoint::GENERATOR; 40 | let points = LookupTable::from(&p); 41 | 42 | let mut expected_point = ExtendedPoint::IDENTITY; 43 | for i in 0..8 { 44 | let selected_point = points.select(i); 45 | assert_eq!(selected_point.to_extended(), expected_point); 46 | 47 | expected_point = expected_point 48 | .to_extensible() 49 | .add_extended(&p) 50 | .to_extended(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /ed448-goldilocks/src/curve/twedwards.rs: -------------------------------------------------------------------------------- 1 | /// This module will contain the EC arithmetic for the Twisted Edwards form of Goldilocks. 2 | /// with the following affine equation : -x^2 + y^2 = 1 - 39082x^2y^2 3 | /// This curve will be used as a backend for the Goldilocks, Ristretto and Decaf through the use of isogenies. 4 | /// It will not be exposed in the public API. 5 | pub(crate) mod affine; 6 | pub(crate) mod extended; 7 | pub(crate) mod extensible; 8 | pub(crate) mod projective; 9 | -------------------------------------------------------------------------------- /ed448-goldilocks/src/curve/twedwards/projective.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | 3 | use crate::curve::twedwards::{extended::ExtendedPoint, extensible::ExtensiblePoint}; 4 | use crate::field::FieldElement; 5 | use subtle::{Choice, ConditionallyNegatable, ConditionallySelectable}; 6 | 7 | impl Default for ProjectiveNielsPoint { 8 | fn default() -> ProjectiveNielsPoint { 9 | ProjectiveNielsPoint::identity() 10 | } 11 | } 12 | 13 | // Its a variant of Niels, where a Z coordinate is added for unmixed readdition 14 | // ((y+x)/2, (y-x)/2, dxy, Z) 15 | #[derive(Copy, Clone)] 16 | pub struct ProjectiveNielsPoint { 17 | pub(crate) Y_plus_X: FieldElement, 18 | pub(crate) Y_minus_X: FieldElement, 19 | pub(crate) Td: FieldElement, 20 | pub(crate) Z: FieldElement, 21 | } 22 | 23 | impl PartialEq for ProjectiveNielsPoint { 24 | fn eq(&self, other: &ProjectiveNielsPoint) -> bool { 25 | self.to_extended().eq(&other.to_extended()) 26 | } 27 | } 28 | impl Eq for ProjectiveNielsPoint {} 29 | 30 | impl ConditionallySelectable for ProjectiveNielsPoint { 31 | fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { 32 | ProjectiveNielsPoint { 33 | Y_plus_X: FieldElement::conditional_select(&a.Y_plus_X, &b.Y_plus_X, choice), 34 | Y_minus_X: FieldElement::conditional_select(&a.Y_minus_X, &b.Y_minus_X, choice), 35 | Td: FieldElement::conditional_select(&a.Td, &b.Td, choice), 36 | Z: FieldElement::conditional_select(&a.Z, &b.Z, choice), 37 | } 38 | } 39 | } 40 | impl ConditionallyNegatable for ProjectiveNielsPoint { 41 | fn conditional_negate(&mut self, choice: Choice) { 42 | FieldElement::conditional_swap(&mut self.Y_minus_X, &mut self.Y_plus_X, choice); 43 | self.Td.conditional_negate(choice); 44 | } 45 | } 46 | 47 | impl ProjectiveNielsPoint { 48 | pub fn identity() -> ProjectiveNielsPoint { 49 | ExtensiblePoint::IDENTITY.to_projective_niels() 50 | } 51 | 52 | pub fn to_extended(self) -> ExtendedPoint { 53 | let A = self.Y_plus_X - self.Y_minus_X; 54 | let B = self.Y_plus_X + self.Y_minus_X; 55 | ExtendedPoint { 56 | X: self.Z * A, 57 | Y: self.Z * B, 58 | Z: self.Z.square(), 59 | T: B * A, 60 | } 61 | } 62 | } 63 | #[cfg(test)] 64 | mod tests { 65 | use super::*; 66 | 67 | #[test] 68 | fn test_conditional_negate() { 69 | let bp = ExtendedPoint::GENERATOR; 70 | 71 | let mut bp_neg = bp.to_extensible().to_projective_niels(); 72 | bp_neg.conditional_negate(1.into()); 73 | 74 | let expect_identity = bp_neg.to_extended().add(&bp); 75 | assert_eq!(ExtendedPoint::IDENTITY, expect_identity); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /ed448-goldilocks/src/decaf.rs: -------------------------------------------------------------------------------- 1 | // This will be the module for Decaf over Ed448 2 | // This is the newer version of the Decaf strategy, which looks simpler 3 | 4 | pub mod affine; 5 | mod ops; 6 | pub mod points; 7 | 8 | pub use affine::AffinePoint; 9 | pub use points::{CompressedDecaf, DecafPoint}; 10 | -------------------------------------------------------------------------------- /ed448-goldilocks/src/field.rs: -------------------------------------------------------------------------------- 1 | mod element; 2 | mod scalar; 3 | 4 | pub(crate) use element::*; 5 | pub use scalar::{MODULUS_LIMBS, ORDER, Scalar, ScalarBytes, WIDE_ORDER, WideScalarBytes}; 6 | 7 | use crate::curve::edwards::EdwardsPoint; 8 | use crate::curve::twedwards::extended::ExtendedPoint as TwExtendedPoint; 9 | 10 | use elliptic_curve::bigint::{ 11 | U448, impl_modulus, 12 | modular::{ConstMontyForm, ConstMontyParams}, 13 | }; 14 | 15 | impl_modulus!( 16 | MODULUS, 17 | U448, 18 | "fffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffff" 19 | ); 20 | pub(crate) type ConstMontyType = ConstMontyForm; 21 | 22 | pub const GOLDILOCKS_BASE_POINT: EdwardsPoint = EdwardsPoint { 23 | X: FieldElement(ConstMontyType::new(&U448::from_be_hex( 24 | "4f1970c66bed0ded221d15a622bf36da9e146570470f1767ea6de324a3d3a46412ae1af72ab66511433b80e18b00938e2626a82bc70cc05e", 25 | ))), 26 | Y: FieldElement(ConstMontyType::new(&U448::from_be_hex( 27 | "693f46716eb6bc248876203756c9c7624bea73736ca3984087789c1e05a0c2d73ad3ff1ce67c39c4fdbd132c4ed7c8ad9808795bf230fa14", 28 | ))), 29 | Z: FieldElement::ONE, 30 | T: FieldElement(ConstMontyType::new(&U448::from_be_hex( 31 | "c75eb58aee221c6ccec39d2d508d91c9c5056a183f8451d260d71667e2356d58f179de90b5b27da1f78fa07d85662d1deb06624e82af95f3", 32 | ))), 33 | }; 34 | 35 | pub const TWISTED_EDWARDS_BASE_POINT: TwExtendedPoint = TwExtendedPoint { 36 | X: FieldElement(ConstMontyType::new(&U448::from_be_hex( 37 | "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffe80000000000000000000000000000000000000000000000000000000", 38 | ))), 39 | Y: FieldElement(ConstMontyType::new(&U448::from_be_hex( 40 | "8508de14f04286d48d06c13078ca240805264370504c74c393d5242c5045271414181844d73f48e5199b0c1e3ab470a1c86079b4dfdd4a64", 41 | ))), 42 | Z: FieldElement::ONE, 43 | T: FieldElement(ConstMontyType::new(&U448::from_be_hex( 44 | "6d3669e173c6a450e23d5682a9ffe1ddc2b86da60f794be956382384a319b57519c9854dde98e342140362071833f4e093e3c816dc198105", 45 | ))), 46 | }; 47 | -------------------------------------------------------------------------------- /ed448-goldilocks/src/ristretto.rs: -------------------------------------------------------------------------------- 1 | // This will be the module for Ristretto over Ed448 2 | 3 | pub mod constants; 4 | pub mod points; 5 | 6 | pub use points::{CompressedRistretto, RistrettoPoint}; 7 | -------------------------------------------------------------------------------- /ed448-goldilocks/src/ristretto/constants.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /ed448-goldilocks/src/ristretto/points.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | 3 | use crate::curve::twedwards::extended::ExtendedPoint; 4 | use subtle::{Choice, ConstantTimeEq}; 5 | 6 | /// The bytes representation of a compressed point. 7 | pub type RistrettoPointBytes = [u8; 56]; 8 | 9 | #[derive(Copy, Clone, Debug)] 10 | /// Ristretto point. 11 | pub struct RistrettoPoint(pub(crate) ExtendedPoint); 12 | 13 | #[derive(Copy, Clone, Debug)] 14 | #[repr(transparent)] 15 | /// Compressed Ristretto point. 16 | pub struct CompressedRistretto(pub RistrettoPointBytes); 17 | 18 | impl Default for CompressedRistretto { 19 | fn default() -> Self { 20 | Self::IDENTITY 21 | } 22 | } 23 | 24 | impl ConstantTimeEq for CompressedRistretto { 25 | fn ct_eq(&self, other: &CompressedRistretto) -> Choice { 26 | self.as_bytes().ct_eq(other.as_bytes()) 27 | } 28 | } 29 | 30 | impl PartialEq for CompressedRistretto { 31 | fn eq(&self, other: &CompressedRistretto) -> bool { 32 | self.ct_eq(other).into() 33 | } 34 | } 35 | 36 | impl Eq for CompressedRistretto {} 37 | 38 | impl CompressedRistretto { 39 | /// The identity element of the group: the point at infinity. 40 | pub const IDENTITY: Self = Self([0u8; 56]); 41 | 42 | /// Get the bytes of the compressed point. 43 | pub fn as_bytes(&self) -> &[u8] { 44 | &self.0 45 | } 46 | } 47 | 48 | impl RistrettoPoint { 49 | /// The generator of the Ristretto group. 50 | pub const GENERATOR: RistrettoPoint = RistrettoPoint(ExtendedPoint::GENERATOR); 51 | /// The identity element of the group: the point at infinity. 52 | pub const IDENTITY: RistrettoPoint = RistrettoPoint(ExtendedPoint::IDENTITY); 53 | 54 | /// Check whether the point is the identity point. 55 | pub fn equals(&self, other: &RistrettoPoint) -> bool { 56 | let XY = self.0.X * other.0.Y; 57 | let YX = self.0.Y * other.0.X; 58 | XY == YX 59 | } 60 | 61 | /// Decode the compressed point. 62 | pub fn encode(&self) -> CompressedRistretto { 63 | todo!() 64 | } 65 | } 66 | 67 | impl CompressedRistretto { 68 | /// The identity element of the group: the point at infinity. 69 | pub fn identity() -> CompressedRistretto { 70 | CompressedRistretto([0; 56]) 71 | } 72 | 73 | /// Decode the compressed point. 74 | pub fn decode(&self) -> Option { 75 | todo!() 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /ed448-goldilocks/src/sign/context.rs: -------------------------------------------------------------------------------- 1 | /// Ed448 contexts as used by Ed448ph. 2 | /// 3 | /// Contexts are domain separator strings that can be used to isolate uses of 4 | /// the algorithm between different protocols (which is very hard to reliably do 5 | /// otherwise) and between different uses within the same protocol. 6 | /// 7 | /// To create a context, call either of the following: 8 | /// 9 | /// - [`SigningKey::with_context`](crate::SigningKey::with_context) 10 | /// - [`VerifyingKey::with_context`](crate::VerifyingKey::with_context) 11 | #[derive(Copy, Clone, Debug)] 12 | pub struct Context<'k, 'v, K> { 13 | pub(crate) key: &'k K, 14 | pub(crate) value: &'v [u8], 15 | } 16 | 17 | impl<'k, 'v, K> Context<'k, 'v, K> { 18 | /// Maximum length of a context string. 19 | pub const MAX_LENGTH: usize = 255; 20 | 21 | /// Borrow the key 22 | pub fn key(&self) -> &'k K { 23 | self.key 24 | } 25 | 26 | /// Borrow the value 27 | pub fn value(&self) -> &'v [u8] { 28 | self.value 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ed448-goldilocks/src/sign/error.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | error::Error, 3 | fmt::{self, Display, Formatter}, 4 | }; 5 | 6 | /// Signing errors 7 | #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] 8 | pub enum SigningError { 9 | /// Prehashed context length is invalid 10 | PrehashedContextLength, 11 | /// Public key bytes are invalid 12 | InvalidPublicKeyBytes, 13 | /// Signature S component is invalid 14 | InvalidSignatureSComponent, 15 | /// Signature R component is invalid 16 | InvalidSignatureRComponent, 17 | /// Signature length is invalid 18 | InvalidSignatureLength, 19 | /// Signature verification failed 20 | Verify, 21 | } 22 | 23 | impl Display for SigningError { 24 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 25 | match self { 26 | SigningError::PrehashedContextLength => { 27 | write!(f, "prehashed context length is invalid") 28 | } 29 | SigningError::InvalidPublicKeyBytes => write!(f, "public key bytes are invalid"), 30 | SigningError::InvalidSignatureSComponent => { 31 | write!(f, "signature S component is invalid") 32 | } 33 | SigningError::InvalidSignatureRComponent => { 34 | write!(f, "signature R component is invalid") 35 | } 36 | SigningError::InvalidSignatureLength => write!(f, "signature length is invalid"), 37 | SigningError::Verify => write!(f, "signature verification failed"), 38 | } 39 | } 40 | } 41 | 42 | impl Error for SigningError {} 43 | 44 | impl From for crypto_signature::Error { 45 | #[cfg(feature = "alloc")] 46 | fn from(err: SigningError) -> Self { 47 | crypto_signature::Error::from_source(err) 48 | } 49 | 50 | #[cfg(not(feature = "alloc"))] 51 | fn from(_err: SigningError) -> Self { 52 | crypto_signature::Error::new() 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /ed448-goldilocks/src/sign/signature.rs: -------------------------------------------------------------------------------- 1 | use crate::*; 2 | use elliptic_curve::array::Array; 3 | 4 | pub use ed448::Signature; 5 | 6 | impl From for Signature { 7 | fn from(inner: InnerSignature) -> Self { 8 | let mut s = [0u8; SECRET_KEY_LENGTH]; 9 | s.copy_from_slice(&inner.s.to_bytes_rfc_8032()); 10 | Self::from_components(inner.r.compress(), s) 11 | } 12 | } 13 | 14 | impl TryFrom<&Signature> for InnerSignature { 15 | type Error = SigningError; 16 | 17 | fn try_from(signature: &Signature) -> Result { 18 | let s_bytes: &Array = (signature.s_bytes()).into(); 19 | let s = Option::from(Scalar::from_canonical_bytes(s_bytes)) 20 | .ok_or(SigningError::InvalidSignatureSComponent)?; 21 | let r = Option::from(CompressedEdwardsY::from(*signature.r_bytes()).decompress()) 22 | .ok_or(SigningError::InvalidSignatureRComponent)?; 23 | Ok(Self { r, s }) 24 | } 25 | } 26 | 27 | pub(crate) struct InnerSignature { 28 | pub(crate) r: EdwardsPoint, 29 | pub(crate) s: Scalar, 30 | } 31 | 32 | impl TryFrom for InnerSignature { 33 | type Error = SigningError; 34 | 35 | fn try_from(signature: Signature) -> Result { 36 | Self::try_from(&signature) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /k256/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020-2024 RustCrypto Developers 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /k256/benches/ecdsa.rs: -------------------------------------------------------------------------------- 1 | //! secp256k1 scalar arithmetic benchmarks 2 | 3 | use criterion::{Criterion, criterion_group, criterion_main}; 4 | use k256::{ 5 | FieldBytes, NonZeroScalar, Scalar, 6 | ecdsa::{ 7 | Signature, SigningKey, 8 | signature::hazmat::{PrehashSigner, PrehashVerifier}, 9 | }, 10 | elliptic_curve::group::ff::PrimeField, 11 | }; 12 | use std::hint::black_box; 13 | 14 | fn test_scalar_d() -> NonZeroScalar { 15 | NonZeroScalar::new( 16 | Scalar::from_repr( 17 | [ 18 | 0xbb, 0x48, 0x8a, 0xef, 0x41, 0x6a, 0x41, 0xd7, 0x68, 0x0d, 0x1c, 0xf0, 0x1d, 0x70, 19 | 0xf5, 0x9b, 0x60, 0xd7, 0xf5, 0xf7, 0x7e, 0x30, 0xe7, 0x8b, 0x8b, 0xf9, 0xd2, 0xd8, 20 | 0x82, 0xf1, 0x56, 0xa6, 21 | ] 22 | .into(), 23 | ) 24 | .unwrap(), 25 | ) 26 | .unwrap() 27 | } 28 | 29 | fn test_scalar_z() -> FieldBytes { 30 | [ 31 | 0xe3, 0x35, 0x80, 0xeb, 0x6e, 0xd0, 0x22, 0xae, 0xd6, 0xaf, 0x20, 0xd9, 0x22, 0x37, 0x63, 32 | 0x5e, 0x7c, 0x20, 0xc5, 0xf1, 0xbc, 0xd6, 0xae, 0xe8, 0x81, 0x82, 0xed, 0x71, 0x80, 0xf6, 33 | 0xe2, 0x67, 34 | ] 35 | .into() 36 | } 37 | 38 | fn bench_ecdsa(c: &mut Criterion) { 39 | let mut group = c.benchmark_group("ecdsa"); 40 | 41 | let d = SigningKey::from(test_scalar_d()); 42 | let z = test_scalar_z(); 43 | 44 | group.bench_function("try_sign_prehashed", |b| { 45 | b.iter(|| { 46 | let _: Signature = black_box(&d).sign_prehash(&black_box(z)).unwrap(); 47 | }) 48 | }); 49 | 50 | let q = d.verifying_key(); 51 | let s: Signature = d.sign_prehash(&z).unwrap(); 52 | 53 | group.bench_function("verify_prehashed", |b| { 54 | b.iter(|| { 55 | black_box(q) 56 | .verify_prehash(&black_box(z), &black_box(s)) 57 | .unwrap() 58 | }) 59 | }); 60 | 61 | group.finish(); 62 | } 63 | 64 | criterion_group!(benches, bench_ecdsa); 65 | criterion_main!(benches); 66 | -------------------------------------------------------------------------------- /k256/benches/field.rs: -------------------------------------------------------------------------------- 1 | //! secp256k1 field element benchmarks 2 | 3 | use criterion::{ 4 | BenchmarkGroup, Criterion, criterion_group, criterion_main, measurement::Measurement, 5 | }; 6 | use k256::FieldElement; 7 | use std::hint::black_box; 8 | 9 | fn test_field_element_x() -> FieldElement { 10 | FieldElement::from_bytes( 11 | &[ 12 | 0xbb, 0x48, 0x8a, 0xef, 0x41, 0x6a, 0x41, 0xd7, 0x68, 0x0d, 0x1c, 0xf0, 0x1d, 0x70, 13 | 0xf5, 0x9b, 0x60, 0xd7, 0xf5, 0xf7, 0x7e, 0x30, 0xe7, 0x8b, 0x8b, 0xf9, 0xd2, 0xd8, 14 | 0x82, 0xf1, 0x56, 0xa6, 15 | ] 16 | .into(), 17 | ) 18 | .unwrap() 19 | } 20 | 21 | fn test_field_element_y() -> FieldElement { 22 | FieldElement::from_bytes( 23 | &[ 24 | 0x67, 0xe2, 0xf6, 0x80, 0x71, 0xed, 0x82, 0x81, 0xe8, 0xae, 0xd6, 0xbc, 0xf1, 0xc5, 25 | 0x20, 0x7c, 0x5e, 0x63, 0x37, 0x22, 0xd9, 0x20, 0xaf, 0xd6, 0xae, 0x22, 0xd0, 0x6e, 26 | 0xeb, 0x80, 0x35, 0xe3, 27 | ] 28 | .into(), 29 | ) 30 | .unwrap() 31 | } 32 | 33 | fn bench_field_element_normalize_weak<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { 34 | let x = test_field_element_x(); 35 | group.bench_function("normalize_weak", |b| { 36 | b.iter(|| black_box(x).normalize_weak()) 37 | }); 38 | } 39 | 40 | fn bench_field_element_normalize<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { 41 | let x = test_field_element_x(); 42 | group.bench_function("normalize", |b| b.iter(|| black_box(x).normalize())); 43 | } 44 | 45 | fn bench_field_element_mul<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { 46 | let x = test_field_element_x(); 47 | let y = test_field_element_y(); 48 | group.bench_function("mul", |b| b.iter(|| &black_box(x) * &black_box(y))); 49 | } 50 | 51 | fn bench_field_element_square<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { 52 | let x = test_field_element_x(); 53 | group.bench_function("square", |b| b.iter(|| black_box(x).square())); 54 | } 55 | 56 | fn bench_field_element_sqrt<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { 57 | let x = test_field_element_x(); 58 | group.bench_function("sqrt", |b| b.iter(|| black_box(x).sqrt())); 59 | } 60 | 61 | fn bench_field_element_invert<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { 62 | let x = test_field_element_x(); 63 | group.bench_function("invert", |b| b.iter(|| black_box(x).invert())); 64 | } 65 | 66 | fn bench_field_element(c: &mut Criterion) { 67 | let mut group = c.benchmark_group("field element operations"); 68 | bench_field_element_normalize_weak(&mut group); 69 | bench_field_element_normalize(&mut group); 70 | bench_field_element_mul(&mut group); 71 | bench_field_element_square(&mut group); 72 | bench_field_element_invert(&mut group); 73 | bench_field_element_sqrt(&mut group); 74 | group.finish(); 75 | } 76 | 77 | criterion_group!(benches, bench_field_element); 78 | criterion_main!(benches); 79 | -------------------------------------------------------------------------------- /k256/proptest-regressions/arithmetic/scalar.txt: -------------------------------------------------------------------------------- 1 | # Seeds for failure cases proptest has generated in the past. It is 2 | # automatically read and these particular cases re-run before any 3 | # novel cases are generated. 4 | # 5 | # It is recommended to check this file in to source control so that 6 | # everyone who runs the test benefits from these saved cases. 7 | cc 6511feae44fafd76e794999ecd3410c4a507306bbea8776dc08bb6f44160332a # shrinks to a = Scalar(Uint(0x0000000000000000000000000000000000000008000000000000000000000000)), b = 256 8 | -------------------------------------------------------------------------------- /k256/src/arithmetic.rs: -------------------------------------------------------------------------------- 1 | //! A pure-Rust implementation of group operations on secp256k1. 2 | 3 | pub(crate) mod affine; 4 | mod field; 5 | #[cfg(feature = "hash2curve")] 6 | mod hash2curve; 7 | mod mul; 8 | pub(crate) mod projective; 9 | pub(crate) mod scalar; 10 | 11 | #[cfg(test)] 12 | mod dev; 13 | 14 | pub use field::FieldElement; 15 | 16 | use self::{affine::AffinePoint, projective::ProjectivePoint, scalar::Scalar}; 17 | use crate::Secp256k1; 18 | use elliptic_curve::CurveArithmetic; 19 | 20 | impl CurveArithmetic for Secp256k1 { 21 | type AffinePoint = AffinePoint; 22 | type ProjectivePoint = ProjectivePoint; 23 | type Scalar = Scalar; 24 | } 25 | 26 | const CURVE_EQUATION_B_SINGLE: u32 = 7u32; 27 | 28 | #[rustfmt::skip] 29 | pub(crate) const CURVE_EQUATION_B: FieldElement = FieldElement::from_bytes_unchecked(&[ 30 | 0, 0, 0, 0, 0, 0, 0, 0, 31 | 0, 0, 0, 0, 0, 0, 0, 0, 32 | 0, 0, 0, 0, 0, 0, 0, 0, 33 | 0, 0, 0, 0, 0, 0, 0, CURVE_EQUATION_B_SINGLE as u8, 34 | ]); 35 | 36 | #[cfg(test)] 37 | mod tests { 38 | use super::CURVE_EQUATION_B; 39 | use hex_literal::hex; 40 | 41 | const CURVE_EQUATION_B_BYTES: [u8; 32] = 42 | hex!("0000000000000000000000000000000000000000000000000000000000000007"); 43 | 44 | #[test] 45 | fn verify_constants() { 46 | assert_eq!(CURVE_EQUATION_B.to_bytes(), CURVE_EQUATION_B_BYTES); 47 | } 48 | 49 | #[test] 50 | fn generate_secret_key() { 51 | use crate::SecretKey; 52 | use elliptic_curve::rand_core::{OsRng, TryRngCore}; 53 | let key = SecretKey::random(&mut OsRng.unwrap_mut()); 54 | 55 | // Sanity check 56 | assert!(!key.to_bytes().iter().all(|b| *b == 0)) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /k256/src/arithmetic/dev.rs: -------------------------------------------------------------------------------- 1 | //! Development helper functions. 2 | 3 | use num_bigint::{BigUint, ToBigUint}; 4 | use num_traits::cast::ToPrimitive; 5 | 6 | /// Converts a byte array (big-endian) to BigUint. 7 | pub fn bytes_to_biguint(bytes: &[u8; 32]) -> BigUint { 8 | bytes 9 | .iter() 10 | .enumerate() 11 | .map(|(i, w)| w.to_biguint().unwrap() << ((31 - i) * 8)) 12 | .sum() 13 | } 14 | 15 | /// Converts a BigUint to a byte array (big-endian). 16 | pub fn biguint_to_bytes(x: &BigUint) -> [u8; 32] { 17 | let mask = BigUint::from(u8::MAX); 18 | let mut bytes = [0u8; 32]; 19 | for i in 0..32 { 20 | bytes[i] = ((x >> ((31 - i) * 8)) as BigUint & &mask).to_u8().unwrap(); 21 | } 22 | bytes 23 | } 24 | -------------------------------------------------------------------------------- /k256/src/ecdh.rs: -------------------------------------------------------------------------------- 1 | //! Elliptic Curve Diffie-Hellman (Ephemeral) Support. 2 | //! 3 | //! This module contains a high-level interface for performing ephemeral 4 | //! Diffie-Hellman key exchanges using the secp256k1 elliptic curve. 5 | //! 6 | //! # Usage 7 | //! 8 | //! This usage example is from the perspective of two participants in the 9 | //! exchange, nicknamed "Alice" and "Bob". 10 | //! 11 | //! ``` 12 | //! use k256::{EncodedPoint, PublicKey, ecdh::EphemeralSecret}; 13 | //! use rand_core::{OsRng, TryRngCore}; // requires 'os_rng' feature 14 | //! 15 | //! // Alice 16 | //! let alice_secret = EphemeralSecret::try_from_rng(&mut OsRng).unwrap(); 17 | //! let alice_pk_bytes = EncodedPoint::from(alice_secret.public_key()); 18 | //! 19 | //! // Bob 20 | //! let bob_secret = EphemeralSecret::try_from_rng(&mut OsRng).unwrap(); 21 | //! let bob_pk_bytes = EncodedPoint::from(bob_secret.public_key()); 22 | //! 23 | //! // Alice decodes Bob's serialized public key and computes a shared secret from it 24 | //! let bob_public = PublicKey::from_sec1_bytes(bob_pk_bytes.as_ref()) 25 | //! .expect("bob's public key is invalid!"); // In real usage, don't panic, handle this! 26 | //! 27 | //! let alice_shared = alice_secret.diffie_hellman(&bob_public); 28 | //! 29 | //! // Bob decodes Alice's serialized public key and computes the same shared secret 30 | //! let alice_public = PublicKey::from_sec1_bytes(alice_pk_bytes.as_ref()) 31 | //! .expect("alice's public key is invalid!"); // In real usage, don't panic, handle this! 32 | //! 33 | //! let bob_shared = bob_secret.diffie_hellman(&alice_public); 34 | //! 35 | //! // Both participants arrive on the same shared secret 36 | //! assert_eq!(alice_shared.raw_secret_bytes(), bob_shared.raw_secret_bytes()); 37 | //! ``` 38 | 39 | pub use elliptic_curve::ecdh::diffie_hellman; 40 | 41 | use crate::{AffinePoint, Secp256k1}; 42 | 43 | /// secp256k1 Ephemeral Diffie-Hellman Secret. 44 | pub type EphemeralSecret = elliptic_curve::ecdh::EphemeralSecret; 45 | 46 | /// Shared secret value computed via ECDH key agreement. 47 | pub type SharedSecret = elliptic_curve::ecdh::SharedSecret; 48 | 49 | impl From<&AffinePoint> for SharedSecret { 50 | fn from(affine: &AffinePoint) -> SharedSecret { 51 | affine.x.to_bytes().into() 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /k256/src/test_vectors.rs: -------------------------------------------------------------------------------- 1 | //! secp256k1 test vectors 2 | 3 | #[cfg(test)] 4 | pub mod ecdsa; 5 | pub mod field; 6 | pub mod group; 7 | -------------------------------------------------------------------------------- /k256/src/test_vectors/data/wycheproof-p1316.blb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RustCrypto/elliptic-curves/d317ce8100dc09416901d50b223ba45f39549568/k256/src/test_vectors/data/wycheproof-p1316.blb -------------------------------------------------------------------------------- /k256/src/test_vectors/data/wycheproof.blb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RustCrypto/elliptic-curves/d317ce8100dc09416901d50b223ba45f39549568/k256/src/test_vectors/data/wycheproof.blb -------------------------------------------------------------------------------- /k256/src/test_vectors/ecdsa.rs: -------------------------------------------------------------------------------- 1 | //! ECDSA/secp256k1 test vectors 2 | 3 | use ecdsa_core::dev::TestVector; 4 | use hex_literal::hex; 5 | 6 | /// ECDSA/secp256k1 test vectors 7 | pub const ECDSA_TEST_VECTORS: &[TestVector] = &[TestVector { 8 | d: &hex!("ebb2c082fd7727890a28ac82f6bdf97bad8de9f5d7c9028692de1a255cad3e0f"), 9 | q_x: &hex!("779dd197a5df977ed2cf6cb31d82d43328b790dc6b3b7d4437a427bd5847dfcd"), 10 | q_y: &hex!("e94b724a555b6d017bb7607c3e3281daf5b1699d6ef4124975c9237b917d426f"), 11 | k: &hex!("49a0d7b786ec9cde0d0721d72804befd06571c974b191efb42ecf322ba9ddd9a"), 12 | m: &hex!("4b688df40bcedbe641ddb16ff0a1842d9c67ea1c3bf63f3e0471baa664531d1a"), 13 | r: &hex!("241097efbf8b63bf145c8961dbdf10c310efbb3b2676bbc0f8b08505c9e2f795"), 14 | s: &hex!("021006b7838609339e8b415a7f9acb1b661828131aef1ecbc7955dfb01f3ca0e"), 15 | }]; 16 | -------------------------------------------------------------------------------- /p192/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## 0.14.0 (UNRELEASED) 8 | ### Added 9 | - `bits` feature ([#868]) 10 | - `elliptic_curve::ops::Invert` implementation ([#971]) 11 | 12 | ## Changed 13 | - Update to `elliptic-curve` v0.14 ([#1011]) 14 | - Update to `ecdsa` v0.17 ([#1011]) 15 | - Update to `sec1` v0.8 ([#1011]) 16 | - Update to `secdect` v0.3 ([#1084]) 17 | - Update to `rand_core` v0.9 ([#1125]) 18 | - Update to `hybrid-array` v0.3 ([#1125]) 19 | - Edition changed to 2024 and MSRV bumped to 1.85 ([#1125]) 20 | - Relax MSRV policy and allow MSRV bumps in patch releases 21 | 22 | [#868]: https://github.com/RustCrypto/elliptic-curves/pull/868 23 | [#971]: https://github.com/RustCrypto/elliptic-curves/pull/971 24 | [#1011]: https://github.com/RustCrypto/elliptic-curves/pull/1011 25 | [#1084]: https://github.com/RustCrypto/elliptic-curves/pull/1084 26 | [#1125]: https://github.com/RustCrypto/elliptic-curves/pull/1125 27 | 28 | ## 0.13.0 (2023-04-15) 29 | - Initial release 30 | -------------------------------------------------------------------------------- /p192/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "p192" 3 | version = "0.14.0-pre" 4 | description = """ 5 | Pure Rust implementation of the NIST P-192 (a.k.a. secp192r1) elliptic curve 6 | as defined in SP 800-186 7 | """ 8 | authors = ["RustCrypto Developers"] 9 | license = "Apache-2.0 OR MIT" 10 | documentation = "https://docs.rs/p192" 11 | homepage = "https://github.com/RustCrypto/elliptic-curves/tree/master/p192" 12 | repository = "https://github.com/RustCrypto/elliptic-curves" 13 | readme = "README.md" 14 | categories = ["cryptography", "no-std"] 15 | keywords = ["crypto", "ecc", "nist", "secp192r1"] 16 | edition = "2024" 17 | rust-version = "1.85" 18 | 19 | [dependencies] 20 | elliptic-curve = { version = "0.14.0-rc.5", default-features = false, features = ["sec1"] } 21 | sec1 = { version = "0.8.0-rc.1", default-features = false } 22 | 23 | # optional dependencies 24 | ecdsa-core = { version = "0.17.0-rc.0", package = "ecdsa", optional = true, default-features = false, features = ["der"] } 25 | hex-literal = { version = "1", optional = true } 26 | primefield = { version = "=0.14.0-pre.2", optional = true } 27 | primeorder = { version = "=0.14.0-pre.4", optional = true } 28 | serdect = { version = "0.3", optional = true, default-features = false } 29 | 30 | [dev-dependencies] 31 | ecdsa-core = { version = "0.17.0-rc.0", package = "ecdsa", default-features = false, features = ["dev"] } 32 | hex-literal = "1" 33 | primeorder = { version = "=0.14.0-pre.4", features = ["dev"] } 34 | 35 | [features] 36 | default = ["arithmetic", "ecdsa", "pem", "std"] 37 | alloc = ["elliptic-curve/alloc", "primeorder?/alloc"] 38 | std = ["alloc", "elliptic-curve/std"] 39 | 40 | arithmetic = ["dep:primefield", "dep:primeorder", "elliptic-curve/arithmetic"] 41 | bits = ["arithmetic", "elliptic-curve/bits"] 42 | digest = ["ecdsa-core/digest", "ecdsa-core/hazmat"] 43 | ecdsa = ["arithmetic", "ecdsa-core/signing", "ecdsa-core/verifying"] 44 | pem = ["elliptic-curve/pem", "pkcs8"] 45 | pkcs8 = ["elliptic-curve/pkcs8"] 46 | serde = ["elliptic-curve/serde", "primeorder?/serde", "serdect"] 47 | test-vectors = ["hex-literal"] 48 | 49 | [package.metadata.docs.rs] 50 | all-features = true 51 | rustdoc-args = ["--cfg", "docsrs"] 52 | -------------------------------------------------------------------------------- /p192/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2023 RustCrypto Developers 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /p192/src/arithmetic.rs: -------------------------------------------------------------------------------- 1 | //! Pure Rust implementation of group operations on secp192r1. 2 | //! 3 | //! Curve parameters can be found in [FIPS 186-4] § D.1.2.1: Curve P-192. 4 | //! 5 | //! [FIPS 186-4]: https://csrc.nist.gov/publications/detail/fips/186/4/final 6 | 7 | pub(crate) mod field; 8 | pub(crate) mod scalar; 9 | 10 | use self::{field::FieldElement, scalar::Scalar}; 11 | use crate::NistP192; 12 | use elliptic_curve::{CurveArithmetic, PrimeCurveArithmetic}; 13 | use primeorder::{PrimeCurveParams, point_arithmetic}; 14 | 15 | /// Elliptic curve point in affine coordinates. 16 | pub type AffinePoint = primeorder::AffinePoint; 17 | 18 | /// Elliptic curve point in projective coordinates. 19 | pub type ProjectivePoint = primeorder::ProjectivePoint; 20 | 21 | impl CurveArithmetic for NistP192 { 22 | type AffinePoint = AffinePoint; 23 | type ProjectivePoint = ProjectivePoint; 24 | type Scalar = Scalar; 25 | } 26 | 27 | impl PrimeCurveArithmetic for NistP192 { 28 | type CurveGroup = ProjectivePoint; 29 | } 30 | 31 | /// Adapted from [FIPS 186-4] § D.1.2.1: Curve P-192. 32 | /// 33 | /// [FIPS 186-4]: https://csrc.nist.gov/publications/detail/fips/186/4/final 34 | impl PrimeCurveParams for NistP192 { 35 | type FieldElement = FieldElement; 36 | type PointArithmetic = point_arithmetic::EquationAIsMinusThree; 37 | 38 | /// a = -3 (=0xffffffff ffffffff ffffffff fffffffe ffffffff ffffffff fffffffe) 39 | const EQUATION_A: FieldElement = FieldElement::from_u64(3).neg(); 40 | 41 | /// b = 0x64210519 e59c80e7 0fa7e9ab 72243049 feb8deec c146b9b1 42 | const EQUATION_B: FieldElement = 43 | FieldElement::from_hex("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1"); 44 | 45 | /// Base point of P-192. 46 | /// 47 | /// ```text 48 | /// Gₓ = 0x188da80e b03090f6 7cbf20eb 43a18800 f4ff0afd 82ff1012 49 | /// Gᵧ = 0x07192b95 ffc8da78 631011ed 6b24cdd5 73f977a1 1e794811 50 | /// ``` 51 | const GENERATOR: (FieldElement, FieldElement) = ( 52 | FieldElement::from_hex("188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012"), 53 | FieldElement::from_hex("07192b95ffc8da78631011ed6b24cdd573f977a11e794811"), 54 | ); 55 | } 56 | -------------------------------------------------------------------------------- /p192/src/ecdsa.rs: -------------------------------------------------------------------------------- 1 | //! Elliptic Curve Digital Signature Algorithm (ECDSA) 2 | //! 3 | //! This module contains support for computing and verifying ECDSA signatures. 4 | //! To use it, you will need to enable one of the two following Cargo features: 5 | //! 6 | //! - `ecdsa-core`: provides only the [`Signature`] type (which represents an 7 | //! ECDSA/P-192 signature). Does not require the `arithmetic` feature. This is 8 | //! useful for 3rd-party crates which wish to use the `Signature` type for 9 | //! interoperability purposes. Example use cases for this include other 10 | //! software implementations of ECDSA/P-192 and wrappers for cloud KMS 11 | //! services or hardware devices (HSM or crypto hardware wallet). 12 | //! - `ecdsa`: provides `ecdsa-core` features plus [`VerifyingKey`] types 13 | //! which natively implement ECDSA/P-192 verification. 14 | //! 15 | //! ## Verification only 16 | //! 17 | //! Following guidance from [NIST Special Publication 800-131A Revision 2]: 18 | //! "Transitioning the Use of Cryptographic Algorithms and Key Lengths", this 19 | //! crate only supports ECDSA verification, not signing. 20 | //! 21 | //! From Section 3: Digital Signatures: 22 | //! 23 | //! > <112 bits of security strength: ECDSA: len(n) < 224 24 | //! > 25 | //! > [...] 26 | //! > 27 | //! > Digital signature generation: 28 | //! > 29 | //! > Private-key lengths providing less than 112 bits of security **shall not** be used to 30 | //! > generate digital signatures. 31 | //! 32 | //! [NIST Special Publication 800-131A Revision 2]: https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar2.pdf 33 | 34 | pub use ecdsa_core::signature::{self, Error}; 35 | 36 | use super::NistP192; 37 | use ecdsa_core::EcdsaCurve; 38 | 39 | /// ECDSA/P-192 signature (fixed-size) 40 | pub type Signature = ecdsa_core::Signature; 41 | 42 | /// ECDSA/P-192 signature (ASN.1 DER encoded) 43 | pub type DerSignature = ecdsa_core::der::Signature; 44 | 45 | impl EcdsaCurve for NistP192 { 46 | const NORMALIZE_S: bool = false; 47 | } 48 | 49 | /// ECDSA/P-192 verification key (i.e. public key) 50 | #[cfg(feature = "ecdsa")] 51 | pub type VerifyingKey = ecdsa_core::VerifyingKey; 52 | 53 | #[cfg(all(test, feature = "ecdsa"))] 54 | mod tests { 55 | mod verify { 56 | use crate::{NistP192, test_vectors::ecdsa::ECDSA_TEST_VECTORS}; 57 | ecdsa_core::new_verification_test!(NistP192, ECDSA_TEST_VECTORS); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /p192/src/test_vectors.rs: -------------------------------------------------------------------------------- 1 | //! secp192r1 test vectors. 2 | 3 | #[cfg(test)] 4 | pub mod ecdsa; 5 | pub mod group; 6 | -------------------------------------------------------------------------------- /p192/tests/projective.rs: -------------------------------------------------------------------------------- 1 | //! Projective arithmetic tests. 2 | 3 | #![cfg(all(feature = "arithmetic", feature = "test-vectors"))] 4 | 5 | use elliptic_curve::{ 6 | group::ff::PrimeField, 7 | sec1::{self, ToEncodedPoint}, 8 | }; 9 | use p192::{ 10 | AffinePoint, ProjectivePoint, Scalar, 11 | test_vectors::group::{ADD_TEST_VECTORS, MUL_TEST_VECTORS}, 12 | }; 13 | use primeorder::{Double, test_projective_arithmetic}; 14 | 15 | test_projective_arithmetic!( 16 | AffinePoint, 17 | ProjectivePoint, 18 | Scalar, 19 | ADD_TEST_VECTORS, 20 | MUL_TEST_VECTORS 21 | ); 22 | -------------------------------------------------------------------------------- /p224/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## 0.14.0 (UNRELEASED) 8 | ### Added 9 | - `bits` feature ([#868]) 10 | - `Scalar::sqrt` implementation ([#904]) 11 | - `elliptic_curve::ops::Invert` implementation ([#971]) 12 | 13 | ## Changed 14 | - Update to `elliptic-curve` v0.14 ([#1011]) 15 | - Update to `ecdsa` v0.17 ([#1011]) 16 | - Update to `sec1` v0.8 ([#1011]) 17 | - Update to `secdect` v0.3 ([#1084]) 18 | - Update to `rand_core` v0.9 ([#1125]) 19 | - Update to `hybrid-array` v0.3 ([#1125]) 20 | - Edition changed to 2024 and MSRV bumped to 1.85 ([#1125]) 21 | - Relax MSRV policy and allow MSRV bumps in patch releases 22 | 23 | [#868]: https://github.com/RustCrypto/elliptic-curves/pull/868 24 | [#904]: https://github.com/RustCrypto/elliptic-curves/pull/904 25 | [#971]: https://github.com/RustCrypto/elliptic-curves/pull/971 26 | [#1011]: https://github.com/RustCrypto/elliptic-curves/pull/1011 27 | [#1084]: https://github.com/RustCrypto/elliptic-curves/pull/1084 28 | [#1125]: https://github.com/RustCrypto/elliptic-curves/pull/1125 29 | 30 | ## 0.13.2 (2023-04-15) 31 | ### Changed 32 | - Enable `arithmetic` and `ecdsa` by default ([#833]) 33 | 34 | ### Fixed 35 | - Have `serde` feature enable `primeorder/serde` ([#851]) 36 | 37 | [#833]: https://github.com/RustCrypto/elliptic-curves/pull/833 38 | [#851]: https://github.com/RustCrypto/elliptic-curves/pull/851 39 | 40 | ## 0.13.1 (2023-04-09) 41 | ### Added 42 | - Projective arithmetic tests ([#813]) 43 | - `ecdh` feature ([#814]) 44 | - `arithmetic` feature ([#815]) 45 | - `ecdsa` feature ([#816]) 46 | - FIPS 186-4 ECDSA test vectors ([#817]) 47 | - Wycheproof test vectors ([#818]) 48 | - Bump `primeorder` to v0.13.1 ([#819]) 49 | 50 | ### Changed 51 | - Better `Debug` for field elements ([#798]) 52 | - Make `primeorder` dependency optional ([#799]) 53 | 54 | [#798]: https://github.com/RustCrypto/elliptic-curves/pull/798 55 | [#799]: https://github.com/RustCrypto/elliptic-curves/pull/799 56 | [#813]: https://github.com/RustCrypto/elliptic-curves/pull/813 57 | [#814]: https://github.com/RustCrypto/elliptic-curves/pull/814 58 | [#815]: https://github.com/RustCrypto/elliptic-curves/pull/815 59 | [#816]: https://github.com/RustCrypto/elliptic-curves/pull/816 60 | [#817]: https://github.com/RustCrypto/elliptic-curves/pull/817 61 | [#818]: https://github.com/RustCrypto/elliptic-curves/pull/818 62 | [#819]: https://github.com/RustCrypto/elliptic-curves/pull/819 63 | 64 | ## 0.13.0 (2023-03-03) 65 | - Initial release 66 | -------------------------------------------------------------------------------- /p224/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "p224" 3 | version = "0.14.0-pre" 4 | description = """ 5 | Pure Rust implementation of the NIST P-224 (a.k.a. secp224r1) elliptic curve 6 | as defined in SP 800-186 7 | """ 8 | authors = ["RustCrypto Developers"] 9 | license = "Apache-2.0 OR MIT" 10 | documentation = "https://docs.rs/p224" 11 | homepage = "https://github.com/RustCrypto/elliptic-curves/tree/master/p224" 12 | repository = "https://github.com/RustCrypto/elliptic-curves" 13 | readme = "README.md" 14 | categories = ["cryptography", "no-std"] 15 | keywords = ["crypto", "ecc", "nist", "secp224r1"] 16 | edition = "2024" 17 | rust-version = "1.85" 18 | 19 | [dependencies] 20 | elliptic-curve = { version = "0.14.0-rc.5", default-features = false, features = ["sec1"] } 21 | 22 | # optional dependencies 23 | ecdsa-core = { version = "0.17.0-rc.0", package = "ecdsa", optional = true, default-features = false, features = ["der"] } 24 | hex-literal = { version = "1", optional = true } 25 | primefield = { version = "=0.14.0-pre.2", optional = true } 26 | primeorder = { version = "=0.14.0-pre.4", optional = true } 27 | serdect = { version = "0.3", optional = true, default-features = false } 28 | sha2 = { version = "0.11.0-rc.0", optional = true, default-features = false } 29 | 30 | [dev-dependencies] 31 | blobby = "0.3" 32 | ecdsa-core = { version = "0.17.0-rc.0", package = "ecdsa", default-features = false, features = ["dev"] } 33 | hex-literal = "1" 34 | primeorder = { version = "=0.14.0-pre.4", features = ["dev"] } 35 | rand_core = { version = "0.9", features = ["os_rng"] } 36 | 37 | [features] 38 | default = ["arithmetic", "ecdsa", "pem", "std"] 39 | alloc = ["elliptic-curve/alloc", "primeorder?/alloc"] 40 | std = ["alloc", "elliptic-curve/std"] 41 | 42 | arithmetic = ["dep:primefield", "dep:primeorder", "elliptic-curve/arithmetic"] 43 | bits = ["arithmetic", "elliptic-curve/bits"] 44 | digest = ["ecdsa-core/digest", "ecdsa-core/hazmat"] 45 | ecdh = ["arithmetic", "elliptic-curve/ecdh"] 46 | ecdsa = ["arithmetic", "ecdsa-core/signing", "ecdsa-core/verifying", "sha224"] 47 | pem = ["elliptic-curve/pem", "pkcs8"] 48 | pkcs8 = ["ecdsa-core?/pkcs8", "elliptic-curve/pkcs8"] 49 | serde = ["ecdsa-core?/serde", "elliptic-curve/serde", "primeorder?/serde", "serdect"] 50 | sha224 = ["digest", "sha2"] 51 | test-vectors = ["dep:hex-literal"] 52 | 53 | [package.metadata.docs.rs] 54 | all-features = true 55 | rustdoc-args = ["--cfg", "docsrs"] 56 | -------------------------------------------------------------------------------- /p224/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2023 RustCrypto Developers 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /p224/README.md: -------------------------------------------------------------------------------- 1 | # [RustCrypto]: NIST P-224 (secp224r1) elliptic curve 2 | 3 | [![crate][crate-image]][crate-link] 4 | [![Docs][docs-image]][docs-link] 5 | [![Build Status][build-image]][build-link] 6 | ![Apache2/MIT licensed][license-image] 7 | ![Rust Version][rustc-image] 8 | [![Project Chat][chat-image]][chat-link] 9 | 10 | Pure Rust implementation of the NIST P-224 (a.k.a. secp224r1) elliptic curve 11 | with support for ECDH, ECDSA signing/verification, and general purpose curve 12 | arithmetic support implemented in terms of traits from the [`elliptic-curve`] 13 | crate. 14 | 15 | [Documentation][docs-link] 16 | 17 | ## ⚠️ Security Warning 18 | 19 | The elliptic curve arithmetic contained in this crate has never been 20 | independently audited! 21 | 22 | This crate has been designed with the goal of ensuring that secret-dependent 23 | operations are performed in constant time (using the `subtle` crate and 24 | constant-time formulas). However, it has not been thoroughly assessed to ensure 25 | that generated assembly is constant time on common CPU architectures. 26 | 27 | USE AT YOUR OWN RISK! 28 | 29 | ## Supported Algorithms 30 | 31 | - [Elliptic Curve Diffie-Hellman (ECDH)][ECDH]: gated under the `ecdh` feature. 32 | - [Elliptic Curve Digital Signature Algorithm (ECDSA)][ECDSA]: gated under the 33 | `ecdsa` feature. 34 | 35 | ## About P-224 36 | 37 | NIST P-224 is a Weierstrass curve specified in [SP 800-186]: 38 | Recommendations for Discrete Logarithm-based Cryptography: 39 | Elliptic Curve Domain Parameters. 40 | 41 | Also known as secp224r1 (SECG). 42 | 43 | ## License 44 | 45 | All crates licensed under either of 46 | 47 | * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) 48 | * [MIT license](http://opensource.org/licenses/MIT) 49 | 50 | at your option. 51 | 52 | ### Contribution 53 | 54 | Unless you explicitly state otherwise, any contribution intentionally submitted 55 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall be 56 | dual licensed as above, without any additional terms or conditions. 57 | 58 | [//]: # (badges) 59 | 60 | [crate-image]: https://img.shields.io/crates/v/p224?logo=rust 61 | [crate-link]: https://crates.io/crates/p224 62 | [docs-image]: https://docs.rs/p224/badge.svg 63 | [docs-link]: https://docs.rs/p224/ 64 | [build-image]: https://github.com/RustCrypto/elliptic-curves/actions/workflows/p224.yml/badge.svg 65 | [build-link]: https://github.com/RustCrypto/elliptic-curves/actions/workflows/p224.yml 66 | [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg 67 | [rustc-image]: https://img.shields.io/badge/rustc-1.85+-blue.svg 68 | [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg 69 | [chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/260040-elliptic-curves 70 | 71 | [//]: # (general links) 72 | 73 | [RustCrypto]: https://github.com/rustcrypto/ 74 | [`elliptic-curve`]: https://github.com/RustCrypto/traits/tree/master/elliptic-curve 75 | [ECDH]: https://en.wikipedia.org/wiki/Elliptic-curve_Diffie-Hellman 76 | [ECDSA]: https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm 77 | [SP 800-186]: https://csrc.nist.gov/publications/detail/sp/800-186/final 78 | -------------------------------------------------------------------------------- /p224/src/ecdh.rs: -------------------------------------------------------------------------------- 1 | //! Elliptic Curve Diffie-Hellman (Ephemeral) Support. 2 | //! 3 | //! This module contains a high-level interface for performing ephemeral 4 | //! Diffie-Hellman key exchanges using the secp224r1 elliptic curve. 5 | //! 6 | //! # Usage 7 | //! 8 | //! This usage example is from the perspective of two participants in the 9 | //! exchange, nicknamed "Alice" and "Bob". 10 | //! 11 | //! ``` 12 | //! use p224::{EncodedPoint, PublicKey, ecdh::EphemeralSecret}; 13 | //! use rand_core::OsRng; // requires 'os_rng' feature 14 | //! 15 | //! // Alice 16 | //! let alice_secret = EphemeralSecret::try_from_rng(&mut OsRng).unwrap(); 17 | //! let alice_pk_bytes = EncodedPoint::from(alice_secret.public_key()); 18 | //! 19 | //! // Bob 20 | //! let bob_secret = EphemeralSecret::try_from_rng(&mut OsRng).unwrap(); 21 | //! let bob_pk_bytes = EncodedPoint::from(bob_secret.public_key()); 22 | //! 23 | //! // Alice decodes Bob's serialized public key and computes a shared secret from it 24 | //! let bob_public = PublicKey::from_sec1_bytes(bob_pk_bytes.as_ref()) 25 | //! .expect("bob's public key is invalid!"); // In real usage, don't panic, handle this! 26 | //! 27 | //! let alice_shared = alice_secret.diffie_hellman(&bob_public); 28 | //! 29 | //! // Bob decodes Alice's serialized public key and computes the same shared secret 30 | //! let alice_public = PublicKey::from_sec1_bytes(alice_pk_bytes.as_ref()) 31 | //! .expect("alice's public key is invalid!"); // In real usage, don't panic, handle this! 32 | //! 33 | //! let bob_shared = bob_secret.diffie_hellman(&alice_public); 34 | //! 35 | //! // Both participants arrive on the same shared secret 36 | //! assert_eq!(alice_shared.raw_secret_bytes(), bob_shared.raw_secret_bytes()); 37 | //! ``` 38 | 39 | pub use elliptic_curve::ecdh::diffie_hellman; 40 | 41 | use crate::NistP224; 42 | 43 | /// NIST P-224 Ephemeral Diffie-Hellman Secret. 44 | pub type EphemeralSecret = elliptic_curve::ecdh::EphemeralSecret; 45 | 46 | /// Shared secret value computed via ECDH key agreement. 47 | pub type SharedSecret = elliptic_curve::ecdh::SharedSecret; 48 | -------------------------------------------------------------------------------- /p224/src/test_vectors.rs: -------------------------------------------------------------------------------- 1 | //! secp224r1 test vectors. 2 | 3 | #[cfg(test)] 4 | pub mod ecdsa; 5 | pub mod group; 6 | -------------------------------------------------------------------------------- /p224/src/test_vectors/data/wycheproof.blb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RustCrypto/elliptic-curves/d317ce8100dc09416901d50b223ba45f39549568/p224/src/test_vectors/data/wycheproof.blb -------------------------------------------------------------------------------- /p224/tests/projective.rs: -------------------------------------------------------------------------------- 1 | //! Projective arithmetic tests. 2 | 3 | #![cfg(all(feature = "arithmetic", feature = "test-vectors"))] 4 | 5 | use elliptic_curve::{ 6 | group::ff::PrimeField, 7 | sec1::{self, ToEncodedPoint}, 8 | }; 9 | use p224::{ 10 | AffinePoint, ProjectivePoint, Scalar, 11 | test_vectors::group::{ADD_TEST_VECTORS, MUL_TEST_VECTORS}, 12 | }; 13 | use primeorder::{Double, test_projective_arithmetic}; 14 | 15 | test_projective_arithmetic!( 16 | AffinePoint, 17 | ProjectivePoint, 18 | Scalar, 19 | ADD_TEST_VECTORS, 20 | MUL_TEST_VECTORS 21 | ); 22 | -------------------------------------------------------------------------------- /p256/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "p256" 3 | version = "0.14.0-pre.5" 4 | description = """ 5 | Pure Rust implementation of the NIST P-256 (a.k.a. secp256r1, prime256v1) 6 | elliptic curve as defined in SP 800-186, with support for ECDH, ECDSA 7 | signing/verification, and general purpose curve arithmetic 8 | """ 9 | authors = ["RustCrypto Developers"] 10 | license = "Apache-2.0 OR MIT" 11 | documentation = "https://docs.rs/p256" 12 | homepage = "https://github.com/RustCrypto/elliptic-curves/tree/master/p256" 13 | repository = "https://github.com/RustCrypto/elliptic-curves" 14 | readme = "README.md" 15 | categories = ["cryptography", "no-std"] 16 | keywords = ["crypto", "ecc", "nist", "prime256v1", "secp256r1"] 17 | edition = "2024" 18 | rust-version = "1.85" 19 | 20 | [dependencies] 21 | elliptic-curve = { version = "0.14.0-rc.5", default-features = false, features = ["sec1"] } 22 | 23 | # optional dependencies 24 | ecdsa-core = { version = "0.17.0-rc.0", package = "ecdsa", optional = true, default-features = false, features = ["der"] } 25 | hex-literal = { version = "1", optional = true } 26 | primefield = { version = "=0.14.0-pre.2", optional = true } 27 | primeorder = { version = "=0.14.0-pre.4", optional = true } 28 | serdect = { version = "0.3", optional = true, default-features = false } 29 | sha2 = { version = "0.11.0-rc.0", optional = true, default-features = false } 30 | 31 | [dev-dependencies] 32 | blobby = "0.3" 33 | criterion = "0.6" 34 | ecdsa-core = { version = "0.17.0-rc.0", package = "ecdsa", default-features = false, features = ["dev"] } 35 | hex-literal = "1" 36 | primefield = { version = "=0.14.0-pre.2" } 37 | primeorder = { version = "=0.14.0-pre.4", features = ["dev"] } 38 | proptest = "1" 39 | rand_core = { version = "0.9", features = ["os_rng"] } 40 | 41 | [features] 42 | default = ["arithmetic", "ecdsa", "pem", "std"] 43 | alloc = ["ecdsa-core?/alloc", "elliptic-curve/alloc", "primeorder?/alloc"] 44 | std = ["alloc", "ecdsa-core?/std", "elliptic-curve/std"] 45 | 46 | arithmetic = ["dep:primefield", "dep:primeorder", "elliptic-curve/arithmetic"] 47 | bits = ["arithmetic", "elliptic-curve/bits"] 48 | digest = ["ecdsa-core/digest", "ecdsa-core/hazmat"] 49 | ecdh = ["arithmetic", "elliptic-curve/ecdh"] 50 | ecdsa = ["arithmetic", "ecdsa-core/signing", "ecdsa-core/verifying", "sha256"] 51 | expose-field = ["arithmetic"] 52 | hash2curve = ["arithmetic", "elliptic-curve/hash2curve"] 53 | jwk = ["elliptic-curve/jwk"] 54 | oprf = ["hash2curve", "elliptic-curve/oprf", "sha2"] 55 | pem = ["elliptic-curve/pem", "ecdsa-core/pem", "pkcs8"] 56 | pkcs8 = ["ecdsa-core?/pkcs8", "elliptic-curve/pkcs8"] 57 | serde = ["ecdsa-core?/serde", "elliptic-curve/serde", "primeorder?/serde", "serdect"] 58 | sha256 = ["digest", "sha2"] 59 | test-vectors = ["dep:hex-literal"] 60 | 61 | [package.metadata.docs.rs] 62 | all-features = true 63 | rustdoc-args = ["--cfg", "docsrs"] 64 | 65 | [[bench]] 66 | name = "field" 67 | harness = false 68 | required-features = ["expose-field"] 69 | 70 | [[bench]] 71 | name = "scalar" 72 | harness = false 73 | -------------------------------------------------------------------------------- /p256/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020-2023 RustCrypto Developers 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /p256/benches/field.rs: -------------------------------------------------------------------------------- 1 | //! secp256r1 field element benchmarks 2 | 3 | use criterion::{ 4 | BenchmarkGroup, Criterion, criterion_group, criterion_main, measurement::Measurement, 5 | }; 6 | use hex_literal::hex; 7 | use p256::FieldElement; 8 | 9 | fn test_field_element_x() -> FieldElement { 10 | FieldElement::from_bytes( 11 | hex!("1ccbe91c075fc7f4f033bfa248db8fccd3565de94bbfb12f3c59ff46c271bf83").as_ref(), 12 | ) 13 | .unwrap() 14 | } 15 | 16 | fn test_field_element_y() -> FieldElement { 17 | FieldElement::from_bytes( 18 | hex!("ce4014c68811f9a21a1fdb2c0e6113e06db7ca93b7404e78dc7ccd5ca89a4ca9").as_ref(), 19 | ) 20 | .unwrap() 21 | } 22 | 23 | fn bench_field_element_mul<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { 24 | let x = test_field_element_x(); 25 | let y = test_field_element_y(); 26 | group.bench_function("mul", |b| b.iter(|| &x * &y)); 27 | } 28 | 29 | fn bench_field_element_square<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { 30 | let x = test_field_element_x(); 31 | group.bench_function("square", |b| b.iter(|| x.square())); 32 | } 33 | 34 | fn bench_field_element_sqrt<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { 35 | let x = test_field_element_x(); 36 | group.bench_function("sqrt", |b| b.iter(|| x.sqrt())); 37 | } 38 | 39 | fn bench_field_element_invert<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { 40 | let x = test_field_element_x(); 41 | group.bench_function("invert", |b| b.iter(|| x.invert())); 42 | } 43 | 44 | fn bench_field_element(c: &mut Criterion) { 45 | let mut group = c.benchmark_group("field element operations"); 46 | bench_field_element_mul(&mut group); 47 | bench_field_element_square(&mut group); 48 | bench_field_element_invert(&mut group); 49 | bench_field_element_sqrt(&mut group); 50 | group.finish(); 51 | } 52 | 53 | criterion_group!(benches, bench_field_element); 54 | criterion_main!(benches); 55 | -------------------------------------------------------------------------------- /p256/benches/scalar.rs: -------------------------------------------------------------------------------- 1 | //! secp256r1 scalar arithmetic benchmarks 2 | 3 | use criterion::{ 4 | BenchmarkGroup, Criterion, criterion_group, criterion_main, measurement::Measurement, 5 | }; 6 | use hex_literal::hex; 7 | use p256::{ProjectivePoint, Scalar, elliptic_curve::group::ff::PrimeField}; 8 | 9 | fn test_scalar_x() -> Scalar { 10 | Scalar::from_repr( 11 | hex!("519b423d715f8b581f4fa8ee59f4771a5b44c8130b4e3eacca54a56dda72b464").into(), 12 | ) 13 | .unwrap() 14 | } 15 | 16 | fn test_scalar_y() -> Scalar { 17 | Scalar::from_repr( 18 | hex!("0f56db78ca460b055c500064824bed999a25aaf48ebb519ac201537b85479813").into(), 19 | ) 20 | .unwrap() 21 | } 22 | 23 | fn bench_point_mul(group: &mut BenchmarkGroup<'_, M>) { 24 | let p = ProjectivePoint::GENERATOR; 25 | let m = test_scalar_x(); 26 | let s = Scalar::from_repr(m.into()).unwrap(); 27 | group.bench_function("point-scalar mul", |b| b.iter(|| p * s)); 28 | } 29 | 30 | fn bench_scalar_sub(group: &mut BenchmarkGroup<'_, M>) { 31 | let x = test_scalar_x(); 32 | let y = test_scalar_y(); 33 | group.bench_function("sub", |b| b.iter(|| x - y)); 34 | } 35 | 36 | fn bench_scalar_add(group: &mut BenchmarkGroup<'_, M>) { 37 | let x = test_scalar_x(); 38 | let y = test_scalar_y(); 39 | group.bench_function("add", |b| b.iter(|| x + y)); 40 | } 41 | 42 | fn bench_scalar_mul(group: &mut BenchmarkGroup<'_, M>) { 43 | let x = test_scalar_x(); 44 | let y = test_scalar_y(); 45 | group.bench_function("mul", |b| b.iter(|| x * y)); 46 | } 47 | 48 | fn bench_scalar_negate(group: &mut BenchmarkGroup<'_, M>) { 49 | let x = test_scalar_x(); 50 | group.bench_function("negate", |b| b.iter(|| -x)); 51 | } 52 | 53 | fn bench_scalar_invert(group: &mut BenchmarkGroup<'_, M>) { 54 | let x = test_scalar_x(); 55 | group.bench_function("invert", |b| b.iter(|| x.invert())); 56 | } 57 | 58 | fn bench_point(c: &mut Criterion) { 59 | let mut group = c.benchmark_group("point operations"); 60 | bench_point_mul(&mut group); 61 | group.finish(); 62 | } 63 | 64 | fn bench_scalar(c: &mut Criterion) { 65 | let mut group = c.benchmark_group("scalar operations"); 66 | bench_scalar_sub(&mut group); 67 | bench_scalar_add(&mut group); 68 | bench_scalar_mul(&mut group); 69 | bench_scalar_negate(&mut group); 70 | bench_scalar_invert(&mut group); 71 | group.finish(); 72 | } 73 | 74 | criterion_group!(benches, bench_point, bench_scalar); 75 | criterion_main!(benches); 76 | -------------------------------------------------------------------------------- /p256/src/arithmetic.rs: -------------------------------------------------------------------------------- 1 | //! Pure Rust implementation of group operations on secp256r1. 2 | //! 3 | //! Curve parameters can be found in [NIST SP 800-186] § G.1.2: Curve P-256. 4 | //! 5 | //! [NIST SP 800-186]: https://csrc.nist.gov/publications/detail/sp/800-186/final 6 | 7 | pub(crate) mod field; 8 | #[cfg(feature = "hash2curve")] 9 | mod hash2curve; 10 | pub(crate) mod scalar; 11 | 12 | use self::{field::FieldElement, scalar::Scalar}; 13 | use crate::NistP256; 14 | use elliptic_curve::{CurveArithmetic, PrimeCurveArithmetic}; 15 | use primeorder::{PrimeCurveParams, point_arithmetic}; 16 | 17 | /// Elliptic curve point in affine coordinates. 18 | pub type AffinePoint = primeorder::AffinePoint; 19 | 20 | /// Elliptic curve point in projective coordinates. 21 | pub type ProjectivePoint = primeorder::ProjectivePoint; 22 | 23 | impl CurveArithmetic for NistP256 { 24 | type AffinePoint = AffinePoint; 25 | type ProjectivePoint = ProjectivePoint; 26 | type Scalar = Scalar; 27 | } 28 | 29 | impl PrimeCurveArithmetic for NistP256 { 30 | type CurveGroup = ProjectivePoint; 31 | } 32 | 33 | /// Adapted from [NIST SP 800-186] § G.1.2: Curve P-256. 34 | /// 35 | /// [NIST SP 800-186]: https://csrc.nist.gov/publications/detail/sp/800-186/final 36 | impl PrimeCurveParams for NistP256 { 37 | type FieldElement = FieldElement; 38 | type PointArithmetic = point_arithmetic::EquationAIsMinusThree; 39 | 40 | /// a = -3 41 | const EQUATION_A: FieldElement = FieldElement::from_u64(3).neg(); 42 | 43 | const EQUATION_B: FieldElement = 44 | FieldElement::from_hex("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b"); 45 | 46 | /// Base point of P-256. 47 | /// 48 | /// Defined in NIST SP 800-186 § G.1.2: 49 | /// 50 | /// ```text 51 | /// Gₓ = 6b17d1f2 e12c4247 f8bce6e5 63a440f2 77037d81 2deb33a0 f4a13945 d898c296 52 | /// Gᵧ = 4fe342e2 fe1a7f9b 8ee7eb4a 7c0f9e16 2bce3357 6b315ece cbb64068 37bf51f5 53 | /// ``` 54 | const GENERATOR: (FieldElement, FieldElement) = ( 55 | FieldElement::from_hex("6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296"), 56 | FieldElement::from_hex("4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5"), 57 | ); 58 | } 59 | -------------------------------------------------------------------------------- /p256/src/ecdh.rs: -------------------------------------------------------------------------------- 1 | //! Elliptic Curve Diffie-Hellman (Ephemeral) Support. 2 | //! 3 | //! This module contains a high-level interface for performing ephemeral 4 | //! Diffie-Hellman key exchanges using the secp256r1 elliptic curve. 5 | //! 6 | //! # Usage 7 | //! 8 | //! This usage example is from the perspective of two participants in the 9 | //! exchange, nicknamed "Alice" and "Bob". 10 | //! 11 | //! ``` 12 | //! use p256::{EncodedPoint, PublicKey, ecdh::EphemeralSecret}; 13 | //! use rand_core::OsRng; // requires 'os_rng' feature 14 | //! 15 | //! // Alice 16 | //! let alice_secret = EphemeralSecret::try_from_rng(&mut OsRng).unwrap(); 17 | //! let alice_pk_bytes = EncodedPoint::from(alice_secret.public_key()); 18 | //! 19 | //! // Bob 20 | //! let bob_secret = EphemeralSecret::try_from_rng(&mut OsRng).unwrap(); 21 | //! let bob_pk_bytes = EncodedPoint::from(bob_secret.public_key()); 22 | //! 23 | //! // Alice decodes Bob's serialized public key and computes a shared secret from it 24 | //! let bob_public = PublicKey::from_sec1_bytes(bob_pk_bytes.as_ref()) 25 | //! .expect("bob's public key is invalid!"); // In real usage, don't panic, handle this! 26 | //! 27 | //! let alice_shared = alice_secret.diffie_hellman(&bob_public); 28 | //! 29 | //! // Bob decodes Alice's serialized public key and computes the same shared secret 30 | //! let alice_public = PublicKey::from_sec1_bytes(alice_pk_bytes.as_ref()) 31 | //! .expect("alice's public key is invalid!"); // In real usage, don't panic, handle this! 32 | //! 33 | //! let bob_shared = bob_secret.diffie_hellman(&alice_public); 34 | //! 35 | //! // Both participants arrive on the same shared secret 36 | //! assert_eq!(alice_shared.raw_secret_bytes(), bob_shared.raw_secret_bytes()); 37 | //! ``` 38 | 39 | pub use elliptic_curve::ecdh::diffie_hellman; 40 | 41 | use crate::NistP256; 42 | 43 | /// NIST P-256 Ephemeral Diffie-Hellman Secret. 44 | pub type EphemeralSecret = elliptic_curve::ecdh::EphemeralSecret; 45 | 46 | /// Shared secret value computed via ECDH key agreement. 47 | pub type SharedSecret = elliptic_curve::ecdh::SharedSecret; 48 | -------------------------------------------------------------------------------- /p256/src/test_vectors.rs: -------------------------------------------------------------------------------- 1 | //! secp256r1 test vectors. 2 | 3 | #[cfg(test)] 4 | pub mod ecdsa; 5 | pub mod field; 6 | pub mod group; 7 | -------------------------------------------------------------------------------- /p256/src/test_vectors/data/wycheproof.blb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RustCrypto/elliptic-curves/d317ce8100dc09416901d50b223ba45f39549568/p256/src/test_vectors/data/wycheproof.blb -------------------------------------------------------------------------------- /p256/tests/ecdsa.rs: -------------------------------------------------------------------------------- 1 | //! ECDSA tests. 2 | 3 | #![cfg(feature = "arithmetic")] 4 | 5 | use elliptic_curve::ops::Reduce; 6 | use p256::{ 7 | NonZeroScalar, U256, 8 | ecdsa::{SigningKey, VerifyingKey}, 9 | }; 10 | use proptest::prelude::*; 11 | 12 | prop_compose! { 13 | fn signing_key()(bytes in any::<[u8; 32]>()) -> SigningKey { 14 | >::reduce_bytes(&bytes.into()).into() 15 | } 16 | } 17 | 18 | proptest! { 19 | #[test] 20 | fn recover_from_msg(sk in signing_key()) { 21 | let msg = b"example"; 22 | let (signature, v) = sk.sign_recoverable(msg).unwrap(); 23 | let recovered_vk = VerifyingKey::recover_from_msg(msg, &signature, v).unwrap(); 24 | prop_assert_eq!(sk.verifying_key(), &recovered_vk); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /p256/tests/examples/pkcs8-private-key.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RustCrypto/elliptic-curves/d317ce8100dc09416901d50b223ba45f39549568/p256/tests/examples/pkcs8-private-key.der -------------------------------------------------------------------------------- /p256/tests/examples/pkcs8-private-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgaWJBcVYaYzQN4OfY 3 | afKgVJJVjhoEhotqn4VKhmeIGI2hRANCAAQcrP+1Xy8s79idies3SyaBFSRSgC3u 4 | oJkWBoE32DnPf8SBpESSME1+9mrBF77+g6jQjxVfK1L59hjdRHApBI4P 5 | -----END PRIVATE KEY----- 6 | -------------------------------------------------------------------------------- /p256/tests/examples/pkcs8-public-key.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RustCrypto/elliptic-curves/d317ce8100dc09416901d50b223ba45f39549568/p256/tests/examples/pkcs8-public-key.der -------------------------------------------------------------------------------- /p256/tests/examples/pkcs8-public-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEHKz/tV8vLO/YnYnrN0smgRUkUoAt 3 | 7qCZFgaBN9g5z3/EgaREkjBNfvZqwRe+/oOo0I8VXytS+fYY3URwKQSODw== 4 | -----END PUBLIC KEY----- 5 | -------------------------------------------------------------------------------- /p256/tests/projective.rs: -------------------------------------------------------------------------------- 1 | //! Projective arithmetic tests. 2 | 3 | #![cfg(all(feature = "arithmetic", feature = "test-vectors"))] 4 | 5 | use elliptic_curve::{ 6 | group::{GroupEncoding, ff::PrimeField}, 7 | sec1::{self, ToEncodedPoint}, 8 | }; 9 | use p256::{ 10 | AffinePoint, ProjectivePoint, Scalar, 11 | test_vectors::group::{ADD_TEST_VECTORS, MUL_TEST_VECTORS}, 12 | }; 13 | use primeorder::{Double, test_projective_arithmetic}; 14 | 15 | test_projective_arithmetic!( 16 | AffinePoint, 17 | ProjectivePoint, 18 | Scalar, 19 | ADD_TEST_VECTORS, 20 | MUL_TEST_VECTORS 21 | ); 22 | 23 | #[test] 24 | fn projective_identity_to_bytes() { 25 | // This is technically an invalid SEC1 encoding, but is preferable to panicking. 26 | assert_eq!([0; 33], ProjectivePoint::IDENTITY.to_bytes().as_slice()); 27 | } 28 | -------------------------------------------------------------------------------- /p256/tests/scalar.rs: -------------------------------------------------------------------------------- 1 | //! Scalar arithmetic tests. 2 | 3 | #![cfg(feature = "arithmetic")] 4 | 5 | use elliptic_curve::ops::{Invert, Reduce}; 6 | use p256::{Scalar, U256}; 7 | use proptest::prelude::*; 8 | 9 | prop_compose! { 10 | fn scalar()(bytes in any::<[u8; 32]>()) -> Scalar { 11 | >::reduce_bytes(&bytes.into()) 12 | } 13 | } 14 | 15 | proptest! { 16 | #[test] 17 | fn invert_and_invert_vartime_are_equivalent(w in scalar()) { 18 | let inv: Option = w.invert().into(); 19 | let inv_vartime: Option = w.invert_vartime().into(); 20 | prop_assert_eq!(inv, inv_vartime); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /p384/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "p384" 3 | version = "0.14.0-pre.5" 4 | description = """ 5 | Pure Rust implementation of the NIST P-384 (a.k.a. secp384r1) elliptic curve 6 | as defined in SP 800-186 with support for ECDH, ECDSA signing/verification, 7 | and general purpose curve arithmetic support. 8 | """ 9 | authors = ["RustCrypto Developers", "Frank Denis "] 10 | license = "Apache-2.0 OR MIT" 11 | documentation = "https://docs.rs/p384" 12 | homepage = "https://github.com/RustCrypto/elliptic-curves/tree/master/p384" 13 | repository = "https://github.com/RustCrypto/elliptic-curves" 14 | readme = "README.md" 15 | categories = ["cryptography", "no-std"] 16 | keywords = ["crypto", "ecc", "nist", "secp384r1"] 17 | edition = "2024" 18 | rust-version = "1.85" 19 | 20 | [dependencies] 21 | elliptic-curve = { version = "0.14.0-rc.5", default-features = false, features = ["sec1"] } 22 | 23 | # optional dependencies 24 | ecdsa-core = { version = "0.17.0-rc.0", package = "ecdsa", optional = true, default-features = false, features = ["der"] } 25 | hex-literal = { version = "1", optional = true } 26 | primefield = { version = "=0.14.0-pre.2", optional = true } 27 | primeorder = { version = "=0.14.0-pre.4", optional = true } 28 | serdect = { version = "0.3", optional = true, default-features = false } 29 | sha2 = { version = "0.11.0-rc.0", optional = true, default-features = false } 30 | 31 | [dev-dependencies] 32 | blobby = "0.3" 33 | criterion = "0.6" 34 | ecdsa-core = { version = "0.17.0-rc.0", package = "ecdsa", default-features = false, features = ["dev"] } 35 | hex-literal = "1" 36 | primeorder = { version = "=0.14.0-pre.4", features = ["dev"] } 37 | proptest = "1.7" 38 | rand_core = { version = "0.9", features = ["os_rng"] } 39 | 40 | [features] 41 | default = ["arithmetic", "ecdsa", "pem", "std"] 42 | alloc = ["ecdsa-core?/alloc", "elliptic-curve/alloc", "primeorder?/alloc"] 43 | std = ["alloc", "ecdsa-core?/std", "elliptic-curve/std"] 44 | 45 | arithmetic = [ 46 | "dep:primefield", 47 | "dep:primeorder", 48 | "elliptic-curve/arithmetic", 49 | "elliptic-curve/digest" 50 | ] 51 | bits = ["arithmetic", "elliptic-curve/bits"] 52 | digest = ["ecdsa-core/digest", "ecdsa-core/hazmat"] 53 | ecdh = ["arithmetic", "elliptic-curve/ecdh"] 54 | ecdsa = ["arithmetic", "ecdsa-core/signing", "ecdsa-core/verifying", "sha384"] 55 | expose-field = ["arithmetic"] 56 | hash2curve = ["arithmetic", "elliptic-curve/hash2curve"] 57 | jwk = ["elliptic-curve/jwk"] 58 | oprf = ["hash2curve", "elliptic-curve/oprf", "sha2"] 59 | pem = ["elliptic-curve/pem", "ecdsa-core/pem", "pkcs8"] 60 | pkcs8 = ["ecdsa-core/pkcs8", "elliptic-curve/pkcs8"] 61 | serde = ["ecdsa-core?/serde", "elliptic-curve/serde", "primeorder?/serde", "serdect"] 62 | sha384 = ["digest", "sha2"] 63 | test-vectors = ["hex-literal"] 64 | 65 | [package.metadata.docs.rs] 66 | all-features = true 67 | rustdoc-args = ["--cfg", "docsrs"] 68 | 69 | [[bench]] 70 | name = "field" 71 | harness = false 72 | required-features = ["expose-field"] 73 | 74 | [[bench]] 75 | name = "scalar" 76 | harness = false 77 | -------------------------------------------------------------------------------- /p384/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020-2021 RustCrypto Developers 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /p384/benches/field.rs: -------------------------------------------------------------------------------- 1 | //! secp384r1 field element benchmarks 2 | 3 | use criterion::{ 4 | BenchmarkGroup, Criterion, criterion_group, criterion_main, measurement::Measurement, 5 | }; 6 | use hex_literal::hex; 7 | use p384::FieldElement; 8 | 9 | fn test_field_element_x() -> FieldElement { 10 | FieldElement::from_bytes( 11 | &hex!("c2b47944fb5de342d03285880177ca5f7d0f2fcad7678cce4229d6e1932fcac11bfc3c3e97d942a3c56bf34123013dbf").into() 12 | ) 13 | .unwrap() 14 | } 15 | 16 | fn test_field_element_y() -> FieldElement { 17 | FieldElement::from_bytes( 18 | &hex!("37257906a8223866eda0743c519616a76a758ae58aee81c5fd35fbf3a855b7754a36d4a0672df95d6c44a81cf7620c2d").into() 19 | ) 20 | .unwrap() 21 | } 22 | 23 | fn bench_field_element_mul<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { 24 | let x = test_field_element_x(); 25 | let y = test_field_element_y(); 26 | group.bench_function("mul", |b| b.iter(|| &x * &y)); 27 | } 28 | 29 | fn bench_field_element_square<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { 30 | let x = test_field_element_x(); 31 | group.bench_function("square", |b| b.iter(|| x.square())); 32 | } 33 | 34 | fn bench_field_element_sqrt<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { 35 | let x = test_field_element_x(); 36 | group.bench_function("sqrt", |b| b.iter(|| x.sqrt())); 37 | } 38 | 39 | fn bench_field_element_invert<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { 40 | let x = test_field_element_x(); 41 | group.bench_function("invert", |b| b.iter(|| x.invert())); 42 | } 43 | 44 | fn bench_field_element(c: &mut Criterion) { 45 | let mut group = c.benchmark_group("field element operations"); 46 | bench_field_element_mul(&mut group); 47 | bench_field_element_square(&mut group); 48 | bench_field_element_invert(&mut group); 49 | bench_field_element_sqrt(&mut group); 50 | group.finish(); 51 | } 52 | 53 | criterion_group!(benches, bench_field_element); 54 | criterion_main!(benches); 55 | -------------------------------------------------------------------------------- /p384/benches/scalar.rs: -------------------------------------------------------------------------------- 1 | //! secp384r1 scalar arithmetic benchmarks 2 | 3 | use criterion::{ 4 | BenchmarkGroup, Criterion, criterion_group, criterion_main, measurement::Measurement, 5 | }; 6 | use hex_literal::hex; 7 | use p384::{ProjectivePoint, Scalar, elliptic_curve::group::ff::PrimeField}; 8 | 9 | fn test_scalar_x() -> Scalar { 10 | Scalar::from_repr( 11 | hex!("201b432d8df14324182d6261db3e4b3f46a8284482d52e370da41e6cbdf45ec2952f5db7ccbce3bc29449f4fb080ac97").into() 12 | ).unwrap() 13 | } 14 | 15 | fn test_scalar_y() -> Scalar { 16 | Scalar::from_repr( 17 | hex!("23d9f4ea6d87b7d6163d64256e3449255db14786401a51daa7847161bf56d494325ad2ac8ba928394e01061d882c3528").into() 18 | ).unwrap() 19 | } 20 | 21 | fn bench_point_mul(group: &mut BenchmarkGroup<'_, M>) { 22 | let p = ProjectivePoint::GENERATOR; 23 | let m = test_scalar_x(); 24 | let s = Scalar::from_repr(m.into()).unwrap(); 25 | group.bench_function("point-scalar mul", |b| b.iter(|| p * s)); 26 | } 27 | 28 | fn bench_scalar_sub(group: &mut BenchmarkGroup<'_, M>) { 29 | let x = test_scalar_x(); 30 | let y = test_scalar_y(); 31 | group.bench_function("sub", |b| b.iter(|| x - y)); 32 | } 33 | 34 | fn bench_scalar_add(group: &mut BenchmarkGroup<'_, M>) { 35 | let x = test_scalar_x(); 36 | let y = test_scalar_y(); 37 | group.bench_function("add", |b| b.iter(|| x + y)); 38 | } 39 | 40 | fn bench_scalar_mul(group: &mut BenchmarkGroup<'_, M>) { 41 | let x = test_scalar_x(); 42 | let y = test_scalar_y(); 43 | group.bench_function("mul", |b| b.iter(|| x * y)); 44 | } 45 | 46 | fn bench_scalar_negate(group: &mut BenchmarkGroup<'_, M>) { 47 | let x = test_scalar_x(); 48 | group.bench_function("negate", |b| b.iter(|| -x)); 49 | } 50 | 51 | fn bench_scalar_invert(group: &mut BenchmarkGroup<'_, M>) { 52 | let x = test_scalar_x(); 53 | group.bench_function("invert", |b| b.iter(|| x.invert())); 54 | } 55 | 56 | fn bench_point(c: &mut Criterion) { 57 | let mut group = c.benchmark_group("point operations"); 58 | bench_point_mul(&mut group); 59 | group.finish(); 60 | } 61 | 62 | fn bench_scalar(c: &mut Criterion) { 63 | let mut group = c.benchmark_group("scalar operations"); 64 | bench_scalar_sub(&mut group); 65 | bench_scalar_add(&mut group); 66 | bench_scalar_mul(&mut group); 67 | bench_scalar_negate(&mut group); 68 | bench_scalar_invert(&mut group); 69 | group.finish(); 70 | } 71 | 72 | criterion_group!(benches, bench_point, bench_scalar); 73 | criterion_main!(benches); 74 | -------------------------------------------------------------------------------- /p384/src/arithmetic.rs: -------------------------------------------------------------------------------- 1 | //! Pure Rust implementation of group operations on secp384r1. 2 | //! 3 | //! Curve parameters can be found in [NIST SP 800-186] § G.1.3: Curve P-384. 4 | //! 5 | //! [NIST SP 800-186]: https://csrc.nist.gov/publications/detail/sp/800-186/final 6 | 7 | pub(crate) mod field; 8 | #[cfg(feature = "hash2curve")] 9 | mod hash2curve; 10 | pub(crate) mod scalar; 11 | 12 | use self::{field::FieldElement, scalar::Scalar}; 13 | use crate::NistP384; 14 | use elliptic_curve::{CurveArithmetic, PrimeCurveArithmetic}; 15 | use primeorder::{PrimeCurveParams, point_arithmetic}; 16 | 17 | /// Elliptic curve point in affine coordinates. 18 | pub type AffinePoint = primeorder::AffinePoint; 19 | 20 | /// Elliptic curve point in projective coordinates. 21 | pub type ProjectivePoint = primeorder::ProjectivePoint; 22 | 23 | impl CurveArithmetic for NistP384 { 24 | type AffinePoint = AffinePoint; 25 | type ProjectivePoint = ProjectivePoint; 26 | type Scalar = Scalar; 27 | } 28 | 29 | impl PrimeCurveArithmetic for NistP384 { 30 | type CurveGroup = ProjectivePoint; 31 | } 32 | 33 | /// Adapted from [NIST SP 800-186] § G.1.3: Curve P-384. 34 | /// 35 | /// [NIST SP 800-186]: https://csrc.nist.gov/publications/detail/sp/800-186/final 36 | impl PrimeCurveParams for NistP384 { 37 | type FieldElement = FieldElement; 38 | type PointArithmetic = point_arithmetic::EquationAIsMinusThree; 39 | 40 | /// a = -3 (0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc) 41 | const EQUATION_A: FieldElement = FieldElement::from_u64(3).neg(); 42 | 43 | /// b = b3312fa7 e23ee7e4 988e056b e3f82d19 181d9c6e fe814112 44 | /// 0314088f 5013875a c656398d 8a2ed19d 2a85c8ed d3ec2aef 45 | const EQUATION_B: FieldElement = FieldElement::from_hex( 46 | "b3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef", 47 | ); 48 | 49 | /// Base point of P-384. 50 | /// 51 | /// Defined in NIST SP 800-186 § G.1.3: Curve P-384. 52 | /// 53 | /// ```text 54 | /// Gₓ = aa87ca22 be8b0537 8eb1c71e f320ad74 6e1d3b62 8ba79b98 55 | /// 59f741e0 82542a38 5502f25d bf55296c 3a545e38 72760ab7 56 | /// Gᵧ = 3617de4a 96262c6f 5d9e98bf 9292dc29 f8f41dbd 289a147c 57 | /// e9da3113 b5f0b8c0 0a60b1ce 1d7e819d 7a431d7c 90ea0e5f 58 | /// ``` 59 | const GENERATOR: (FieldElement, FieldElement) = ( 60 | FieldElement::from_hex( 61 | "aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7", 62 | ), 63 | FieldElement::from_hex( 64 | "3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f", 65 | ), 66 | ); 67 | } 68 | -------------------------------------------------------------------------------- /p384/src/ecdh.rs: -------------------------------------------------------------------------------- 1 | //! Elliptic Curve Diffie-Hellman (Ephemeral) Support. 2 | //! 3 | //! This module contains a high-level interface for performing ephemeral 4 | //! Diffie-Hellman key exchanges using the secp384r1 elliptic curve. 5 | //! 6 | //! # Usage 7 | //! 8 | //! This usage example is from the perspective of two participants in the 9 | //! exchange, nicknamed "Alice" and "Bob". 10 | //! 11 | //! ``` 12 | //! use p384::{EncodedPoint, PublicKey, ecdh::EphemeralSecret}; 13 | //! use rand_core::OsRng; // requires 'os_rng' feature 14 | //! 15 | //! // Alice 16 | //! let alice_secret = EphemeralSecret::try_from_rng(&mut OsRng).unwrap(); 17 | //! let alice_pk_bytes = EncodedPoint::from(alice_secret.public_key()); 18 | //! 19 | //! // Bob 20 | //! let bob_secret = EphemeralSecret::try_from_rng(&mut OsRng).unwrap(); 21 | //! let bob_pk_bytes = EncodedPoint::from(bob_secret.public_key()); 22 | //! 23 | //! // Alice decodes Bob's serialized public key and computes a shared secret from it 24 | //! let bob_public = PublicKey::from_sec1_bytes(bob_pk_bytes.as_ref()) 25 | //! .expect("bob's public key is invalid!"); // In real usage, don't panic, handle this! 26 | //! 27 | //! let alice_shared = alice_secret.diffie_hellman(&bob_public); 28 | //! 29 | //! // Bob decodes Alice's serialized public key and computes the same shared secret 30 | //! let alice_public = PublicKey::from_sec1_bytes(alice_pk_bytes.as_ref()) 31 | //! .expect("alice's public key is invalid!"); // In real usage, don't panic, handle this! 32 | //! 33 | //! let bob_shared = bob_secret.diffie_hellman(&alice_public); 34 | //! 35 | //! // Both participants arrive on the same shared secret 36 | //! assert_eq!(alice_shared.raw_secret_bytes(), bob_shared.raw_secret_bytes()); 37 | //! ``` 38 | 39 | pub use elliptic_curve::ecdh::diffie_hellman; 40 | 41 | use crate::NistP384; 42 | 43 | /// NIST P-384 Ephemeral Diffie-Hellman Secret. 44 | pub type EphemeralSecret = elliptic_curve::ecdh::EphemeralSecret; 45 | 46 | /// Shared secret value computed via ECDH key agreement. 47 | pub type SharedSecret = elliptic_curve::ecdh::SharedSecret; 48 | -------------------------------------------------------------------------------- /p384/src/test_vectors.rs: -------------------------------------------------------------------------------- 1 | //! secp384r1 test vectors. 2 | 3 | #[cfg(test)] 4 | pub mod ecdsa; 5 | pub mod group; 6 | -------------------------------------------------------------------------------- /p384/src/test_vectors/data/wycheproof.blb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RustCrypto/elliptic-curves/d317ce8100dc09416901d50b223ba45f39549568/p384/src/test_vectors/data/wycheproof.blb -------------------------------------------------------------------------------- /p384/tests/affine.rs: -------------------------------------------------------------------------------- 1 | //! Affine arithmetic tests. 2 | 3 | // TODO(tarcieri): point compaction support 4 | 5 | #![cfg(all(feature = "arithmetic", feature = "test-vectors"))] 6 | 7 | use elliptic_curve::{ 8 | group::{GroupEncoding, prime::PrimeCurveAffine}, 9 | sec1::{FromEncodedPoint, ToEncodedPoint}, 10 | }; 11 | use hex_literal::hex; 12 | 13 | use p384::{AffinePoint, EncodedPoint}; 14 | 15 | const UNCOMPRESSED_BASEPOINT: &[u8] = &hex!( 16 | "04 aa87ca22 be8b0537 8eb1c71e f320ad74 6e1d3b62 8ba79b98 17 | 59f741e0 82542a38 5502f25d bf55296c 3a545e38 72760ab7 18 | 3617de4a 96262c6f 5d9e98bf 9292dc29 f8f41dbd 289a147c 19 | e9da3113 b5f0b8c0 0a60b1ce 1d7e819d 7a431d7c 90ea0e5f" 20 | ); 21 | 22 | const COMPRESSED_BASEPOINT: &[u8] = &hex!( 23 | "03 aa87ca22 be8b0537 8eb1c71e f320ad74 6e1d3b62 8ba79b98 24 | 59f741e0 82542a38 5502f25d bf55296c 3a545e38 72760ab7" 25 | ); 26 | 27 | #[test] 28 | fn uncompressed_round_trip() { 29 | let pubkey = EncodedPoint::from_bytes(UNCOMPRESSED_BASEPOINT).unwrap(); 30 | let point = AffinePoint::from_encoded_point(&pubkey).unwrap(); 31 | assert_eq!(point, AffinePoint::generator()); 32 | 33 | let res: EncodedPoint = point.into(); 34 | assert_eq!(res, pubkey); 35 | } 36 | 37 | #[test] 38 | fn compressed_round_trip() { 39 | let pubkey = EncodedPoint::from_bytes(COMPRESSED_BASEPOINT).unwrap(); 40 | let point = AffinePoint::from_encoded_point(&pubkey).unwrap(); 41 | assert_eq!(point, AffinePoint::generator()); 42 | 43 | let res: EncodedPoint = point.to_encoded_point(true); 44 | assert_eq!(res, pubkey); 45 | } 46 | 47 | #[test] 48 | fn uncompressed_to_compressed() { 49 | let encoded = EncodedPoint::from_bytes(UNCOMPRESSED_BASEPOINT).unwrap(); 50 | 51 | let res = AffinePoint::from_encoded_point(&encoded) 52 | .unwrap() 53 | .to_encoded_point(true); 54 | 55 | assert_eq!(res.as_bytes(), COMPRESSED_BASEPOINT); 56 | } 57 | 58 | #[test] 59 | fn compressed_to_uncompressed() { 60 | let encoded = EncodedPoint::from_bytes(COMPRESSED_BASEPOINT).unwrap(); 61 | 62 | let res = AffinePoint::from_encoded_point(&encoded) 63 | .unwrap() 64 | .to_encoded_point(false); 65 | 66 | assert_eq!(res.as_bytes(), UNCOMPRESSED_BASEPOINT); 67 | } 68 | 69 | #[test] 70 | fn affine_negation() { 71 | let basepoint = AffinePoint::generator(); 72 | assert_eq!(-(-basepoint), basepoint); 73 | } 74 | 75 | #[test] 76 | fn identity_encoding() { 77 | // This is technically an invalid SEC1 encoding, but is preferable to panicking. 78 | assert_eq!([0; 49], AffinePoint::IDENTITY.to_bytes().as_slice()); 79 | assert!(bool::from( 80 | AffinePoint::from_bytes(&AffinePoint::IDENTITY.to_bytes()) 81 | .unwrap() 82 | .is_identity() 83 | )) 84 | } 85 | -------------------------------------------------------------------------------- /p384/tests/projective.rs: -------------------------------------------------------------------------------- 1 | //! Projective arithmetic tests. 2 | 3 | #![cfg(all(feature = "arithmetic", feature = "test-vectors"))] 4 | 5 | use elliptic_curve::{ 6 | PrimeField, 7 | sec1::{self, ToEncodedPoint}, 8 | }; 9 | use p384::{ 10 | AffinePoint, ProjectivePoint, Scalar, 11 | test_vectors::group::{ADD_TEST_VECTORS, MUL_TEST_VECTORS}, 12 | }; 13 | use primeorder::{Double, test_projective_arithmetic}; 14 | 15 | test_projective_arithmetic!( 16 | AffinePoint, 17 | ProjectivePoint, 18 | Scalar, 19 | ADD_TEST_VECTORS, 20 | MUL_TEST_VECTORS 21 | ); 22 | -------------------------------------------------------------------------------- /p521/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## 0.14.0 (UNRELEASED) 8 | ### Added 9 | - `elliptic_curve::ops::Invert` implementation ([#971]) 10 | - make `LooseFieldElement` pub ([#978]) 11 | 12 | ### Changed 13 | - merge `u576_to_le_bytes` into `FieldBytes::from_uint_unchecked` ([#969]) 14 | - switch to upstream RFC6979-based ECDSA ([#1016]) 15 | - Update to `elliptic-curve` v0.14 ([#1011]) 16 | - Update to `ecdsa` v0.17 ([#1011]) 17 | - Update to `sec1` v0.8 ([#1011]) 18 | - Update to `secdect` v0.3 ([#1084]) 19 | - Update to `rand_core` v0.9 ([#1125]) 20 | - Update to `hybrid-array` v0.3 ([#1125]) 21 | - Edition changed to 2024 and MSRV bumped to 1.85 ([#1125]) 22 | - Relax MSRV policy and allow MSRV bumps in patch releases 23 | 24 | [#969]: https://github.com/RustCrypto/elliptic-curves/pull/969 25 | [#971]: https://github.com/RustCrypto/elliptic-curves/pull/971 26 | [#978]: https://github.com/RustCrypto/elliptic-curves/pull/978 27 | [#1011]: https://github.com/RustCrypto/elliptic-curves/pull/1011 28 | [#1016]: https://github.com/RustCrypto/elliptic-curves/pull/1016 29 | [#1084]: https://github.com/RustCrypto/elliptic-curves/pull/1084 30 | [#1125]: https://github.com/RustCrypto/elliptic-curves/pull/1125 31 | 32 | ## 0.13.3 (2023-11-11) 33 | ### Added 34 | - Implement hash2curve ([#964]) 35 | 36 | ### Fixed 37 | - Panics when decoding `FieldElement`s ([#967]) 38 | 39 | [#964]: https://github.com/RustCrypto/elliptic-curves/pull/964 40 | [#967]: https://github.com/RustCrypto/elliptic-curves/pull/967 41 | 42 | ## 0.13.2 (2023-11-09) 43 | ### Added 44 | - `serde` feature ([#962]) 45 | 46 | ### Changed 47 | - Remove `pub` from `arithmetic` module ([#961]) 48 | 49 | [#961]: https://github.com/RustCrypto/elliptic-curves/pull/961 50 | [#962]: https://github.com/RustCrypto/elliptic-curves/pull/962 51 | 52 | ## 0.13.1 (2023-11-09) [YANKED] 53 | ### Added 54 | - Bernstein-Yang scalar inversions ([#786]) 55 | - VOPRF support ([#924]) 56 | - `arithmetic` feature ([#953]) 57 | - `ecdh` feature ([#954]) 58 | - `ecdsa` feature ([#956]) 59 | 60 | [#786]: https://github.com/RustCrypto/elliptic-curves/pull/786 61 | [#924]: https://github.com/RustCrypto/elliptic-curves/pull/924 62 | [#953]: https://github.com/RustCrypto/elliptic-curves/pull/953 63 | [#954]: https://github.com/RustCrypto/elliptic-curves/pull/954 64 | [#956]: https://github.com/RustCrypto/elliptic-curves/pull/956 65 | 66 | ## 0.13.0 (2023-03-03) [YANKED] 67 | - Initial release 68 | -------------------------------------------------------------------------------- /p521/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "p521" 3 | version = "0.14.0-pre.5" 4 | description = """ 5 | Pure Rust implementation of the NIST P-521 (a.k.a. secp521r1) elliptic curve 6 | as defined in SP 800-186 7 | """ 8 | authors = ["RustCrypto Developers"] 9 | license = "Apache-2.0 OR MIT" 10 | documentation = "https://docs.rs/p521" 11 | homepage = "https://github.com/RustCrypto/elliptic-curves/tree/master/p521" 12 | repository = "https://github.com/RustCrypto/elliptic-curves" 13 | readme = "README.md" 14 | categories = ["cryptography", "no-std"] 15 | keywords = ["crypto", "ecc", "nist", "secp521r1"] 16 | edition = "2024" 17 | rust-version = "1.85" 18 | 19 | [dependencies] 20 | base16ct = "0.2" 21 | elliptic-curve = { version = "0.14.0-rc.5", default-features = false, features = ["sec1"] } 22 | 23 | # optional dependencies 24 | ecdsa-core = { version = "0.17.0-rc.0", package = "ecdsa", optional = true, default-features = false, features = ["der"] } 25 | hex-literal = { version = "1", optional = true } 26 | primefield = { version = "=0.14.0-pre.2", optional = true } 27 | primeorder = { version = "=0.14.0-pre.4", optional = true } 28 | rand_core = { version = "0.9", optional = true, default-features = false } 29 | serdect = { version = "0.3", optional = true, default-features = false } 30 | sha2 = { version = "0.11.0-rc.0", optional = true, default-features = false } 31 | 32 | [dev-dependencies] 33 | blobby = "0.3" 34 | criterion = "0.6" 35 | ecdsa-core = { version = "0.17.0-rc.0", package = "ecdsa", default-features = false, features = ["dev"] } 36 | hex-literal = "1" 37 | primeorder = { version = "=0.14.0-pre.4", features = ["dev"] } 38 | proptest = "1.7" 39 | rand_core = { version = "0.9", features = ["os_rng"] } 40 | 41 | [features] 42 | default = ["arithmetic", "ecdsa", "getrandom", "pem", "std"] 43 | alloc = ["ecdsa-core?/alloc", "elliptic-curve/alloc", "primeorder?/alloc"] 44 | std = ["alloc", "ecdsa-core?/std", "elliptic-curve/std"] 45 | 46 | arithmetic = ["dep:primefield", "dep:primeorder"] 47 | digest = ["ecdsa-core/digest", "ecdsa-core/hazmat"] 48 | ecdh = ["arithmetic", "elliptic-curve/ecdh"] 49 | ecdsa = ["arithmetic", "ecdsa-core/signing", "ecdsa-core/verifying", "sha512"] 50 | expose-field = ["arithmetic"] 51 | getrandom = ["rand_core/os_rng"] 52 | hash2curve = ["arithmetic", "elliptic-curve/hash2curve"] 53 | jwk = ["elliptic-curve/jwk"] 54 | oprf = ["hash2curve", "elliptic-curve/oprf", "dep:sha2"] 55 | pem = ["elliptic-curve/pem", "pkcs8"] 56 | pkcs8 = ["ecdsa-core?/pkcs8", "elliptic-curve/pkcs8"] 57 | serde = ["ecdsa-core?/serde", "elliptic-curve/serde", "primeorder?/serde", "serdect"] 58 | sha512 = ["digest", "dep:sha2"] 59 | test-vectors = ["dep:hex-literal"] 60 | 61 | [package.metadata.docs.rs] 62 | all-features = true 63 | rustdoc-args = ["--cfg", "docsrs"] 64 | 65 | [[bench]] 66 | name = "field" 67 | harness = false 68 | required-features = ["expose-field"] 69 | 70 | [[bench]] 71 | name = "scalar" 72 | harness = false 73 | -------------------------------------------------------------------------------- /p521/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020-2022 RustCrypto Developers 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /p521/README.md: -------------------------------------------------------------------------------- 1 | # [RustCrypto]: NIST P-521 (secp521r1) elliptic curve 2 | 3 | [![crate][crate-image]][crate-link] 4 | [![Docs][docs-image]][docs-link] 5 | [![Build Status][build-image]][build-link] 6 | ![Apache2/MIT licensed][license-image] 7 | ![Rust Version][rustc-image] 8 | [![Project Chat][chat-image]][chat-link] 9 | 10 | Pure Rust implementation of the NIST P-521 (a.k.a. secp521r1) elliptic curve. 11 | 12 | [Documentation][docs-link] 13 | 14 | ## ⚠️ Security Warning 15 | 16 | The elliptic curve arithmetic contained in this crate has never been 17 | independently audited! 18 | 19 | This crate has been designed with the goal of ensuring that secret-dependent 20 | operations are performed in constant time (using the `subtle` crate and 21 | constant-time formulas). However, it has not been thoroughly assessed to ensure 22 | that generated assembly is constant time on common CPU architectures. 23 | 24 | USE AT YOUR OWN RISK! 25 | 26 | ## Supported Algorithms 27 | 28 | - [Elliptic Curve Diffie-Hellman (ECDH)][ECDH]: gated under the `ecdh` feature. 29 | - [Elliptic Curve Digital Signature Algorithm (ECDSA)][ECDSA]: gated under the 30 | `ecdsa` feature. 31 | 32 | ## About P-521 33 | 34 | NIST P-521 is a Weierstrass curve specified in [SP 800-186]: 35 | Recommendations for Discrete Logarithm-based Cryptography: 36 | Elliptic Curve Domain Parameters. 37 | 38 | Also known as secp521r1 (SECG). 39 | 40 | ## License 41 | 42 | All crates licensed under either of 43 | 44 | * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) 45 | * [MIT license](http://opensource.org/licenses/MIT) 46 | 47 | at your option. 48 | 49 | ### Contribution 50 | 51 | Unless you explicitly state otherwise, any contribution intentionally submitted 52 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall be 53 | dual licensed as above, without any additional terms or conditions. 54 | 55 | [//]: # (badges) 56 | 57 | [crate-image]: https://img.shields.io/crates/v/p521?logo=rust 58 | [crate-link]: https://crates.io/crates/p521 59 | [docs-image]: https://docs.rs/p521/badge.svg 60 | [docs-link]: https://docs.rs/p521/ 61 | [build-image]: https://github.com/RustCrypto/elliptic-curves/actions/workflows/p521.yml/badge.svg 62 | [build-link]: https://github.com/RustCrypto/elliptic-curves/actions/workflows/p521.yml 63 | [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg 64 | [rustc-image]: https://img.shields.io/badge/rustc-1.85+-blue.svg 65 | [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg 66 | [chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/260040-elliptic-curves 67 | 68 | [//]: # (links) 69 | 70 | [RustCrypto]: https://github.com/rustcrypto/ 71 | [`elliptic-curve`]: https://github.com/RustCrypto/traits/tree/master/elliptic-curve 72 | [ECDH]: https://en.wikipedia.org/wiki/Elliptic-curve_Diffie-Hellman 73 | [ECDSA]: https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm 74 | [SP 800-186]: https://csrc.nist.gov/publications/detail/sp/800-186/final 75 | -------------------------------------------------------------------------------- /p521/benches/field.rs: -------------------------------------------------------------------------------- 1 | //! secp521r1 field element benchmarks 2 | 3 | use criterion::{ 4 | BenchmarkGroup, Criterion, criterion_group, criterion_main, measurement::Measurement, 5 | }; 6 | use hex_literal::hex; 7 | use p521::FieldElement; 8 | use std::hint::black_box; 9 | 10 | fn test_field_element_x() -> FieldElement { 11 | black_box(FieldElement::from_bytes( 12 | hex!("01a7596d38aac7868327ddc1ef5e8178cf052b7ebc512828e8a45955d85bef49494d15278198bbcc5454358c12a2af9a3874e7002e1a2f02fcb36ff3e3b4bc0c69e7").as_ref() 13 | ) 14 | .unwrap()) 15 | } 16 | 17 | fn test_field_element_y() -> FieldElement { 18 | black_box(FieldElement::from_bytes( 19 | hex!("0184902e515982bb225b8c84f245e61b327c08e94d41c07d0b4101a963e02fe52f6a9f33e8b1de2394e0cb74c40790b4e489b5500e6804cabed0fe8c192443d4027b").as_ref() 20 | ) 21 | .unwrap()) 22 | } 23 | 24 | fn bench_field_element_mul<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { 25 | let x = test_field_element_x(); 26 | let y = test_field_element_y(); 27 | group.bench_function("mul", |b| b.iter(|| &x * &y)); 28 | } 29 | 30 | fn bench_field_element_square<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { 31 | let x = test_field_element_x(); 32 | group.bench_function("square", |b| b.iter(|| x.square())); 33 | } 34 | 35 | fn bench_field_element_sqrt<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { 36 | let x = test_field_element_x(); 37 | group.bench_function("sqrt", |b| b.iter(|| x.sqrt())); 38 | } 39 | 40 | fn bench_field_element_invert<'a, M: Measurement>(group: &mut BenchmarkGroup<'a, M>) { 41 | let x = test_field_element_x(); 42 | group.bench_function("invert", |b| b.iter(|| x.invert())); 43 | } 44 | 45 | fn bench_field_element(c: &mut Criterion) { 46 | let mut group = c.benchmark_group("field element operations"); 47 | bench_field_element_mul(&mut group); 48 | bench_field_element_square(&mut group); 49 | bench_field_element_invert(&mut group); 50 | bench_field_element_sqrt(&mut group); 51 | group.finish(); 52 | } 53 | 54 | criterion_group!(benches, bench_field_element); 55 | criterion_main!(benches); 56 | -------------------------------------------------------------------------------- /p521/benches/scalar.rs: -------------------------------------------------------------------------------- 1 | //! secp521r1 scalar arithmetic benchmarks 2 | 3 | use criterion::{ 4 | BenchmarkGroup, Criterion, criterion_group, criterion_main, measurement::Measurement, 5 | }; 6 | use hex_literal::hex; 7 | use p521::{ProjectivePoint, Scalar, elliptic_curve::group::ff::PrimeField}; 8 | use std::hint::black_box; 9 | 10 | fn test_scalar_x() -> Scalar { 11 | black_box(Scalar::from_repr( 12 | hex!("01d7bb864c5b5ecae019296cf9b5c63a166f5f1113942819b1933d889a96d12245777a99428f93de4fc9a18d709bf91889d7f8dddd522b4c364aeae13c983e9fae46").into() 13 | ).unwrap()) 14 | } 15 | 16 | fn test_scalar_y() -> Scalar { 17 | black_box(Scalar::from_repr( 18 | hex!("017e49b8ea8f9d1b7c0378e378a7a42e68e12cf78779ed41dcd29a090ae7e0f883b0d0f2cbc8f0473c0ad6732bea40d371a7f363bc6537d075bd1a4c23e558b0bc73").into() 19 | ).unwrap()) 20 | } 21 | 22 | fn bench_point_mul(group: &mut BenchmarkGroup<'_, M>) { 23 | let p = ProjectivePoint::GENERATOR; 24 | let m = test_scalar_x(); 25 | let s = Scalar::from_repr(m.into()).unwrap(); 26 | group.bench_function("point-scalar mul", |b| b.iter(|| p * s)); 27 | } 28 | 29 | fn bench_scalar_sub(group: &mut BenchmarkGroup<'_, M>) { 30 | let x = test_scalar_x(); 31 | let y = test_scalar_y(); 32 | group.bench_function("sub", |b| b.iter(|| x - y)); 33 | } 34 | 35 | fn bench_scalar_add(group: &mut BenchmarkGroup<'_, M>) { 36 | let x = test_scalar_x(); 37 | let y = test_scalar_y(); 38 | group.bench_function("add", |b| b.iter(|| x + y)); 39 | } 40 | 41 | fn bench_scalar_mul(group: &mut BenchmarkGroup<'_, M>) { 42 | let x = test_scalar_x(); 43 | let y = test_scalar_y(); 44 | group.bench_function("mul", |b| b.iter(|| x * y)); 45 | } 46 | 47 | fn bench_scalar_negate(group: &mut BenchmarkGroup<'_, M>) { 48 | let x = test_scalar_x(); 49 | group.bench_function("negate", |b| b.iter(|| -x)); 50 | } 51 | 52 | fn bench_scalar_invert(group: &mut BenchmarkGroup<'_, M>) { 53 | let x = test_scalar_x(); 54 | group.bench_function("invert", |b| b.iter(|| x.invert())); 55 | } 56 | 57 | fn bench_point(c: &mut Criterion) { 58 | let mut group = c.benchmark_group("point operations"); 59 | bench_point_mul(&mut group); 60 | group.finish(); 61 | } 62 | 63 | fn bench_scalar(c: &mut Criterion) { 64 | let mut group = c.benchmark_group("scalar operations"); 65 | bench_scalar_sub(&mut group); 66 | bench_scalar_add(&mut group); 67 | bench_scalar_mul(&mut group); 68 | bench_scalar_negate(&mut group); 69 | bench_scalar_invert(&mut group); 70 | group.finish(); 71 | } 72 | 73 | criterion_group!(benches, bench_point, bench_scalar); 74 | criterion_main!(benches); 75 | -------------------------------------------------------------------------------- /p521/src/arithmetic.rs: -------------------------------------------------------------------------------- 1 | //! Pure Rust implementation of group operations on secp521r1. 2 | //! 3 | //! Curve parameters can be found in [NIST SP 800-186] § 3.2.1.5: P-521. 4 | //! 5 | //! [NIST SP 800-186]: https://csrc.nist.gov/publications/detail/sp/800-186/final 6 | 7 | pub(crate) mod field; 8 | #[cfg(feature = "hash2curve")] 9 | mod hash2curve; 10 | pub(crate) mod scalar; 11 | mod util; 12 | 13 | pub use self::scalar::Scalar; 14 | 15 | use self::field::FieldElement; 16 | use crate::NistP521; 17 | use elliptic_curve::{CurveArithmetic, PrimeCurveArithmetic}; 18 | use primeorder::{PrimeCurveParams, point_arithmetic}; 19 | 20 | /// Elliptic curve point in affine coordinates. 21 | pub type AffinePoint = primeorder::AffinePoint; 22 | 23 | /// Elliptic curve point in projective coordinates. 24 | pub type ProjectivePoint = primeorder::ProjectivePoint; 25 | 26 | impl CurveArithmetic for NistP521 { 27 | type AffinePoint = AffinePoint; 28 | type ProjectivePoint = ProjectivePoint; 29 | type Scalar = Scalar; 30 | } 31 | 32 | impl PrimeCurveArithmetic for NistP521 { 33 | type CurveGroup = ProjectivePoint; 34 | } 35 | 36 | /// Adapted from [NIST SP 800-186] § 3.2.1.5: P-521. 37 | /// 38 | /// [NIST SP 800-186]: https://csrc.nist.gov/publications/detail/sp/800-186/final 39 | impl PrimeCurveParams for NistP521 { 40 | type FieldElement = FieldElement; 41 | type PointArithmetic = point_arithmetic::EquationAIsMinusThree; 42 | 43 | /// a = -3 (0x1ff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff 44 | /// ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff 45 | /// ffffffff ffffffff ffffffff fffffffc) 46 | const EQUATION_A: FieldElement = FieldElement::from_u64(3).neg(); 47 | 48 | /// b = 0x051 953eb961 8e1c9a1f 929a21a0 b68540ee a2da725b 99b315f3 49 | /// b8b48991 8ef109e1 56193951 ec7e937b 1652c0bd 3bb1bf07 50 | /// 3573df88 3d2c34f1 ef451fd4 6b503f00 51 | const EQUATION_B: FieldElement = FieldElement::from_hex( 52 | "0000000000000051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00", 53 | ); 54 | 55 | /// Base point of P-521. 56 | /// 57 | /// ```text 58 | /// Gₓ = 0x0c6 858e06b7 0404e9cd 9e3ecb66 2395b442 9c648139 053fb521 59 | /// f828af60 6b4d3dba a14b5e77 efe75928 fe1dc127 a2ffa8de 60 | /// 3348b3c1 856a429b f97e7e31 c2e5bd66 61 | /// Gᵧ = 0x118 39296a78 9a3bc004 5c8a5fb4 2c7d1bd9 98f54449 579b4468 62 | /// 17afbd17 273e662c 97ee7299 5ef42640 c550b901 3fad0761 63 | /// 353c7086 a272c240 88be9476 9fd16650 64 | /// ``` 65 | const GENERATOR: (FieldElement, FieldElement) = ( 66 | FieldElement::from_hex( 67 | "00000000000000c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66", 68 | ), 69 | FieldElement::from_hex( 70 | "000000000000011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650", 71 | ), 72 | ); 73 | } 74 | -------------------------------------------------------------------------------- /p521/src/arithmetic/field/loose.rs: -------------------------------------------------------------------------------- 1 | use super::{FieldElement, field_impl::*}; 2 | use core::ops::Mul; 3 | 4 | /// "Loose" field element: unreduced and intended to be followed by an 5 | /// additional operation which will perform a reduction. 6 | pub struct LooseFieldElement(pub(super) fiat_p521_loose_field_element); 7 | 8 | impl LooseFieldElement { 9 | /// Reduce field element. 10 | #[inline] 11 | pub const fn carry(&self) -> FieldElement { 12 | let mut out = fiat_p521_tight_field_element([0; 9]); 13 | fiat_p521_carry(&mut out, &self.0); 14 | FieldElement(out) 15 | } 16 | 17 | /// Multiplies two field elements and reduces the result. 18 | #[inline] 19 | pub const fn multiply(&self, rhs: &Self) -> FieldElement { 20 | let mut out = fiat_p521_tight_field_element([0; 9]); 21 | fiat_p521_carry_mul(&mut out, &self.0, &rhs.0); 22 | FieldElement(out) 23 | } 24 | 25 | /// Squares a field element and reduces the result. 26 | #[inline] 27 | pub const fn square(&self) -> FieldElement { 28 | let mut out = fiat_p521_tight_field_element([0; 9]); 29 | fiat_p521_carry_square(&mut out, &self.0); 30 | FieldElement(out) 31 | } 32 | } 33 | 34 | impl From for LooseFieldElement { 35 | #[inline] 36 | fn from(tight: FieldElement) -> LooseFieldElement { 37 | LooseFieldElement::from(&tight) 38 | } 39 | } 40 | 41 | impl From<&FieldElement> for LooseFieldElement { 42 | #[inline] 43 | fn from(tight: &FieldElement) -> LooseFieldElement { 44 | tight.relax() 45 | } 46 | } 47 | 48 | impl From for FieldElement { 49 | #[inline] 50 | fn from(loose: LooseFieldElement) -> FieldElement { 51 | FieldElement::from(&loose) 52 | } 53 | } 54 | 55 | impl From<&LooseFieldElement> for FieldElement { 56 | #[inline] 57 | fn from(loose: &LooseFieldElement) -> FieldElement { 58 | loose.carry() 59 | } 60 | } 61 | 62 | impl Mul for LooseFieldElement { 63 | type Output = FieldElement; 64 | 65 | #[inline] 66 | fn mul(self, rhs: LooseFieldElement) -> FieldElement { 67 | Self::multiply(&self, &rhs) 68 | } 69 | } 70 | 71 | impl Mul<&LooseFieldElement> for LooseFieldElement { 72 | type Output = FieldElement; 73 | 74 | #[inline] 75 | fn mul(self, rhs: &LooseFieldElement) -> FieldElement { 76 | Self::multiply(&self, rhs) 77 | } 78 | } 79 | 80 | impl Mul<&LooseFieldElement> for &LooseFieldElement { 81 | type Output = FieldElement; 82 | 83 | #[inline] 84 | fn mul(self, rhs: &LooseFieldElement) -> FieldElement { 85 | LooseFieldElement::multiply(self, rhs) 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /p521/src/arithmetic/util.rs: -------------------------------------------------------------------------------- 1 | //! Utility functions. 2 | 3 | /// Convert an 18-element array of `u32` into a 9-element array of `u16`, 4 | /// assuming integer arrays are in little-endian order. 5 | #[cfg(target_pointer_width = "32")] 6 | pub(crate) const fn u32x18_to_u64x9(w: &[u32; 18]) -> [u64; 9] { 7 | let mut ret = [0u64; 9]; 8 | let mut i = 0; 9 | 10 | while i < 9 { 11 | ret[i] = (w[i * 2] as u64) | ((w[(i * 2) + 1] as u64) << 32); 12 | i += 1; 13 | } 14 | 15 | ret 16 | } 17 | 18 | /// Convert a 9-element array of `u64` into an 18-element array of `u32`, 19 | /// assuming integers are in little-endian order. 20 | #[cfg(target_pointer_width = "32")] 21 | pub(crate) const fn u64x9_to_u32x18(w: &[u64; 9]) -> [u32; 18] { 22 | let mut ret = [0u32; 18]; 23 | let mut i = 0; 24 | 25 | while i < 9 { 26 | ret[i * 2] = (w[i] & 0xFFFFFFFF) as u32; 27 | ret[(i * 2) + 1] = (w[i] >> 32) as u32; 28 | i += 1; 29 | } 30 | 31 | ret 32 | } 33 | -------------------------------------------------------------------------------- /p521/src/ecdh.rs: -------------------------------------------------------------------------------- 1 | //! Elliptic Curve Diffie-Hellman (Ephemeral) Support. 2 | //! 3 | //! This module contains a high-level interface for performing ephemeral 4 | //! Diffie-Hellman key exchanges using the secp521r1 elliptic curve. 5 | //! 6 | //! # Usage 7 | //! 8 | //! This usage example is from the perspective of two participants in the 9 | //! exchange, nicknamed "Alice" and "Bob". 10 | //! 11 | //! ``` 12 | //! use p521::{EncodedPoint, PublicKey, ecdh::EphemeralSecret}; 13 | //! use rand_core::{OsRng, TryRngCore}; // requires 'os_rng' feature 14 | //! 15 | //! // Alice 16 | //! let alice_secret = EphemeralSecret::try_from_rng(&mut OsRng).unwrap(); 17 | //! let alice_pk_bytes = EncodedPoint::from(alice_secret.public_key()); 18 | //! 19 | //! // Bob 20 | //! let bob_secret = EphemeralSecret::try_from_rng(&mut OsRng).unwrap(); 21 | //! let bob_pk_bytes = EncodedPoint::from(bob_secret.public_key()); 22 | //! 23 | //! // Alice decodes Bob's serialized public key and computes a shared secret from it 24 | //! let bob_public = PublicKey::from_sec1_bytes(bob_pk_bytes.as_ref()) 25 | //! .expect("bob's public key is invalid!"); // In real usage, don't panic, handle this! 26 | //! 27 | //! let alice_shared = alice_secret.diffie_hellman(&bob_public); 28 | //! 29 | //! // Bob decodes Alice's serialized public key and computes the same shared secret 30 | //! let alice_public = PublicKey::from_sec1_bytes(alice_pk_bytes.as_ref()) 31 | //! .expect("alice's public key is invalid!"); // In real usage, don't panic, handle this! 32 | //! 33 | //! let bob_shared = bob_secret.diffie_hellman(&alice_public); 34 | //! 35 | //! // Both participants arrive on the same shared secret 36 | //! assert_eq!(alice_shared.raw_secret_bytes(), bob_shared.raw_secret_bytes()); 37 | //! ``` 38 | 39 | pub use elliptic_curve::ecdh::diffie_hellman; 40 | 41 | use crate::NistP521; 42 | 43 | /// NIST P-521 Ephemeral Diffie-Hellman Secret. 44 | pub type EphemeralSecret = elliptic_curve::ecdh::EphemeralSecret; 45 | 46 | /// Shared secret value computed via ECDH key agreement. 47 | pub type SharedSecret = elliptic_curve::ecdh::SharedSecret; 48 | -------------------------------------------------------------------------------- /p521/src/test_vectors.rs: -------------------------------------------------------------------------------- 1 | //! secp521r1 test vectors. 2 | 3 | #[cfg(test)] 4 | pub mod ecdsa; 5 | pub mod group; 6 | -------------------------------------------------------------------------------- /p521/src/test_vectors/data/wycheproof.blb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RustCrypto/elliptic-curves/d317ce8100dc09416901d50b223ba45f39549568/p521/src/test_vectors/data/wycheproof.blb -------------------------------------------------------------------------------- /p521/tests/projective.rs: -------------------------------------------------------------------------------- 1 | //! Projective arithmetic tests. 2 | 3 | #![cfg(all(feature = "arithmetic", feature = "test-vectors"))] 4 | 5 | use elliptic_curve::{ 6 | group::ff::PrimeField, 7 | sec1::{self, ToEncodedPoint}, 8 | }; 9 | use p521::{ 10 | AffinePoint, ProjectivePoint, Scalar, 11 | test_vectors::group::{ADD_TEST_VECTORS, MUL_TEST_VECTORS}, 12 | }; 13 | use primeorder::{Double, test_projective_arithmetic}; 14 | 15 | test_projective_arithmetic!( 16 | AffinePoint, 17 | ProjectivePoint, 18 | Scalar, 19 | ADD_TEST_VECTORS, 20 | MUL_TEST_VECTORS 21 | ); 22 | -------------------------------------------------------------------------------- /primefield/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## 0.14.0 (UNRELEASED) 8 | - Initial release 9 | 10 | -------------------------------------------------------------------------------- /primefield/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "primefield" 3 | version = "0.14.0-pre.2" 4 | description = "Macros for generating prime field implementations" 5 | authors = ["RustCrypto Developers"] 6 | license = "Apache-2.0 OR MIT" 7 | documentation = "https://docs.rs/primefield" 8 | homepage = "https://github.com/RustCrypto/elliptic-curves/tree/master/primefield" 9 | repository = "https://github.com/RustCrypto/elliptic-curves" 10 | readme = "README.md" 11 | categories = ["cryptography", "no-std"] 12 | keywords = ["crypto", "ecc", "field", "prime"] 13 | edition = "2024" 14 | rust-version = "1.85" 15 | 16 | [dependencies] 17 | bigint = { package = "crypto-bigint", version = "=0.7.0-pre.4", default-features = false } 18 | ff = { version = "=0.14.0-pre.0", default-features = false } 19 | subtle = { version = "2.6", default-features = false } 20 | rand_core = { version = "0.9", default-features = false } 21 | zeroize = { version = "1.7", default-features = false } 22 | -------------------------------------------------------------------------------- /primefield/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2024 RustCrypto Developers 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /primefield/README.md: -------------------------------------------------------------------------------- 1 | # [RustCrypto]: Prime Field Macros 2 | 3 | [![crate][crate-image]][crate-link] 4 | [![Docs][docs-image]][docs-link] 5 | [![Build Status][build-image]][build-link] 6 | ![Apache2/MIT licensed][license-image] 7 | ![Rust Version][rustc-image] 8 | [![Project Chat][chat-image]][chat-link] 9 | 10 | Macros for generating prime field implementations. 11 | 12 | Used by [RustCrypto] to implement elliptic curves. 13 | 14 | [Documentation][docs-link] 15 | 16 | ## License 17 | 18 | All crates licensed under either of: 19 | 20 | - [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) 21 | - [MIT license](http://opensource.org/licenses/MIT) 22 | 23 | at your option. 24 | 25 | ### Contribution 26 | 27 | Unless you explicitly state otherwise, any contribution intentionally submitted 28 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall be 29 | dual licensed as above, without any additional terms or conditions. 30 | 31 | [//]: # (badges) 32 | 33 | [crate-image]: https://img.shields.io/crates/v/primefield?logo=rust 34 | [crate-link]: https://crates.io/crates/primefield 35 | [docs-image]: https://docs.rs/primefield/badge.svg 36 | [docs-link]: https://docs.rs/primefield/ 37 | [build-image]: https://github.com/RustCrypto/elliptic-curves/actions/workflows/primefield.yml/badge.svg 38 | [build-link]: https://github.com/RustCrypto/elliptic-curves/actions/workflows/primefield.yml 39 | [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg 40 | [rustc-image]: https://img.shields.io/badge/rustc-1.81+-blue.svg 41 | [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg 42 | [chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/260040-elliptic-curves 43 | 44 | [//]: # (links) 45 | 46 | [RustCrypto]: https://github.com/rustcrypto/ 47 | -------------------------------------------------------------------------------- /primeorder/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "primeorder" 3 | version = "0.14.0-pre.4" 4 | description = """ 5 | Pure Rust implementation of complete addition formulas for prime order elliptic 6 | curves (Renes-Costello-Batina 2015). Generic over field elements and curve 7 | equation coefficients 8 | """ 9 | authors = ["RustCrypto Developers"] 10 | license = "Apache-2.0 OR MIT" 11 | documentation = "https://docs.rs/primeorder" 12 | homepage = "https://github.com/RustCrypto/elliptic-curves/tree/master/primeorder" 13 | repository = "https://github.com/RustCrypto/elliptic-curves" 14 | readme = "README.md" 15 | categories = ["cryptography", "no-std"] 16 | keywords = ["crypto", "ecc"] 17 | edition = "2024" 18 | rust-version = "1.85" 19 | 20 | [dependencies] 21 | elliptic-curve = { version = "0.14.0-rc.5", default-features = false, features = ["arithmetic", "sec1"] } 22 | 23 | # optional dependencies 24 | serdect = { version = "0.3", optional = true, default-features = false } 25 | 26 | [features] 27 | alloc = ["elliptic-curve/alloc"] 28 | std = ["alloc", "elliptic-curve/std"] 29 | 30 | dev = [] 31 | serde = ["elliptic-curve/serde", "serdect"] 32 | 33 | [package.metadata.docs.rs] 34 | all-features = true 35 | rustdoc-args = ["--cfg", "docsrs"] 36 | -------------------------------------------------------------------------------- /primeorder/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020-2023 RustCrypto Developers 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /primeorder/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![cfg_attr(docsrs, feature(doc_auto_cfg))] 3 | #![doc( 4 | html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg", 5 | html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg" 6 | )] 7 | #![forbid(unsafe_code)] 8 | #![warn(missing_docs, rust_2018_idioms, unused_qualifications)] 9 | #![doc = include_str!("../README.md")] 10 | 11 | #[cfg(feature = "alloc")] 12 | #[macro_use] 13 | extern crate alloc; 14 | 15 | pub mod point_arithmetic; 16 | 17 | mod affine; 18 | #[cfg(feature = "dev")] 19 | mod dev; 20 | mod projective; 21 | 22 | pub use crate::{affine::AffinePoint, projective::ProjectivePoint}; 23 | pub use elliptic_curve::{self, Field, FieldBytes, PrimeCurve, PrimeField, array, point::Double}; 24 | 25 | use elliptic_curve::{CurveArithmetic, ops::Invert, subtle::CtOption}; 26 | 27 | /// Parameters for elliptic curves of prime order which can be described by the 28 | /// short Weierstrass equation. 29 | pub trait PrimeCurveParams: 30 | PrimeCurve 31 | + CurveArithmetic 32 | + CurveArithmetic> 33 | + CurveArithmetic> 34 | { 35 | /// Base field element type. 36 | type FieldElement: PrimeField> 37 | + Invert>; 38 | 39 | /// [Point arithmetic](point_arithmetic) implementation, might be optimized for this specific curve 40 | type PointArithmetic: point_arithmetic::PointArithmetic; 41 | 42 | /// Coefficient `a` in the curve equation. 43 | const EQUATION_A: Self::FieldElement; 44 | 45 | /// Coefficient `b` in the curve equation. 46 | const EQUATION_B: Self::FieldElement; 47 | 48 | /// Generator point's affine coordinates: (x, y). 49 | const GENERATOR: (Self::FieldElement, Self::FieldElement); 50 | } 51 | -------------------------------------------------------------------------------- /sm2/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## 0.14.0 (UNRELEASED) 8 | ## Added 9 | - Signature and key PKCS8 support ([#1127]) 10 | 11 | ## Changed 12 | - Update to `elliptic-curve` v0.14 ([#1011]) 13 | - Update to `secdect` v0.3 ([#1084]) 14 | - Update to `rand_core` v0.9 ([#1125]) 15 | - Edition changed to 2024 and MSRV bumped to 1.85 ([#1125]) 16 | - Relax MSRV policy and allow MSRV bumps in patch releases 17 | 18 | [#964]: https://github.com/RustCrypto/elliptic-curves/pull/964 19 | [#1011]: https://github.com/RustCrypto/elliptic-curves/pull/1011 20 | [#1084]: https://github.com/RustCrypto/elliptic-curves/pull/1084 21 | [#1125]: https://github.com/RustCrypto/elliptic-curves/pull/1125 22 | [#1127]: https://github.com/RustCrypto/elliptic-curves/pull/1127 23 | 24 | ## 0.13.3 (2023-11-20) 25 | ### Added 26 | - Impl `Randomized*Signer` for `sm2::dsa::SigningKey` ([#993]) 27 | 28 | [#993]: https://github.com/RustCrypto/elliptic-curves/pull/993 29 | 30 | ## 0.13.2 (2023-04-15) 31 | ### Changed 32 | - Factor out `distid` module ([#865]) 33 | 34 | [#865]: https://github.com/RustCrypto/elliptic-curves/pull/865 35 | 36 | ## 0.13.1 (2023-04-15) [YANKED] 37 | ### Added 38 | - Enable `dsa` feature by default ([#862]) 39 | 40 | [#862]: https://github.com/RustCrypto/elliptic-curves/pull/862 41 | 42 | ## 0.13.0 (2023-04-15) [YANKED] 43 | - Initial RustCrypto release 44 | 45 | ## 0.0.1 (2020-03-02) 46 | -------------------------------------------------------------------------------- /sm2/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sm2" 3 | version = "0.14.0-pre" 4 | description = """ 5 | Pure Rust implementation of the SM2 elliptic curve as defined in the Chinese 6 | national standard GM/T 0003-2012 as well as ISO/IEC 14888. Includes support for 7 | the SM2DSA Digital Signature Algorithm. 8 | """ 9 | authors = ["RustCrypto Developers"] 10 | license = "Apache-2.0 OR MIT" 11 | documentation = "https://docs.rs/sm2" 12 | homepage = "https://github.com/RustCrypto/elliptic-curves/tree/master/sm2" 13 | repository = "https://github.com/RustCrypto/elliptic-curves" 14 | readme = "README.md" 15 | categories = ["cryptography", "no-std"] 16 | keywords = ["crypto", "ecc", "shangmi", "signature", "encryption"] 17 | edition = "2024" 18 | rust-version = "1.85" 19 | 20 | [dependencies] 21 | elliptic-curve = { version = "0.14.0-rc.5", default-features = false, features = ["sec1"] } 22 | rand_core = { version = "0.9", default-features = false } 23 | 24 | # optional dependencies 25 | primefield = { version = "=0.14.0-pre.2", optional = true } 26 | primeorder = { version = "=0.14.0-pre.4", optional = true } 27 | rfc6979 = { version = "0.5.0-rc.0", optional = true } 28 | serdect = { version = "0.3", optional = true, default-features = false } 29 | signature = { version = "3.0.0-rc.1", optional = true, features = ["rand_core"] } 30 | sm3 = { version = "0.5.0-rc.0", optional = true, default-features = false } 31 | 32 | [dev-dependencies] 33 | hex-literal = "1" 34 | proptest = "1" 35 | rand_core = { version = "0.9", features = ["os_rng"] } 36 | 37 | [features] 38 | default = ["arithmetic", "dsa", "pke", "pem", "std"] 39 | alloc = ["elliptic-curve/alloc"] 40 | std = ["alloc", "elliptic-curve/std"] 41 | 42 | arithmetic = ["dep:primefield", "dep:primeorder", "elliptic-curve/arithmetic"] 43 | bits = ["arithmetic", "elliptic-curve/bits"] 44 | dsa = ["arithmetic", "dep:rfc6979", "dep:signature", "dep:sm3"] 45 | pke = ["arithmetic", "dep:sm3"] 46 | pem = ["elliptic-curve/pem", "pkcs8"] 47 | pkcs8 = ["elliptic-curve/pkcs8"] 48 | serde = ["elliptic-curve/serde", "primeorder?/serde", "serdect"] 49 | 50 | [package.metadata.docs.rs] 51 | all-features = true 52 | rustdoc-args = ["--cfg", "docsrs"] 53 | -------------------------------------------------------------------------------- /sm2/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2023 RustCrypto Developers 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /sm2/src/arithmetic.rs: -------------------------------------------------------------------------------- 1 | //! Pure Rust implementation of group operations on the SM2 elliptic curve. 2 | //! 3 | //! Curve parameters can be found in [draft-shen-sm2-ecdsa Appendix D]: 4 | //! Recommended Parameters. 5 | //! 6 | //! [draft-shen-sm2-ecdsa Appendix D]: https://datatracker.ietf.org/doc/html/draft-shen-sm2-ecdsa-02#appendix-D 7 | 8 | pub(crate) mod field; 9 | pub(crate) mod scalar; 10 | 11 | pub use self::scalar::Scalar; 12 | 13 | use self::field::FieldElement; 14 | use crate::Sm2; 15 | use elliptic_curve::{CurveArithmetic, PrimeCurveArithmetic}; 16 | use primeorder::{PrimeCurveParams, point_arithmetic}; 17 | 18 | /// Elliptic curve point in affine coordinates. 19 | pub type AffinePoint = primeorder::AffinePoint; 20 | 21 | /// Elliptic curve point in projective coordinates. 22 | pub type ProjectivePoint = primeorder::ProjectivePoint; 23 | 24 | impl CurveArithmetic for Sm2 { 25 | type AffinePoint = AffinePoint; 26 | type ProjectivePoint = ProjectivePoint; 27 | type Scalar = Scalar; 28 | } 29 | 30 | impl PrimeCurveArithmetic for Sm2 { 31 | type CurveGroup = ProjectivePoint; 32 | } 33 | 34 | /// Adapted from [draft-shen-sm2-ecdsa Appendix D]: Recommended Parameters. 35 | /// 36 | /// [draft-shen-sm2-ecdsa Appendix D]: https://datatracker.ietf.org/doc/html/draft-shen-sm2-ecdsa-02#appendix-D 37 | impl PrimeCurveParams for Sm2 { 38 | type FieldElement = FieldElement; 39 | type PointArithmetic = point_arithmetic::EquationAIsMinusThree; 40 | 41 | /// a = -3 (0xFFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 00000000 FFFFFFFF FFFFFFFC) 42 | const EQUATION_A: FieldElement = FieldElement::from_u64(3).neg(); 43 | 44 | /// b = 0x28E9FA9E 9D9F5E34 4D5A9E4B CF6509A7 F39789F5 15AB8F92 DDBCBD41 4D940E93 45 | const EQUATION_B: FieldElement = 46 | FieldElement::from_hex("28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93"); 47 | 48 | /// Base point of SM2. 49 | /// 50 | /// ```text 51 | /// Gₓ = 0x32C4AE2C 1F198119 5F990446 6A39C994 8FE30BBF F2660BE1 715A4589 334C74C7 52 | /// Gᵧ = 0xBC3736A2 F4F6779C 59BDCEE3 6B692153 D0A9877C C62A4740 02DF32E5 2139F0A0 53 | /// ``` 54 | const GENERATOR: (FieldElement, FieldElement) = ( 55 | FieldElement::from_hex("32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7"), 56 | FieldElement::from_hex("BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0"), 57 | ); 58 | } 59 | -------------------------------------------------------------------------------- /sm2/src/distid.rs: -------------------------------------------------------------------------------- 1 | //! Distinguished identifier support. 2 | 3 | use crate::{AffinePoint, Hash, Sm2}; 4 | use elliptic_curve::{ 5 | Error, Result, 6 | sec1::{self, ToEncodedPoint}, 7 | }; 8 | use primeorder::PrimeCurveParams; 9 | use sm3::{Digest, Sm3}; 10 | 11 | /// Type which represents distinguishing identifiers. 12 | pub(crate) type DistId = str; 13 | 14 | /// Compute user information hash `Z` according to [draft-shen-sm2-ecdsa § 5.1.4.4]. 15 | /// 16 | /// ```text 17 | /// ZA=H256(ENTLA || IDA || a || b || xG || yG || xA || yA) 18 | /// ``` 19 | /// 20 | /// [draft-shen-sm2-ecdsa § 5.1.4.4]: https://datatracker.ietf.org/doc/html/draft-shen-sm2-ecdsa-02#section-5.1.4.4 21 | pub(crate) fn hash_z(distid: &DistId, public_key: &impl AsRef) -> Result { 22 | let entla: u16 = distid 23 | .len() 24 | .checked_mul(8) 25 | .and_then(|l| l.try_into().ok()) 26 | .ok_or(Error)?; 27 | 28 | let mut sm3 = Sm3::new(); 29 | sm3.update(entla.to_be_bytes()); 30 | sm3.update(distid); 31 | sm3.update(Sm2::EQUATION_A.to_bytes()); 32 | sm3.update(Sm2::EQUATION_B.to_bytes()); 33 | sm3.update(Sm2::GENERATOR.0.to_bytes()); 34 | sm3.update(Sm2::GENERATOR.1.to_bytes()); 35 | 36 | match public_key.as_ref().to_encoded_point(false).coordinates() { 37 | sec1::Coordinates::Uncompressed { x, y } => { 38 | sm3.update(x); 39 | sm3.update(y); 40 | Ok(sm3.finalize()) 41 | } 42 | _ => Err(Error), 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /sm2/tests/dsa_extended.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "dsa")] 2 | 3 | use elliptic_curve::ops::Reduce; 4 | use proptest::prelude::*; 5 | use sm2::{ 6 | NonZeroScalar, Scalar, U256, 7 | dsa::{ 8 | Signature, SigningKey, 9 | signature::{Signer, Verifier}, 10 | }, 11 | }; 12 | 13 | const IDENTITY: &str = "test@rustcrypto.org"; 14 | 15 | /// Helper function to create a signing key from test data 16 | fn create_test_signing_key() -> SigningKey { 17 | // Use a fixed test key for deterministic testing 18 | let test_key = [42u8; 32]; 19 | let scalar = >::reduce_bytes(&test_key.into()); 20 | let scalar = NonZeroScalar::new(scalar).unwrap(); 21 | SigningKey::from_nonzero_scalar(IDENTITY.into(), scalar).unwrap() 22 | } 23 | 24 | #[test] 25 | fn test_varying_message_lengths() { 26 | let sk = create_test_signing_key(); 27 | let test_messages = vec![ 28 | vec![], // Empty message 29 | vec![1u8; 1], // 1 byte 30 | vec![2u8; 32], // 32 bytes 31 | vec![3u8; 1024], // 1KB 32 | ]; 33 | 34 | for msg in test_messages { 35 | let sig = sk.sign(&msg); 36 | assert!(sk.verifying_key().verify(&msg, &sig).is_ok()); 37 | } 38 | } 39 | 40 | #[test] 41 | fn test_signature_tampering() { 42 | let sk = create_test_signing_key(); 43 | let msg = b"test message"; 44 | let sig = sk.sign(msg); 45 | let mut tampered_sig = sig.to_bytes(); 46 | 47 | // Modify each byte of signature 48 | for i in 0..64 { 49 | tampered_sig[i] ^= 1; 50 | let invalid_sig = Signature::from_bytes(&tampered_sig).unwrap(); 51 | assert!(sk.verifying_key().verify(msg, &invalid_sig).is_err()); 52 | tampered_sig[i] ^= 1; // Restore 53 | } 54 | } 55 | 56 | #[test] 57 | fn test_special_messages() { 58 | let sk = create_test_signing_key(); 59 | let special_msgs = vec![ 60 | vec![0u8; 32], // All zeros 61 | vec![255u8; 32], // All ones 62 | b"\n\r\t".to_vec(), // Control chars 63 | ]; 64 | 65 | for msg in special_msgs { 66 | let sig = sk.sign(&msg); 67 | assert!(sk.verifying_key().verify(&msg, &sig).is_ok()); 68 | } 69 | } 70 | 71 | proptest! { 72 | #[test] 73 | fn test_signature_consistency( 74 | msg1 in any::>(), 75 | msg2 in any::>() 76 | ) { 77 | let sk = create_test_signing_key(); 78 | let sig1 = sk.sign(&msg1); 79 | let sig2 = sk.sign(&msg1); // Same message 80 | let sig3 = sk.sign(&msg2); // Different message 81 | 82 | // Same message should verify with both signatures 83 | prop_assert!(sk.verifying_key().verify(&msg1, &sig1).is_ok()); 84 | prop_assert!(sk.verifying_key().verify(&msg1, &sig2).is_ok()); 85 | 86 | // Different messages should have different signatures 87 | if msg1 != msg2 { 88 | prop_assert_ne!(sig1.to_bytes(), sig3.to_bytes()); 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /sm2/tests/examples/pkcs8-private-key.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RustCrypto/elliptic-curves/d317ce8100dc09416901d50b223ba45f39549568/sm2/tests/examples/pkcs8-private-key.der -------------------------------------------------------------------------------- /sm2/tests/examples/pkcs8-private-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQgS7jfUFciKZWSy+1C 3 | g7NUoT/10/7rOgZgxb3zyHxVlJmhRANCAAQI13rgTAHMTBEENg3Yr2tvffM0KD18 4 | Gmr9VlJAe4e+5QFOKlfDbBUNFjJNxmTjHmQyNZYJxOeYR6WxYcjHNkyK 5 | -----END PRIVATE KEY----- 6 | -------------------------------------------------------------------------------- /sm2/tests/examples/pkcs8-public-key.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RustCrypto/elliptic-curves/d317ce8100dc09416901d50b223ba45f39549568/sm2/tests/examples/pkcs8-public-key.der -------------------------------------------------------------------------------- /sm2/tests/examples/pkcs8-public-key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAECNd64EwBzEwRBDYN2K9rb33zNCg9 3 | fBpq/VZSQHuHvuUBTipXw2wVDRYyTcZk4x5kMjWWCcTnmEelsWHIxzZMig== 4 | -----END PUBLIC KEY----- 5 | -------------------------------------------------------------------------------- /sm2/tests/sm2dsa.rs: -------------------------------------------------------------------------------- 1 | //! ECDSA tests. 2 | 3 | #![cfg(feature = "dsa")] 4 | 5 | use elliptic_curve::ops::Reduce; 6 | use hex_literal::hex; 7 | use proptest::prelude::*; 8 | use sm2::{ 9 | NonZeroScalar, Scalar, U256, 10 | dsa::{ 11 | Signature, SigningKey, VerifyingKey, 12 | signature::{Signer, Verifier}, 13 | }, 14 | }; 15 | 16 | const PUBLIC_KEY: [u8; 65] = hex!( 17 | "0408D77AE04C01CC4C1104360DD8AF6B6F7DF334283D7C1A6AFD5652407B87BEE5014E2A57C36C150D16324DC664E31E6432359609C4E79847A5B161C8C7364C8A" 18 | ); 19 | const IDENTITY: &str = "example@rustcrypto.org"; 20 | const MSG: &[u8] = b"testing"; 21 | 22 | // Created using: 23 | // $ openssl pkeyutl -sign -in - -inkey pkcs8-private-key.pem -out sig -digest sm3 -pkeyopt distid:example@rustcrypto.org 24 | const SIG: [u8; 64] = hex!( 25 | "d1dcccedd9fb785e0f67c16b7c52901625c0b69de9bca2144acc7be713cad2fc" // r 26 | "f7d1eae6e3a157b36c65f672f738ca8b46298bf149a6510072c431b49cd88b1c" // s 27 | ); 28 | 29 | #[test] 30 | fn verify_test_vector() { 31 | let vk = VerifyingKey::from_sec1_bytes(IDENTITY, &PUBLIC_KEY).unwrap(); 32 | let sig = Signature::try_from(&SIG).unwrap(); 33 | assert!(vk.verify(MSG, &sig).is_ok()); 34 | } 35 | 36 | prop_compose! { 37 | fn signing_key()(bytes in any::<[u8; 32]>()) -> SigningKey { 38 | loop { 39 | let scalar = >::reduce_bytes(&bytes.into()); 40 | if let Some(scalar) = Option::from(NonZeroScalar::new(scalar)) { 41 | return SigningKey::from_nonzero_scalar(IDENTITY, scalar).unwrap(); 42 | } 43 | } 44 | } 45 | } 46 | 47 | proptest! { 48 | #[test] 49 | fn sign_and_verify(sk in signing_key()) { 50 | let signature = sk.sign(MSG); 51 | prop_assert!(sk.verifying_key().verify(MSG, &signature).is_ok()); 52 | } 53 | 54 | #[test] 55 | fn reject_invalid_signature(sk in signing_key(), byte in 0usize..32, bit in 0usize..8) { 56 | let mut signature_bytes = sk.sign(MSG).to_bytes(); 57 | 58 | // tweak signature to make it invalid 59 | signature_bytes[byte] ^= 1 << bit; 60 | 61 | let signature = Signature::from_bytes(&signature_bytes).unwrap(); 62 | prop_assert!(sk.verifying_key().verify(MSG, &signature).is_err()); 63 | } 64 | } 65 | --------------------------------------------------------------------------------