├── .gitignore ├── src ├── lib.rs ├── errors.rs ├── main.rs ├── serde.rs ├── arithmetic.rs ├── points.rs └── scalars.rs ├── LICENSE ├── Cargo.toml ├── Makefile ├── README.md └── doc └── API.md /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /Cargo.lock 3 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![doc = include_str!("../README.md")] 2 | #![doc = include_str!("../doc/API.md")] 3 | 4 | #[cfg(all(not(feature = "secp256k1"), not(feature = "k256")))] 5 | compile_error!("At least one of the `secp256k1` or `k256` features must be enabled."); 6 | 7 | mod arithmetic; 8 | pub mod errors; 9 | mod points; 10 | mod scalars; 11 | mod serde; 12 | 13 | pub use points::*; 14 | pub use scalars::*; 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /src/errors.rs: -------------------------------------------------------------------------------- 1 | macro_rules! simple_error { 2 | ($name:ident, $error:expr, $doc:literal) => { 3 | #[doc=$doc] 4 | #[derive(Debug, PartialEq, Eq)] 5 | pub struct $name; 6 | 7 | impl std::fmt::Display for $name { 8 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 9 | f.write_str($error) 10 | } 11 | } 12 | 13 | impl std::error::Error for $name {} 14 | }; 15 | } 16 | 17 | simple_error!( 18 | InvalidScalarBytes, 19 | "received invalid scalar bytes", 20 | "Returned when parsing a scalar from an incorrectly formatted byte-array." 21 | ); 22 | 23 | simple_error!( 24 | InvalidScalarString, 25 | "received invalid scalar hex string", 26 | "Returned when parsing a scalar from an incorrectly formatted hex string." 27 | ); 28 | 29 | simple_error!( 30 | InvalidPointBytes, 31 | "received invalid point byte representation", 32 | "Returned when parsing a point from an incorrectly formatted byte-array." 33 | ); 34 | 35 | simple_error!( 36 | InvalidPointString, 37 | "received invalid point hex string representation", 38 | "Returned when parsing a point from an incorrectly formatted hex string." 39 | ); 40 | 41 | simple_error!( 42 | ZeroScalarError, 43 | "expected valid non-zero scalar", 44 | "Returned when asserting a `MaybeScalar` is not zero, \ 45 | or converting from a `MaybeScalar` to a `Scalar`." 46 | ); 47 | 48 | simple_error!( 49 | InfinityPointError, 50 | "expected valid non-infinity point", 51 | "Returned when asserting a `MaybePoint` is not infinity, \ 52 | or converting from a `MaybePoint` to a `Point`." 53 | ); 54 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "secp" 3 | version = "0.6.0" 4 | edition = "2021" 5 | authors = ["conduition "] 6 | description = "A flexible and secure secp256k1 elliptic curve math library with constant-time support and superb ergonomics." 7 | readme = "README.md" 8 | license = "Unlicense" 9 | repository = "https://github.com/conduition/secp" 10 | keywords = ["secp256k1", "k256", "elliptic", "curve", "schnorr"] 11 | 12 | [dependencies] 13 | base16ct = { version = "0.2", default-features = false } 14 | crypto-bigint = { version = "0.5", default-features = false, optional = true } 15 | k256 = { version = "0.13", optional = true, default-features = false, features = ["std", "arithmetic"] } 16 | num-traits = { version = "0.2", default-features = false, optional = true } 17 | once_cell = { version = "1.21", default-features = false, features = ["std"] } 18 | rand = { version = "0.9", optional = true, default-features = false } 19 | secp256k1 = { version = "0.31", optional = true, default-features = false, features = ["std"] } 20 | serde = { version = "1.0", default-features = false, optional = true } 21 | serdect = { version = "0.3", default-features = false, optional = true, features = ["alloc"] } 22 | subtle = { version = "2", default-features = false, features = ["std", "const-generics"] } 23 | 24 | [dev-dependencies] 25 | serde = { version = "1.0.219", features = ["serde_derive"] } 26 | serde_json = "1.0.140" 27 | serde_cbor = "0.11.2" 28 | hex = "0.4.3" 29 | crypto-bigint = "0.5.5" 30 | rand = "0.9.1" 31 | sha2 = "0.10.9" 32 | 33 | [features] 34 | default = ["secp256k1"] 35 | cli-rng = ["rand", "rand/std"] 36 | secp256k1 = ["dep:secp256k1"] 37 | k256 = ["dep:k256"] 38 | serde = ["dep:serde", "secp256k1?/serde", "dep:serdect"] 39 | rand = ["dep:rand", "secp256k1?/rand"] 40 | secp256k1-invert = ["dep:crypto-bigint"] 41 | num-traits = ["dep:num-traits"] 42 | 43 | [package.metadata.docs.rs] 44 | all-features = true 45 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: check check-* test test-* cli-* 2 | check: check-default check-mixed check-secp256k1 check-k256 3 | 4 | # Checks the source code with default features enabled. 5 | check-default: 6 | cargo clippy 7 | 8 | # Checks the source code with all features enabled. 9 | check-mixed: 10 | cargo clippy --all-features 11 | cargo clippy --all-features --tests 12 | 13 | # Checks the source code with variations of libsecp256k1 feature sets. 14 | check-secp256k1: 15 | cargo clippy --no-default-features --features secp256k1 16 | cargo clippy --no-default-features --features secp256k1,serde 17 | cargo clippy --no-default-features --features secp256k1,serde,rand 18 | cargo clippy --no-default-features --features secp256k1,serde,rand,secp256k1-invert,num-traits 19 | cargo clippy --no-default-features --features secp256k1,serde,rand,secp256k1-invert,num-traits --tests 20 | 21 | # Checks the source code with variations of pure-rust feature sets. 22 | check-k256: 23 | cargo clippy --no-default-features --features k256 24 | cargo clippy --no-default-features --features k256,serde 25 | cargo clippy --no-default-features --features k256,serde,rand,num-traits 26 | cargo clippy --no-default-features --features k256,serde,rand,num-traits --tests 27 | 28 | 29 | test: test-default test-mixed test-secp256k1 test-k256 30 | 31 | test-default: 32 | cargo test 33 | 34 | test-mixed: 35 | cargo test --all-features 36 | 37 | test-secp256k1: 38 | cargo test --no-default-features --features secp256k1,serde,rand,secp256k1-invert,num-traits 39 | 40 | test-k256: 41 | cargo test --no-default-features --features k256,serde,rand,num-traits 42 | 43 | cli: cli-release 44 | 45 | cli-debug: 46 | cargo build --no-default-features --features secp256k1,secp256k1-invert,cli-rng 47 | 48 | cli-release: 49 | cargo build --release --no-default-features --features secp256k1,secp256k1-invert,cli-rng 50 | 51 | .PHONY: docwatch 52 | docwatch: 53 | watch -n 5 cargo doc --all-features 54 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `secp` 2 | 3 | A flexible and secure secp256k1 elliptic curve math library, with constant-time support, and superb ergonomics. 4 | 5 | `secp` takes full advantage of Rust's `std::ops` traits to make elliptic curve cryptography code easy to read, easy to write, succinct, readable, and secure. 6 | 7 | ## Example 8 | 9 | Here's an implementation of simple Schnorr signatures using the `secp` crate. 10 | 11 | ```rust 12 | use secp::{MaybeScalar, Point, Scalar}; 13 | use sha2::{Digest, Sha256}; 14 | 15 | fn compute_challenge(nonce_point: &Point, pubkey: &Point, msg: &[u8]) -> MaybeScalar { 16 | let hash: [u8; 32] = Sha256::new() 17 | .chain_update(&nonce_point.serialize()) 18 | .chain_update(&pubkey.serialize()) 19 | .chain_update(msg) 20 | .finalize() 21 | .into(); 22 | MaybeScalar::reduce_from(&hash) 23 | } 24 | 25 | fn random_scalar() -> Scalar { 26 | // In an actual implementation this would produce a scalar value 27 | // sampled from a CSPRNG. 28 | Scalar::two() 29 | } 30 | 31 | fn schnorr_sign(secret_key: Scalar, message: &[u8]) -> (Point, MaybeScalar) { 32 | let nonce = random_scalar(); 33 | let nonce_point = nonce.base_point_mul(); 34 | let pubkey = secret_key.base_point_mul(); 35 | 36 | let e = compute_challenge(&nonce_point, &pubkey, message); 37 | let s = nonce + secret_key * e; 38 | (nonce_point, s) 39 | } 40 | 41 | fn schnorr_verify(public_key: Point, signature: (Point, MaybeScalar), message: &[u8]) -> bool { 42 | let (r, s) = signature; 43 | let e = compute_challenge(&r, &public_key, message); 44 | s.base_point_mul() == r + e * public_key 45 | } 46 | 47 | let secret_key: Scalar = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" 48 | .parse() 49 | .unwrap(); 50 | let public_key = secret_key.base_point_mul(); 51 | 52 | let message = b"I am the dragon!"; 53 | 54 | let signature = schnorr_sign(secret_key, message); 55 | assert!(schnorr_verify(public_key, signature, message)); 56 | ``` 57 | 58 | ## Choice of Backbone 59 | 60 | This crate does not implement elliptic curve point math directly. Instead we depend on one of two reputable elliptic curve cryptography libraries: 61 | 62 | - C bindings to [`libsecp256k1`](https://github.com/bitcoin-core/secp256k1), via [the `secp256k1` crate](https://crates.io/crates/secp256k1), maintained by the Bitcoin Core team. 63 | - A pure-rust implementation via [the `k256` crate](https://crates.io/crates/k256), maintained by the [RustCrypto](https://github.com/RustCrypto) team. 64 | 65 | **One or the other can be used.** By default, this crate prefers to rely on `libsecp256k1`, as this is the most vetted and publicly trusted implementation of secp256k1 curve math available anywhere. However, if you need a pure-rust implementation, you can install this crate without it, and use the pure-rust `k256` crate instead. 66 | 67 | ```notrust 68 | cargo add secp --no-default-features --features k256 69 | ``` 70 | 71 | If both `k256` and `secp256k1` features are enabled, then we default to using `libsecp256k1` bindings for the actual math, but still provide trait implementations to make this crate interoperable with `k256`. 72 | 73 | ## Documentation 74 | 75 | To see the API documentation, [head on over to docs.rs](https://docs.rs/secp). 76 | 77 | ## CLI 78 | 79 | This crate also offers a CLI tool for computing secp256k1 curve operations in your shell. Build it with `make cli`. A binary will be built at `target/release/secp`. 80 | 81 | ```not_rust 82 | Usage: 83 | 84 | -- Scalar operations -- 85 | secp scalar gen Generate a random scalar. 86 | secp scalar add [...] Sum two or more scalars. 87 | secp scalar mul [...] Multiply two or more scalars. 88 | secp scalar inv Multiplicative inverse of a scalar mod n. 89 | 90 | -- Point operations -- 91 | secp scalar gen Generate a random point. 92 | secp point add [...] Sum two or more points. 93 | secp point mul [...] Multiply a point by one or more scalars. 94 | 95 | -- Formats -- 96 | 97 | Points are represented in 65-byte compressed hex format. Example: 98 | 99 | 02eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee 100 | 101 | Scalars are represented in 32-byte hex format. Example: 102 | 103 | e8c23ee3c98e040adea5dc92c5c381d6be93615f289ec2d505909657368a0c8f 104 | 105 | Prepending a minus sign '-' in front of a point or scalar will negate it. Example: 106 | 107 | -02eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee 108 | 109 | -- Special values -- 110 | 111 | - The values '0', '1', or '-1' may be substituted for any scalar. 112 | - The value 'G' may be substituted for any point to represent the secp256k1 base point. 113 | - The value '0' may be substituted for any point to represent the additive identity point (infinity). 114 | ``` 115 | 116 | Example usage: 117 | 118 | ```console 119 | s1=`secp scalar gen` 120 | s2=`secp scalar gen` 121 | p1=`secp point mul G $s1` 122 | p2=`secp point mul G $s2` 123 | p3=`secp point add $p1 $p2` 124 | p4=`secp point add $p1 -$p2` 125 | ``` 126 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | #[cfg(all(not(feature = "secp256k1"), not(feature = "k256")))] 2 | compile_error!("At least one of the `secp256k1` or `k256` features must be enabled."); 3 | 4 | mod arithmetic; 5 | mod errors; 6 | mod points; 7 | mod scalars; 8 | 9 | use points::*; 10 | use scalars::*; 11 | 12 | use std::{env, process}; 13 | 14 | fn usage() { 15 | println!("Usage:"); 16 | println!(); 17 | println!("-- Scalar operations --"); 18 | 19 | #[cfg(feature = "cli-rng")] 20 | println!(" secp scalar gen Generate a random scalar."); 21 | println!(" secp scalar add [...] Sum two or more scalars."); 22 | println!(" secp scalar mul [...] Multiply two or more scalars."); 23 | #[cfg(any(feature = "k256", feature = "secp256k1-invert"))] 24 | println!( 25 | " secp scalar inv Multiplicative inverse of a scalar mod n." 26 | ); 27 | println!(); 28 | println!("-- Point operations --"); 29 | #[cfg(feature = "cli-rng")] 30 | println!(" secp scalar gen Generate a random point."); 31 | println!(" secp point add [...] Sum two or more points."); 32 | println!( 33 | " secp point mul [...] Multiply a point by one or more scalars." 34 | ); 35 | println!(); 36 | println!("-- Formats --"); 37 | println!(); 38 | println!("Points are represented in 65-byte compressed hex format. Example:"); 39 | println!(); 40 | println!(" 02eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"); 41 | println!(); 42 | println!("Scalars are represented in 32-byte hex format. Example:"); 43 | println!(); 44 | println!(" e8c23ee3c98e040adea5dc92c5c381d6be93615f289ec2d505909657368a0c8f"); 45 | println!(); 46 | println!("Prepending a minus sign '-' in front of a point or scalar will negate it. Example:"); 47 | println!(); 48 | println!(" -02eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"); 49 | println!(); 50 | println!("-- Special values --"); 51 | println!(); 52 | println!("- The values '0', '1', or '-1' may be substituted for any scalar."); 53 | println!( 54 | "- The value 'G' may be substituted for any point to represent the secp256k1 base point." 55 | ); 56 | println!("- The value '0' may be substituted for any point to represent the additive identity point (infinity)."); 57 | println!(); 58 | } 59 | 60 | enum Error { 61 | Usage(String), 62 | Runtime(String), 63 | } 64 | 65 | fn main() { 66 | let argv: Vec = env::args().collect(); 67 | 68 | if argv.len() < 3 { 69 | usage(); 70 | process::exit(1); 71 | } 72 | 73 | let result = match argv[1].as_str() { 74 | "scalar" => run_scalar_op(&argv[2..]), 75 | "point" => run_point_op(&argv[2..]), 76 | arg => { 77 | usage(); 78 | eprintln!("invalid command '{arg}'"); 79 | process::exit(1); 80 | } 81 | }; 82 | 83 | if let Err(e) = result { 84 | match e { 85 | Error::Usage(msg) => { 86 | usage(); 87 | eprintln!("Error: {}", msg); 88 | process::exit(1); 89 | } 90 | Error::Runtime(msg) => { 91 | usage(); 92 | eprintln!("Error: {}", msg); 93 | process::exit(2); 94 | } 95 | } 96 | } 97 | } 98 | 99 | fn parse_scalar(mut scalar_str: &str) -> Result { 100 | let is_neg = scalar_str.starts_with('-'); 101 | if is_neg { 102 | scalar_str = &scalar_str[1..]; 103 | } 104 | 105 | let scalar = match scalar_str { 106 | "0" => MaybeScalar::Zero, 107 | "1" => MaybeScalar::one(), 108 | v => v 109 | .parse::() 110 | .map_err(|e| Error::Runtime(e.to_string()))?, 111 | }; 112 | 113 | if is_neg { 114 | Ok(-scalar) 115 | } else { 116 | Ok(scalar) 117 | } 118 | } 119 | 120 | fn parse_point(mut point_str: &str) -> Result { 121 | let is_neg = point_str.starts_with('-'); 122 | if is_neg { 123 | point_str = &point_str[1..]; 124 | } 125 | 126 | let point = match point_str { 127 | "0" => MaybePoint::Infinity, 128 | "G" => MaybePoint::Valid(Point::generator()), 129 | v => v 130 | .parse::() 131 | .map_err(|e| Error::Runtime(e.to_string()))?, 132 | }; 133 | 134 | if is_neg { 135 | Ok(-point) 136 | } else { 137 | Ok(point) 138 | } 139 | } 140 | 141 | fn run_scalar_op(args: &[String]) -> Result<(), Error> { 142 | match args[0].as_str() { 143 | #[cfg(feature = "cli-rng")] 144 | "gen" => { 145 | println!("{:x}", Scalar::random(&mut rand::rng())); 146 | } 147 | 148 | "add" => { 149 | let mut sum: MaybeScalar = parse_scalar( 150 | args.get(1) 151 | .ok_or_else(|| Error::Usage("missing scalar arguments".to_string()))?, 152 | )?; 153 | 154 | for arg in &args[2..] { 155 | sum += parse_scalar(arg)?; 156 | } 157 | println!("{:x}", sum); 158 | } 159 | 160 | "mul" => { 161 | let mut product: MaybeScalar = parse_scalar( 162 | args.get(1) 163 | .ok_or_else(|| Error::Usage("missing scalar arguments".to_string()))?, 164 | )?; 165 | 166 | for arg in &args[2..] { 167 | product *= parse_scalar(arg)?; 168 | } 169 | 170 | println!("{:x}", product); 171 | } 172 | 173 | #[cfg(any(feature = "k256", feature = "secp256k1-invert"))] 174 | "inv" => { 175 | let v = parse_scalar( 176 | args.get(1) 177 | .ok_or_else(|| Error::Usage("missing scalar argument".to_string()))?, 178 | )? 179 | .not_zero() 180 | .map_err(|_| Error::Runtime("cannot invert zero scalar".to_string()))?; 181 | 182 | println!("{:x}", Scalar::one() / v); 183 | } 184 | 185 | op => { 186 | return Err(Error::Usage(format!("unknown scalar operation '{op}'"))); 187 | } 188 | }; 189 | 190 | Ok(()) 191 | } 192 | 193 | fn run_point_op(args: &[String]) -> Result<(), Error> { 194 | match args[0].as_str() { 195 | #[cfg(feature = "cli-rng")] 196 | "gen" => { 197 | println!("{:x}", Scalar::random(&mut rand::rng()) * G); 198 | } 199 | 200 | "add" => { 201 | let mut sum: MaybePoint = parse_point( 202 | args.get(1) 203 | .ok_or_else(|| Error::Usage("missing point arguments".to_string()))?, 204 | )?; 205 | 206 | for arg in &args[2..] { 207 | sum += parse_point(arg)?; 208 | } 209 | println!("{:x}", sum); 210 | } 211 | 212 | "mul" => { 213 | let mut product = parse_point( 214 | args.get(1) 215 | .ok_or_else(|| Error::Usage("missing point argument".to_string()))?, 216 | )?; 217 | 218 | for arg in &args[2..] { 219 | product *= parse_scalar(arg)?; 220 | } 221 | println!("{:x}", product); 222 | } 223 | 224 | op => { 225 | return Err(Error::Usage(format!("unknown point operation '{op}'"))); 226 | } 227 | }; 228 | 229 | Ok(()) 230 | } 231 | -------------------------------------------------------------------------------- /src/serde.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "serde")] 2 | 3 | use super::{MaybePoint, MaybeScalar, Point, Scalar}; 4 | 5 | use serde::{Deserialize, Deserializer, Serialize, Serializer}; 6 | 7 | impl Serialize for Scalar { 8 | fn serialize(&self, serializer: S) -> Result { 9 | serdect::array::serialize_hex_lower_or_bin(&self.serialize(), serializer) 10 | } 11 | } 12 | 13 | impl<'de> Deserialize<'de> for Scalar { 14 | fn deserialize>(deserializer: D) -> Result { 15 | let maybe_scalar = MaybeScalar::deserialize(deserializer)?; 16 | maybe_scalar.not_zero().map_err(|_| { 17 | serde::de::Error::invalid_value( 18 | serde::de::Unexpected::Other("zero scalar"), 19 | &"a non-zero scalar", 20 | ) 21 | }) 22 | } 23 | } 24 | 25 | impl Serialize for MaybeScalar { 26 | fn serialize(&self, serializer: S) -> Result { 27 | serdect::array::serialize_hex_lower_or_bin(&self.serialize(), serializer) 28 | } 29 | } 30 | 31 | impl<'de> Deserialize<'de> for MaybeScalar { 32 | fn deserialize>(deserializer: D) -> Result { 33 | let mut bytes = [0; 32]; 34 | serdect::array::deserialize_hex_or_bin(&mut bytes, deserializer)?; 35 | MaybeScalar::try_from(bytes).map_err(|_| { 36 | serde::de::Error::invalid_value( 37 | serde::de::Unexpected::Bytes(&bytes), 38 | &"a 32-byte array representing a scalar", 39 | ) 40 | }) 41 | } 42 | } 43 | 44 | impl Serialize for Point { 45 | fn serialize(&self, serializer: S) -> Result { 46 | serdect::array::serialize_hex_lower_or_bin(&self.serialize(), serializer) 47 | } 48 | } 49 | 50 | impl<'de> Deserialize<'de> for Point { 51 | fn deserialize>(deserializer: D) -> Result { 52 | let maybe_point = MaybePoint::deserialize(deserializer)?; 53 | maybe_point.not_inf().map_err(|_| { 54 | serde::de::Error::invalid_value( 55 | serde::de::Unexpected::Other("infinity curve point"), 56 | &"a non-infinity curve point", 57 | ) 58 | }) 59 | } 60 | } 61 | 62 | impl Serialize for MaybePoint { 63 | fn serialize(&self, serializer: S) -> Result { 64 | serdect::array::serialize_hex_lower_or_bin(&self.serialize(), serializer) 65 | } 66 | } 67 | 68 | impl<'de> Deserialize<'de> for MaybePoint { 69 | fn deserialize>(deserializer: D) -> Result { 70 | let mut buffer = [0; 65]; 71 | let bytes = serdect::slice::deserialize_hex_or_bin(&mut buffer, deserializer)?; 72 | MaybePoint::try_from(bytes).map_err(|_| { 73 | serde::de::Error::invalid_value( 74 | serde::de::Unexpected::Bytes(bytes), 75 | &"a 33-byte array representing a compressed curve point or infinity", 76 | ) 77 | }) 78 | } 79 | } 80 | 81 | #[cfg(test)] 82 | mod tests { 83 | use super::*; 84 | 85 | #[test] 86 | fn scalar_serialize_json() { 87 | let scalar = "b21643ba6bd9b6ca2e1f6da85561092ad44949835519d71dd837be8a8c67fe7f" 88 | .parse::() 89 | .unwrap(); 90 | 91 | // Serialize a `Scalar` 92 | let serialized = serde_json::to_string(&scalar).unwrap(); 93 | assert_eq!( 94 | &serialized, 95 | "\"b21643ba6bd9b6ca2e1f6da85561092ad44949835519d71dd837be8a8c67fe7f\"" 96 | ); 97 | 98 | // Deserialize a `Scalar` 99 | let deserialized: Scalar = 100 | serde_json::from_str(&serialized).expect("error deserializing Scalar"); 101 | assert_eq!(deserialized, scalar); 102 | 103 | // Deserialize a `MaybeScalar` 104 | let maybe_deserialized: MaybeScalar = 105 | serde_json::from_str(&serialized).expect("error deserializing MaybeScalar"); 106 | assert_eq!(maybe_deserialized, MaybeScalar::Valid(scalar)); 107 | 108 | // Serialize a `MaybeScalar` 109 | assert_eq!( 110 | &serde_json::to_string(&MaybeScalar::Valid(scalar)) 111 | .expect("failed to serialize MaybeScalar"), 112 | &serialized 113 | ); 114 | 115 | // Deserialize zero 116 | let zero_deserialized: MaybeScalar = serde_json::from_str( 117 | "\"0000000000000000000000000000000000000000000000000000000000000000\"", 118 | ) 119 | .expect("error deserializing zero"); 120 | 121 | assert_eq!(zero_deserialized, MaybeScalar::Zero); 122 | 123 | // Serialize zero 124 | assert_eq!( 125 | serde_json::to_string(&MaybeScalar::Zero).expect("failed to serialize zero"), 126 | "\"0000000000000000000000000000000000000000000000000000000000000000\"" 127 | ); 128 | } 129 | 130 | #[test] 131 | fn point_serialize_json() { 132 | let point = "02d4d12f80d7e01f09322198408b4302716b5b8e9c7587e5c022cf65054d7cf722" 133 | .parse::() 134 | .unwrap(); 135 | 136 | // Serialize a `Point` 137 | let serialized = serde_json::to_string(&point).expect("failed to serialize Point"); 138 | assert_eq!( 139 | &serialized, 140 | "\"02d4d12f80d7e01f09322198408b4302716b5b8e9c7587e5c022cf65054d7cf722\"" 141 | ); 142 | 143 | // Deserialize a `Point` 144 | let deserialized: Point = 145 | serde_json::from_str(&serialized).expect("error deserializing Point"); 146 | assert_eq!(deserialized, point); 147 | 148 | // Deserialize a `MaybePoint` 149 | let maybe_deserialized: MaybePoint = 150 | serde_json::from_str(&serialized).expect("error deserializing Point"); 151 | assert_eq!(maybe_deserialized, MaybePoint::Valid(point)); 152 | 153 | // Serialize a `MaybePoint` 154 | assert_eq!( 155 | &serde_json::to_string(&maybe_deserialized).expect("failed to serialize MaybePoint"), 156 | &serialized, 157 | ); 158 | 159 | // Deserialize infinity 160 | let inf_deserialized: MaybePoint = serde_json::from_str( 161 | "\"000000000000000000000000000000000000000000000000000000000000000000\"", 162 | ) 163 | .expect("failed to deserialize infinity point"); 164 | 165 | assert_eq!(inf_deserialized, MaybePoint::Infinity); 166 | 167 | // Serialize infinity 168 | let inf_serialized = 169 | serde_json::to_string(&MaybePoint::Infinity).expect("failed to serialize zero"); 170 | assert_eq!( 171 | inf_serialized, 172 | "\"000000000000000000000000000000000000000000000000000000000000000000\"" 173 | ); 174 | 175 | // Can deserialize uncompressed points as well. 176 | let uncompressed_hex = concat!( 177 | "\"04", 178 | "fdbf1eee1ffc22505dd284e866a3b16006e218f130c20c0bbf455d4b2c063acf", 179 | "aa031ac5f64874895ffa5c17b4b9f06cfa63407e34a2c8017a630651f8e8bd9d\"", 180 | ); 181 | let uncompressed_deserialized: Point = serde_json::from_str(uncompressed_hex) 182 | .expect("failed to deserialize uncompressed point"); 183 | 184 | assert_eq!( 185 | uncompressed_deserialized, 186 | "03fdbf1eee1ffc22505dd284e866a3b16006e218f130c20c0bbf455d4b2c063acf" 187 | .parse::() 188 | .unwrap() 189 | ); 190 | } 191 | 192 | #[test] 193 | fn scalar_serialize_cbor() { 194 | let scalar = "b21643ba6bd9b6ca2e1f6da85561092ad44949835519d71dd837be8a8c67fe7f" 195 | .parse::() 196 | .unwrap(); 197 | 198 | // Serialize a `Scalar` 199 | let serialized = serde_cbor::to_vec(&scalar).unwrap(); 200 | assert_eq!( 201 | &hex::encode(&serialized), 202 | "5820b21643ba6bd9b6ca2e1f6da85561092ad44949835519d71dd837be8a8c67fe7f" 203 | ); 204 | 205 | // Deserialize a `Scalar` 206 | let deserialized: Scalar = 207 | serde_cbor::from_slice(&serialized).expect("error deserializing Scalar"); 208 | assert_eq!(deserialized, scalar); 209 | 210 | // Deserialize a `MaybeScalar` 211 | let maybe_deserialized: MaybeScalar = 212 | serde_cbor::from_slice(&serialized).expect("error deserializing MaybeScalar"); 213 | assert_eq!(maybe_deserialized, MaybeScalar::Valid(scalar)); 214 | 215 | // Serialize a `MaybeScalar` 216 | assert_eq!( 217 | &serde_cbor::to_vec(&MaybeScalar::Valid(scalar)) 218 | .expect("failed to serialize MaybeScalar"), 219 | &serialized 220 | ); 221 | 222 | // Deserialize zero 223 | let zero_deserialized: MaybeScalar = serde_cbor::from_slice( 224 | &hex::decode("58200000000000000000000000000000000000000000000000000000000000000000") 225 | .unwrap(), 226 | ) 227 | .expect("error deserializing zero"); 228 | 229 | assert_eq!(zero_deserialized, MaybeScalar::Zero); 230 | 231 | // Serialize zero 232 | assert_eq!( 233 | &hex::encode(serde_cbor::to_vec(&MaybeScalar::Zero).expect("failed to serialize zero")), 234 | "58200000000000000000000000000000000000000000000000000000000000000000" 235 | ); 236 | } 237 | 238 | #[test] 239 | fn point_serialize_cbor() { 240 | let point = "02d4d12f80d7e01f09322198408b4302716b5b8e9c7587e5c022cf65054d7cf722" 241 | .parse::() 242 | .unwrap(); 243 | 244 | // Serialize a `Point` 245 | let serialized = serde_cbor::to_vec(&point).expect("failed to serialize Point"); 246 | assert_eq!( 247 | &hex::encode(&serialized), 248 | "582102d4d12f80d7e01f09322198408b4302716b5b8e9c7587e5c022cf65054d7cf722" 249 | ); 250 | 251 | // Deserialize a `Point` 252 | let deserialized: Point = 253 | serde_cbor::from_slice(&serialized).expect("error deserializing Point"); 254 | assert_eq!(deserialized, point); 255 | 256 | // Deserialize a `MaybePoint` 257 | let maybe_deserialized: MaybePoint = 258 | serde_cbor::from_slice(&serialized).expect("error deserializing Point"); 259 | assert_eq!(maybe_deserialized, MaybePoint::Valid(point)); 260 | 261 | // Serialize a `MaybePoint` 262 | assert_eq!( 263 | &serde_cbor::to_vec(&maybe_deserialized).expect("failed to serialize MaybePoint"), 264 | &serialized, 265 | ); 266 | 267 | // Serialize infinity 268 | let inf_serialized = 269 | serde_cbor::to_vec(&MaybePoint::Infinity).expect("failed to serialize zero"); 270 | assert_eq!( 271 | &hex::encode(inf_serialized), 272 | "5821000000000000000000000000000000000000000000000000000000000000000000" 273 | ); 274 | 275 | // Can deserialize uncompressed points as well. 276 | let uncompressed_hex = concat!( 277 | "5841", 278 | "04", 279 | "fdbf1eee1ffc22505dd284e866a3b16006e218f130c20c0bbf455d4b2c063acf", 280 | "aa031ac5f64874895ffa5c17b4b9f06cfa63407e34a2c8017a630651f8e8bd9d", 281 | ); 282 | let uncompressed_deserialized: Point = 283 | serde_cbor::from_slice(&hex::decode(uncompressed_hex).unwrap()) 284 | .expect("failed to deserialize uncompressed point"); 285 | 286 | assert_eq!( 287 | uncompressed_deserialized, 288 | "03fdbf1eee1ffc22505dd284e866a3b16006e218f130c20c0bbf455d4b2c063acf" 289 | .parse::() 290 | .unwrap() 291 | ); 292 | } 293 | } 294 | -------------------------------------------------------------------------------- /doc/API.md: -------------------------------------------------------------------------------- 1 | # Features 2 | 3 | | Feature | Description | Dependencies | Enabled by Default | 4 | |---------|-------------|--------------|:------------------:| 5 | | `secp256k1` | Use [`libsecp256k1`](https://github.com/bitcoin-core/secp256k1) bindings for elliptic curve math. Include trait implementations for converting to and from types in [the `secp256k1` crate][secp256k1]. This feature supercedes the `k256` feature if that one is enabled. | [`secp256k1`] | ✅ | 6 | | `k256` | Use [the `k256` crate][k256] for elliptic curve math. This enables a pure-rust build. Include trait implementations for types from `k256`. If the `secp256k1` feature is enabled, then `k256` will still be brought in and trait implementations will be included, but the actual curve math will be done by `libsecp256k1`. | [`k256`] | ❌ | 7 | | `serde` | Implement serialization and deserialization for types in this crate. | [`serde`](https://docs.rs/serde) | ❌ | 8 | | `rand` | Enable support for random scalar sampling with a CSPRNG, via [the `rand` crate](https://crates.io/crates/rand) | [`rand`] | ❌ | 9 | | `secp256k1-invert` | `libsecp256k1` doesn't expose any functionality to invert scalars modulo the curve order (i.e. to compute t-1 for some scalar t, so that t(t-1) = 1 mod n). Inversion is useful for certain cryptographic operations, such as ECDSA signing, or OPRFs.

