1 // Copyright 2015-2016 Brian Smith.
2 //
3 // Permission to use, copy, modify, and/or distribute this software for any
4 // purpose with or without fee is hereby granted, provided that the above
5 // copyright notice and this permission notice appear in all copies.
6 //
7 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
8 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
10 // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 
15 //! ECDSA Signatures using the P-256 and P-384 curves.
16 
17 use crate::{
18     digest,
19     ec::suite_b::ops::*,
20     limb::{self, LIMB_BYTES},
21 };
22 
23 /// Calculate the digest of `msg` using the digest algorithm `digest_alg`. Then
24 /// convert the digest to a scalar in the range [0, n) as described in
25 /// NIST's FIPS 186-4 Section 4.2. Note that this is one of the few cases where
26 /// a `Scalar` is allowed to have the value zero.
27 ///
28 /// NIST's FIPS 186-4 4.2 says "When the length of the output of the hash
29 /// function is greater than N (i.e., the bit length of q), then the leftmost N
30 /// bits of the hash function output block shall be used in any calculation
31 /// using the hash function output during the generation or verification of a
32 /// digital signature."
33 ///
34 /// "Leftmost N bits" means "N most significant bits" because we interpret the
35 /// digest as a bit-endian encoded integer.
36 ///
37 /// The NSA guide instead vaguely suggests that we should convert the digest
38 /// value to an integer and then reduce it mod `n`. However, real-world
39 /// implementations (e.g. `digest_to_bn` in OpenSSL and `hashToInt` in Go) do
40 /// what FIPS 186-4 says to do, not what the NSA guide suggests.
41 ///
42 /// Why shifting the value right by at most one bit is sufficient: P-256's `n`
43 /// has its 256th bit set; i.e. 2**255 < n < 2**256. Once we've truncated the
44 /// digest to 256 bits and converted it to an integer, it will have a value
45 /// less than 2**256. If the value is larger than `n` then shifting it one bit
46 /// right will give a value less than 2**255, which is less than `n`. The
47 /// analogous argument applies for P-384. However, it does *not* apply in
48 /// general; for example, it doesn't apply to P-521.
digest_scalar(ops: &ScalarOps, msg: digest::Digest) -> Scalar49 pub fn digest_scalar(ops: &ScalarOps, msg: digest::Digest) -> Scalar {
50     digest_scalar_(ops, msg.as_ref())
51 }
52 
53 #[cfg(test)]
digest_bytes_scalar(ops: &ScalarOps, digest: &[u8]) -> Scalar54 pub(crate) fn digest_bytes_scalar(ops: &ScalarOps, digest: &[u8]) -> Scalar {
55     digest_scalar_(ops, digest)
56 }
57 
58 // This is a separate function solely so that we can test specific digest
59 // values like all-zero values and values larger than `n`.
digest_scalar_(ops: &ScalarOps, digest: &[u8]) -> Scalar60 fn digest_scalar_(ops: &ScalarOps, digest: &[u8]) -> Scalar {
61     let cops = ops.common;
62     let num_limbs = cops.num_limbs;
63     let digest = if digest.len() > num_limbs * LIMB_BYTES {
64         &digest[..(num_limbs * LIMB_BYTES)]
65     } else {
66         digest
67     };
68 
69     scalar_parse_big_endian_partially_reduced_variable_consttime(
70         cops,
71         limb::AllowZero::Yes,
72         untrusted::Input::from(digest),
73     )
74     .unwrap()
75 }
76 
77 #[cfg(test)]
78 mod tests {
79     use super::digest_bytes_scalar;
80     use crate::{
81         digest,
82         ec::suite_b::ops::*,
83         limb::{self, LIMB_BYTES},
84         test,
85     };
86 
87     #[test]
test()88     fn test() {
89         test::run(
90             test_file!("ecdsa_digest_scalar_tests.txt"),
91             |section, test_case| {
92                 assert_eq!(section, "");
93 
94                 let curve_name = test_case.consume_string("Curve");
95                 let digest_name = test_case.consume_string("Digest");
96                 let input = test_case.consume_bytes("Input");
97                 let output = test_case.consume_bytes("Output");
98 
99                 let (ops, digest_alg) = match (curve_name.as_str(), digest_name.as_str()) {
100                     ("P-256", "SHA256") => (&p256::PUBLIC_SCALAR_OPS, &digest::SHA256),
101                     ("P-256", "SHA384") => (&p256::PUBLIC_SCALAR_OPS, &digest::SHA384),
102                     ("P-384", "SHA256") => (&p384::PUBLIC_SCALAR_OPS, &digest::SHA256),
103                     ("P-384", "SHA384") => (&p384::PUBLIC_SCALAR_OPS, &digest::SHA384),
104                     _ => {
105                         panic!("Unsupported curve+digest: {}+{}", curve_name, digest_name);
106                     }
107                 };
108 
109                 let num_limbs = ops.public_key_ops.common.num_limbs;
110                 assert_eq!(input.len(), digest_alg.output_len());
111                 assert_eq!(
112                     output.len(),
113                     ops.public_key_ops.common.num_limbs * LIMB_BYTES
114                 );
115 
116                 let expected = scalar_parse_big_endian_variable(
117                     ops.public_key_ops.common,
118                     limb::AllowZero::Yes,
119                     untrusted::Input::from(&output),
120                 )
121                 .unwrap();
122 
123                 let actual = digest_bytes_scalar(ops.scalar_ops, &input);
124 
125                 assert_eq!(actual.limbs[..num_limbs], expected.limbs[..num_limbs]);
126 
127                 Ok(())
128             },
129         );
130     }
131 }
132