Enable this feature if you need to invert scalars but you only have the `secp256k1` feature enabled. This feature is only useful if the `secp256k1` feature is enabled but `k256` is not, as the [`k256`] crate provides scalar inversion methods. This feature pulls in [the `crypto-bigint` crate][crypto_bigint] to perform the inversion. | [`crypto_bigint`] | ❌ | 10 | | `num-traits` | Enable support for numeric identity traits via [the `num-traits` crate](https://crates.io/crates/num-traits). | [`num_traits`] | ❌ | 11 | | `cli-rng` | Enable RNG features needed to compile the `secp` CLI program. **Not for public use.** | [`rand`] | ❌ | 12 | 13 | # Usage 14 | 15 | The `secp` crate's primary export is four types which can be used to represent elliptic curve points (e.g. public keys) and scalars (e.g. private keys). 16 | 17 | - [`Scalar`] for non-zero scalar values. 18 | - [`Point`] for non-infinity curve points 19 | - [`MaybeScalar`] for possibly-zero scalars. 20 | - [`MaybePoint`] for possibly-infinity curve points. 21 | 22 | Depending on which features of this crate are enabled, we implement various conversion traits between these types and higher-level types such as [`secp256k1::PublicKey`] or [`k256::SecretKey`]. 23 | 24 | ```rust 25 | # #[cfg(all(feature = "secp256k1", feature = "rand"))] 26 | # { 27 | let seckey = secp256k1::SecretKey::new(&mut rand::rng()); 28 | let scalar = secp::Scalar::from(seckey); 29 | secp256k1::SecretKey::from(scalar); 30 | secp256k1::Scalar::from(scalar); 31 | 32 | let point: secp::Point = scalar.base_point_mul(); 33 | secp256k1::PublicKey::from(point); 34 | # } 35 | 36 | # #[cfg(feature = "k256")] 37 | # { 38 | let mut seckey_bytes = [0u8; 32]; 39 | rand::RngCore::fill_bytes(&mut rand::rng(), &mut seckey_bytes); 40 | let seckey = k256::SecretKey::from_slice(&seckey_bytes).unwrap(); 41 | let scalar = secp::Scalar::from(seckey); 42 | k256::SecretKey::from(scalar); 43 | k256::Scalar::from(scalar); 44 | k256::NonZeroScalar::from(scalar); 45 | k256::Scalar::from(secp::MaybeScalar::Valid(scalar)); 46 | assert!(k256::NonZeroScalar::try_from(secp::MaybeScalar::Valid(scalar)).is_ok()); 47 | assert!(k256::NonZeroScalar::try_from(secp::MaybeScalar::Zero).is_err()); 48 | 49 | let point: secp::Point = scalar.base_point_mul(); 50 | k256::PublicKey::from(point); 51 | k256::AffinePoint::from(point); 52 | # } 53 | ``` 54 | 55 | # Scalars 56 | 57 | A [`Scalar`] can represent any integers in the range `[1, n)`, while a [`MaybeScalar`] represents any integer in the range `[0, n)`, where `n` is the secp256k1 elliptic curve order (the number of possible points on the curve). As [`Scalar`] is never zero it doesn't implement [`Default`]). [`MaybeScalar::Zero`] represents the integer zero. 58 | 59 | ```rust 60 | # use secp::Scalar; 61 | pub enum MaybeScalar { 62 | Zero, 63 | Valid(Scalar), 64 | } 65 | ``` 66 | 67 | ## Arithmetic 68 | 69 | Addition, subtract, and multiplication operators are supported by default between the two scalar types. All operations are done in the finite field modulo `n`. 70 | 71 | ```rust 72 | use secp::{MaybeScalar, Scalar}; 73 | 74 | assert_eq!( 75 | (Scalar::one() + Scalar::two()) * Scalar::max(), 76 | Scalar::max() - Scalar::two() 77 | ); 78 | 79 | // Addition or subtraction of two non-zero [`Scalar`] instances will 80 | // output a [`MaybeScalar`], since the sum of two non-zero numbers 81 | // could be zero in a finite field. 82 | assert_eq!(Scalar::one() + Scalar::one(), MaybeScalar::two()); 83 | 84 | // Arithmetic works across commutatively both scalar types. 85 | assert_eq!( 86 | MaybeScalar::from(20) * Scalar::two() - Scalar::try_from(10).unwrap(), 87 | MaybeScalar::from(30) 88 | ); 89 | 90 | // Zero acts like zero. 91 | assert_eq!(MaybeScalar::Zero + Scalar::two(), MaybeScalar::two()); 92 | assert_eq!(MaybeScalar::Zero * Scalar::two(), MaybeScalar::Zero); 93 | ``` 94 | 95 | Division is supported via [modular multiplicative inversion](https://en.wikipedia.org/wiki/Modular_multiplicative_inverse). Since libsecp256k1 does not support this out of the box, scalar inversion requires either the `k256` feature or the `secp256k1-invert` feature to be enabled. 96 | 97 | ```rust 98 | # #[cfg(any(feature = "k256", feature = "secp256k1-invert"))] 99 | # { 100 | # use secp::Scalar; 101 | let x = "0000000000000000000000000000000000000000000000000000000000000aae" 102 | .parse::() 103 | .unwrap(); 104 | 105 | assert_eq!( 106 | x / Scalar::two(), 107 | "0000000000000000000000000000000000000000000000000000000000000557" 108 | .parse() 109 | .unwrap() 110 | ); 111 | 112 | // Since `0xAAF` is an odd number, this would be a fraction if we were 113 | // operating in the real numbers. Since we're operating in a finite field, 114 | // there does exist an integer solution to the equation `x * 2 = 0xAAF` 115 | assert_eq!( 116 | (x + Scalar::one()) / Scalar::two(), 117 | "7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b25f8" 118 | .parse() 119 | .unwrap() 120 | ); 121 | # } 122 | ``` 123 | 124 | Division by a `MaybeScalar` is not defined, since the divisor might be zero. 125 | 126 | ```compile_fail 127 | # use secp::{MaybeScalar, Scalar}; 128 | Scalar::two() / MaybeScalar::two(); 129 | ``` 130 | 131 | ## Formatting 132 | 133 | To reduce the risk of accidental exposure of private keys, signatures, or other secret scalar values, `Scalar` does not implement [`Display`][std::fmt::Display]. 134 | 135 | ```compile_fail 136 | println!("{}", Scalar::max()); 137 | ``` 138 | 139 | Instead, `Scalar`s can be formatted as hex strings explicitly by using `{:x}` or `{:X}` format directives, via the [`LowerHex`][std::fmt::LowerHex] or [`UpperHex`][std::fmt::UpperHex] trait implementations on `Scalar`. Conversion to hex is done in constant-time, but we can't make any guarantees about side-channel leakage beyond that point. 140 | 141 | ```rust 142 | # use secp::{MaybeScalar, Scalar}; 143 | let hex = "e2df7e885217c19c42a8159fd02633f0dc463fadfafc09a71af20bfa2b9036c6"; 144 | let scalar = hex.parse::().unwrap(); 145 | 146 | assert_eq!(format!("{:x}", scalar), hex); 147 | assert_eq!(format!("{:X}", scalar), hex.to_uppercase()); 148 | assert_eq!(format!("{:x}", MaybeScalar::Valid(scalar)), hex); 149 | assert_eq!(format!("{:X}", MaybeScalar::Valid(scalar)), hex.to_uppercase()); 150 | assert_eq!( 151 | format!("{:x}", MaybeScalar::Zero), 152 | "0000000000000000000000000000000000000000000000000000000000000000" 153 | ); 154 | ``` 155 | 156 | # Points 157 | 158 | Valid elliptic curve points are represented by the [`Point`] type. There is a special curve point called _infinity,_ or the _identity point,_ or the _zero point,_ which we represent as [`MaybePoint::Infinity`]. 159 | 160 | ```rust 161 | # use secp::Point; 162 | pub enum MaybePoint { 163 | Infinity, 164 | Valid(Point), 165 | } 166 | ``` 167 | 168 | ## Arithmetic 169 | 170 | Points can be added and subtracted from one-another. 171 | 172 | ```rust 173 | use secp::{MaybePoint, Point}; 174 | 175 | let P1 = "02b435092055e2dc9a1474dac777302c172dde0a40323f0879bff48d002575b685" 176 | .parse::() 177 | .unwrap(); 178 | let P2 = "0375663d8ea90563709204f1b1ff4822220cfb257ed5602609282314ba4e7d492c" 179 | .parse::() 180 | .unwrap(); 181 | 182 | let P3 = "02bc0b73e8233f4fbaa30bcfa540f76d517d385383dd8c9a13ba6dad097f8ea9db" 183 | .parse::() 184 | .unwrap(); 185 | 186 | // Similar to `Scalar`, adding and subtracting non-infinity points 187 | // results in a `MaybePoint`, because point addition is cyclic just 188 | // like scalar addition. 189 | assert_eq!(P1 + P2, MaybePoint::Valid(P3)); 190 | assert_eq!(P3 - P2, MaybePoint::Valid(P1)); 191 | 192 | // Iterators of points can be summed like any other number-like type. 193 | // Prefer this over manually implementing a summation reducer, as 194 | // we offload most of the work to libsecp256k1. 195 | assert_eq!( 196 | [P1, P2].into_iter().sum::(), 197 | MaybePoint::Valid(P3) 198 | ); 199 | ``` 200 | 201 | And of course, the most important operation in elliptic curve cryptography, **scalar-point multiplication** is also supported. 202 | 203 | ```rust 204 | use secp::{MaybePoint, Point, Scalar}; 205 | 206 | let P = "02b435092055e2dc9a1474dac777302c172dde0a40323f0879bff48d002575b685" 207 | .parse::() 208 | .unwrap(); 209 | 210 | let d = Scalar::try_from(3).unwrap(); 211 | 212 | // Multiplying by one is a no-op. 213 | assert_eq!(P * Scalar::one(), P); 214 | 215 | // Multiplying by a non-zero scalar guarantees a non-zero 216 | // point is the output. 217 | assert_eq!( 218 | P * d, 219 | (P + P + P).unwrap() 220 | ); 221 | 222 | // Multiplying by the secp256k1 base point `G` is easy. 223 | assert_eq!( 224 | d.base_point_mul(), 225 | d * Point::generator() 226 | ); 227 | 228 | // We provide a static shortcut to the generator point `G` 229 | // which works with arithemtic operators. 230 | use secp::G; 231 | assert_eq!( 232 | G * d, 233 | (G + G + G).unwrap() 234 | ); 235 | assert_eq!(G - G, MaybePoint::Infinity); 236 | 237 | // Point-scalar division works if scalar inversion is enabled 238 | // by the feature set. 239 | # #[cfg(any(feature = "k256", feature = "secp256k1-invert"))] 240 | assert_eq!(d * G / d, (*G)); 241 | ``` 242 | 243 | ## Formatting 244 | 245 | Like the scalars, [`Point`] and [`MaybePoint`] can be formatted compressed form as hex strings explicitly using `{:x}` and `{:X}` directives. They also implement [`Display`][std::fmt::Display]. The default displayable string value of [`Point`] and [`MaybePoint`] is the compressed lower-case hex encoding. Uncompressed keys can be formatted by adding the `+` flag to the directive, i.e. by formatting as `{:+}` or `{:+x}`. 246 | 247 | ```rust 248 | # use secp::{MaybePoint, Point}; 249 | // Compressed 250 | let point_hex = "02bc0b73e8233f4fbaa30bcfa540f76d517d385383dd8c9a13ba6dad097f8ea9db"; 251 | let point: Point = point_hex.parse().unwrap(); 252 | assert_eq!(point.to_string(), point_hex); 253 | assert_eq!(format!("{}", point), point_hex); 254 | assert_eq!(format!("{:x}", point), point_hex); 255 | assert_eq!(format!("{:X}", point), point_hex.to_uppercase()); 256 | assert_eq!(format!("{:x}", MaybePoint::Valid(point)), point_hex); 257 | assert_eq!(format!("{:X}", MaybePoint::Valid(point)), point_hex.to_uppercase()); 258 | assert_eq!( 259 | format!("{:x}", MaybePoint::Infinity), 260 | "000000000000000000000000000000000000000000000000000000000000000000" 261 | ); 262 | 263 | // Uncompressed 264 | let point_hex_uncompressed = 265 | "04bc0b73e8233f4fbaa30bcfa540f76d517d385383dd8c9a13ba6dad097f8ea9db\ 266 | 6c11d8da7d251e5756c297147a40767bd21d3cd18a830bf79dd4d17ba26fc546"; 267 | let point: Point = point_hex_uncompressed.parse().unwrap(); 268 | assert_eq!(format!("{:+}", point), point_hex_uncompressed); 269 | assert_eq!(format!("{:+x}", point), point_hex_uncompressed); 270 | assert_eq!(format!("{:+X}", point), point_hex_uncompressed.to_uppercase()); 271 | assert_eq!(format!("{:+x}", MaybePoint::Valid(point)), point_hex_uncompressed); 272 | assert_eq!(format!("{:+X}", MaybePoint::Valid(point)), point_hex_uncompressed.to_uppercase()); 273 | assert_eq!( 274 | format!("{:+x}", MaybePoint::Infinity), 275 | "000000000000000000000000000000000000000000000000000000000000000000\ 276 | 0000000000000000000000000000000000000000000000000000000000000000" 277 | ); 278 | ``` 279 | -------------------------------------------------------------------------------- /src/arithmetic.rs: -------------------------------------------------------------------------------- 1 | use super::{MaybePoint, MaybeScalar, Point, Scalar, G}; 2 | 3 | #[cfg(feature = "secp256k1")] 4 | use super::LIBSECP256K1_CTX; 5 | 6 | /// Can't just use `Option` directly here because the blanket 7 | /// `impl Option for T` in the standard library causes conflicts. 8 | trait Optional { 9 | fn option(self) -> Option; 10 | } 11 | 12 | impl Optional for Scalar { 13 | fn option(self) -> Option { 14 | Some(self) 15 | } 16 | } 17 | impl Optional for MaybeScalar { 18 | fn option(self) -> Option { 19 | self.into_option() 20 | } 21 | } 22 | impl Optional for Point { 23 | fn option(self) -> Option { 24 | Some(self) 25 | } 26 | } 27 | impl Optional for MaybePoint { 28 | fn option(self) -> Option { 29 | self.into_option() 30 | } 31 | } 32 | impl Optional for G { 33 | fn option(self) -> Option { 34 | Some(Point::generator()) 35 | } 36 | } 37 | 38 | mod inner_operator_impl { 39 | use super::*; 40 | 41 | /// `Scalar` + `Scalar` 42 | impl std::ops::Add for Scalar { 43 | type Output = MaybeScalar; 44 | 45 | fn add(self, other: Scalar) -> Self::Output { 46 | #[cfg(feature = "secp256k1")] 47 | let inner_result = self.inner.add_tweak(&secp256k1::Scalar::from(other.inner)); 48 | 49 | #[cfg(all(feature = "k256", not(feature = "secp256k1")))] 50 | let inner_result: Option = 51 | (k256::NonZeroScalar::new(self.inner.as_ref() + other.inner.as_ref())).into(); 52 | 53 | inner_result 54 | .map(MaybeScalar::from) 55 | .unwrap_or(MaybeScalar::Zero) 56 | } 57 | } 58 | 59 | /// `Point` + `Point` 60 | impl std::ops::Add for Point { 61 | type Output = MaybePoint; 62 | fn add(self, other: Point) -> Self::Output { 63 | #[cfg(feature = "secp256k1")] 64 | let inner_result = self.inner.combine(&other.inner); 65 | 66 | #[cfg(all(feature = "k256", not(feature = "secp256k1")))] 67 | let inner_result = 68 | k256::PublicKey::try_from(self.inner.to_projective() + other.inner.as_affine()); 69 | 70 | inner_result 71 | .map(MaybePoint::from) 72 | .unwrap_or(MaybePoint::Infinity) 73 | } 74 | } 75 | 76 | /// Note: `Scalar` * `Scalar` always outputs a non-zero `Scalar`. 77 | impl std::ops::Mul for Scalar { 78 | type Output = Scalar; 79 | fn mul(self, other: Scalar) -> Self::Output { 80 | #[cfg(feature = "secp256k1")] 81 | return self 82 | .inner 83 | .mul_tweak(&secp256k1::Scalar::from(other.inner)) 84 | .map(Scalar::from) 85 | .expect("non-zero scalar multiplication never results in zero"); 86 | 87 | #[cfg(all(feature = "k256", not(feature = "secp256k1")))] 88 | return Scalar::from(self.inner * other.inner); 89 | } 90 | } 91 | 92 | /// `Point` * `Scalar` 93 | impl std::ops::Mul for Point { 94 | type Output = Point; 95 | fn mul(self, scalar: Scalar) -> Self::Output { 96 | #[cfg(feature = "secp256k1")] 97 | return self.mul(&LIBSECP256K1_CTX, scalar); 98 | 99 | #[cfg(all(feature = "k256", not(feature = "secp256k1")))] 100 | return { 101 | let nonidentity = 102 | k256::elliptic_curve::point::NonIdentity::new(self.inner.to_projective()) 103 | .unwrap(); 104 | let inner = k256::PublicKey::from(nonidentity * scalar.inner); 105 | Point::from(inner) 106 | }; 107 | } 108 | } 109 | /// `Scalar` * `Point` 110 | impl std::ops::Mul for Scalar { 111 | type Output = Point; 112 | fn mul(self, point: Point) -> Self::Output { 113 | point * self 114 | } 115 | } 116 | 117 | /// -`Scalar` 118 | impl std::ops::Neg for Scalar { 119 | type Output = Scalar; 120 | fn neg(self) -> Self::Output { 121 | #[cfg(feature = "secp256k1")] 122 | let inner = self.inner.negate(); 123 | 124 | #[cfg(all(feature = "k256", not(feature = "secp256k1")))] 125 | let inner = -self.inner; 126 | 127 | Scalar::from(inner) 128 | } 129 | } 130 | impl std::ops::Neg for MaybeScalar { 131 | type Output = MaybeScalar; 132 | fn neg(self) -> Self::Output { 133 | self.into_option() 134 | .map(|scalar| MaybeScalar::Valid(-scalar)) 135 | .unwrap_or(MaybeScalar::Zero) 136 | } 137 | } 138 | 139 | /// `-Point` 140 | impl std::ops::Neg for Point { 141 | type Output = Point; 142 | fn neg(self) -> Self::Output { 143 | #[cfg(feature = "secp256k1")] 144 | return self.negate(&LIBSECP256K1_CTX); 145 | 146 | #[cfg(all(feature = "k256", not(feature = "secp256k1")))] 147 | return Point::from(k256::PublicKey::from_affine(-(*self.inner.as_affine())).unwrap()); 148 | } 149 | } 150 | impl std::ops::Neg for MaybePoint { 151 | type Output = MaybePoint; 152 | fn neg(self) -> Self::Output { 153 | self.into_option() 154 | .map(|p| MaybePoint::Valid(-p)) 155 | .unwrap_or(MaybePoint::Infinity) 156 | } 157 | } 158 | } 159 | 160 | mod generator_ops { 161 | use super::*; 162 | 163 | /// `G` + `G`s 164 | impl std::ops::Add for G { 165 | type Output = Point; 166 | fn add(self, _: G) -> Self::Output { 167 | Scalar::two().base_point_mul() 168 | } 169 | } 170 | 171 | /// `Scalar` * `G` 172 | impl std::ops::Mul for Scalar { 173 | type Output = Point; 174 | fn mul(self, _: G) -> Self::Output { 175 | self.base_point_mul() 176 | } 177 | } 178 | 179 | /// `G` * `Scalar` 180 | impl std::ops::Mul for G { 181 | type Output = Point; 182 | fn mul(self, scalar: Scalar) -> Self::Output { 183 | scalar.base_point_mul() 184 | } 185 | } 186 | 187 | /// `-G` 188 | impl std::ops::Neg for G { 189 | type Output = Point; 190 | fn neg(self) -> Self::Output { 191 | -Point::generator() 192 | } 193 | } 194 | } 195 | 196 | /// Adds any two types together. These could be `Point`, `Scalar`, or the 197 | /// maybe-versions of each - as long as their shared inner type `I` is additive. 198 | /// The output type T3 is always either `MaybePoint` or `MaybeScalar` because 199 | /// addition operations can always result in zero/infinity. 200 | fn add_any(a: T1, b: T2) -> T3 201 | where 202 | T1: Optional, 203 | T2: Optional, 204 | I: std::ops::Add, 205 | T3: From + Default, 206 | { 207 | match a.option() { 208 | None => match b.option() { 209 | None => T3::default(), 210 | Some(b_inner) => T3::from(b_inner), 211 | }, 212 | Some(a_inner) => match b.option() { 213 | None => T3::from(a_inner), 214 | Some(b_inner) => a_inner + b_inner, 215 | }, 216 | } 217 | } 218 | 219 | /// Simply addition with the right-hand-side negated. 220 | fn subtract_any(a: T1, b: T2) -> T3 221 | where 222 | T1: std::ops::Add, 223 | T2: std::ops::Neg, 224 | { 225 | a + (-b) 226 | } 227 | 228 | /// Multiplies any two items which must be commutatively multiplicative, 229 | /// (i.e. a*b = b*a) where the product of their inner types `I1` and `I2` 230 | /// can be converted to the output type `T3`. 231 | /// 232 | /// This implementation supports both point multiplication by scalars, or 233 | /// scalar-by-scalar multiplication. 234 | fn multiply_any(a: T1, b: T2) -> T3 235 | where 236 | T1: Optional, 237 | T2: Optional, 238 | I1: std::ops::Mul, 239 | I2: std::ops::Mul, 240 | T3: Default + From, 241 | { 242 | match a.option().zip(b.option()) { 243 | None => T3::default(), 244 | Some((a_inner, b_inner)) => T3::from(a_inner * b_inner), 245 | } 246 | } 247 | 248 | /// Implement a binary operator from `std::ops`. 249 | /// 250 | /// - `$opname` is the trait name from `std::ops`, such as `Add`, `Sub`, or `Mul`. 251 | /// - `$opfunc` is the function identifier for the trait. 252 | /// - `$op_logic` is a function which generically implements the operation logic. 253 | /// - `$lhs_type` and `$rhs_type` are types to implement the trait on. 254 | /// - `$operator` is the binary operator which is being implemented. This is just for decoration. 255 | macro_rules! implement_binary_ops { 256 | ( 257 | $opname:ident, $opfunc:ident, // Add, add, 258 | $op_logic:ident, // implementation function 259 | $( $lhs_type:ident $operator:tt $rhs_type:ident -> $output_type:ident; )+ // Type1 + Type2 -> OutputType 260 | ) => { 261 | $( 262 | impl std::ops::$opname<$rhs_type> for $lhs_type { 263 | type Output = $output_type; 264 | 265 | fn $opfunc(self, rhs: $rhs_type) -> Self::Output { 266 | $op_logic(self, rhs) 267 | } 268 | } 269 | )+ 270 | }; 271 | } 272 | 273 | /// Implement a binary assignment operator from `std::ops`. 274 | /// 275 | /// - `$opname` is the trait name from `std::ops`, such as `AddAssign`, or `MulAssign`. 276 | /// - `$opfunc` is the function identifier for the trait. 277 | /// - `$lhs_type` and `$rhs_type` are types to implement the trait on. 278 | /// - `$operator` is the binary operator which is being implemented. This is used 279 | /// to invoke the actual binary operator. 280 | macro_rules! implement_assign_ops { 281 | ( 282 | $opname:ident, $opfunc:ident, // AddAssign, add_assign, 283 | $( $lhs_type:ident $operator:tt $rhs_type:ident; )+ 284 | ) => { 285 | $( 286 | impl std::ops::$opname<$rhs_type> for $lhs_type { 287 | fn $opfunc(&mut self, rhs: $rhs_type) { 288 | *self = *self $operator rhs; 289 | } 290 | } 291 | )+ 292 | }; 293 | } 294 | 295 | implement_binary_ops!( 296 | Add, add, add_any, 297 | 298 | Scalar + MaybeScalar -> MaybeScalar; 299 | MaybeScalar + Scalar -> MaybeScalar; 300 | MaybeScalar + MaybeScalar -> MaybeScalar; 301 | 302 | Point + MaybePoint -> MaybePoint; 303 | MaybePoint + Point -> MaybePoint; 304 | MaybePoint + MaybePoint -> MaybePoint; 305 | 306 | Point + G -> MaybePoint; 307 | MaybePoint + G -> MaybePoint; 308 | G + Point -> MaybePoint; 309 | G + MaybePoint -> MaybePoint; 310 | ); 311 | 312 | implement_binary_ops!( 313 | Sub, sub, subtract_any, 314 | 315 | Scalar - Scalar -> MaybeScalar; 316 | Scalar - MaybeScalar -> MaybeScalar; 317 | MaybeScalar - Scalar -> MaybeScalar; 318 | MaybeScalar - MaybeScalar -> MaybeScalar; 319 | 320 | Point - Point -> MaybePoint; 321 | Point - MaybePoint -> MaybePoint; 322 | MaybePoint - Point -> MaybePoint; 323 | MaybePoint - MaybePoint -> MaybePoint; 324 | 325 | G - G -> MaybePoint; 326 | Point - G -> MaybePoint; 327 | MaybePoint - G -> MaybePoint; 328 | G - Point -> MaybePoint; 329 | G - MaybePoint -> MaybePoint; 330 | ); 331 | 332 | implement_binary_ops!( 333 | Mul, mul, multiply_any, 334 | 335 | Scalar * MaybeScalar -> MaybeScalar; 336 | MaybeScalar * Scalar -> MaybeScalar; 337 | MaybeScalar * MaybeScalar -> MaybeScalar; 338 | 339 | Point * MaybeScalar -> MaybePoint; 340 | MaybePoint * Scalar -> MaybePoint; 341 | MaybePoint * MaybeScalar -> MaybePoint; 342 | 343 | MaybeScalar * Point -> MaybePoint; 344 | Scalar * MaybePoint -> MaybePoint; 345 | MaybeScalar * MaybePoint -> MaybePoint; 346 | 347 | MaybeScalar * G -> MaybePoint; 348 | G * MaybeScalar -> MaybePoint; 349 | ); 350 | 351 | implement_assign_ops!( 352 | AddAssign, add_assign, 353 | 354 | MaybeScalar + Scalar; 355 | MaybeScalar + MaybeScalar; 356 | 357 | MaybePoint + Point; 358 | MaybePoint + MaybePoint; 359 | MaybePoint + G; 360 | 361 | // Cannot `AddAssign` to `Scalar` or `Point`, 362 | // because addition can always result in a zero result. 363 | ); 364 | 365 | implement_assign_ops!( 366 | SubAssign, sub_assign, 367 | MaybeScalar - Scalar; 368 | MaybeScalar - MaybeScalar; 369 | 370 | MaybePoint - Point; 371 | MaybePoint - MaybePoint; 372 | MaybePoint - G; 373 | 374 | // Cannot `SubAssign` to `Scalar` or `Point`, 375 | // because addition can always result in a zero result. 376 | ); 377 | 378 | implement_assign_ops!( 379 | MulAssign, mul_assign, 380 | 381 | Scalar * Scalar; 382 | MaybeScalar * Scalar; 383 | MaybeScalar * MaybeScalar; 384 | 385 | Point * Scalar; 386 | MaybePoint * Scalar; 387 | MaybePoint * MaybeScalar; 388 | ); 389 | 390 | #[cfg(any(feature = "k256", feature = "secp256k1-invert"))] 391 | mod division { 392 | use super::*; 393 | 394 | /// To divide by `rhs`, we simply multiply by `rhs.inverse()`, because `rhs.inverse()` 395 | /// is algebraically the same as `1 / rhs`. 396 | #[allow(clippy::suspicious_arithmetic_impl)] 397 | impl std::ops::Div for Scalar { 398 | type Output = Scalar; 399 | fn div(self, rhs: Scalar) -> Self::Output { 400 | self * rhs.invert() 401 | } 402 | } 403 | 404 | /// To divide by `rhs`, we simply multiply by `rhs.inverse()`, because `rhs.inverse()` 405 | /// is algebraically the same as `1 / rhs`. 406 | #[allow(clippy::suspicious_arithmetic_impl)] 407 | impl std::ops::Div for Point { 408 | type Output = Point; 409 | fn div(self, rhs: Scalar) -> Self::Output { 410 | self * rhs.invert() 411 | } 412 | } 413 | 414 | /// To divide by `rhs`, we simply multiply by `rhs.inverse()`, because `rhs.inverse()` 415 | /// is algebraically the same as `1 / rhs`. 416 | #[allow(clippy::suspicious_arithmetic_impl)] 417 | impl std::ops::Div for G { 418 | type Output = Point; 419 | fn div(self, rhs: Scalar) -> Self::Output { 420 | self * rhs.invert() 421 | } 422 | } 423 | 424 | /// Divides any two items which can be divided. The left-hand-side type `T1` 425 | /// can be optional with internal type `I1`, but the right-hand-side must 426 | /// be non-zero for division to be defined. 427 | /// 428 | /// The quotient type of `T1 / I1` must be convertible to the output type `T3`. 429 | /// 430 | /// This implementation supports point multiplication by inverted scalars, or 431 | /// modular division of scalars. 432 | fn divide_any(a: T1, b: T2) -> T3 433 | where 434 | T1: Optional, 435 | I1: std::ops::Div, 436 | T3: Default + From, 437 | { 438 | match a.option() { 439 | None => T3::default(), 440 | Some(a_inner) => T3::from(a_inner / b), 441 | } 442 | } 443 | 444 | implement_binary_ops!( 445 | Div, div, divide_any, 446 | MaybeScalar / Scalar -> MaybeScalar; 447 | MaybePoint / Scalar -> MaybePoint; 448 | ); 449 | 450 | implement_assign_ops!( 451 | DivAssign, div_assign, 452 | 453 | Scalar / Scalar; 454 | MaybeScalar / Scalar; 455 | 456 | Point / Scalar; 457 | MaybePoint / Scalar; 458 | ); 459 | } 460 | -------------------------------------------------------------------------------- /src/points.rs: -------------------------------------------------------------------------------- 1 | use once_cell::sync::Lazy; 2 | use subtle::ConditionallySelectable; 3 | 4 | use super::errors::{InfinityPointError, InvalidPointBytes, InvalidPointString}; 5 | 6 | #[cfg(feature = "secp256k1")] 7 | use super::{MaybeScalar, Scalar}; 8 | 9 | use subtle::ConstantTimeEq as _; 10 | 11 | #[cfg(all(feature = "k256", not(feature = "secp256k1")))] 12 | use k256::elliptic_curve::point::{AffineCoordinates as _, DecompactPoint as _}; 13 | 14 | #[cfg(feature = "k256")] 15 | use k256::elliptic_curve::sec1::ToEncodedPoint as _; 16 | 17 | const GENERATOR_POINT_BYTES: [u8; 65] = [ 18 | 0x04, // The DER encoding tag 19 | // 20 | // The X coordinate of the generator. 21 | 0x79, 0xbe, 0x66, 0x7e, 0xf9, 0xdc, 0xbb, 0xac, 0x55, 0xa0, 0x62, 0x95, 0xce, 0x87, 0x0b, 0x07, 22 | 0x02, 0x9b, 0xfc, 0xdb, 0x2d, 0xce, 0x28, 0xd9, 0x59, 0xf2, 0x81, 0x5b, 0x16, 0xf8, 0x17, 0x98, 23 | // 24 | // The Y coordinate of the generator. 25 | 0x48, 0x3a, 0xda, 0x77, 0x26, 0xa3, 0xc4, 0x65, 0x5d, 0xa4, 0xfb, 0xfc, 0x0e, 0x11, 0x08, 0xa8, 26 | 0xfd, 0x17, 0xb4, 0x48, 0xa6, 0x85, 0x54, 0x19, 0x9c, 0x47, 0xd0, 0x8f, 0xfb, 0x10, 0xd4, 0xb8, 27 | ]; 28 | 29 | static GENERATOR_POINT: Lazy = 30 | Lazy::new(|| Point::try_from(&GENERATOR_POINT_BYTES).unwrap()); 31 | 32 | /// This struct type represents the secp256k1 generator point, and can be 33 | /// used for scalar-point multiplication. 34 | /// 35 | /// ``` 36 | /// use secp::{G, Scalar}; 37 | /// 38 | /// let privkey = Scalar::try_from([0xAB; 32]).unwrap(); 39 | /// assert_eq!(privkey * G, privkey.base_point_mul()); 40 | /// ``` 41 | /// 42 | /// `G` dereferences as [`Point`], allowing reuse of `Point` methods and traits. 43 | /// 44 | /// ``` 45 | /// # use secp::G; 46 | /// assert!(G.has_even_y()); 47 | /// assert_eq!( 48 | /// G.serialize_uncompressed(), 49 | /// [ 50 | /// 0x04, 0x79, 0xbe, 0x66, 0x7e, 0xf9, 0xdc, 0xbb, 0xac, 0x55, 0xa0, 0x62, 0x95, 0xce, 51 | /// 0x87, 0x0b, 0x07, 0x02, 0x9b, 0xfc, 0xdb, 0x2d, 0xce, 0x28, 0xd9, 0x59, 0xf2, 0x81, 52 | /// 0x5b, 0x16, 0xf8, 0x17, 0x98, 0x48, 0x3a, 0xda, 0x77, 0x26, 0xa3, 0xc4, 0x65, 0x5d, 53 | /// 0xa4, 0xfb, 0xfc, 0x0e, 0x11, 0x08, 0xa8, 0xfd, 0x17, 0xb4, 0x48, 0xa6, 0x85, 0x54, 54 | /// 0x19, 0x9c, 0x47, 0xd0, 0x8f, 0xfb, 0x10, 0xd4, 0xb8, 55 | /// ] 56 | /// ); 57 | /// ``` 58 | #[derive(Debug, Default)] 59 | pub struct G; 60 | 61 | impl std::ops::Deref for G { 62 | type Target = Point; 63 | fn deref(&self) -> &Self::Target { 64 | &GENERATOR_POINT 65 | } 66 | } 67 | 68 | /// Represents a valid non-infinity point on the secp256k1 curve. 69 | /// Internally this wraps either [`secp256k1::PublicKey`] or [`k256::PublicKey`] 70 | /// depending on which feature set is enabled. 71 | /// 72 | /// `Point` supports constant time arithmetic operations using addition, 73 | /// subtraction, negation, and multiplication with other types in this crate. 74 | /// 75 | /// Curve arithmetic is performed using traits from [`std::ops`]. 76 | #[derive(Clone, Copy, PartialEq, Eq)] 77 | #[cfg_attr(feature = "secp256k1", derive(Ord, PartialOrd))] 78 | pub struct Point { 79 | #[cfg(feature = "secp256k1")] 80 | pub(crate) inner: secp256k1::PublicKey, 81 | 82 | #[cfg(all(feature = "k256", not(feature = "secp256k1")))] 83 | pub(crate) inner: k256::PublicKey, 84 | } 85 | 86 | impl Point { 87 | /// Returns the secp256k1 generator base point `G`. 88 | pub fn generator() -> Point { 89 | *GENERATOR_POINT 90 | } 91 | 92 | /// Serializes the point into compressed DER encoding. This consists of a parity 93 | /// byte at the beginning, which is either `0x02` (even parity) or `0x03` (odd parity), 94 | /// followed by the big-endian encoding of the point's X-coordinate. 95 | pub fn serialize(&self) -> [u8; 33] { 96 | #[cfg(feature = "secp256k1")] 97 | return self.inner.serialize(); 98 | 99 | #[cfg(all(feature = "k256", not(feature = "secp256k1")))] 100 | return { 101 | let encoded_point = self.inner.to_encoded_point(true); 102 | <[u8; 33]>::try_from(encoded_point.as_bytes()).unwrap() 103 | }; 104 | } 105 | 106 | /// Serializes the point into uncompressed DER encoding. This consists of a static tag 107 | /// byte `0x04`, followed by the point's X-coordinate and Y-coordinate encoded sequentially 108 | /// (X then Y) as big-endian integers. 109 | pub fn serialize_uncompressed(&self) -> [u8; 65] { 110 | #[cfg(feature = "secp256k1")] 111 | return self.inner.serialize_uncompressed(); 112 | 113 | #[cfg(all(feature = "k256", not(feature = "secp256k1")))] 114 | return { 115 | let encoded_point = self.inner.to_encoded_point(false); 116 | <[u8; 65]>::try_from(encoded_point.as_bytes()).unwrap() 117 | }; 118 | } 119 | 120 | /// Serializes the point into BIP340 X-only representation. This consists solely of the 121 | /// big-endian encoding of the point's X-coordinate. 122 | pub fn serialize_xonly(&self) -> [u8; 32] { 123 | #[cfg(feature = "secp256k1")] 124 | return self.inner.x_only_public_key().0.serialize(); 125 | 126 | #[cfg(all(feature = "k256", not(feature = "secp256k1")))] 127 | return <[u8; 32]>::from(self.inner.as_affine().x()); 128 | } 129 | 130 | /// Parses a non-infinity point from a given byte slice, which can be either 33 or 65 131 | /// bytes long, depending on whether it represents a compressed or uncompressed point. 132 | pub fn from_slice(bytes: &[u8]) -> Result { 133 | Self::try_from(bytes) 134 | } 135 | 136 | /// Parses a non-infinity point from a given hex string, which can be 137 | /// in compressed or uncompressed format. 138 | pub fn from_hex(hex: &str) -> Result { 139 | let mut bytes = [0; 65]; 140 | let slice = base16ct::mixed::decode(hex, &mut bytes).map_err(|_| InvalidPointString)?; 141 | Point::try_from(slice).map_err(|_| InvalidPointString) 142 | } 143 | 144 | /// Returns `subtle::Choice::from(0)` if the point's Y-coordinate is even, or 145 | /// `subtle::Choice::from(1)` if the Y-coordinate is odd. 146 | pub fn parity(&self) -> subtle::Choice { 147 | #[cfg(feature = "secp256k1")] 148 | return self.inner.x_only_public_key().1.to_u8().into(); 149 | 150 | #[cfg(all(feature = "k256", not(feature = "secp256k1")))] 151 | return self.inner.as_affine().y_is_odd(); 152 | } 153 | 154 | /// Returns `true` if the point's Y-coordinate is even, or `false` if the Y-coordinate is odd. 155 | pub fn has_even_y(&self) -> bool { 156 | bool::from(!self.parity()) 157 | } 158 | 159 | /// Returns `true` if the point's Y-coordinate is odd, or `false` if the Y-coordinate is even. 160 | pub fn has_odd_y(&self) -> bool { 161 | bool::from(self.parity()) 162 | } 163 | 164 | /// Returns a point with the same X-coordinate but with the Y-coordinate's parity set 165 | /// to the given parity, with `subtle::Choice::from(1)` indicating odd parity and 166 | /// `subtle::Choice::from(0)` indicating even parity. 167 | pub fn with_parity(self, parity: subtle::Choice) -> Self { 168 | #[cfg(feature = "secp256k1")] 169 | let inner = secp256k1::PublicKey::from_x_only_public_key( 170 | self.inner.x_only_public_key().0, 171 | secp256k1::Parity::from_u8(parity.unwrap_u8()) 172 | .expect("subtle::Choice should only represent parity of either 0 or 1"), 173 | ); 174 | 175 | #[cfg(all(feature = "k256", not(feature = "secp256k1")))] 176 | let inner = { 177 | let mut affine = *self.inner.as_affine(); 178 | let should_negate = affine.y_is_odd() ^ parity; 179 | affine.conditional_assign(&(-affine), should_negate); 180 | k256::PublicKey::from_affine(affine).unwrap() 181 | }; 182 | 183 | Point::from(inner) 184 | } 185 | 186 | /// Returns a new point with the Y-coordinate coerced flipped to be even. 187 | pub fn to_even_y(self) -> Self { 188 | self.with_parity(subtle::Choice::from(0)) 189 | } 190 | 191 | /// Returns a new point with the Y-coordinate coerced flipped to be odd. 192 | pub fn to_odd_y(self) -> Self { 193 | self.with_parity(subtle::Choice::from(1)) 194 | } 195 | 196 | /// Parses a point with even parity from a BIP340 X-only public-key serialization representation. 197 | /// 198 | /// Every possible non-zero X-coordinate on the secp256k1 curve has exactly 199 | /// two corresponding Y-coordinates: one even, and one odd. This function computes 200 | /// the point for which the X-coordinate is represented by `x_bytes`, and the Y-coordinate 201 | /// is even. 202 | pub fn lift_x(x_bytes: [u8; 32]) -> Result { 203 | #[cfg(feature = "secp256k1")] 204 | return secp256k1::XOnlyPublicKey::from_byte_array(x_bytes) 205 | .map(|xonly| Point::from((xonly, secp256k1::Parity::Even))) 206 | .map_err(|_| InvalidPointBytes); 207 | 208 | #[cfg(all(feature = "k256", not(feature = "secp256k1")))] 209 | return { 210 | let point_opt = k256::AffinePoint::decompact((&x_bytes).into()) 211 | .and_then(k256::elliptic_curve::point::NonIdentity::new); 212 | 213 | Option::>::from(point_opt) 214 | .map(k256::PublicKey::from) 215 | .map(Point::from) 216 | .ok_or(InvalidPointBytes) 217 | }; 218 | } 219 | 220 | /// Parses a point from a BIP340 X-only public-key hex serialization. 221 | /// 222 | /// Every possible non-zero X-coordinate on the secp256k1 curve has exactly 223 | /// two corresponding Y-coordinates: one even, and one odd. This function computes 224 | /// the point for which the X-coordinate is represented by `x_bytes_hex`, and the 225 | /// Y-coordinate is even. 226 | pub fn lift_x_hex(x_bytes_hex: &str) -> Result { 227 | #[cfg(feature = "secp256k1")] 228 | return x_bytes_hex 229 | .parse::() 230 | .map(|xonly| Point::from((xonly, secp256k1::Parity::Even))) 231 | .map_err(|_| InvalidPointString); 232 | 233 | #[cfg(all(feature = "k256", not(feature = "secp256k1")))] 234 | return { 235 | let mut x_bytes = [0; 32]; 236 | base16ct::mixed::decode(x_bytes_hex, &mut x_bytes).map_err(|_| InvalidPointString)?; 237 | Point::lift_x(x_bytes).map_err(|_| InvalidPointString) 238 | }; 239 | } 240 | 241 | /// Aggregate an iterator of points together by simple summation. 242 | /// The iterator item type `T` can be any type that borrows as a 243 | /// `Point`, including `Point` itself, or `&Point`. 244 | /// 245 | /// `Point::sum(points)` should be preferred over summing up the `points` 246 | /// one at a time. This function offloads most of the work to `libsecp256k1`, 247 | /// reducing overhead if the `secp256k1` crate feature is enabled. 248 | pub fn sum(points: impl IntoIterator) -> MaybePoint 249 | where 250 | T: std::borrow::Borrow, 251 | { 252 | #[cfg(feature = "secp256k1")] 253 | return { 254 | let points_vec: Vec = points.into_iter().collect(); 255 | 256 | let pubkeys_vec: Vec<&secp256k1::PublicKey> = points_vec 257 | .iter() 258 | .map(|point| &point.borrow().inner) 259 | .collect(); 260 | 261 | secp256k1::PublicKey::combine_keys(&pubkeys_vec) 262 | .map(MaybePoint::from) 263 | .unwrap_or(MaybePoint::Infinity) 264 | }; 265 | 266 | #[cfg(all(feature = "k256", not(feature = "secp256k1")))] 267 | return { 268 | let affine = points 269 | .into_iter() 270 | .map(|p| p.borrow().inner.to_projective()) 271 | .sum::() 272 | .to_affine(); 273 | 274 | k256::PublicKey::try_from(affine) 275 | .map(MaybePoint::from) 276 | .unwrap_or(MaybePoint::Infinity) 277 | }; 278 | } 279 | 280 | /// Negates the point, returning the point `P` such that `self + P = MaybePoint::Infinity`. 281 | /// Always returns a non-infinity point. 282 | /// 283 | /// This method uses a specific `libsecp256k1` context object instead of the global 284 | /// context used by the `std::ops` implementations. 285 | #[cfg(feature = "secp256k1")] 286 | pub fn negate(self, secp: &secp256k1::Secp256k1) -> Point { 287 | Point::from(self.inner.negate(secp)) 288 | } 289 | 290 | /// Subtracts two points, returning `self - other`. This computes the point `P` such 291 | /// that `self + P = other`. Returns `MaybePoint::Infinity` if `self == other`. 292 | /// 293 | /// This method uses a specific `libsecp256k1` context object instead of the global 294 | /// context used by the `std::ops` implementations. 295 | #[cfg(feature = "secp256k1")] 296 | pub fn sub( 297 | self, 298 | secp: &secp256k1::Secp256k1, 299 | other: Point, 300 | ) -> MaybePoint { 301 | self + other.negate(secp) 302 | } 303 | 304 | /// Subtracts two points, returning `self - other`. This computes the point `P` such 305 | /// that `self + P = other`. Returns [`MaybePoint::Infinity`] if `self == other`. 306 | /// Returns `self` if `other == MaybePoint::Infinity`. 307 | /// 308 | /// This method uses a specific `libsecp256k1` context object instead of the global 309 | /// context used by the `std::ops` implementations. 310 | #[cfg(feature = "secp256k1")] 311 | pub fn sub_maybe( 312 | self, 313 | secp: &secp256k1::Secp256k1, 314 | other: MaybePoint, 315 | ) -> MaybePoint { 316 | self + other.negate(secp) 317 | } 318 | 319 | /// Multiplies the point by the given scalar. Always returns a non-infinity point. 320 | /// 321 | /// This method uses a specific `libsecp256k1` context object instead of the global 322 | /// context used by the `std::ops` implementations. 323 | #[cfg(feature = "secp256k1")] 324 | pub fn mul( 325 | self, 326 | secp: &secp256k1::Secp256k1, 327 | scalar: Scalar, 328 | ) -> Point { 329 | Point::from( 330 | self.inner 331 | .mul_tweak(secp, &secp256k1::Scalar::from(scalar)) 332 | .unwrap(), // point multiplication by a non-zero scalar never fails or hits infinity. 333 | ) 334 | } 335 | 336 | /// Multiplies the point by the given scalar. Returns [`MaybePoint::Infinity`] 337 | /// if `scalar == MaybeScalar::Zero`. 338 | /// 339 | /// This method uses a specific `libsecp256k1` context object instead of the global 340 | /// context used by the `std::ops` implementations. 341 | #[cfg(feature = "secp256k1")] 342 | pub fn mul_maybe( 343 | self, 344 | secp: &secp256k1::Secp256k1, 345 | scalar: MaybeScalar, 346 | ) -> MaybePoint { 347 | match scalar.into_option() { 348 | Some(scalar) => Valid(self.mul(secp, scalar)), 349 | None => Infinity, 350 | } 351 | } 352 | 353 | /// Negates the point in constant-time if the given parity bit is a 1. 354 | pub fn negate_if(self, parity: subtle::Choice) -> Point { 355 | Point::conditional_select(&self, &(-self), parity) 356 | } 357 | } 358 | 359 | /// This type is effectively the same as [`Point`], except it can also 360 | /// represent the point at infinity, exposed as [`MaybePoint::Infinity`]. 361 | /// This is the special 'zero-point', or 'identity element' on the curve 362 | /// for which `MaybePoint::Infinity + X = X` and 363 | /// `MaybePoint::Infinity * X = MaybePoint::Infinity` for any other point `X`. 364 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 365 | pub enum MaybePoint { 366 | /// Represents the point at infinity, for which `MaybePoint::Infinity + X = X` 367 | /// and `MaybePoint::Infinity * X = MaybePoint::Infinity` for any other point `X`. 368 | Infinity, 369 | 370 | /// Represents a valid non-infinity curve point. 371 | Valid(Point), 372 | } 373 | 374 | use MaybePoint::*; 375 | 376 | impl MaybePoint { 377 | /// Serializes the point into compressed DER encoding. This consists of a parity 378 | /// byte at the beginning, which is either `0x02` (even parity) or `0x03` (odd parity), 379 | /// followed by the big-endian encoding of the point's X-coordinate. 380 | /// 381 | /// If `self == MaybePoint::Infinity`, this returns 33 zero bytes. 382 | pub fn serialize(&self) -> [u8; 33] { 383 | match self { 384 | Valid(point) => point.serialize(), 385 | Infinity => [0; 33], 386 | } 387 | } 388 | 389 | /// Serializes the point into uncompressed DER encoding. This consists of a static tag 390 | /// byte `0x04`, followed by the point's X-coordinate and Y-coordinate encoded sequentially 391 | /// (X then Y) as big-endian integers. 392 | /// 393 | /// If `self == MaybePoint::Infinity`, this returns 65 zero bytes. 394 | pub fn serialize_uncompressed(&self) -> [u8; 65] { 395 | match self { 396 | Valid(point) => point.serialize_uncompressed(), 397 | Infinity => [0; 65], 398 | } 399 | } 400 | 401 | /// Serializes the point into BIP340 X-only representation. This consists solely of the 402 | /// big-endian encoding of the point's X-coordinate. 403 | /// 404 | /// If `self == MaybePoint::Infinity`, this returns 32 zero bytes. 405 | pub fn serialize_xonly(&self) -> [u8; 32] { 406 | match self { 407 | Valid(point) => point.serialize_xonly(), 408 | Infinity => [0; 32], 409 | } 410 | } 411 | 412 | /// Parses a point from a given byte slice, which can be either 33 or 65 bytes 413 | /// long, depending on whether it represents a compressed or uncompressed point. 414 | pub fn from_slice(bytes: &[u8]) -> Result { 415 | Self::try_from(bytes) 416 | } 417 | 418 | /// Parses a point from a given hex string, which can be in compressed 419 | /// or uncompressed format. 420 | /// 421 | /// Returns [`MaybePoint::Infinity`] if the input is 33-hex-encoded zero bytes. 422 | pub fn from_hex(hex: &str) -> Result { 423 | let is_compressed_inf = hex 424 | .as_bytes() 425 | .ct_eq(POINT_INFINITY_COMPRESSED_STR.as_bytes()); 426 | let is_uncompressed_inf = hex 427 | .as_bytes() 428 | .ct_eq(POINT_INFINITY_UNCOMPRESSED_STR.as_bytes()); 429 | 430 | if bool::from(is_compressed_inf | is_uncompressed_inf) { 431 | return Ok(MaybePoint::Infinity); 432 | } 433 | 434 | Ok(MaybePoint::Valid(Point::from_hex(hex)?)) 435 | } 436 | 437 | /// Returns `subtle::Choice::from(0)` if the point's Y-coordinate is even or infinity. 438 | /// Returns `subtle::Choice::from(1)` if the Y-coordinate is odd. 439 | pub fn parity(&self) -> subtle::Choice { 440 | match self { 441 | Infinity => subtle::Choice::from(0), 442 | Valid(p) => p.parity(), 443 | } 444 | } 445 | 446 | /// Returns `true` if the point's Y-coordinate is even, or `false` if the Y-coordinate is odd. 447 | /// Also returns true if the point is [`Infinity`]. 448 | pub fn has_even_y(&self) -> bool { 449 | bool::from(!self.parity()) 450 | } 451 | 452 | /// Returns `true` if the point's Y-coordinate is odd, or `false` if the Y-coordinate is even. 453 | /// Returns false if the point is [`Infinity`]. 454 | pub fn has_odd_y(&self) -> bool { 455 | bool::from(self.parity()) 456 | } 457 | 458 | /// Returns a point with the same X-coordinate but with the Y-coordinate's parity set 459 | /// to the given parity, with `subtle::Choice::from(1)` indicating odd parity and 460 | /// `subtle::Choice::from(0)` indicating even parity. 461 | /// 462 | /// The [`Infinity`] point is returned unchanged. 463 | pub fn with_parity(self, parity: subtle::Choice) -> Self { 464 | match self { 465 | Infinity => self, 466 | Valid(p) => Valid(p.with_parity(parity)), 467 | } 468 | } 469 | 470 | /// Returns a new point with the Y-coordinate coerced flipped to be even. 471 | /// The [`Infinity`] point is returned unchanged. 472 | pub fn to_even_y(self) -> Self { 473 | self.with_parity(subtle::Choice::from(0)) 474 | } 475 | 476 | /// Returns a new point with the Y-coordinate coerced flipped to be odd. 477 | /// The [`Infinity`] point is returned unchanged. 478 | pub fn to_odd_y(self) -> Self { 479 | self.with_parity(subtle::Choice::from(1)) 480 | } 481 | 482 | /// Aggregate an iterator of points together by simple summation. 483 | /// The iterator item type `T` can be any type that borrows as a 484 | /// [`MaybePoint`], including `MaybePoint` itself, or `&MaybePoint`. 485 | /// 486 | /// `MaybePoint::sum(maybe_points)` should be preferred over summing up 487 | /// the `maybe_points` one at a time. This function offloads most of the 488 | /// work to libsecp256k1, reducing overhead if the `secp256k1` crate feature 489 | /// is enabled. 490 | /// 491 | /// This logic is also used in the implementation of `std::iter::Sum`. 492 | pub fn sum(maybe_points: impl IntoIterator) -> MaybePoint 493 | where 494 | T: std::borrow::Borrow, 495 | { 496 | let points_vec: Vec = maybe_points 497 | .into_iter() 498 | .filter_map(|maybe_point| maybe_point.borrow().into_option()) // filter out points at infinity 499 | .collect(); 500 | Point::sum(points_vec) 501 | } 502 | 503 | /// Negates the point, returning the point `P` such that `self + P = MaybePoint::Infinity` 504 | /// Returns [`MaybePoint::Infinity`] if `self == MaybePoint::Infinity`. 505 | /// 506 | /// This method uses a specific `libsecp256k1` context object instead of the global 507 | /// context used by the `std::ops` implementations. 508 | #[cfg(feature = "secp256k1")] 509 | pub fn negate(self, secp: &secp256k1::Secp256k1) -> MaybePoint { 510 | match self { 511 | Valid(point) => Valid(point.negate(secp)), 512 | Infinity => Infinity, 513 | } 514 | } 515 | 516 | /// Subtracts two points, returning `self - other`. This computes the point `P` such 517 | /// that `self + P = other`. Returns [`MaybePoint::Infinity`] if `self == other`. 518 | /// Returns `-other` if `self == MaybePoint::Infinity`. 519 | /// 520 | /// This method uses a specific `libsecp256k1` context object instead of the global 521 | /// context used by the `std::ops` implementations. 522 | #[cfg(feature = "secp256k1")] 523 | pub fn sub( 524 | self, 525 | secp: &secp256k1::Secp256k1, 526 | other: Point, 527 | ) -> MaybePoint { 528 | self + other.negate(secp) 529 | } 530 | 531 | /// Subtracts two points, returning `self - other`. This computes the point `P` such 532 | /// that `self + P = other`. Returns [`MaybePoint::Infinity`] if `self == other`. 533 | /// Returns `self` if `other == MaybePoint::Infinity`. 534 | /// 535 | /// This method uses a specific `libsecp256k1` context object instead of the global 536 | /// context used by the `std::ops` implementations. 537 | #[cfg(feature = "secp256k1")] 538 | pub fn sub_maybe( 539 | self, 540 | secp: &secp256k1::Secp256k1, 541 | other: MaybePoint, 542 | ) -> MaybePoint { 543 | self + other.negate(secp) 544 | } 545 | 546 | /// Multiplies the point by the given scalar. Returns[ `MaybePoint::Infinity`] 547 | /// if `self == MaybePoint::Infinity`. 548 | /// 549 | /// This method uses a specific `libsecp256k1` context object instead of the global 550 | /// context used by the `std::ops` implementations. 551 | #[cfg(feature = "secp256k1")] 552 | pub fn mul( 553 | self, 554 | secp: &secp256k1::Secp256k1, 555 | scalar: Scalar, 556 | ) -> MaybePoint { 557 | match self { 558 | Valid(point) => Valid(point.mul(secp, scalar)), 559 | Infinity => Infinity, 560 | } 561 | } 562 | 563 | /// Multiplies the point by a scalar. Returns [`MaybePoint::Infinity`] if 564 | /// `self == MaybePoint::Infinity || scalar == MaybeScalar::Zero`. 565 | /// 566 | /// This method uses a specific `libsecp256k1` context object instead of the global 567 | /// context used by the `std::ops` implementations. 568 | #[cfg(feature = "secp256k1")] 569 | pub fn mul_maybe( 570 | self, 571 | secp: &secp256k1::Secp256k1, 572 | scalar: MaybeScalar, 573 | ) -> MaybePoint { 574 | match self { 575 | Valid(point) => point.mul_maybe(secp, scalar), 576 | Infinity => Infinity, 577 | } 578 | } 579 | 580 | /// Returns an option which is `None` if `self == MaybePoint::Infinity`, 581 | /// or a `Some(Point)` otherwise. 582 | pub fn into_option(self) -> Option { 583 | Option::from(self) 584 | } 585 | 586 | /// Returns `Ok(Point)` if the `MaybePoint` is a valid point or `Err(InfinityPointError)` 587 | /// if `self == MaybePoint::Infinity`. 588 | /// 589 | /// Also see `impl TryFrom for Point`. 590 | pub fn not_inf(self) -> Result { 591 | Point::try_from(self) 592 | } 593 | 594 | /// Coerces the `MaybePoint` into a valid [`Point`]. Panics if `self == MaybePoint::Infinity`. 595 | pub fn unwrap(self) -> Point { 596 | match self { 597 | Valid(point) => point, 598 | Infinity => panic!("called unwrap on MaybePoint::Infinity"), 599 | } 600 | } 601 | 602 | /// Returns true if `self == MaybePoint::Infinity`. 603 | pub fn is_infinity(&self) -> bool { 604 | self == &Infinity 605 | } 606 | 607 | /// Negates the point in constant-time if the given parity bit is a 1. 608 | pub fn negate_if(self, parity: subtle::Choice) -> MaybePoint { 609 | MaybePoint::conditional_select(&self, &(-self), parity) 610 | } 611 | } 612 | 613 | mod std_traits { 614 | use super::*; 615 | 616 | /// Need to implement this manually because [`k256::PublicKey`] does not implement `Hash`. 617 | impl std::hash::Hash for Point { 618 | fn hash(&self, state: &mut H) { 619 | self.serialize().hash(state); 620 | } 621 | } 622 | 623 | impl std::fmt::Debug for Point { 624 | /// Formats the point into a string like `"Point(025fa83ed...)"`. 625 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 626 | write!(f, "Point({:x})", self) 627 | } 628 | } 629 | 630 | impl Default for MaybePoint { 631 | /// Returns the point at infinity, which acts as an 632 | /// identity element in the additive curve group. 633 | fn default() -> Self { 634 | MaybePoint::Infinity 635 | } 636 | } 637 | 638 | #[cfg(all(feature = "k256", not(feature = "secp256k1")))] 639 | mod pubkey_ord { 640 | use super::*; 641 | 642 | impl Ord for Point { 643 | fn cmp(&self, other: &Self) -> std::cmp::Ordering { 644 | // The `k256` crate implements `Ord` based on uncompressed encoding. 645 | // To match BIP327, we must sort keys based on their compressed encoding. 646 | self.inner 647 | .to_encoded_point(true) 648 | .cmp(&other.inner.to_encoded_point(true)) 649 | } 650 | } 651 | 652 | impl PartialOrd for Point { 653 | fn partial_cmp(&self, other: &Self) -> Option { 654 | Some(self.cmp(other)) 655 | } 656 | } 657 | } 658 | } 659 | 660 | mod conversions { 661 | use super::*; 662 | 663 | mod as_ref_conversions { 664 | use super::*; 665 | 666 | #[cfg(feature = "secp256k1")] 667 | impl AsRef for Point { 668 | fn as_ref(&self) -> &secp256k1::PublicKey { 669 | &self.inner 670 | } 671 | } 672 | 673 | #[cfg(all(feature = "k256", not(feature = "secp256k1")))] 674 | impl AsRef for Point { 675 | fn as_ref(&self) -> &k256::PublicKey { 676 | &self.inner 677 | } 678 | } 679 | } 680 | 681 | mod internal_conversions { 682 | use super::*; 683 | 684 | impl From for Option { 685 | /// Converts the `MaybePoint` into an `Option`, returning `None` if 686 | /// `maybe_point == MaybePoint::Infinity` or `Some(p)` if 687 | /// `maybe_point == MaybePoint::Valid(p)`. 688 | fn from(maybe_point: MaybePoint) -> Self { 689 | match maybe_point { 690 | Valid(point) => Some(point), 691 | Infinity => None, 692 | } 693 | } 694 | } 695 | 696 | impl From for MaybePoint { 697 | /// Converts the point into a [`MaybePoint::Valid`] instance. 698 | fn from(point: Point) -> MaybePoint { 699 | MaybePoint::Valid(point) 700 | } 701 | } 702 | 703 | impl TryFrom for Point { 704 | type Error = InfinityPointError; 705 | 706 | /// Converts the `MaybePoint` into a `Result`, 707 | /// returning `Ok(Point)` if the point is a valid non-infinity point, 708 | /// or `Err(InfinityPointError)` if `maybe_point == MaybePoint::Infinity`. 709 | fn try_from(maybe_point: MaybePoint) -> Result { 710 | match maybe_point { 711 | Valid(point) => Ok(point), 712 | Infinity => Err(InfinityPointError), 713 | } 714 | } 715 | } 716 | } 717 | 718 | #[cfg(feature = "secp256k1")] 719 | mod secp256k1_conversions { 720 | use super::*; 721 | 722 | mod public_key { 723 | use super::*; 724 | 725 | impl From for Point { 726 | fn from(pubkey: secp256k1::PublicKey) -> Self { 727 | Point { inner: pubkey } 728 | } 729 | } 730 | 731 | impl From for MaybePoint { 732 | fn from(pubkey: secp256k1::PublicKey) -> Self { 733 | MaybePoint::Valid(Point::from(pubkey)) 734 | } 735 | } 736 | 737 | impl From for secp256k1::PublicKey { 738 | fn from(point: Point) -> Self { 739 | point.inner 740 | } 741 | } 742 | 743 | impl TryFrom for secp256k1::PublicKey { 744 | type Error = InfinityPointError; 745 | fn try_from(maybe_point: MaybePoint) -> Result { 746 | Ok(maybe_point.not_inf()?.inner) 747 | } 748 | } 749 | } 750 | 751 | mod xonly_public_key { 752 | use super::*; 753 | 754 | type KeyAndParity = (secp256k1::XOnlyPublicKey, secp256k1::Parity); 755 | 756 | impl From for Point { 757 | /// Converts an X-only public key with a given parity into a [`Point`]. 758 | fn from((xonly, parity): KeyAndParity) -> Self { 759 | let pk = secp256k1::PublicKey::from_x_only_public_key(xonly, parity); 760 | Point::from(pk) 761 | } 762 | } 763 | 764 | impl From for MaybePoint { 765 | fn from((xonly, parity): KeyAndParity) -> Self { 766 | MaybePoint::Valid(Point::from((xonly, parity))) 767 | } 768 | } 769 | 770 | impl From for KeyAndParity { 771 | fn from(point: Point) -> Self { 772 | point.inner.x_only_public_key() 773 | } 774 | } 775 | 776 | impl TryFrom for KeyAndParity { 777 | type Error = InfinityPointError; 778 | fn try_from(maybe_point: MaybePoint) -> Result { 779 | Ok(KeyAndParity::from(maybe_point.not_inf()?)) 780 | } 781 | } 782 | 783 | impl From for secp256k1::XOnlyPublicKey { 784 | fn from(point: Point) -> Self { 785 | let (x, _) = point.inner.x_only_public_key(); 786 | x 787 | } 788 | } 789 | 790 | impl TryFrom for secp256k1::XOnlyPublicKey { 791 | type Error = InfinityPointError; 792 | fn try_from(maybe_point: MaybePoint) -> Result { 793 | Ok(secp256k1::XOnlyPublicKey::from(maybe_point.not_inf()?)) 794 | } 795 | } 796 | } 797 | } 798 | 799 | #[cfg(feature = "k256")] 800 | mod k256_conversions { 801 | use super::*; 802 | 803 | mod public_key { 804 | use super::*; 805 | 806 | impl From for Point { 807 | fn from(pubkey: k256::PublicKey) -> Self { 808 | #[cfg(feature = "secp256k1")] 809 | let inner = { 810 | let encoded_point = pubkey.to_encoded_point(false); 811 | secp256k1::PublicKey::from_slice(encoded_point.as_bytes()).unwrap() 812 | }; 813 | 814 | #[cfg(not(feature = "secp256k1"))] 815 | let inner = pubkey; 816 | 817 | Point { inner } 818 | } 819 | } 820 | 821 | impl From for MaybePoint { 822 | fn from(pubkey: k256::PublicKey) -> Self { 823 | MaybePoint::Valid(Point::from(pubkey)) 824 | } 825 | } 826 | 827 | impl From for k256::PublicKey { 828 | fn from(point: Point) -> Self { 829 | #[cfg(feature = "secp256k1")] 830 | return k256::PublicKey::from_sec1_bytes(&point.serialize()).unwrap(); 831 | 832 | #[cfg(not(feature = "secp256k1"))] 833 | return point.inner; 834 | } 835 | } 836 | 837 | impl TryFrom for k256::PublicKey { 838 | type Error = InfinityPointError; 839 | 840 | fn try_from(maybe_point: MaybePoint) -> Result { 841 | Ok(k256::PublicKey::from(maybe_point.not_inf()?)) 842 | } 843 | } 844 | } 845 | 846 | mod encoded_point { 847 | use super::*; 848 | 849 | impl TryFrom for Point { 850 | type Error = InvalidPointBytes; 851 | fn try_from(encoded_point: k256::EncodedPoint) -> Result { 852 | Self::from_slice(encoded_point.as_bytes()) 853 | } 854 | } 855 | 856 | impl TryFrom for MaybePoint { 857 | type Error = InvalidPointBytes; 858 | fn try_from(encoded_point: k256::EncodedPoint) -> Result { 859 | Self::from_slice(encoded_point.as_bytes()) 860 | } 861 | } 862 | 863 | impl From for k256::EncodedPoint { 864 | fn from(point: Point) -> Self { 865 | k256::EncodedPoint::from(MaybePoint::Valid(point)) 866 | } 867 | } 868 | 869 | impl From for k256::EncodedPoint { 870 | fn from(maybe_point: MaybePoint) -> Self { 871 | let uncompressed = maybe_point.serialize_uncompressed(); 872 | k256::EncodedPoint::from_bytes(&uncompressed[1..]).unwrap() 873 | } 874 | } 875 | } 876 | 877 | mod affine_point { 878 | use super::*; 879 | 880 | impl TryFrom for Point { 881 | type Error = InfinityPointError; 882 | fn try_from(affine_point: k256::AffinePoint) -> Result { 883 | MaybePoint::from(affine_point).not_inf() 884 | } 885 | } 886 | 887 | impl From for MaybePoint { 888 | fn from(affine_point: k256::AffinePoint) -> Self { 889 | #[cfg(feature = "secp256k1")] 890 | return MaybePoint::try_from(affine_point.to_encoded_point(false)).unwrap(); 891 | 892 | #[cfg(not(feature = "secp256k1"))] 893 | return Point::try_from(affine_point) 894 | .map(MaybePoint::Valid) 895 | .unwrap_or(MaybePoint::Infinity); 896 | } 897 | } 898 | 899 | impl From for k256::AffinePoint { 900 | fn from(point: Point) -> Self { 901 | k256::AffinePoint::from(k256::PublicKey::from(point)) 902 | } 903 | } 904 | 905 | impl From for k256::AffinePoint { 906 | fn from(point: MaybePoint) -> Self { 907 | match point { 908 | MaybePoint::Infinity => k256::AffinePoint::IDENTITY, 909 | MaybePoint::Valid(point) => k256::AffinePoint::from(point), 910 | } 911 | } 912 | } 913 | } 914 | } 915 | } 916 | 917 | const POINT_INFINITY_COMPRESSED_STR: &str = 918 | "000000000000000000000000000000000000000000000000000000000000000000"; 919 | const POINT_INFINITY_UNCOMPRESSED_STR: &str = 920 | "000000000000000000000000000000000000000000000000000000000000000000\ 921 | 0000000000000000000000000000000000000000000000000000000000000000"; 922 | 923 | mod encodings { 924 | use super::*; 925 | 926 | impl std::fmt::LowerHex for Point { 927 | /// Formats the Point as a DER-compressed hex string in lower case. 928 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 929 | if f.sign_plus() { 930 | let mut buffer = [0; 130]; 931 | let encoded = 932 | base16ct::lower::encode_str(&self.serialize_uncompressed(), &mut buffer) 933 | .unwrap(); 934 | f.write_str(encoded) 935 | } else { 936 | let mut buffer = [0; 66]; 937 | let encoded = base16ct::lower::encode_str(&self.serialize(), &mut buffer).unwrap(); 938 | f.write_str(encoded) 939 | } 940 | } 941 | } 942 | impl std::fmt::UpperHex for Point { 943 | /// Formats the Point as a DER-compressed hex string in upper case. 944 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 945 | if f.sign_plus() { 946 | let mut buffer = [0; 130]; 947 | let encoded = 948 | base16ct::upper::encode_str(&self.serialize_uncompressed(), &mut buffer) 949 | .unwrap(); 950 | f.write_str(encoded) 951 | } else { 952 | let mut buffer = [0; 66]; 953 | let encoded = base16ct::upper::encode_str(&self.serialize(), &mut buffer).unwrap(); 954 | f.write_str(encoded) 955 | } 956 | } 957 | } 958 | 959 | impl std::fmt::LowerHex for MaybePoint { 960 | /// Formats the Point as a DER-compressed hex string in lower case. 961 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 962 | match self { 963 | Valid(point) => point.fmt(f), 964 | Infinity => { 965 | if f.sign_plus() { 966 | f.write_str(POINT_INFINITY_UNCOMPRESSED_STR) 967 | } else { 968 | f.write_str(POINT_INFINITY_COMPRESSED_STR) 969 | } 970 | } 971 | } 972 | } 973 | } 974 | 975 | impl std::fmt::UpperHex for MaybePoint { 976 | /// Formats the Point as a DER-compressed hex string in upper case. 977 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 978 | match self { 979 | Valid(point) => point.fmt(f), 980 | Infinity => ::fmt(self, f), 981 | } 982 | } 983 | } 984 | 985 | impl std::fmt::Display for Point { 986 | /// Serializes and displays the point as a compressed point 987 | /// in hex format. 988 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 989 | ::fmt(self, f) 990 | } 991 | } 992 | 993 | impl std::fmt::Display for MaybePoint { 994 | /// Serializes and displays the point as a compressed point 995 | /// in hex format. 996 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 997 | ::fmt(self, f) 998 | } 999 | } 1000 | 1001 | impl std::str::FromStr for Point { 1002 | type Err = InvalidPointString; 1003 | 1004 | /// Parses a point from a compressed or uncompressed DER encoded hex string. 1005 | /// The input string should be either 33 or 65 bytes, hex-encoded. 1006 | fn from_str(s: &str) -> Result { 1007 | Self::from_hex(s) 1008 | } 1009 | } 1010 | 1011 | impl std::str::FromStr for MaybePoint { 1012 | type Err = InvalidPointString; 1013 | 1014 | /// Parses a point from a compressed or uncompressed DER encoded hex string. 1015 | /// The input string should be either 33 or 65 bytes, hex-encoded. 1016 | /// 1017 | /// Returns [`MaybePoint::Infinity`] if the input is 33-hex-encoded zero bytes. 1018 | fn from_str(s: &str) -> Result { 1019 | Self::from_hex(s) 1020 | } 1021 | } 1022 | 1023 | impl TryFrom<&[u8]> for Point { 1024 | type Error = InvalidPointBytes; 1025 | 1026 | /// Parses a compressed or uncompressed DER encoding of a point. See 1027 | /// [`Point::serialize`] and [`Point::serialize_uncompressed`]. The slice 1028 | /// length should be either 33 or 65 for compressed and uncompressed 1029 | /// encodings respectively. 1030 | /// 1031 | /// Returns [`InvalidPointBytes`] if the bytes do not represent a valid 1032 | /// non-infinity curve point. 1033 | fn try_from(bytes: &[u8]) -> Result { 1034 | #[cfg(feature = "secp256k1")] 1035 | let decode_result = secp256k1::PublicKey::from_slice(bytes); 1036 | 1037 | #[cfg(all(feature = "k256", not(feature = "secp256k1")))] 1038 | let decode_result = k256::PublicKey::from_sec1_bytes(bytes); 1039 | 1040 | decode_result 1041 | .map(Point::from) 1042 | .map_err(|_| InvalidPointBytes) 1043 | } 1044 | } 1045 | 1046 | impl TryFrom<&[u8]> for MaybePoint { 1047 | type Error = InvalidPointBytes; 1048 | 1049 | /// Parses a compressed or uncompressed DER encoding of a point. See 1050 | /// [`MaybePoint::serialize`] and [`MaybePoint::serialize_uncompressed`]. 1051 | /// 1052 | /// Returns [`InvalidPointBytes`] if the bytes do not represent a valid 1053 | /// curve point, or if `bytes.len()` is neither 33 nor 65. 1054 | /// 1055 | /// Also accepts 33 or 65 zero bytes, which is interpreted as the point 1056 | /// at infinity. 1057 | fn try_from(bytes: &[u8]) -> Result { 1058 | if bool::from(bytes.ct_eq(&[0; 33]) | bytes.ct_eq(&[0; 65])) { 1059 | return Ok(MaybePoint::Infinity); 1060 | } 1061 | Point::try_from(bytes).map(Valid) 1062 | } 1063 | } 1064 | 1065 | impl TryFrom<&[u8; 33]> for Point { 1066 | type Error = InvalidPointBytes; 1067 | 1068 | /// Parses a compressed DER encoding of a point. See [`Point::serialize`]. 1069 | /// Returns [`InvalidPointBytes`] if the bytes do not represent a valid 1070 | /// non-infinity curve point. 1071 | fn try_from(bytes: &[u8; 33]) -> Result { 1072 | Self::try_from(bytes as &[u8]) 1073 | } 1074 | } 1075 | 1076 | impl TryFrom<&[u8; 33]> for MaybePoint { 1077 | type Error = InvalidPointBytes; 1078 | 1079 | /// Parses a compressed DER encoding of a point. See [`MaybePoint::serialize`]. 1080 | /// Returns [`InvalidPointBytes`] if the bytes do not represent a valid 1081 | /// curve point. 1082 | /// 1083 | /// Also accepts 33 zero bytes, which is interpreted as the point at infinity. 1084 | fn try_from(bytes: &[u8; 33]) -> Result { 1085 | if bool::from(bytes.ct_eq(&[0; 33])) { 1086 | return Ok(MaybePoint::Infinity); 1087 | } 1088 | Point::try_from(bytes).map(Valid) 1089 | } 1090 | } 1091 | 1092 | impl TryFrom<[u8; 33]> for Point { 1093 | type Error = InvalidPointBytes; 1094 | 1095 | /// Parses a compressed DER encoding of a point. See [`Point::serialize`]. 1096 | /// Returns [`InvalidPointBytes`] if the bytes do not represent a valid 1097 | /// non-infinity curve point. 1098 | fn try_from(bytes: [u8; 33]) -> Result { 1099 | Self::try_from(&bytes) 1100 | } 1101 | } 1102 | 1103 | impl TryFrom<[u8; 33]> for MaybePoint { 1104 | type Error = InvalidPointBytes; 1105 | 1106 | /// Parses a compressed DER encoding of a point. See [`MaybePoint::serialize`]. 1107 | /// Returns [`InvalidPointBytes`] if the bytes do not represent a valid 1108 | /// curve point. 1109 | /// 1110 | /// Also accepts 33 zero bytes, which is interpreted as the point at infinity. 1111 | fn try_from(bytes: [u8; 33]) -> Result { 1112 | Self::try_from(&bytes) 1113 | } 1114 | } 1115 | 1116 | impl From for [u8; 33] { 1117 | /// Serializes the point to DER-compressed format. 1118 | fn from(point: Point) -> Self { 1119 | point.serialize() 1120 | } 1121 | } 1122 | 1123 | impl From for [u8; 33] { 1124 | /// Serializes the point to DER-compressed format. 1125 | /// 1126 | /// Returns 33 zero bytes if `maybe_point == MaybePoint::Infinity`. 1127 | fn from(maybe_point: MaybePoint) -> Self { 1128 | maybe_point.serialize() 1129 | } 1130 | } 1131 | 1132 | impl TryFrom<&[u8; 65]> for Point { 1133 | type Error = InvalidPointBytes; 1134 | 1135 | /// Parses an uncompressed DER encoding of a point. See [`Point::serialize_uncompressed`]. 1136 | /// Returns [`InvalidPointBytes`] if the bytes do not represent a valid 1137 | /// non-infinity curve point. 1138 | fn try_from(bytes: &[u8; 65]) -> Result { 1139 | Self::try_from(bytes as &[u8]) 1140 | } 1141 | } 1142 | 1143 | impl TryFrom<&[u8; 65]> for MaybePoint { 1144 | type Error = InvalidPointBytes; 1145 | 1146 | /// Parses an uncompressed DER encoding of a point. See [`MaybePoint::serialize_uncompressed`]. 1147 | /// Returns [`InvalidPointBytes`] if the bytes do not represent a valid 1148 | /// curve point. 1149 | /// 1150 | /// Also accepts 65 zero bytes, which is interpreted as the point at infinity. 1151 | fn try_from(bytes: &[u8; 65]) -> Result { 1152 | if bool::from(bytes.ct_eq(&[0; 65])) { 1153 | return Ok(MaybePoint::Infinity); 1154 | } 1155 | Point::try_from(bytes).map(Valid) 1156 | } 1157 | } 1158 | 1159 | impl TryFrom<[u8; 65]> for Point { 1160 | type Error = InvalidPointBytes; 1161 | /// Parses an uncompressed DER encoding of a point. See [`Point::serialize_uncompressed`]. 1162 | /// Returns [`InvalidPointBytes`] if the bytes do not represent a valid 1163 | /// non-infinity curve point. 1164 | fn try_from(bytes: [u8; 65]) -> Result { 1165 | Self::try_from(&bytes) 1166 | } 1167 | } 1168 | 1169 | impl TryFrom<[u8; 65]> for MaybePoint { 1170 | type Error = InvalidPointBytes; 1171 | /// Parses an uncompressed DER encoding of a point. See [`MaybePoint::serialize_uncompressed`]. 1172 | /// Returns [`InvalidPointBytes`] if the bytes do not represent a valid 1173 | /// curve point. 1174 | /// 1175 | /// Also accepts 65 zero bytes, which is interpreted as the point at infinity. 1176 | fn try_from(bytes: [u8; 65]) -> Result { 1177 | Self::try_from(&bytes) 1178 | } 1179 | } 1180 | 1181 | impl From for [u8; 65] { 1182 | /// Serializes the point to DER-uncompressed format. 1183 | fn from(point: Point) -> Self { 1184 | point.serialize_uncompressed() 1185 | } 1186 | } 1187 | 1188 | impl From for [u8; 65] { 1189 | /// Serializes the point to DER-uncompressed format. 1190 | /// 1191 | /// Returns an array of 65 zero bytes if `maybe_point == MaybePoint::Infinity`. 1192 | fn from(maybe_point: MaybePoint) -> Self { 1193 | maybe_point.serialize_uncompressed() 1194 | } 1195 | } 1196 | } 1197 | 1198 | impl ConditionallySelectable for Point { 1199 | /// Conditionally selects one of two points in constant time. No timing 1200 | /// information about the value of either point will be leaked. 1201 | #[inline] 1202 | fn conditional_select(&a: &Self, &b: &Self, choice: subtle::Choice) -> Self { 1203 | #[cfg(feature = "secp256k1")] 1204 | return { 1205 | let mut output_bytes = a.serialize_uncompressed(); 1206 | output_bytes.conditional_assign(&b.serialize_uncompressed(), choice); 1207 | Point::try_from(&output_bytes).unwrap() 1208 | }; 1209 | 1210 | #[cfg(all(feature = "k256", not(feature = "secp256k1")))] 1211 | return { 1212 | let mut nonidentity = a.inner.to_nonidentity(); 1213 | nonidentity.conditional_assign(&b.inner.to_nonidentity(), choice); 1214 | let inner = k256::PublicKey::from(nonidentity); 1215 | Point { inner } 1216 | }; 1217 | } 1218 | } 1219 | 1220 | impl ConditionallySelectable for MaybePoint { 1221 | /// Conditionally selects one of two points in constant time. This may operate 1222 | /// in non-constant time if one of the two points is infinity, but no timing 1223 | /// information about the content of a non-infinity point will be leaked 1224 | #[inline] 1225 | fn conditional_select(&a: &Self, &b: &Self, choice: subtle::Choice) -> Self { 1226 | #[cfg(feature = "secp256k1")] 1227 | return { 1228 | let mut output_bytes = a.serialize_uncompressed(); 1229 | output_bytes.conditional_assign(&b.serialize_uncompressed(), choice); 1230 | MaybePoint::try_from(&output_bytes).unwrap() 1231 | }; 1232 | 1233 | #[cfg(all(feature = "k256", not(feature = "secp256k1")))] 1234 | return { 1235 | let mut affine = match a { 1236 | MaybePoint::Infinity => k256::AffinePoint::IDENTITY, 1237 | MaybePoint::Valid(point) => *point.inner.as_affine(), 1238 | }; 1239 | let b_affine = match b { 1240 | MaybePoint::Infinity => k256::AffinePoint::IDENTITY, 1241 | MaybePoint::Valid(point) => *point.inner.as_affine(), 1242 | }; 1243 | affine.conditional_assign(&b_affine, choice); 1244 | 1245 | let maybe_point_opt = Option::>::from( 1246 | k256::elliptic_curve::point::NonIdentity::new(affine), 1247 | ); 1248 | 1249 | maybe_point_opt 1250 | .map(k256::PublicKey::from) 1251 | .map(MaybePoint::from) 1252 | .unwrap_or(MaybePoint::Infinity) 1253 | }; 1254 | } 1255 | } 1256 | 1257 | /// The type `P` can be either [`Point`] or [`MaybePoint`], or any type 1258 | /// that converts to [`MaybePoint`]. This allows iterators of this type 1259 | /// `P` to be summed to an elliptic curve point efficiently. 1260 | impl

std::iter::Sum

for MaybePoint 1261 | where 1262 | MaybePoint: From

, 1263 | { 1264 | fn sum(mut iter: I) -> Self 1265 | where 1266 | I: Iterator, 1267 | { 1268 | let mut sum = MaybePoint::Infinity; 1269 | let mut chunk = [MaybePoint::Infinity; 2048]; 1270 | let mut next: usize; 1271 | 1272 | loop { 1273 | next = 0; 1274 | while next < chunk.len() { 1275 | if let Some(point) = iter.next() { 1276 | chunk[next] = MaybePoint::from(point); 1277 | next += 1; 1278 | } else { 1279 | break; 1280 | } 1281 | } 1282 | 1283 | sum += MaybePoint::sum(&chunk[..next]); 1284 | if next < chunk.len() { 1285 | return sum; 1286 | } 1287 | } 1288 | } 1289 | } 1290 | 1291 | #[cfg(feature = "num-traits")] 1292 | impl num_traits::Zero for MaybePoint { 1293 | fn zero() -> Self { 1294 | Infinity 1295 | } 1296 | fn is_zero(&self) -> bool { 1297 | self == &Infinity 1298 | } 1299 | } 1300 | 1301 | #[cfg(test)] 1302 | mod tests { 1303 | #![allow(non_snake_case)] 1304 | use super::*; 1305 | use crate::{MaybeScalar, Scalar}; 1306 | 1307 | #[test] 1308 | fn validate_generator() { 1309 | assert_eq!( 1310 | Point::generator().serialize_uncompressed(), 1311 | GENERATOR_POINT_BYTES 1312 | ); 1313 | 1314 | #[cfg(feature = "k256")] 1315 | assert_eq!( 1316 | GENERATOR_POINT_BYTES, 1317 | k256::AffinePoint::GENERATOR 1318 | .to_encoded_point(false) 1319 | .as_bytes(), 1320 | ); 1321 | 1322 | #[cfg(feature = "secp256k1")] 1323 | assert_eq!(GENERATOR_POINT_BYTES, { 1324 | let mut arr = [0; 65]; 1325 | arr[0] = 0x04; 1326 | arr[1..33].clone_from_slice(&secp256k1::constants::GENERATOR_X); 1327 | arr[33..].clone_from_slice(&secp256k1::constants::GENERATOR_Y); 1328 | arr 1329 | }); 1330 | } 1331 | 1332 | #[test] 1333 | fn point_serialize_and_parse() { 1334 | let point: Point = "02F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9" 1335 | .parse() 1336 | .unwrap(); 1337 | 1338 | let compressed_bytes = [ 1339 | 0x02, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34, 0x4F, 0x85, 0xF8, 1340 | 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 1341 | 0x13, 0xBC, 0xE0, 0x36, 0xF9, 1342 | ]; 1343 | assert_eq!(point.serialize(), compressed_bytes); 1344 | assert_eq!(Point::try_from(&compressed_bytes).unwrap(), point); 1345 | assert_eq!(Point::try_from(compressed_bytes).unwrap(), point); 1346 | 1347 | let uncompressed_bytes = [ 1348 | 0x04, 0xf9, 0x30, 0x8a, 0x01, 0x92, 0x58, 0xc3, 0x10, 0x49, 0x34, 0x4f, 0x85, 0xf8, 1349 | 0x9d, 0x52, 0x29, 0xb5, 0x31, 0xc8, 0x45, 0x83, 0x6f, 0x99, 0xb0, 0x86, 0x01, 0xf1, 1350 | 0x13, 0xbc, 0xe0, 0x36, 0xf9, 0x38, 0x8f, 0x7b, 0x0f, 0x63, 0x2d, 0xe8, 0x14, 0x0f, 1351 | 0xe3, 0x37, 0xe6, 0x2a, 0x37, 0xf3, 0x56, 0x65, 0x00, 0xa9, 0x99, 0x34, 0xc2, 0x23, 1352 | 0x1b, 0x6c, 0xb9, 0xfd, 0x75, 0x84, 0xb8, 0xe6, 0x72, 1353 | ]; 1354 | assert_eq!(point.serialize_uncompressed(), uncompressed_bytes); 1355 | assert_eq!(Point::try_from(&uncompressed_bytes).unwrap(), point); 1356 | assert_eq!(Point::try_from(uncompressed_bytes).unwrap(), point); 1357 | 1358 | let xonly_bytes = [ 1359 | 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 1360 | 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 1361 | 0xBC, 0xE0, 0x36, 0xF9, 1362 | ]; 1363 | assert_eq!(point.serialize_xonly(), xonly_bytes); 1364 | assert_eq!(Point::lift_x(xonly_bytes).unwrap(), point); 1365 | 1366 | assert_eq!( 1367 | "020000000000000000000000000000000000000000000000000000000000000000" 1368 | .parse::(), 1369 | Err(InvalidPointString) 1370 | ); 1371 | assert_eq!( 1372 | "000000000000000000000000000000000000000000000000000000000000000000".parse::(), 1373 | Err(InvalidPointString) 1374 | ); 1375 | assert_eq!( 1376 | "000000000000000000000000000000000000000000000000000000000000000000" 1377 | .parse::(), 1378 | Ok(MaybePoint::Infinity) 1379 | ); 1380 | 1381 | assert_eq!( 1382 | "04F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9".parse::(), 1383 | Err(InvalidPointString) 1384 | ); 1385 | 1386 | // Parsing x-only keys must be done explicitly. 1387 | assert_eq!( 1388 | "F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9".parse::(), 1389 | Err(InvalidPointString) 1390 | ); 1391 | assert_eq!( 1392 | Point::lift_x_hex("F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9"), 1393 | Ok(point) 1394 | ); 1395 | } 1396 | 1397 | #[test] 1398 | fn point_addition_subtraction() { 1399 | let point_hex_fixtures = [ 1400 | ( 1401 | "029a167a1116f081185036ec7c4d06022fb173bbb5f825c075eeb8737a193fc252", 1402 | "028c02a23649adf06635db4d8fd093f106c5a0c7f3643c023a2a3ef23325043e3b", 1403 | "02a55fb23de9aa817fcaaf6676c104dfe69c942e7a92a1d49876b18eeb11e84a0d", 1404 | ), 1405 | ( 1406 | "02c1a4892280e30af2e43c7db3d60c3b9c5c413a4ad9dc67fac2d0a2fbf378f451", 1407 | "03b547403b4fe6da07913daaa8e2ab7db65836349435d5e74ec25e2b0092cf52ac", 1408 | "02b1c3aef1cbe5b6533d281d272feec9c1307d29547e57be5ae77522b1e97a7189", 1409 | ), 1410 | ( 1411 | "020000000000000000000000000000000000000000000000000000000000000001", 1412 | "030000000000000000000000000000000000000000000000000000000000000002", 1413 | "02f23a2d865c24c99cc9e7b99bd907fb93ebd6ccce106bcccb0082acf8315e67be", 1414 | ), 1415 | ( 1416 | "000000000000000000000000000000000000000000000000000000000000000000", 1417 | "030000000000000000000000000000000000000000000000000000000000000002", 1418 | "030000000000000000000000000000000000000000000000000000000000000002", 1419 | ), 1420 | ( 1421 | "030000000000000000000000000000000000000000000000000000000000000002", 1422 | "000000000000000000000000000000000000000000000000000000000000000000", 1423 | "030000000000000000000000000000000000000000000000000000000000000002", 1424 | ), 1425 | ( 1426 | "02b1c3aef1cbe5b6533d281d272feec9c1307d29547e57be5ae77522b1e97a7189", 1427 | "000000000000000000000000000000000000000000000000000000000000000000", 1428 | "02b1c3aef1cbe5b6533d281d272feec9c1307d29547e57be5ae77522b1e97a7189", 1429 | ), 1430 | ( 1431 | "02b1c3aef1cbe5b6533d281d272feec9c1307d29547e57be5ae77522b1e97a7189", 1432 | "03b1c3aef1cbe5b6533d281d272feec9c1307d29547e57be5ae77522b1e97a7189", 1433 | "000000000000000000000000000000000000000000000000000000000000000000", 1434 | ), 1435 | ]; 1436 | 1437 | for (p1_str, p2_str, sum_str) in point_hex_fixtures { 1438 | let P1: MaybePoint = p1_str 1439 | .parse() 1440 | .unwrap_or_else(|_| panic!("failed to parse P1 fixture point {}", p1_str)); 1441 | let P2: MaybePoint = p2_str 1442 | .parse() 1443 | .unwrap_or_else(|_| panic!("failed to parse P2 fixture point {}", p2_str)); 1444 | let sum: MaybePoint = sum_str 1445 | .parse() 1446 | .unwrap_or_else(|_| panic!("failed to parse sum fixture point {}", sum_str)); 1447 | 1448 | assert_eq!(P1 + P2, sum, "\n{} \n+ {} \n= {}", P1, P2, sum); 1449 | assert_eq!(sum - P1, P2, "\n{} \n- {} \n= {}", sum, P1, P2); 1450 | assert_eq!(sum - P2, P1, "\n{} \n- {} \n= {}", sum, P2, P1); 1451 | assert_eq!(P2 - sum, -P1, "\n{} \n- {} \n= -{}", P2, sum, P1); 1452 | assert_eq!(P1 - sum, -P2, "\n{} \n- {} \n= -{}", P1, sum, P2); 1453 | 1454 | match P1 { 1455 | Valid(p1_valid) => match P2 { 1456 | Valid(p2_valid) => { 1457 | assert_eq!(p1_valid + p2_valid, sum); // `Point` + `Point` 1458 | assert_eq!(p2_valid + p1_valid, sum); // `Point` + `Point` 1459 | assert_eq!(sum - p1_valid, P2); // `MaybePoint` - `Point` 1460 | assert_eq!(sum - p2_valid, P1); // `MaybePoint` - `Point` 1461 | assert_eq!(p1_valid - p1_valid, Infinity); // `Point` - `Point` 1462 | assert_eq!(p2_valid - p2_valid, Infinity); // `Point` - `Point` 1463 | } 1464 | Infinity => { 1465 | assert_eq!(P1 + P2, P1); 1466 | assert_eq!(P2 + P1, P1); 1467 | } 1468 | }, 1469 | Infinity => match P2 { 1470 | Valid(p2_valid) => { 1471 | assert_eq!(P1 + p2_valid, P2); // `Infinity` + `Point` 1472 | assert_eq!(p2_valid + P1, P2); // `Point` + `Infinity` 1473 | assert_eq!(P1 - p2_valid, -P2); // `Infinity` - `Point` 1474 | assert_eq!(p2_valid - P1, P2); // `Point` - `Infinity` 1475 | assert_eq!(p2_valid - p2_valid, Infinity); // `Point` - `Point` 1476 | } 1477 | Infinity => { 1478 | assert_eq!(P1 + P2, Infinity); // `Infinity` + `Infinity` 1479 | assert_eq!(P1 - P2, Infinity); // `Infinity` - `Infinity` 1480 | assert_eq!(-P1, Infinity); // -`Infinity` 1481 | assert_eq!(-P2, Infinity); // -`Infinity` 1482 | } 1483 | }, 1484 | }; 1485 | } 1486 | } 1487 | 1488 | #[test] 1489 | fn point_multiplication() { 1490 | // `Point` * `Scalar` 1491 | assert_eq!( 1492 | "02c1a4892280e30af2e43c7db3d60c3b9c5c413a4ad9dc67fac2d0a2fbf378f451" 1493 | .parse::() 1494 | .unwrap() 1495 | * Scalar::one(), 1496 | "02c1a4892280e30af2e43c7db3d60c3b9c5c413a4ad9dc67fac2d0a2fbf378f451" 1497 | .parse::() 1498 | .unwrap() 1499 | ); 1500 | 1501 | // `Scalar` * `Point` 1502 | assert_eq!( 1503 | Scalar::one() 1504 | * "02c1a4892280e30af2e43c7db3d60c3b9c5c413a4ad9dc67fac2d0a2fbf378f451" 1505 | .parse::() 1506 | .unwrap(), 1507 | "02c1a4892280e30af2e43c7db3d60c3b9c5c413a4ad9dc67fac2d0a2fbf378f451" 1508 | .parse::() 1509 | .unwrap(), 1510 | ); 1511 | 1512 | // `Point` * `MaybeScalar` 1513 | assert_eq!( 1514 | Point::generator() 1515 | * "6407352af47835f53c660963534e33a090b3073861c95a63d194850503803577" 1516 | .parse::() 1517 | .unwrap(), 1518 | "023c27be1938d5614bbde4501d040cf2955a60564392cc87248f141ad3c7fc1a78" 1519 | .parse::() 1520 | .unwrap() 1521 | ); 1522 | 1523 | // `MaybeScalar` * `Point` 1524 | assert_eq!( 1525 | "6407352af47835f53c660963534e33a090b3073861c95a63d194850503803577" 1526 | .parse::() 1527 | .unwrap() 1528 | * Point::generator(), 1529 | "023c27be1938d5614bbde4501d040cf2955a60564392cc87248f141ad3c7fc1a78" 1530 | .parse::() 1531 | .unwrap() 1532 | ); 1533 | 1534 | // `MaybeScalar` * `MaybePoint` 1535 | assert_eq!( 1536 | "6407352af47835f53c660963534e33a090b3073861c95a63d194850503803577" 1537 | .parse::() 1538 | .unwrap() 1539 | * Valid(Point::generator()), 1540 | "023c27be1938d5614bbde4501d040cf2955a60564392cc87248f141ad3c7fc1a78" 1541 | .parse::() 1542 | .unwrap() 1543 | ); 1544 | 1545 | // `MaybePoint` * `MaybeScalar` 1546 | assert_eq!( 1547 | Valid(Point::generator()) 1548 | * "6407352af47835f53c660963534e33a090b3073861c95a63d194850503803577" 1549 | .parse::() 1550 | .unwrap(), 1551 | "023c27be1938d5614bbde4501d040cf2955a60564392cc87248f141ad3c7fc1a78" 1552 | .parse::() 1553 | .unwrap() 1554 | ); 1555 | 1556 | // `Infinity` * `Scalar` 1557 | assert_eq!( 1558 | Infinity 1559 | * "6407352af47835f53c660963534e33a090b3073861c95a63d194850503803577" 1560 | .parse::() 1561 | .unwrap(), 1562 | Infinity, 1563 | ); 1564 | // `Infinity` * `MaybeScalar` 1565 | assert_eq!( 1566 | Infinity 1567 | * "6407352af47835f53c660963534e33a090b3073861c95a63d194850503803577" 1568 | .parse::() 1569 | .unwrap(), 1570 | Infinity, 1571 | ); 1572 | 1573 | // `Infinity` * `Zero` 1574 | assert_eq!(Infinity * MaybeScalar::Zero, Infinity); 1575 | 1576 | // `Scalar` * `Infinity` 1577 | assert_eq!( 1578 | "6407352af47835f53c660963534e33a090b3073861c95a63d194850503803577" 1579 | .parse::() 1580 | .unwrap() 1581 | * Infinity, 1582 | Infinity, 1583 | ); 1584 | // `MaybeScalar` * `Infinity` 1585 | assert_eq!( 1586 | "6407352af47835f53c660963534e33a090b3073861c95a63d194850503803577" 1587 | .parse::() 1588 | .unwrap() 1589 | * Infinity, 1590 | Infinity, 1591 | ); 1592 | // `Zero` * `Infinity` 1593 | assert_eq!(MaybeScalar::Zero * Infinity, Infinity); 1594 | } 1595 | 1596 | #[test] 1597 | #[cfg(any(feature = "k256", feature = "secp256k1-invert"))] 1598 | fn point_division_by_scalars() { 1599 | let k = "6407352af47835f53c660963534e33a090b3073861c95a63d194850503803577" 1600 | .parse::() 1601 | .unwrap(); 1602 | 1603 | let point = "0303056e2d7a511a34e0f76ebd1e084bba47cb9cb83ee5950e15b95123654c63fe" 1604 | .parse::() 1605 | .unwrap(); 1606 | 1607 | assert_eq!( 1608 | point / k, 1609 | "034fca8b1968dfa19107e2638c109b5951d13d59080d236814f591b3c0652e70c3" 1610 | .parse::() 1611 | .unwrap() 1612 | ); 1613 | 1614 | assert_eq!(k * point / k, point); 1615 | 1616 | // Run a pseudo-oprf: blind a point with k, multiply it by some other 1617 | // secret scalar r to salt the point. 1618 | let blinded = point * k; 1619 | 1620 | let r = "90539EEDE565F5D054F32CC0C220126889ED1E5D193BAF15AEF344FE59D4610C" 1621 | .parse::() 1622 | .unwrap(); 1623 | let salted = blinded * r; 1624 | 1625 | // and then unblind the operation result with k. 1626 | let unblinded = salted / k; 1627 | 1628 | // The result should be the same has having multiplied `point * r` originally. 1629 | assert_eq!(unblinded, point * r); 1630 | 1631 | // MaybePoint / Scalar 1632 | assert_eq!(MaybePoint::Valid(salted) / k, MaybePoint::Valid(unblinded)); 1633 | assert_eq!( 1634 | MaybePoint::Infinity / Scalar::try_from(40).unwrap(), 1635 | MaybePoint::Infinity 1636 | ); 1637 | } 1638 | 1639 | #[test] 1640 | fn point_assignment_operators() { 1641 | let scalar = "b21643ba6bd9b6ca2e1f6da85561092ad44949835519d71dd837be8a8c67fe7f" 1642 | .parse::() 1643 | .unwrap(); 1644 | 1645 | let pub_point = "0303056e2d7a511a34e0f76ebd1e084bba47cb9cb83ee5950e15b95123654c63fe" 1646 | .parse::() 1647 | .unwrap(); 1648 | 1649 | // `Point` *= `Scalar` 1650 | let mut P1 = Point::generator(); 1651 | P1 *= scalar; 1652 | assert_eq!(P1, pub_point); 1653 | 1654 | // `MaybePoint` *= `Scalar` 1655 | let mut P2 = Valid(Point::generator()); 1656 | P2 *= scalar; 1657 | assert_eq!(P2, Valid(pub_point)); 1658 | 1659 | // `MaybePoint` *= `MaybeScalar` 1660 | let mut P2 = Valid(Point::generator()); 1661 | P2 *= MaybeScalar::Valid(scalar); 1662 | assert_eq!(P2, Valid(pub_point)); 1663 | } 1664 | 1665 | #[test] 1666 | fn point_iter_sum() { 1667 | { 1668 | let scalars: Vec = (1..1000) 1669 | .map(|i: u128| Scalar::try_from(i).unwrap()) 1670 | .collect(); 1671 | let points: Vec = scalars.iter().map(|&k| k.base_point_mul()).collect(); 1672 | 1673 | assert_eq!( 1674 | points.into_iter().sum::(), 1675 | scalars.into_iter().sum::().base_point_mul() 1676 | ); 1677 | } 1678 | 1679 | { 1680 | let scalars: Vec = (1..10000) 1681 | .map(|i: u128| Scalar::try_from(i).unwrap()) 1682 | .collect(); 1683 | let points: Vec = scalars.iter().map(|&k| k.base_point_mul()).collect(); 1684 | 1685 | assert_eq!( 1686 | points.into_iter().sum::(), 1687 | scalars.into_iter().sum::().base_point_mul() 1688 | ); 1689 | } 1690 | } 1691 | } 1692 | -------------------------------------------------------------------------------- /src/scalars.rs: -------------------------------------------------------------------------------- 1 | use once_cell::sync::Lazy; 2 | use subtle::{ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater}; 3 | 4 | use super::errors::{InvalidScalarBytes, InvalidScalarString, ZeroScalarError}; 5 | use super::{MaybePoint, Point}; 6 | 7 | #[cfg(feature = "secp256k1")] 8 | pub(crate) static LIBSECP256K1_CTX: Lazy> = 9 | Lazy::new(secp256k1::Secp256k1::new); 10 | 11 | static SCALAR_ONE: Lazy = Lazy::new(|| { 12 | Scalar::try_from(&[ 13 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14 | 0, 1u8, 15 | ]) 16 | .unwrap() 17 | }); 18 | 19 | static SCALAR_TWO: Lazy = Lazy::new(|| { 20 | Scalar::try_from(&[ 21 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22 | 0, 2u8, 23 | ]) 24 | .unwrap() 25 | }); 26 | 27 | static SCALAR_HALF_ORDER: Lazy = Lazy::new(|| { 28 | Scalar::try_from(&[ 29 | 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 30 | 0xff, 0x5d, 0x57, 0x6e, 0x73, 0x57, 0xa4, 0x50, 0x1d, 0xdf, 0xe9, 0x2f, 0x46, 0x68, 0x1b, 31 | 0x20, 0xa0u8, 32 | ]) 33 | .unwrap() 34 | }); 35 | 36 | static SCALAR_MAX: Lazy = 37 | Lazy::new(|| Scalar::try_from(&CURVE_ORDER_MINUS_ONE_BYTES).unwrap()); 38 | 39 | /// This is a big-endian representation of the secp256k1 curve order `n`. 40 | const CURVE_ORDER_BYTES: [u8; 32] = [ 41 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 42 | 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41, 43 | ]; 44 | 45 | /// This is a big-endian representation of the secp256k1 curve order `n` minus one. 46 | const CURVE_ORDER_MINUS_ONE_BYTES: [u8; 32] = [ 47 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 48 | 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x40, 49 | ]; 50 | 51 | /// The largest possible 256-bit integer, represented as a byte array. 52 | const MAX_U256: [u8; 32] = [0xFF; 32]; 53 | 54 | /// Represents a non-zero scalar in the range `[1, n)` where `n` is the order 55 | /// of the secp256k1 curve. A `Scalar` can be: 56 | /// 57 | /// - added, negated, subtracted, and multiplied with other `Scalar` instances. 58 | /// - added, negated, subtracted, and multiplied with [`MaybeScalar`]. 59 | /// - multiplied with [`Point`]. 60 | /// - multiplied with [`MaybePoint`]. 61 | /// 62 | /// ...using the normal Rust arithemtic operators `+`, `-` and `*`. Such operations 63 | /// are commutative, i.e. `a * b = b * a` and `a + b = b + a` in call cases. 64 | /// 65 | /// Depending on the types involved in an operation, certain operators will produce 66 | /// different result types which should be handled depending on your use case. For 67 | /// instance, adding two `Scalar`s results in a [`MaybeScalar`], because the two 68 | /// `Scalar`s may be additive inverses of each other and their output would result 69 | /// in [`MaybeScalar::Zero`] when taken mod `n`. 70 | #[derive(Copy, Clone)] 71 | #[cfg_attr(feature = "secp256k1", derive(PartialEq))] 72 | pub struct Scalar { 73 | #[cfg(feature = "secp256k1")] 74 | pub(crate) inner: secp256k1::SecretKey, 75 | 76 | #[cfg(all(feature = "k256", not(feature = "secp256k1")))] 77 | pub(crate) inner: k256::NonZeroScalar, 78 | } 79 | 80 | impl Scalar { 81 | /// Returns a valid `Scalar` with a value of 1. 82 | pub fn one() -> Scalar { 83 | *SCALAR_ONE 84 | } 85 | 86 | /// Returns a valid `Scalar` with a value of two. 87 | pub fn two() -> Scalar { 88 | *SCALAR_TWO 89 | } 90 | 91 | /// Returns half of the curve order `n`, specifically `n >> 1`. 92 | pub fn half_order() -> Scalar { 93 | *SCALAR_HALF_ORDER 94 | } 95 | 96 | /// Returns a valid `Scalar` with the maximum possible value less 97 | /// than the curve order, `n - 1`. 98 | pub fn max() -> Scalar { 99 | *SCALAR_MAX 100 | } 101 | 102 | /// Returns `subtle::Choice::from(1)` if this scalar is strictly greater 103 | /// than half the curve order; i.e if `self > (n >> 1)`. 104 | /// 105 | /// This is used to reduce malleability of ECDSA signatures, whose `s` values 106 | /// could be considered valid if they are either `s` or `n - s`. Converting 107 | /// the `s` value using [`Scalar::to_low`] and checking it using 108 | /// [`Scalar::is_high`] upon verification fixes this ambiguity. 109 | /// 110 | /// Beware that leaking timing information about this bit may expose a bit 111 | /// of information about the scalar. 112 | pub fn is_high(&self) -> subtle::Choice { 113 | self.ct_gt(&Self::half_order()) 114 | } 115 | 116 | /// If [`self.is_high()`][Self::is_high], this returns `-self`. Otherwise, returns 117 | /// the scalar unchanged. 118 | /// 119 | /// This is used to reduce malleability of ECDSA signatures, whose `s` values 120 | /// could be considered valid if they are either `s` or `n - s`. Converting 121 | /// the `s` value using [`Scalar::to_low`] and checking it using 122 | /// [`Scalar::is_high`] upon verification fixes this ambiguity. 123 | pub fn to_low(self) -> Scalar { 124 | let choice = self.ct_gt(&Self::half_order()); 125 | Scalar::conditional_select(&self, &(-self), choice) 126 | } 127 | 128 | /// Generates a new random scalar from the given CSPRNG. 129 | #[cfg(feature = "rand")] 130 | pub fn random(rng: &mut R) -> Scalar { 131 | #[cfg(feature = "secp256k1")] 132 | let inner = secp256k1::SecretKey::new(rng); 133 | 134 | // TODO: get rid of all this hacky legacy bridging crap once k256 updates to rand v0.9 135 | #[cfg(all(feature = "k256", not(feature = "secp256k1")))] 136 | let inner = k256::NonZeroScalar::random({ 137 | use k256::elliptic_curve::rand_core as legacy_rand_core; 138 | 139 | struct RngBridge<'r, R>(&'r mut R); 140 | 141 | impl legacy_rand_core::CryptoRng for RngBridge<'_, R> {} 142 | impl legacy_rand_core::RngCore for RngBridge<'_, R> { 143 | fn next_u32(&mut self) -> u32 { 144 | rand::RngCore::next_u32(self.0) 145 | } 146 | fn next_u64(&mut self) -> u64 { 147 | rand::RngCore::next_u64(self.0) 148 | } 149 | fn fill_bytes(&mut self, dest: &mut [u8]) { 150 | rand::RngCore::fill_bytes(self.0, dest) 151 | } 152 | fn try_fill_bytes( 153 | &mut self, 154 | dest: &mut [u8], 155 | ) -> Result<(), legacy_rand_core::Error> { 156 | rand::RngCore::fill_bytes(self.0, dest); 157 | Ok(()) 158 | } 159 | } 160 | 161 | &mut RngBridge(rng) 162 | }); 163 | 164 | Scalar::from(inner) 165 | } 166 | 167 | /// Serializes the scalar to a big-endian byte array representation. 168 | /// 169 | /// # Warning 170 | /// 171 | /// Use cautiously. Non-constant time operations on these bytes 172 | /// could reveal secret key material. 173 | pub fn serialize(&self) -> [u8; 32] { 174 | #[cfg(feature = "secp256k1")] 175 | return self.inner.secret_bytes(); 176 | 177 | #[cfg(all(feature = "k256", not(feature = "secp256k1")))] 178 | return self.inner.to_bytes().into(); 179 | } 180 | 181 | /// Parses a non-zero scalar in the range `[1, n)` from a given byte slice, 182 | /// which must be exactly 32-byte long and must represent the scalar in 183 | /// big-endian format. 184 | pub fn from_slice(bytes: &[u8]) -> Result { 185 | #[cfg(feature = "secp256k1")] 186 | let inner = { 187 | let byte_array = <[u8; 32]>::try_from(bytes).map_err(|_| InvalidScalarBytes)?; 188 | secp256k1::SecretKey::from_byte_array(byte_array).map_err(|_| InvalidScalarBytes)? 189 | }; 190 | 191 | #[cfg(all(feature = "k256", not(feature = "secp256k1")))] 192 | let inner = k256::NonZeroScalar::try_from(bytes).map_err(|_| InvalidScalarBytes)?; 193 | 194 | Ok(Scalar::from(inner)) 195 | } 196 | 197 | /// Parses a `Scalar` from a 32-byte hex string representation. 198 | pub fn from_hex(hex: &str) -> Result { 199 | hex.parse() 200 | } 201 | 202 | /// Multiplies the secp256k1 base point by this scalar. This is how 203 | /// public keys (points) are derived from private keys (scalars). 204 | /// Since this scalar is non-zero, the point derived from base-point 205 | /// multiplication is also guaranteed to be valid. 206 | pub fn base_point_mul(&self) -> Point { 207 | #[cfg(feature = "secp256k1")] 208 | let inner = self.inner.public_key(&LIBSECP256K1_CTX); 209 | 210 | #[cfg(all(feature = "k256", not(feature = "secp256k1")))] 211 | let inner = k256::PublicKey::from_secret_scalar(&self.inner); 212 | 213 | Point::from(inner) 214 | } 215 | 216 | /// Negates the scalar in constant-time if the given parity bit is a 1. 217 | pub fn negate_if(self, parity: subtle::Choice) -> Scalar { 218 | Scalar::conditional_select(&self, &(-self), parity) 219 | } 220 | 221 | /// Inverts a scalar modulo the curve order `n` in constant time. This 222 | /// outputs a scalar such that `self * self.inverse() == Scalar::one()` for 223 | /// all non-zero scalars. 224 | #[cfg(any(feature = "k256", feature = "secp256k1-invert"))] 225 | pub fn invert(self) -> Scalar { 226 | // Simplest case: we have a k256::NonZeroScalar available. 227 | #[cfg(feature = "k256")] 228 | return { 229 | use k256::elliptic_curve::ops::Invert as _; 230 | let inverted = k256::NonZeroScalar::from(self).invert(); 231 | Self::from(inverted) 232 | }; 233 | 234 | // Aw jeez we gotta compute the multiplicative inverse ourselves using 235 | // crypto_bigint. Strange that libsecp256k1 doesn't expose this feature. 236 | #[cfg(not(feature = "k256"))] 237 | return { 238 | use crypto_bigint::modular::constant_mod::ResidueParams as _; 239 | use crypto_bigint::Encoding as _; 240 | use crypto_bigint::Invert as _; 241 | 242 | crypto_bigint::impl_modulus!( 243 | CurveModulus, 244 | crypto_bigint::U256, 245 | "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141" // curve order 246 | ); 247 | 248 | let bigint = crypto_bigint::U256::from_be_bytes(self.serialize()); 249 | let residue = crypto_bigint::const_residue!(bigint, CurveModulus); 250 | let nz_residue: crypto_bigint::NonZero<_> = 251 | crypto_bigint::NonZero::new(residue).unwrap(); 252 | let inverted_bytes = nz_residue.invert().retrieve().to_be_bytes(); 253 | 254 | Self::try_from(&inverted_bytes).unwrap() 255 | }; 256 | } 257 | 258 | /// Converts a 32-byte array into a `Scalar` by interpreting it as a big-endian 259 | /// integer `z` and returning `(z % (n-1)) + 1`, where `n` is the secp256k1 260 | /// curve order. This always returns a valid non-zero scalar in the range `[1, n)`. 261 | /// All operations are constant-time, except if `z` works out to be zero. 262 | /// 263 | /// The probability that `z_bytes` represents an integer `z` larger than the 264 | /// curve order is only about 1 in 2^128, but nonetheless this function makes a 265 | /// best-effort attempt to parse all inputs in constant time and reduce them to 266 | /// an integer in the range `[1, n)`. 267 | pub fn reduce_from(z_bytes: &[u8; 32]) -> Self { 268 | let reduced = MaybeScalar::reduce_from_internal(z_bytes, &CURVE_ORDER_MINUS_ONE_BYTES); 269 | 270 | // this will never be zero, because `z` is in the range `[0, n-1)` 271 | (reduced + Scalar::one()).unwrap() 272 | } 273 | } 274 | 275 | // Perform elementwise XOR on two arrays and return the resulting output array. 276 | fn xor_arrays(arr1: &[T; SIZE], arr2: &[T; SIZE]) -> [T; SIZE] 277 | where 278 | T: Copy + Default + std::ops::BitXor, 279 | { 280 | let mut xored = [T::default(); SIZE]; 281 | for i in 0..SIZE { 282 | xored[i] = arr1[i] ^ arr2[i]; 283 | } 284 | xored 285 | } 286 | 287 | /// Compares two slices lexicographically in constant time whose 288 | /// elements can be ordered in constant time. 289 | /// 290 | /// Returns: 291 | /// 292 | /// - `Ordering::Less` if `lhs < rhs` 293 | /// - `Ordering::Equal` if `lhs == rhs` 294 | /// - `Ordering::Greater` if `lhs > rhs` 295 | /// 296 | /// Duplicated from [This PR](https://github.com/dalek-cryptography/subtle/pull/116). 297 | fn ct_slice_lex_cmp(lhs: &[T], rhs: &[T]) -> std::cmp::Ordering 298 | where 299 | T: ConstantTimeEq + ConstantTimeGreater, 300 | { 301 | let mut whole_slice_is_eq = subtle::Choice::from(1); 302 | let mut whole_slice_is_gt = subtle::Choice::from(0); 303 | 304 | // Zip automatically stops iterating once one of the zipped 305 | // iterators has been exhausted. 306 | for (v1, v2) in lhs.iter().zip(rhs.iter()) { 307 | // If the previous elements in the array were all equal, but `v1 > v2` in this 308 | // position, then `lhs` is deemed to be greater than `rhs`. 309 | // 310 | // We want `whole_slice_is_gt` to remain true if we ever found this condition, 311 | // but since we're aiming for constant-time, we cannot break the loop. 312 | whole_slice_is_gt |= whole_slice_is_eq & v1.ct_gt(v2); 313 | 314 | // Track whether all elements in the slices up to this point are equal. 315 | whole_slice_is_eq &= v1.ct_eq(v2); 316 | } 317 | 318 | let l_len = lhs.len() as u64; 319 | let r_len = rhs.len() as u64; 320 | let lhs_is_longer = l_len.ct_gt(&r_len); 321 | let rhs_is_longer = r_len.ct_gt(&l_len); 322 | 323 | // Fallback: lhs < rhs 324 | let mut order = std::cmp::Ordering::Less; 325 | 326 | // both slices up to `min(l_len, r_len)` were equal. 327 | order.conditional_assign(&std::cmp::Ordering::Equal, whole_slice_is_eq); 328 | 329 | // `rhs` is a prefix of `lhs`. `lhs` is lexicographically greater. 330 | order.conditional_assign( 331 | &std::cmp::Ordering::Greater, 332 | whole_slice_is_eq & lhs_is_longer, 333 | ); 334 | 335 | // `lhs` is a prefix of `rhs`. `rhs` is lexicographically greater. 336 | order.conditional_assign(&std::cmp::Ordering::Less, whole_slice_is_eq & rhs_is_longer); 337 | 338 | // `lhs` contains the earliest strictly-greater element. 339 | order.conditional_assign(&std::cmp::Ordering::Greater, whole_slice_is_gt); 340 | 341 | order 342 | } 343 | 344 | /// Represents an elliptic curve scalar value which might be zero. 345 | /// Supports all the same constant-time arithmetic operators supported 346 | /// by [`Scalar`]. 347 | /// 348 | /// `MaybeScalar` should only be used in cases where it is possible for 349 | /// an input to be zero. In all possible cases, using [`Scalar`] is more 350 | /// appropriate. The output of arithmetic operations with non-zero `Scalar`s 351 | /// can result in a `MaybeScalar` - for example, adding two scalars together 352 | /// linearly. 353 | /// 354 | /// ``` 355 | /// use secp::{MaybeScalar, Scalar}; 356 | /// 357 | /// let maybe_scalar: MaybeScalar = Scalar::one() + Scalar::one(); 358 | /// ``` 359 | /// 360 | /// This is because the two scalars might represent values which are additive 361 | /// inverses of each other (i.e. `x + (-x)`), so the output of their addition 362 | /// can result in zero, which must be checked for by the caller where 363 | /// appropriate. 364 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] 365 | pub enum MaybeScalar { 366 | Zero, 367 | Valid(Scalar), 368 | } 369 | 370 | use MaybeScalar::*; 371 | 372 | impl MaybeScalar { 373 | /// Returns a valid `MaybeScalar` with a value of 1. 374 | pub fn one() -> MaybeScalar { 375 | Valid(Scalar::one()) 376 | } 377 | 378 | /// Returns a valid `MaybeScalar` with a value of two. 379 | pub fn two() -> MaybeScalar { 380 | Valid(Scalar::two()) 381 | } 382 | 383 | /// Returns half of the curve order `n`, specifically `n >> 1`. 384 | pub fn half_order() -> MaybeScalar { 385 | Valid(Scalar::half_order()) 386 | } 387 | 388 | /// Returns a valid `MaybeScalar` with the maximum possible value less 389 | /// than the curve order, `n - 1`. 390 | pub fn max() -> MaybeScalar { 391 | Valid(Scalar::max()) 392 | } 393 | 394 | /// Returns true if this scalar represents zero. 395 | pub fn is_zero(&self) -> bool { 396 | self == &Zero 397 | } 398 | 399 | /// Returns `subtle::Choice::from(1)` if this scalar is strictly greater 400 | /// than half the curve order; i.e if `self > (n >> 1)`. 401 | /// 402 | /// This is used to reduce malleability of ECDSA signatures, whose `s` values 403 | /// could be considered valid if they are either `s` or `n - s`. Converting 404 | /// the `s` value using [`MaybeScalar::to_low`] and checking it using 405 | /// [`MaybeScalar::is_high`] upon verification fixes this ambiguity. 406 | /// 407 | /// Beware that leaking timing information about this bit may expose a bit 408 | /// of information about the scalar. 409 | pub fn is_high(&self) -> subtle::Choice { 410 | self.ct_gt(&Self::half_order()) 411 | } 412 | 413 | /// If [`self.is_high()`][Self::is_high], this returns `-self`. Otherwise, 414 | /// returns the original scalar unchanged. 415 | /// 416 | /// This is used to reduce malleability of ECDSA signatures, whose `s` values 417 | /// could be considered valid if they are either `s` or `n - s`. Converting 418 | /// the `s` value using [`MaybeScalar::to_low`] and checking it using 419 | /// [`MaybeScalar::is_high`] upon verification fixes this ambiguity. 420 | pub fn to_low(self) -> MaybeScalar { 421 | let choice = self.ct_gt(&Self::half_order()); 422 | MaybeScalar::conditional_select(&self, &(-self), choice) 423 | } 424 | 425 | /// Serializes the scalar to a big-endian byte array representation. 426 | /// 427 | /// # Warning 428 | /// 429 | /// Use cautiously. Non-constant time operations on these bytes 430 | /// could reveal secret key material. 431 | pub fn serialize(&self) -> [u8; 32] { 432 | match self { 433 | Valid(scalar) => scalar.serialize(), 434 | Zero => [0; 32], 435 | } 436 | } 437 | 438 | /// Parses a non-zero scalar in the range `[0, n)` from a given byte slice, 439 | /// which must be exactly 32-byte long and must represent the scalar in 440 | /// big-endian format. 441 | pub fn from_slice(bytes: &[u8]) -> Result { 442 | Scalar::try_from(bytes) 443 | .map(MaybeScalar::Valid) 444 | .or_else(|e| { 445 | if bool::from(bytes.ct_eq(&[0; 32])) { 446 | Ok(MaybeScalar::Zero) 447 | } else { 448 | Err(e) 449 | } 450 | }) 451 | } 452 | 453 | /// Parses a `MaybeScalar` from a 32-byte hex string representation. 454 | pub fn from_hex(hex: &str) -> Result { 455 | hex.parse() 456 | } 457 | 458 | /// Returns an option which is `None` if `self == MaybeScalar::Zero`, 459 | /// or a `Some(Scalar)` otherwise. 460 | pub fn into_option(self) -> Option { 461 | Option::from(self) 462 | } 463 | 464 | /// Converts the `MaybeScalar` into a `Result`, 465 | /// returning `Ok(Scalar)` if the scalar is a valid non-zero number, or 466 | /// `Err(ZeroScalarError)` if `maybe_scalar == MaybeScalar::Zero`. 467 | pub fn not_zero(self) -> Result { 468 | Scalar::try_from(self) 469 | } 470 | 471 | /// Coerces the `MaybeScalar` into a [`Scalar`]. Panics if `self == MaybeScalar::Zero`. 472 | pub fn unwrap(self) -> Scalar { 473 | match self { 474 | Valid(point) => point, 475 | Zero => panic!("called unwrap on MaybeScalar::Zero"), 476 | } 477 | } 478 | 479 | /// Converts a 32-byte array into a `MaybeScalar` by interpreting it as 480 | /// a big-endian integer `z` and reducing `z` modulo some given `modulus` 481 | /// in constant time. This modulus must less than or equal to the secp256k1 482 | /// curve order `n`. 483 | /// 484 | /// Unfortunately libsecp256k1 does not expose this functionality, so we have done 485 | /// our best to reimplement modular reduction in constant time using only scalar 486 | /// arithmetic on numbers in the range `[0, n)`. 487 | /// 488 | /// Instead of taking the remainder `z % modulus` directly (which we can't do with 489 | /// libsecp256k1), we use XOR to compute the relative distances from `z` and `modulus` 490 | /// to some independent constant, specifically `MAX_U256`. We denote the distances as: 491 | /// 492 | /// - `q = MAX_U256 - z` and 493 | /// - `r = MAX_U256 - modulus` 494 | /// 495 | /// As long as both distances are guaranteed to be smaller than the curve order `n`, this 496 | /// gives us a way to compute `z % modulus` safely in constant time: by computing the 497 | /// difference of the two relative distances: 498 | /// 499 | /// ```notrust 500 | /// r - q = (MAX_U256 - modulus) - (MAX_U256 - z) 501 | /// = z - modulus 502 | /// ``` 503 | /// 504 | /// The above is only needed when `z` might be greater than the `modulus`. If instead 505 | /// `z < modulus`, we set `q = z` and return `q` in constant time, throwing away the 506 | /// result of subtracting `r - q`. 507 | fn reduce_from_internal(z_bytes: &[u8; 32], modulus: &[u8; 32]) -> MaybeScalar { 508 | // Modulus must be less than or equal to `n`, as `n-1` is the largest number we can represent. 509 | debug_assert!(modulus <= &CURVE_ORDER_BYTES); 510 | 511 | let modulus_neg_bytes = xor_arrays(modulus, &MAX_U256); 512 | 513 | // Modulus must not be too small either, or we won't be able 514 | // to represent the distance to MAX_U256. 515 | debug_assert!(modulus_neg_bytes <= CURVE_ORDER_BYTES); 516 | 517 | // Although we cannot operate arithmetically on numbers larger than `n-1`, we can 518 | // still use XOR to subtract from a number represented by all one-bits, such as 519 | // MAX_U256. 520 | let z_bytes_neg = xor_arrays(z_bytes, &MAX_U256); 521 | 522 | let z_needs_reduction = ct_slice_lex_cmp(z_bytes, modulus).ct_gt(&std::cmp::Ordering::Less); 523 | 524 | let q_bytes = <[u8; 32]>::conditional_select( 525 | z_bytes, // `z < modulus`; set `q = z` 526 | &z_bytes_neg, // `z >= modulus`; set `q = MAX_U256 - z` (implies q <= modulus) 527 | z_needs_reduction, 528 | ); 529 | 530 | // By this point, we know for sure that `q_bytes` represents an integer less than `n`, 531 | // so `try_from` should always work here. 532 | let q = MaybeScalar::try_from(&q_bytes).unwrap(); 533 | 534 | // Modulus distance `r` should also always be less than the curve order. 535 | let r = MaybeScalar::try_from(&modulus_neg_bytes).unwrap(); 536 | 537 | // if z < modulus 538 | // return q = z 539 | // 540 | // else 541 | // return r - q = (MAX_U256 - modulus) - (MAX_U256 - z) 542 | // = MAX_U256 - modulus - MAX_U256 + z 543 | // = z - modulus 544 | MaybeScalar::conditional_select(&q, &(r - q), z_needs_reduction) 545 | } 546 | 547 | /// Converts a 32-byte array into a `MaybeScalar` by interpreting it as 548 | /// a big-endian integer `z` and reducing `z` modulo the secp256k1 curve 549 | /// order `n` in constant time. 550 | /// 551 | /// The probability that `z_bytes` represents an integer `z` larger than the 552 | /// curve order is only about 1 in 2^128, but nonetheless this function makes a 553 | /// best-effort attempt to parse all inputs in constant time and reduce them to 554 | /// an integer in the range `[0, n)`. 555 | pub fn reduce_from(z_bytes: &[u8; 32]) -> Self { 556 | Self::reduce_from_internal(z_bytes, &CURVE_ORDER_BYTES) 557 | } 558 | 559 | /// Multiplies the secp256k1 base point by this scalar. This is how 560 | /// public keys (points) are derived from private keys (scalars). 561 | /// 562 | /// If this scalar is [`MaybeScalar::Zero`], this method returns [`MaybePoint::Infinity`]. 563 | pub fn base_point_mul(&self) -> MaybePoint { 564 | match self { 565 | Valid(scalar) => MaybePoint::Valid(scalar.base_point_mul()), 566 | Zero => MaybePoint::Infinity, 567 | } 568 | } 569 | 570 | /// Negates the scalar in constant-time if the given parity bit is a 1. 571 | pub fn negate_if(self, parity: subtle::Choice) -> MaybeScalar { 572 | MaybeScalar::conditional_select(&self, &(-self), parity) 573 | } 574 | } 575 | 576 | mod std_traits { 577 | use super::*; 578 | 579 | /// This implementation was duplicated from the [`secp256k1`] crate, because 580 | /// [`k256::NonZeroScalar`] doesn't implement `Debug`. 581 | impl std::fmt::Debug for Scalar { 582 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 583 | use std::hash::Hasher as _; 584 | const DEBUG_HASH_TAG: &[u8] = &[ 585 | 0x66, 0xa6, 0x77, 0x1b, 0x9b, 0x6d, 0xae, 0xa1, 0xb2, 0xee, 0x4e, 0x07, 0x49, 0x4a, 586 | 0xac, 0x87, 0xa9, 0xb8, 0x5b, 0x4b, 0x35, 0x02, 0xaa, 0x6d, 0x0f, 0x79, 0xcb, 0x63, 587 | 0xe6, 0xf8, 0x66, 0x22, 588 | ]; // =SHA256(b"rust-secp256k1DEBUG"); 589 | 590 | let mut hasher = std::collections::hash_map::DefaultHasher::new(); 591 | hasher.write(DEBUG_HASH_TAG); 592 | hasher.write(DEBUG_HASH_TAG); 593 | hasher.write(&self.serialize()); 594 | let hash = hasher.finish(); 595 | 596 | f.debug_tuple(stringify!(Scalar)) 597 | .field(&format_args!("#{:016x}", hash)) 598 | .finish() 599 | } 600 | } 601 | 602 | /// Reimplemented manually, because [`k256::NonZeroScalar`] doesn't implement 603 | /// `PartialEq`. 604 | #[cfg(all(feature = "k256", not(feature = "secp256k1")))] 605 | impl PartialEq for Scalar { 606 | fn eq(&self, rhs: &Self) -> bool { 607 | self.inner.ct_eq(&rhs.inner).into() 608 | } 609 | } 610 | 611 | impl Eq for Scalar {} 612 | 613 | impl Default for MaybeScalar { 614 | /// Returns [`MaybeScalar::Zero`]. 615 | fn default() -> Self { 616 | MaybeScalar::Zero 617 | } 618 | } 619 | } 620 | 621 | #[cfg(feature = "num-traits")] 622 | mod num_traits_impls { 623 | use super::*; 624 | 625 | impl num_traits::One for Scalar { 626 | fn one() -> Self { 627 | Scalar::one() 628 | } 629 | fn is_one(&self) -> bool { 630 | *self == Scalar::one() 631 | } 632 | } 633 | 634 | impl num_traits::One for MaybeScalar { 635 | fn one() -> Self { 636 | MaybeScalar::one() 637 | } 638 | fn is_one(&self) -> bool { 639 | *self == MaybeScalar::one() 640 | } 641 | } 642 | 643 | impl num_traits::Zero for MaybeScalar { 644 | fn zero() -> Self { 645 | Zero 646 | } 647 | fn is_zero(&self) -> bool { 648 | self == &Zero 649 | } 650 | } 651 | 652 | impl num_traits::Inv for Scalar { 653 | type Output = Scalar; 654 | fn inv(self) -> Self::Output { 655 | self.invert() 656 | } 657 | } 658 | 659 | impl num_traits::Bounded for Scalar { 660 | fn min_value() -> Self { 661 | Scalar::one() 662 | } 663 | fn max_value() -> Self { 664 | Scalar::max() 665 | } 666 | } 667 | 668 | impl num_traits::Bounded for MaybeScalar { 669 | fn min_value() -> Self { 670 | Zero 671 | } 672 | fn max_value() -> Self { 673 | MaybeScalar::max() 674 | } 675 | } 676 | } 677 | 678 | mod conversions { 679 | use super::*; 680 | 681 | #[cfg(feature = "secp256k1")] 682 | mod as_ref_conversions { 683 | use super::*; 684 | 685 | impl AsRef for Scalar { 686 | fn as_ref(&self) -> &secp256k1::SecretKey { 687 | &self.inner 688 | } 689 | } 690 | 691 | impl AsRef<[u8; 32]> for Scalar { 692 | /// Returns a reference to the underlying secret bytes of this scalar. 693 | /// 694 | /// # Warning 695 | /// 696 | /// Use cautiously. Non-constant time operations on these bytes 697 | /// could reveal secret key material. 698 | fn as_ref(&self) -> &[u8; 32] { 699 | self.inner.as_ref() 700 | } 701 | } 702 | 703 | impl AsRef<[u8; 32]> for MaybeScalar { 704 | /// Returns a reference to the underlying secret bytes of this scalar. 705 | /// 706 | /// # Warning 707 | /// 708 | /// Use cautiously. Non-constant time operations on these bytes 709 | /// could reveal secret key material. 710 | fn as_ref(&self) -> &[u8; 32] { 711 | const EMPTY: [u8; 32] = [0; 32]; 712 | match self { 713 | Valid(ref scalar) => scalar.as_ref(), 714 | Zero => &EMPTY, 715 | } 716 | } 717 | } 718 | 719 | impl AsRef<[u8]> for Scalar { 720 | /// Returns a reference to the underlying secret bytes of this scalar. 721 | /// 722 | /// # Warning 723 | /// 724 | /// Use cautiously. Non-constant time operations on these bytes 725 | /// could reveal secret key material. 726 | fn as_ref(&self) -> &[u8] { 727 | >::as_ref(self) as &[u8] 728 | } 729 | } 730 | 731 | impl AsRef<[u8]> for MaybeScalar { 732 | /// Returns a reference to the underlying secret bytes of this scalar. 733 | /// 734 | /// # Warning 735 | /// 736 | /// Use cautiously. Non-constant time operations on these bytes 737 | /// could reveal secret key material. 738 | fn as_ref(&self) -> &[u8] { 739 | >::as_ref(self) as &[u8] 740 | } 741 | } 742 | } 743 | 744 | mod std_conversions { 745 | use super::*; 746 | 747 | impl From for Option { 748 | /// Converts [`MaybeScalar::Zero`] into `None` and a valid [`Scalar`] into `Some`. 749 | fn from(maybe_scalar: MaybeScalar) -> Self { 750 | match maybe_scalar { 751 | Valid(scalar) => Some(scalar), 752 | Zero => None, 753 | } 754 | } 755 | } 756 | 757 | /// Converts any unsigned integer number into a `Scalar`. 758 | /// Returns [`ZeroScalarError`] if the integer is zero. 759 | impl TryFrom for Scalar { 760 | type Error = ZeroScalarError; 761 | fn try_from(value: u128) -> Result { 762 | MaybeScalar::from(value).not_zero() 763 | } 764 | } 765 | 766 | /// Converts any unsigned integer number into a MaybeScalar. 767 | impl From for MaybeScalar { 768 | fn from(value: u128) -> Self { 769 | if value == 0 { 770 | return Zero; 771 | } 772 | 773 | let mut arr = [0; 32]; 774 | arr[16..].clone_from_slice(&value.to_be_bytes()); 775 | 776 | #[cfg(feature = "secp256k1")] 777 | let inner = secp256k1::SecretKey::from_byte_array(arr).unwrap(); 778 | 779 | #[cfg(all(feature = "k256", not(feature = "secp256k1")))] 780 | let inner = k256::NonZeroScalar::from_repr(arr.into()).unwrap(); 781 | 782 | MaybeScalar::from(inner) 783 | } 784 | } 785 | } 786 | 787 | mod internal_conversions { 788 | use super::*; 789 | 790 | impl From for MaybeScalar { 791 | /// Converts the scalar into a [`MaybeScalar::Valid`] instance. 792 | fn from(scalar: Scalar) -> Self { 793 | MaybeScalar::Valid(scalar) 794 | } 795 | } 796 | 797 | impl TryFrom for Scalar { 798 | type Error = ZeroScalarError; 799 | 800 | /// Converts the `MaybeScalar` into a `Result`, 801 | /// returning `Ok(Scalar)` if the scalar is a valid non-zero number, 802 | /// or `Err(ZeroScalarError)` if `maybe_scalar == MaybeScalar::Zero`. 803 | fn try_from(maybe_scalar: MaybeScalar) -> Result { 804 | match maybe_scalar { 805 | Valid(scalar) => Ok(scalar), 806 | Zero => Err(ZeroScalarError), 807 | } 808 | } 809 | } 810 | } 811 | 812 | #[cfg(feature = "secp256k1")] 813 | mod secp256k1_conversions { 814 | use super::*; 815 | 816 | mod secret_key { 817 | use super::*; 818 | 819 | impl From for Scalar { 820 | fn from(inner: secp256k1::SecretKey) -> Self { 821 | Scalar { inner } 822 | } 823 | } 824 | 825 | impl From for MaybeScalar { 826 | fn from(inner: secp256k1::SecretKey) -> Self { 827 | MaybeScalar::Valid(Scalar::from(inner)) 828 | } 829 | } 830 | 831 | impl From for secp256k1::SecretKey { 832 | fn from(scalar: Scalar) -> secp256k1::SecretKey { 833 | scalar.inner 834 | } 835 | } 836 | 837 | impl TryFrom for secp256k1::SecretKey { 838 | type Error = ZeroScalarError; 839 | fn try_from(maybe_scalar: MaybeScalar) -> Result { 840 | Ok(maybe_scalar.not_zero()?.inner) 841 | } 842 | } 843 | } 844 | 845 | mod scalar { 846 | use super::*; 847 | 848 | impl From for Scalar { 849 | fn from(scalar: secp256k1::Scalar) -> Self { 850 | Scalar::try_from(scalar.to_be_bytes()).unwrap() 851 | } 852 | } 853 | 854 | impl From for MaybeScalar { 855 | fn from(scalar: secp256k1::Scalar) -> Self { 856 | MaybeScalar::Valid(Scalar::from(scalar)) 857 | } 858 | } 859 | 860 | impl From for secp256k1::Scalar { 861 | fn from(scalar: Scalar) -> Self { 862 | secp256k1::Scalar::from(scalar.inner) 863 | } 864 | } 865 | 866 | impl TryFrom for secp256k1::Scalar { 867 | type Error = ZeroScalarError; 868 | fn try_from(maybe_scalar: MaybeScalar) -> Result { 869 | Ok(secp256k1::Scalar::from(maybe_scalar.not_zero()?)) 870 | } 871 | } 872 | } 873 | } 874 | 875 | #[cfg(feature = "k256")] 876 | mod k256_conversions { 877 | use super::*; 878 | 879 | mod non_zero_scalar { 880 | use super::*; 881 | 882 | impl From for Scalar { 883 | fn from(nz_scalar: k256::NonZeroScalar) -> Self { 884 | #[cfg(feature = "secp256k1")] 885 | return Scalar::try_from(<[u8; 32]>::from(nz_scalar.to_bytes())).unwrap(); 886 | 887 | #[cfg(not(feature = "secp256k1"))] 888 | return Scalar { inner: nz_scalar }; 889 | } 890 | } 891 | 892 | impl From for MaybeScalar { 893 | fn from(nz_scalar: k256::NonZeroScalar) -> Self { 894 | MaybeScalar::Valid(Scalar::from(nz_scalar)) 895 | } 896 | } 897 | 898 | impl From for k256::NonZeroScalar { 899 | fn from(scalar: Scalar) -> Self { 900 | #[cfg(feature = "secp256k1")] 901 | return k256::NonZeroScalar::from_repr(scalar.serialize().into()).unwrap(); 902 | 903 | #[cfg(not(feature = "secp256k1"))] 904 | return scalar.inner; 905 | } 906 | } 907 | 908 | impl TryFrom for k256::NonZeroScalar { 909 | type Error = ZeroScalarError; 910 | fn try_from(maybe_scalar: MaybeScalar) -> Result { 911 | Ok(k256::NonZeroScalar::from(maybe_scalar.not_zero()?)) 912 | } 913 | } 914 | } 915 | 916 | mod scalar { 917 | use super::*; 918 | 919 | impl TryFrom for Scalar { 920 | type Error = ZeroScalarError; 921 | fn try_from(scalar: k256::Scalar) -> Result { 922 | MaybeScalar::from(scalar).not_zero() 923 | } 924 | } 925 | 926 | impl From for MaybeScalar { 927 | fn from(scalar: k256::Scalar) -> Self { 928 | #[cfg(feature = "secp256k1")] 929 | return MaybeScalar::try_from(scalar.to_bytes()).unwrap(); 930 | 931 | #[cfg(not(feature = "secp256k1"))] 932 | return { 933 | let ct_opt = k256::NonZeroScalar::from_uint(scalar.into()); 934 | match Option::::from(ct_opt) { 935 | Some(inner) => MaybeScalar::from(inner), 936 | None => MaybeScalar::Zero, 937 | } 938 | }; 939 | } 940 | } 941 | 942 | impl From for k256::Scalar { 943 | fn from(scalar: Scalar) -> Self { 944 | *k256::NonZeroScalar::from(scalar).as_ref() 945 | } 946 | } 947 | 948 | impl From for k256::Scalar { 949 | fn from(maybe_scalar: MaybeScalar) -> Self { 950 | match maybe_scalar { 951 | MaybeScalar::Zero => k256::Scalar::ZERO, 952 | MaybeScalar::Valid(scalar) => k256::Scalar::from(scalar), 953 | } 954 | } 955 | } 956 | } 957 | 958 | mod secret_key { 959 | use super::*; 960 | 961 | impl From for Scalar { 962 | fn from(seckey: k256::SecretKey) -> Self { 963 | Scalar::from(k256::NonZeroScalar::from(seckey)) 964 | } 965 | } 966 | 967 | impl From for MaybeScalar { 968 | fn from(seckey: k256::SecretKey) -> Self { 969 | MaybeScalar::Valid(Scalar::from(seckey)) 970 | } 971 | } 972 | 973 | impl From for k256::SecretKey { 974 | fn from(scalar: Scalar) -> Self { 975 | k256::SecretKey::from(k256::NonZeroScalar::from(scalar)) 976 | } 977 | } 978 | 979 | impl TryFrom for k256::SecretKey { 980 | type Error = ZeroScalarError; 981 | fn try_from(maybe_scalar: MaybeScalar) -> Result { 982 | Ok(k256::SecretKey::from(maybe_scalar.not_zero()?)) 983 | } 984 | } 985 | } 986 | } 987 | } 988 | 989 | pub(crate) const SCALAR_ZERO_STR: &str = 990 | "0000000000000000000000000000000000000000000000000000000000000000"; 991 | 992 | mod encodings { 993 | use super::*; 994 | 995 | impl std::fmt::LowerHex for Scalar { 996 | /// Formats the scalar as a hex string in lower case. 997 | /// 998 | /// # Warning 999 | /// 1000 | /// This method may expose private data if the scalar represents a secret key. 1001 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 1002 | let mut buffer = [0; 64]; 1003 | let encoded = base16ct::lower::encode_str(&self.serialize(), &mut buffer).unwrap(); 1004 | f.write_str(encoded) 1005 | } 1006 | } 1007 | 1008 | impl std::fmt::UpperHex for Scalar { 1009 | /// Formats the scalar as a hex string in upper case. 1010 | /// 1011 | /// # Warning 1012 | /// 1013 | /// This method may expose private data if the scalar represents a secret key. 1014 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 1015 | let mut buffer = [0; 64]; 1016 | let encoded = base16ct::upper::encode_str(&self.serialize(), &mut buffer).unwrap(); 1017 | f.write_str(encoded) 1018 | } 1019 | } 1020 | 1021 | impl std::fmt::LowerHex for MaybeScalar { 1022 | /// Formats the scalar as a hex string in lower case. 1023 | /// 1024 | /// # Warning 1025 | /// 1026 | /// This method may expose private data if the scalar represents a secret key. 1027 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 1028 | match self { 1029 | Valid(scalar) => scalar.fmt(f), 1030 | Zero => f.write_str(SCALAR_ZERO_STR), 1031 | } 1032 | } 1033 | } 1034 | 1035 | impl std::fmt::UpperHex for MaybeScalar { 1036 | /// Formats the scalar as a hex string in upper case. 1037 | /// 1038 | /// # Warning 1039 | /// 1040 | /// This method may expose private data if the scalar represents a secret key. 1041 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 1042 | match self { 1043 | Valid(scalar) => scalar.fmt(f), 1044 | Zero => f.write_str(SCALAR_ZERO_STR), 1045 | } 1046 | } 1047 | } 1048 | 1049 | impl std::str::FromStr for Scalar { 1050 | type Err = InvalidScalarString; 1051 | 1052 | /// Parses a `Scalar` from a 32-byte hex string representation. 1053 | fn from_str(s: &str) -> Result { 1054 | let inner = s.parse().map_err(|_| InvalidScalarString)?; 1055 | Ok(Scalar { inner }) 1056 | } 1057 | } 1058 | 1059 | impl std::str::FromStr for MaybeScalar { 1060 | type Err = InvalidScalarString; 1061 | 1062 | /// Parses a scalar from a 32-byte hex string representation. 1063 | /// 1064 | /// If the string is a hex-encoded 32 byte array of zeros, this 1065 | /// will return [`MaybeScalar::Zero`]. 1066 | fn from_str(s: &str) -> Result { 1067 | // Make sure this comparison is executed in constant time to avoid 1068 | // leaking information about secret scalars during deserialization. 1069 | if bool::from(s.as_bytes().ct_eq(SCALAR_ZERO_STR.as_bytes())) { 1070 | return Ok(MaybeScalar::Zero); 1071 | } 1072 | 1073 | let scalar = Scalar::from_str(s)?; 1074 | Ok(Valid(scalar)) 1075 | } 1076 | } 1077 | 1078 | impl TryFrom<&[u8]> for Scalar { 1079 | type Error = InvalidScalarBytes; 1080 | /// Attempts to parse a 32-byte slice as a scalar in the range `[1, n)` 1081 | /// in constant time, where `n` is the curve order. 1082 | /// 1083 | /// Returns [`InvalidScalarBytes`] if the integer represented by the bytes 1084 | /// is greater than or equal to the curve order, or if the bytes are all zero. 1085 | /// 1086 | /// Fails if `bytes.len() != 32`. 1087 | fn try_from(bytes: &[u8]) -> Result { 1088 | Self::from_slice(bytes) 1089 | } 1090 | } 1091 | 1092 | impl TryFrom<&[u8]> for MaybeScalar { 1093 | type Error = InvalidScalarBytes; 1094 | 1095 | /// Attempts to parse a 32-byte slice as a scalar in the range `[0, n)` 1096 | /// in constant time, where `n` is the curve order. Timing information 1097 | /// may be leaked if `bytes` is all zeros or not the right length. 1098 | /// 1099 | /// Returns [`InvalidScalarBytes`] if the integer represented by the bytes 1100 | /// is greater than or equal to the curve order, or if `bytes.len() != 32`. 1101 | fn try_from(bytes: &[u8]) -> Result { 1102 | Self::from_slice(bytes) 1103 | } 1104 | } 1105 | 1106 | impl TryFrom<&[u8; 32]> for MaybeScalar { 1107 | type Error = InvalidScalarBytes; 1108 | 1109 | /// Attempts to parse a 32-byte array as a scalar in the range `[0, n)` 1110 | /// in constant time, where `n` is the curve order. Timing information 1111 | /// may be leaked if `bytes` is the zero array, but then that's not a 1112 | /// very secret value, is it? 1113 | /// 1114 | /// Returns [`InvalidScalarBytes`] if the integer represented by the bytes 1115 | /// is greater than or equal to the curve order. 1116 | fn try_from(bytes: &[u8; 32]) -> Result { 1117 | Self::from_slice(bytes as &[u8]) 1118 | } 1119 | } 1120 | 1121 | impl TryFrom<&[u8; 32]> for Scalar { 1122 | type Error = InvalidScalarBytes; 1123 | 1124 | /// Attempts to parse a 32-byte array as a scalar in the range `[1, n)` 1125 | /// in constant time, where `n` is the curve order. 1126 | /// 1127 | /// Returns [`InvalidScalarBytes`] if the integer represented by the bytes 1128 | /// is greater than or equal to the curve order, or if the bytes are all zero. 1129 | fn try_from(bytes: &[u8; 32]) -> Result { 1130 | Self::from_slice(bytes as &[u8]) 1131 | } 1132 | } 1133 | 1134 | impl TryFrom<[u8; 32]> for MaybeScalar { 1135 | type Error = InvalidScalarBytes; 1136 | 1137 | /// Attempts to parse a 32-byte array as a scalar in the range `[0, n)` 1138 | /// in constant time, where `n` is the curve order. 1139 | /// 1140 | /// Returns [`InvalidScalarBytes`] if the integer represented by the bytes 1141 | /// is greater than or equal to the curve order. 1142 | fn try_from(bytes: [u8; 32]) -> Result { 1143 | Self::from_slice(&bytes) 1144 | } 1145 | } 1146 | 1147 | impl TryFrom<[u8; 32]> for Scalar { 1148 | type Error = InvalidScalarBytes; 1149 | 1150 | /// Attempts to parse a 32-byte array as a scalar in the range `[1, n)` 1151 | /// in constant time, where `n` is the curve order. 1152 | /// 1153 | /// Returns [`InvalidScalarBytes`] if the integer represented by the bytes 1154 | /// is greater than or equal to the curve order, or if the bytes are all zero. 1155 | fn try_from(bytes: [u8; 32]) -> Result { 1156 | Self::from_slice(&bytes) 1157 | } 1158 | } 1159 | 1160 | #[cfg(feature = "k256")] 1161 | impl TryFrom for Scalar { 1162 | type Error = InvalidScalarBytes; 1163 | 1164 | /// Attempts to parse a 32-byte array as a scalar in the range `[1, n)` 1165 | /// in constant time, where `n` is the curve order. 1166 | /// 1167 | /// Returns [`InvalidScalarBytes`] if the integer represented by the bytes 1168 | /// is greater than or equal to the curve order. 1169 | fn try_from(bytes: k256::FieldBytes) -> Result { 1170 | Self::from_slice(&bytes) 1171 | } 1172 | } 1173 | 1174 | #[cfg(feature = "k256")] 1175 | impl TryFrom for MaybeScalar { 1176 | type Error = InvalidScalarBytes; 1177 | 1178 | /// Attempts to parse a 32-byte array as a scalar in the range `[0, n)` 1179 | /// in constant time, where `n` is the curve order. 1180 | /// 1181 | /// Returns [`InvalidScalarBytes`] if the integer represented by the bytes 1182 | /// is greater than or equal to the curve order. 1183 | fn try_from(bytes: k256::FieldBytes) -> Result { 1184 | Self::from_slice(&bytes) 1185 | } 1186 | } 1187 | 1188 | impl From for [u8; 32] { 1189 | /// Serializes the scalar to a big-endian byte array representation. 1190 | fn from(scalar: Scalar) -> Self { 1191 | scalar.serialize() 1192 | } 1193 | } 1194 | 1195 | impl From for [u8; 32] { 1196 | /// Serializes the scalar to a big-endian byte array representation. 1197 | fn from(maybe_scalar: MaybeScalar) -> Self { 1198 | maybe_scalar.serialize() 1199 | } 1200 | } 1201 | } 1202 | 1203 | mod subtle_traits { 1204 | use super::*; 1205 | 1206 | impl ConditionallySelectable for Scalar { 1207 | /// Conditionally selects one of two scalars in constant time. No timing 1208 | /// information about the value of either scalar will be leaked. 1209 | #[inline] 1210 | fn conditional_select(&a: &Self, &b: &Self, choice: subtle::Choice) -> Self { 1211 | #[cfg(feature = "secp256k1")] 1212 | return { 1213 | let mut output_bytes: [u8; 32] = a.serialize(); 1214 | output_bytes.conditional_assign(&b.serialize(), choice); 1215 | Scalar::try_from(&output_bytes).unwrap() 1216 | }; 1217 | 1218 | #[cfg(all(feature = "k256", not(feature = "secp256k1")))] 1219 | return { 1220 | let mut inner = a.inner; 1221 | inner.conditional_assign(&b.inner, choice); 1222 | Scalar::from(inner) 1223 | }; 1224 | } 1225 | } 1226 | 1227 | impl ConditionallySelectable for MaybeScalar { 1228 | /// Conditionally selects one of two scalars in constant time. The exception is if 1229 | /// either `a` or `b` are [`MaybeScalar::Zero`], in which case timing information 1230 | /// about this fact may be leaked. No timing information about the value 1231 | /// of a non-zero scalar will be leaked. 1232 | fn conditional_select(&a: &Self, &b: &Self, choice: subtle::Choice) -> Self { 1233 | #[cfg(feature = "secp256k1")] 1234 | return { 1235 | let mut output_bytes: [u8; 32] = a.serialize(); 1236 | output_bytes.conditional_assign(&b.serialize(), choice); 1237 | MaybeScalar::try_from(&output_bytes).unwrap() 1238 | }; 1239 | 1240 | #[cfg(all(feature = "k256", not(feature = "secp256k1")))] 1241 | return { 1242 | let a_inner = a 1243 | .into_option() 1244 | .map(|scalar| *scalar.inner.as_ref()) 1245 | .unwrap_or(k256::Scalar::ZERO); 1246 | let b_inner = b 1247 | .into_option() 1248 | .map(|scalar| *scalar.inner.as_ref()) 1249 | .unwrap_or(k256::Scalar::ZERO); 1250 | 1251 | let inner_scalar = k256::Scalar::conditional_select(&a_inner, &b_inner, choice); 1252 | 1253 | Option::::from(k256::NonZeroScalar::new(inner_scalar)) 1254 | .map(MaybeScalar::from) 1255 | .unwrap_or(MaybeScalar::Zero) 1256 | }; 1257 | } 1258 | } 1259 | 1260 | impl ConstantTimeEq for Scalar { 1261 | /// Compares this scalar against another in constant time. 1262 | /// Returns `subtle::Choice::from(1)` if and only if the 1263 | /// two scalars represent the same integer. 1264 | #[inline] 1265 | fn ct_eq(&self, other: &Self) -> subtle::Choice { 1266 | self.serialize().ct_eq(&other.serialize()) 1267 | } 1268 | } 1269 | 1270 | impl ConstantTimeEq for MaybeScalar { 1271 | /// Compares this scalar against another in constant time. 1272 | /// Returns `subtle::Choice::from(1)` if and only if the 1273 | /// two scalars represent the same integer. 1274 | #[inline] 1275 | fn ct_eq(&self, other: &Self) -> subtle::Choice { 1276 | self.serialize().ct_eq(&other.serialize()) 1277 | } 1278 | } 1279 | 1280 | impl ConstantTimeGreater for Scalar { 1281 | /// Compares this scalar against another in constant time. 1282 | /// Returns `subtle::Choice::from(1)` if `self` is strictly 1283 | /// lexicographically greater than `other`. 1284 | #[inline] 1285 | fn ct_gt(&self, other: &Self) -> subtle::Choice { 1286 | ct_slice_lex_cmp(&self.serialize(), &other.serialize()) 1287 | .ct_eq(&std::cmp::Ordering::Greater) 1288 | } 1289 | } 1290 | 1291 | impl ConstantTimeGreater for MaybeScalar { 1292 | /// Compares this scalar against another in constant time. 1293 | /// Returns `subtle::Choice::from(1)` if `self` is strictly 1294 | /// lexicographically greater than `other`. 1295 | #[inline] 1296 | fn ct_gt(&self, other: &Self) -> subtle::Choice { 1297 | ct_slice_lex_cmp(&self.serialize(), &other.serialize()) 1298 | .ct_eq(&std::cmp::Ordering::Greater) 1299 | } 1300 | } 1301 | 1302 | impl subtle::ConstantTimeLess for Scalar {} 1303 | impl subtle::ConstantTimeLess for MaybeScalar {} 1304 | } 1305 | 1306 | /// This implementation allows iterators of [`Scalar`] or [`MaybeScalar`] 1307 | /// to be summed with [`Iterator::sum`]. 1308 | /// 1309 | /// Here the type `S` may be either [`Scalar`] or [`MaybeScalar`], or 1310 | /// any other type which can be summed with a [`MaybeScalar`]. 1311 | /// 1312 | /// ``` 1313 | /// use secp::{Scalar, MaybeScalar}; 1314 | /// 1315 | /// let scalars = [ 1316 | /// Scalar::one(), 1317 | /// Scalar::one(), 1318 | /// Scalar::one(), 1319 | /// ]; 1320 | /// let expected = "0000000000000000000000000000000000000000000000000000000000000003" 1321 | /// .parse::() 1322 | /// .unwrap(); 1323 | /// 1324 | /// assert_eq!(scalars.into_iter().sum::(), expected); 1325 | /// assert_eq!( 1326 | /// scalars 1327 | /// .into_iter() 1328 | /// .map(MaybeScalar::Valid) 1329 | /// .sum::(), 1330 | /// expected 1331 | /// ); 1332 | /// ``` 1333 | impl std::iter::Sum for MaybeScalar 1334 | where 1335 | MaybeScalar: std::ops::Add, 1336 | { 1337 | fn sum>(iter: I) -> Self { 1338 | let mut sum = MaybeScalar::Zero; 1339 | for scalar in iter { 1340 | sum = sum + scalar; 1341 | } 1342 | sum 1343 | } 1344 | } 1345 | 1346 | /// This implementation allows iterators of [`Scalar`] 1347 | /// to be multiplied together with [`Iterator::product`]. 1348 | /// 1349 | /// Since all scalars in the iterator are guaranteed to 1350 | /// be non-zero, the resulting product is also guaranteed 1351 | /// to be non-zero. 1352 | /// 1353 | /// ``` 1354 | /// use secp::Scalar; 1355 | /// 1356 | /// let scalars = [ 1357 | /// Scalar::two(), 1358 | /// Scalar::two(), 1359 | /// Scalar::two(), 1360 | /// ]; 1361 | /// let expected = "0000000000000000000000000000000000000000000000000000000000000008" 1362 | /// .parse::() 1363 | /// .unwrap(); 1364 | /// 1365 | /// assert_eq!(scalars.into_iter().product::(), expected); 1366 | /// ``` 1367 | /// 1368 | /// Returns `Scalar::one()` if the iterator is empty. 1369 | impl std::iter::Product for Scalar { 1370 | fn product>(iter: I) -> Self { 1371 | let mut product = Scalar::one(); 1372 | for scalar in iter { 1373 | product *= scalar; 1374 | } 1375 | product 1376 | } 1377 | } 1378 | 1379 | /// This implementation allows iterators of [`Scalar`] or [`MaybeScalar`] 1380 | /// to be multiplied together with [`Iterator::product`]. 1381 | /// 1382 | /// Here the type `S` may be either [`Scalar`] or [`MaybeScalar`], or 1383 | /// any other type which can be multiplied with a [`MaybeScalar`]. 1384 | /// 1385 | /// ``` 1386 | /// use secp::{Scalar, MaybeScalar}; 1387 | /// 1388 | /// let scalars = [ 1389 | /// Scalar::two(), 1390 | /// Scalar::two(), 1391 | /// Scalar::two(), 1392 | /// ]; 1393 | /// let expected = "0000000000000000000000000000000000000000000000000000000000000008" 1394 | /// .parse::() 1395 | /// .unwrap(); 1396 | /// 1397 | /// assert_eq!(scalars.into_iter().product::(), expected); 1398 | /// assert_eq!( 1399 | /// scalars 1400 | /// .into_iter() 1401 | /// .map(MaybeScalar::Valid) 1402 | /// .product::(), 1403 | /// expected 1404 | /// ); 1405 | /// ``` 1406 | /// 1407 | /// Returns `MaybeScalar::one()` if the iterator is empty. 1408 | impl std::iter::Product for MaybeScalar 1409 | where 1410 | MaybeScalar: std::ops::Mul, 1411 | { 1412 | fn product>(iter: I) -> Self { 1413 | let mut product = MaybeScalar::one(); 1414 | for scalar in iter { 1415 | product = product * scalar; 1416 | } 1417 | product 1418 | } 1419 | } 1420 | 1421 | #[cfg(test)] 1422 | mod tests { 1423 | use super::*; 1424 | 1425 | #[test] 1426 | fn test_curve_order() { 1427 | #[cfg(feature = "secp256k1")] 1428 | assert_eq!(CURVE_ORDER_BYTES, secp256k1::constants::CURVE_ORDER); 1429 | } 1430 | 1431 | #[test] 1432 | fn test_scalar_parsing() { 1433 | let valid_scalar_hex = [ 1434 | "0000000000000000000000000000000000000000000000000000000000000001", 1435 | "0000000000000000000000000000000000000000000000000000000000000002", 1436 | "0000000000000000000000000000000000000000000000000000000000000003", 1437 | "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 1438 | "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", 1439 | ]; 1440 | 1441 | for scalar_hex in valid_scalar_hex { 1442 | let parsed = scalar_hex 1443 | .parse::() 1444 | .unwrap_or_else(|_| panic!("failed to parse valid Scalar: {}", scalar_hex)); 1445 | let maybe_parsed = scalar_hex 1446 | .parse::() 1447 | .unwrap_or_else(|_| panic!("failed to parse valid MaybeScalar: {}", scalar_hex)); 1448 | 1449 | let bytes = <[u8; 32]>::try_from(hex::decode(scalar_hex).unwrap()) 1450 | .expect("failed to parse hex as 32-byte array"); 1451 | 1452 | assert_eq!( 1453 | Scalar::try_from(&bytes).expect("failed to parse 32-byte array as Scalar"), 1454 | parsed 1455 | ); 1456 | assert_eq!( 1457 | MaybeScalar::try_from(&bytes) 1458 | .expect("failed to parse 32-byte array as MaybeScalar"), 1459 | maybe_parsed 1460 | ); 1461 | } 1462 | 1463 | // Invalid scalars 1464 | let invalid_scalar_hex = [ 1465 | "nonsense", // not hex 1466 | "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", // curve order 1467 | "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaax", // non-hex char 1468 | "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab", // too long 1469 | "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabb", // too long 1470 | "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", // too short 1471 | "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", // too short 1472 | "", // too short 1473 | "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ", // spaces 1474 | ]; 1475 | 1476 | for scalar_hex in invalid_scalar_hex { 1477 | scalar_hex.parse::().expect_err(&format!( 1478 | "should not have parsed invalid hex as Scalar: {}", 1479 | scalar_hex 1480 | )); 1481 | scalar_hex.parse::().expect_err(&format!( 1482 | "should not have parsed invalid hex as MaybeScalar: {}", 1483 | scalar_hex 1484 | )); 1485 | 1486 | match hex::decode(scalar_hex) { 1487 | Err(_) => {} // Ignore 1488 | Ok(decoded) => match <[u8; 32]>::try_from(decoded) { 1489 | Err(_) => {} // Ignore 1490 | Ok(bytes) => { 1491 | Scalar::try_from(bytes).expect_err(&format!( 1492 | "should have failed to decode invalid byte array {}", 1493 | scalar_hex, 1494 | )); 1495 | } 1496 | }, 1497 | }; 1498 | } 1499 | 1500 | "0000000000000000000000000000000000000000000000000000000000000000" 1501 | .parse::() 1502 | .expect_err("cannot parse zero as Scalar"); 1503 | 1504 | assert_eq!( 1505 | "0000000000000000000000000000000000000000000000000000000000000000" 1506 | .parse::() 1507 | .expect("parses zero as MaybeScalar::Zero"), 1508 | MaybeScalar::Zero, 1509 | ); 1510 | } 1511 | 1512 | fn curve_order_plus(b: i8) -> [u8; 32] { 1513 | let mut bytes = CURVE_ORDER_BYTES; 1514 | 1515 | let carry: bool; 1516 | (bytes[31], carry) = bytes[31].overflowing_add_signed(b); 1517 | 1518 | if carry { 1519 | if b >= 0 { 1520 | bytes[30] += 1; 1521 | } else { 1522 | bytes[30] -= 1; 1523 | } 1524 | } 1525 | bytes 1526 | } 1527 | 1528 | #[test] 1529 | fn test_scalar_from_bytes() { 1530 | assert_eq!( 1531 | Scalar::try_from([ 1532 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1533 | 0, 0, 0, 29, 1534 | ]) 1535 | .unwrap(), 1536 | scalar(29), 1537 | ); 1538 | assert_eq!( 1539 | Scalar::try_from([ 1540 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1541 | 0, 0, 0, 1, 1542 | ]) 1543 | .unwrap(), 1544 | Scalar::one(), 1545 | ); 1546 | assert_eq!( 1547 | MaybeScalar::try_from([ 1548 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1549 | 0, 0, 0, 29, 1550 | ]) 1551 | .unwrap(), 1552 | MaybeScalar::from(29), 1553 | ); 1554 | assert_eq!( 1555 | MaybeScalar::try_from([ 1556 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1557 | 0, 0, 0, 1, 1558 | ]) 1559 | .unwrap(), 1560 | MaybeScalar::from(1), 1561 | ); 1562 | 1563 | assert_eq!( 1564 | Scalar::try_from(curve_order_plus(-1)).unwrap(), 1565 | Scalar::max() 1566 | ); 1567 | assert_eq!( 1568 | Scalar::try_from(curve_order_plus(-2)).unwrap(), 1569 | (Scalar::max() - Scalar::one()).unwrap() 1570 | ); 1571 | 1572 | assert_eq!( 1573 | MaybeScalar::try_from(curve_order_plus(-1)).unwrap(), 1574 | MaybeScalar::max() 1575 | ); 1576 | assert_eq!( 1577 | MaybeScalar::try_from(curve_order_plus(-2)).unwrap(), 1578 | MaybeScalar::max() - MaybeScalar::one() 1579 | ); 1580 | 1581 | assert_eq!(MaybeScalar::try_from(&[0; 32]).unwrap(), MaybeScalar::Zero); 1582 | assert_eq!(Scalar::try_from(&[0; 32]).unwrap_err(), InvalidScalarBytes); 1583 | 1584 | assert_eq!( 1585 | Scalar::try_from(curve_order_plus(1)).unwrap_err(), 1586 | InvalidScalarBytes 1587 | ); 1588 | assert_eq!( 1589 | Scalar::try_from(curve_order_plus(2)).unwrap_err(), 1590 | InvalidScalarBytes 1591 | ); 1592 | assert_eq!( 1593 | Scalar::try_from(CURVE_ORDER_BYTES).unwrap_err(), 1594 | InvalidScalarBytes 1595 | ); 1596 | 1597 | assert_eq!( 1598 | MaybeScalar::try_from(curve_order_plus(1)).unwrap_err(), 1599 | InvalidScalarBytes 1600 | ); 1601 | assert_eq!( 1602 | MaybeScalar::try_from(curve_order_plus(2)).unwrap_err(), 1603 | InvalidScalarBytes 1604 | ); 1605 | assert_eq!( 1606 | MaybeScalar::try_from(CURVE_ORDER_BYTES).unwrap_err(), 1607 | InvalidScalarBytes 1608 | ); 1609 | } 1610 | 1611 | fn scalar(n: u128) -> Scalar { 1612 | Scalar::try_from(n).unwrap() 1613 | } 1614 | 1615 | #[test] 1616 | fn test_scalar_addition() { 1617 | // test scalar addition 1618 | 1619 | // Scalar + Scalar 1620 | assert_eq!(scalar(28) + scalar(2), MaybeScalar::from(30)); 1621 | 1622 | // MaybeScalar + Scalar 1623 | assert_eq!(MaybeScalar::from(1) + scalar(2), MaybeScalar::from(3)); 1624 | 1625 | // Scalar + MaybeScalar 1626 | assert_eq!(scalar(88) + MaybeScalar::from(12), MaybeScalar::from(100)); 1627 | 1628 | // Scalar + MaybeScalar 1629 | assert_eq!( 1630 | MaybeScalar::from(88) + MaybeScalar::from(12), 1631 | MaybeScalar::from(100) 1632 | ); 1633 | 1634 | // Zero + Scalar 1635 | assert_eq!(MaybeScalar::Zero + scalar(20), MaybeScalar::from(20)); 1636 | 1637 | // Zero + MaybeScalar 1638 | assert_eq!( 1639 | MaybeScalar::Zero + MaybeScalar::from(20), 1640 | MaybeScalar::from(20) 1641 | ); 1642 | 1643 | // Scalar + Zero 1644 | assert_eq!(scalar(20) + MaybeScalar::Zero, MaybeScalar::from(20)); 1645 | 1646 | // MaybeScalar + Zero 1647 | assert_eq!( 1648 | MaybeScalar::from(20) + MaybeScalar::Zero, 1649 | MaybeScalar::from(20) 1650 | ); 1651 | 1652 | // MaybeScalar + MaybeScalar 1653 | assert_eq!( 1654 | MaybeScalar::from(4) + MaybeScalar::from(20), 1655 | MaybeScalar::from(24) 1656 | ); 1657 | 1658 | // Test overflow 1659 | assert_eq!( 1660 | Scalar::try_from(curve_order_plus(-1)).unwrap() + MaybeScalar::Zero, 1661 | MaybeScalar::max() 1662 | ); 1663 | assert_eq!( 1664 | Scalar::try_from(curve_order_plus(-1)).unwrap() + scalar(1), 1665 | MaybeScalar::Zero 1666 | ); 1667 | assert_eq!( 1668 | Scalar::try_from(curve_order_plus(-1)).unwrap() + scalar(2), 1669 | MaybeScalar::one() 1670 | ); 1671 | assert_eq!( 1672 | Scalar::try_from(curve_order_plus(-1)).unwrap() + scalar(3), 1673 | MaybeScalar::two() 1674 | ); 1675 | } 1676 | 1677 | #[test] 1678 | fn test_scalar_negation() { 1679 | assert_eq!(-scalar(1), Scalar::try_from(curve_order_plus(-1)).unwrap(),); 1680 | assert_eq!(-scalar(2), Scalar::try_from(curve_order_plus(-2)).unwrap(),); 1681 | assert_eq!(-Scalar::try_from(curve_order_plus(-1)).unwrap(), scalar(1),); 1682 | assert_eq!(-Scalar::try_from(curve_order_plus(-2)).unwrap(), scalar(2),); 1683 | 1684 | assert_eq!( 1685 | -MaybeScalar::try_from(curve_order_plus(-1)).unwrap(), 1686 | MaybeScalar::from(1), 1687 | ); 1688 | assert_eq!( 1689 | -MaybeScalar::try_from(curve_order_plus(-2)).unwrap(), 1690 | MaybeScalar::from(2), 1691 | ); 1692 | 1693 | assert_eq!(-MaybeScalar::Zero, MaybeScalar::Zero); 1694 | } 1695 | 1696 | #[test] 1697 | fn test_scalar_subtraction() { 1698 | // Scalar - Scalar 1699 | assert_eq!(scalar(5) - scalar(3), MaybeScalar::from(2)); 1700 | assert_eq!( 1701 | scalar(1) - scalar(5), 1702 | MaybeScalar::try_from(curve_order_plus(-4)).unwrap(), 1703 | ); 1704 | assert_eq!(scalar(4) - scalar(4), MaybeScalar::Zero); 1705 | 1706 | // Scalar - MaybeScalar 1707 | assert_eq!(scalar(10) - MaybeScalar::from(3), MaybeScalar::from(7),); 1708 | assert_eq!( 1709 | scalar(3) - MaybeScalar::from(8), 1710 | MaybeScalar::try_from(curve_order_plus(-5)).unwrap(), 1711 | ); 1712 | assert_eq!(scalar(9) - MaybeScalar::from(9), MaybeScalar::Zero); 1713 | 1714 | // MaybeScalar - Scalar 1715 | assert_eq!(MaybeScalar::from(13) - scalar(2), MaybeScalar::from(11),); 1716 | assert_eq!( 1717 | MaybeScalar::from(4) - scalar(9), 1718 | MaybeScalar::try_from(curve_order_plus(-5)).unwrap(), 1719 | ); 1720 | assert_eq!( 1721 | MaybeScalar::Zero - scalar(5), 1722 | MaybeScalar::try_from(curve_order_plus(-5)).unwrap(), 1723 | ); 1724 | 1725 | // MaybeScalar - MaybeScalar 1726 | assert_eq!( 1727 | MaybeScalar::from(13) - MaybeScalar::from(2), 1728 | MaybeScalar::from(11), 1729 | ); 1730 | assert_eq!( 1731 | MaybeScalar::from(4) - MaybeScalar::from(9), 1732 | MaybeScalar::try_from(curve_order_plus(-5)).unwrap(), 1733 | ); 1734 | assert_eq!( 1735 | MaybeScalar::Zero - MaybeScalar::from(5), 1736 | MaybeScalar::try_from(curve_order_plus(-5)).unwrap(), 1737 | ); 1738 | } 1739 | 1740 | #[test] 1741 | fn test_scalar_multiplication() { 1742 | // Scalar * Scalar 1743 | assert_eq!(scalar(28) * scalar(3), scalar(84)); 1744 | 1745 | // Scalar * ONE 1746 | assert_eq!(scalar(45) * Scalar::one(), scalar(45)); 1747 | 1748 | // Scalar * MaybeScalar 1749 | assert_eq!(scalar(45) * MaybeScalar::Zero, MaybeScalar::Zero); 1750 | 1751 | // MaybeScalar * Scalar 1752 | assert_eq!(MaybeScalar::from(3) * scalar(25), MaybeScalar::from(75)); 1753 | 1754 | // Zero * Scalar 1755 | assert_eq!(MaybeScalar::Zero * scalar(45), MaybeScalar::Zero); 1756 | 1757 | // Zero * MaybeScalar 1758 | assert_eq!(MaybeScalar::Zero * MaybeScalar::from(45), MaybeScalar::Zero); 1759 | 1760 | // Scalar * Zero 1761 | assert_eq!(scalar(30) * MaybeScalar::Zero, MaybeScalar::Zero); 1762 | 1763 | // MaybeScalar * Zero 1764 | assert_eq!(MaybeScalar::from(30) * MaybeScalar::Zero, MaybeScalar::Zero); 1765 | 1766 | // MaybeScalar * MaybeScalar 1767 | assert_eq!( 1768 | MaybeScalar::from(3) * MaybeScalar::from(3), 1769 | MaybeScalar::from(9) 1770 | ); 1771 | } 1772 | 1773 | #[test] 1774 | #[cfg(any(feature = "k256", feature = "secp256k1-invert"))] 1775 | fn test_scalar_division() { 1776 | // Scalar / Scalar 1777 | assert_eq!(scalar(9) / scalar(3), scalar(3)); 1778 | assert_eq!(Scalar::one() / Scalar::one(), Scalar::one()); 1779 | assert_eq!(scalar(2) / Scalar::one(), scalar(2)); 1780 | assert_eq!(Scalar::one() / Scalar::max(), Scalar::max()); 1781 | 1782 | // t * t^-1 = 1 1783 | assert_eq!(scalar(3514) * (Scalar::one() / scalar(3514)), Scalar::one()); 1784 | 1785 | // MaybeScalar / Scalar 1786 | assert_eq!(MaybeScalar::from(10) / scalar(2), MaybeScalar::from(5)); 1787 | assert_eq!(MaybeScalar::Zero / scalar(3), MaybeScalar::Zero); 1788 | } 1789 | 1790 | #[test] 1791 | fn test_scalar_assign_ops() { 1792 | // (20 + 2 + 1) * 3 - 5 = 64 1793 | let mut n = MaybeScalar::from(20); 1794 | n += Scalar::two(); 1795 | n += Scalar::one(); 1796 | n *= scalar(3); 1797 | n -= scalar(5); 1798 | assert_eq!(n, MaybeScalar::from(64)); 1799 | 1800 | // (20 + 2 + 1) * 3 - 5 = 64 1801 | let mut n = MaybeScalar::from(20); 1802 | n += MaybeScalar::two(); 1803 | n += MaybeScalar::one(); 1804 | n *= MaybeScalar::Valid(scalar(3)); 1805 | n -= MaybeScalar::Valid(scalar(5)); 1806 | assert_eq!(n, MaybeScalar::from(64)); 1807 | 1808 | // 20 * 5 = 100 1809 | let mut n = scalar(20); 1810 | n *= scalar(5); 1811 | assert_eq!(n, scalar(100)); 1812 | 1813 | #[cfg(any(feature = "k256", feature = "secp256k1-invert"))] 1814 | { 1815 | // 100 / 5 = 20 1816 | n /= scalar(5); 1817 | assert_eq!(n, scalar(20)); 1818 | } 1819 | } 1820 | 1821 | #[test] 1822 | fn test_scalar_reduction() { 1823 | let reduction_tests = vec![ 1824 | ( 1825 | CURVE_ORDER_BYTES, 1826 | [ 1827 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1828 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1829 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1830 | ], 1831 | ), 1832 | ( 1833 | curve_order_plus(0), 1834 | [ 1835 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1836 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1837 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1838 | ], 1839 | ), 1840 | ( 1841 | curve_order_plus(1), 1842 | [ 1843 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1844 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1845 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 1846 | ], 1847 | ), 1848 | ( 1849 | curve_order_plus(-1), 1850 | [ 1851 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1852 | 0xff, 0xff, 0xfe, 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, 0xbf, 0xd2, 1853 | 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40, 1854 | ], 1855 | ), 1856 | ( 1857 | curve_order_plus(5), 1858 | [ 1859 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1860 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1861 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 1862 | ], 1863 | ), 1864 | ( 1865 | curve_order_plus(-5), 1866 | [ 1867 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1868 | 0xff, 0xff, 0xfe, 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, 0xbf, 0xd2, 1869 | 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x3c, 1870 | ], 1871 | ), 1872 | ( 1873 | [ 1874 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 1875 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 1876 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 1877 | ], 1878 | xor_arrays(&CURVE_ORDER_BYTES, &MAX_U256), 1879 | ), 1880 | ( 1881 | [ 1882 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 1883 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 1884 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 1885 | ], 1886 | [ 1887 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1888 | 0x00, 0x00, 0x01, 0x45, 0x51, 0x23, 0x19, 0x50, 0xb7, 0x5f, 0xc4, 0x40, 0x2d, 1889 | 0xa1, 0x73, 0x2f, 0xc9, 0xbe, 0xbd, 1890 | ], 1891 | ), 1892 | ( 1893 | [ 1894 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1895 | 0, 0, 0, 0, 0, 54, 1896 | ], 1897 | [ 1898 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1899 | 0, 0, 0, 0, 0, 54, 1900 | ], 1901 | ), 1902 | ]; 1903 | 1904 | for (input, expected) in reduction_tests { 1905 | assert_eq!( 1906 | &MaybeScalar::reduce_from(&input).serialize(), 1907 | &expected, 1908 | "{} mod n != {}", 1909 | hex::encode(input), 1910 | hex::encode(expected), 1911 | ); 1912 | 1913 | #[cfg(feature = "k256")] 1914 | { 1915 | use crypto_bigint::U256; 1916 | use k256::elliptic_curve::ops::{Reduce, ReduceNonZero}; 1917 | 1918 | let input_field_bytes = k256::FieldBytes::from(input); 1919 | let expected = 1920 | <[u8; 32]>::from(k256::FieldBytes::from( 1921 | >::reduce_bytes(&input_field_bytes), 1922 | )); 1923 | let nonzero_expected = <[u8; 32]>::from(k256::FieldBytes::from( 1924 | >::reduce_nonzero_bytes( 1925 | &input_field_bytes, 1926 | ), 1927 | )); 1928 | 1929 | assert_eq!(MaybeScalar::reduce_from(&input).serialize(), expected); 1930 | 1931 | assert_eq!(Scalar::reduce_from(&input).serialize(), nonzero_expected); 1932 | } 1933 | } 1934 | } 1935 | 1936 | #[test] 1937 | fn test_scalar_ordering() { 1938 | let mut scalars: [Scalar; 20] = [ 1939 | "44477400e59c41025e4e18c4de244b90b14554dcdcbfa396ead4659aa6343249" 1940 | .parse() 1941 | .unwrap(), 1942 | "bee6529c72b7655e47cc1ffaf6f9ceeecce7fee2e99d093aa658ce6ec5d03a6a" 1943 | .parse() 1944 | .unwrap(), 1945 | "33c17c36c25f156828d4f15f8a4131570625342e76b3e5f60a69baac6f4ca7d3" 1946 | .parse() 1947 | .unwrap(), 1948 | "6ae373f53d30121ccce571aa2ff8413d5643938005e1b36f4cb8dd94e93db3cd" 1949 | .parse() 1950 | .unwrap(), 1951 | "d2647f5821eeaad342e4008edd7fa5086ebcb73bde386dac06fec437050cf771" 1952 | .parse() 1953 | .unwrap(), 1954 | "6f2781b0e3f11d4911486d1e8ce405c84eeb05f4cf62b14d6d258cc265ffec0a" 1955 | .parse() 1956 | .unwrap(), 1957 | "1aeeb3548154f5ee09116c8a61af0b8543157e7a75949c71d1dab788852e0b22" 1958 | .parse() 1959 | .unwrap(), 1960 | "0a557df2fee78ed14cc78870511cf35e6a73459bb1a2273edeb14e4c1290932d" 1961 | .parse() 1962 | .unwrap(), 1963 | "ea55f89ba4debf7a6815fb977919f417782928b7ec4f69d645a1ef57bafbe732" 1964 | .parse() 1965 | .unwrap(), 1966 | "e23265f6a6e97e9c4d2af4ecea844eb83eeb81cb4c6f86d34c3a5074396009bd" 1967 | .parse() 1968 | .unwrap(), 1969 | "88a23adeff10f0a90cc8a598cfe4c6339c9afc03042ea9d7dfac6f031ef4e497" 1970 | .parse() 1971 | .unwrap(), 1972 | "01238f0b0f9b11e5edaed8c1fcc47d4c879bc27aa735572fdd92db8f3119676b" 1973 | .parse() 1974 | .unwrap(), 1975 | "f505ef52fbf0ecb0c4103728241f711ad27dad8cdb1ce29de769cfd3da5fecd9" 1976 | .parse() 1977 | .unwrap(), 1978 | "8dbea02c7e0ae34fe9040ac3bb97678c4e77e5f8820520a5beaa8fe0d36922a7" 1979 | .parse() 1980 | .unwrap(), 1981 | "ae94a02018ea6b54ec0c773c9f188cd6eb411bb3379331002239954f56443386" 1982 | .parse() 1983 | .unwrap(), 1984 | "8e96840200c19bcc3d4342ca7bdbab9f96a0fb5dcc88eb0278d073ed7f4891d5" 1985 | .parse() 1986 | .unwrap(), 1987 | "dad344a73abfe216af680186ca908e89b9ad54d7115a449c5c393e45632f2d76" 1988 | .parse() 1989 | .unwrap(), 1990 | "851faf8fbe7d6054d051ac88d94048428d35c9f2918f09e4db452e926a6420be" 1991 | .parse() 1992 | .unwrap(), 1993 | "c20bfccc406545448ec501cd909b655062fe8ac087c21817a8dd2d4574cab657" 1994 | .parse() 1995 | .unwrap(), 1996 | "416c0e50cab9251e5a0f63f9be7b93ab4f8162a4d0598c7f9f79b9ab4b0ece02" 1997 | .parse() 1998 | .unwrap(), 1999 | ]; 2000 | 2001 | let mut expected_sorting = scalars; 2002 | expected_sorting.sort_by_key(|a| a.serialize()); 2003 | 2004 | scalars.sort_by(|a, b| { 2005 | if bool::from(a.ct_gt(b)) { 2006 | std::cmp::Ordering::Greater 2007 | } else if bool::from(a.ct_eq(b)) { 2008 | std::cmp::Ordering::Equal 2009 | } else { 2010 | std::cmp::Ordering::Less 2011 | } 2012 | }); 2013 | 2014 | assert_eq!(scalars, expected_sorting); 2015 | } 2016 | } 2017 | --------------------------------------------------------------------------------