scclib
Stable Cloud Computing C++ Library
ecc.cc
Go to the documentation of this file.
1 /*
2 BSD 3-Clause License
3 
4 Copyright (c) 2022, Stable Cloud Computing, Inc.
5 
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
8 
9 1. Redistributions of source code must retain the above copyright notice, this
10  list of conditions and the following disclaimer.
11 
12 2. Redistributions in binary form must reproduce the above copyright notice,
13  this list of conditions and the following disclaimer in the documentation
14  and/or other materials provided with the distribution.
15 
16 3. Neither the name of the copyright holder nor the names of its
17  contributors may be used to endorse or promote products derived from
18  this software without specific prior written permission.
19 
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31 #include <gtest/gtest.h>
32 #include <crypto/ecc.h>
33 #include <iostream>
34 
47 using std::cout;
48 using std::endl;
49 using std::vector;
50 using std::string;
54 
55 struct EccTest : public testing::Test
56 {
57  EccTest() {}
58  virtual ~EccTest() {}
59 
60  EccGfp ecc;
61 
62  void print(const Bignum& v)
63  {
64  cout << "width=" << v.width() << " val=" << v << endl;
65  }
66  void print(const EccGfpPoint& point)
67  {
68  Bignum x, y;
69  point.get(x, y);
70  cout << "width=( " << x.width() << " , " << y.width() << " ) val=( " << x << " , " << y << " )" << endl;
71  }
72  /*void equal_test(const EccGfpPoint& point1, const EccGfpPoint& point2)
73  {
74  Bignum x1, y1;
75  point1.get(x1, y1, ecc);
76  Bignum x2, y2;
77  point2.get(x2, y2, ecc);
78  ASSERT_EQ(x1, x2);
79  ASSERT_EQ(y1, y2);
80  }*/
81 };
82 
83 TEST_F(EccTest, reset)
84 {
85  ASSERT_TRUE(ecc.valid());
86  ASSERT_EQ(ecc.bit_width(), 256);
87  ecc.reset(EccGfp::Type::std_p521r1);
88  ASSERT_TRUE(ecc.valid());
89  ASSERT_EQ(ecc.bit_width(), 521);
90 }
91 
92 TEST_F(EccTest, point_reset)
93 {
94  EccGfpPoint p;
95  ASSERT_FALSE(p.valid());
96  Bignum x, y;
97  ASSERT_THROW(p.get(x, y), std::runtime_error);
98 
99  p.reset(ecc);
100  print(p);
101  ASSERT_FALSE(p.valid());
102  ASSERT_TRUE(p.infinite());
103 }
104 
105 TEST_F(EccTest, private_key)
106 {
107  cout << "curve width=" << ecc.bit_width() << endl;
108 
109  Bignum key;
110  ecc.private_key(key);
111  cout << "private key ";
112  print(key);
113 }
114 
115 TEST_F(EccTest, key_pair)
116 {
117  cout << "curve width=" << ecc.bit_width() << endl;
118 
119  Bignum key;
120  EccGfpPoint pub;
121  ecc.generate_key_pair(key, pub);
122  cout << "private key ";
123  print(key);
124  cout << "public key ";
125  print(pub);
126  ASSERT_TRUE(pub.valid());
127  ASSERT_FALSE(pub.infinite());
128 
129  EccGfpPoint inf(ecc), inf2(ecc);
130  ASSERT_TRUE(inf.infinite());
131  ASSERT_EQ(inf, inf2);
132  ASSERT_NE(inf, pub);
133 
134  ASSERT_TRUE(EccGfp::validate_key_pair(key, pub));
135  ASSERT_FALSE(EccGfp::validate_key_pair(key, inf));
136 }
137 
138 TEST_F(EccTest, infinity)
139 {
140  Bignum key;
141  EccGfpPoint pub;
142  ecc.generate_key_pair(key, pub);
143  cout << "public key ";
144  print(pub);
145  pub.set();
146  cout << "set to infinity ";
147  print(pub);
148 }
149 
150 TEST_F(EccTest, ecdsa_sign)
151 {
152  Bignum key;
153  EccGfpPoint pub;
154  ecc.generate_key_pair(key, pub); // this is the regular key pair
155  cout << "sign test" << endl;
156  cout << "regular private key ";
157  print(key);
158  cout << "public key ";
159  print(pub);
160 
161  Bignum eph;
162  ecc.private_key(eph); // this is the ephemeral private key
163  cout << "ephemeral private key ";
164  print(eph);
165 
166  EccGfpPoint eph_pub; // a public key derived from the ephemeral key should not validate the signature
167  ecc.public_key(eph, eph_pub);
168  cout << "ephemeral public key ";
169  print(eph_pub);
170 
171  string sign("this is a test!");
172  string sign2("another test!");
173 
174  Bignum a, b;
175  EccGfp::sign_ecdsa(sign.data(), sign.size(), ecc, key, eph, a, b);
176  cout << "sign a ";
177  print(a);
178  cout << "sign b ";
179  print(b);
180 
181  ASSERT_TRUE(EccGfp::verify_ecdsa(sign.data(), sign.size(), pub, a, b)); // test with the correct data
182  ASSERT_FALSE(EccGfp::verify_ecdsa(sign2.data(), sign2.size(), pub, a, b)); // test with the wrong data
183 
184  EccGfpPoint inf(ecc); // infinity
185  ASSERT_FALSE(EccGfp::verify_ecdsa(sign.data(), sign.size(), inf, a, b)); // test with an infinite public key
186 
187  Bignum zero;
188  ASSERT_FALSE(EccGfp::verify_ecdsa(sign.data(), sign.size(), pub, a, zero)); // test with wrong signature
189 
190  ASSERT_FALSE(EccGfp::verify_ecdsa(sign.data(), sign.size(), eph_pub, a, b)); // test with the wrong public key
191 }
192 
193 TEST_F(EccTest, ecdsa_get_and_set_binary)
194 {
195  auto fn = [&](EccGfp::Type t)
196  {
197  ecc.reset(t);
198  Bignum priv;
199  EccGfpPoint pub;
200  ecc.generate_key_pair(priv, pub);
201  print(priv);
202  print(pub);
203 
204  vector<char> v;
205  pub.get(v);
206 
207  EccGfpPoint pub2;
208  pub2.set(v, ecc);
209  print(pub2);
210 
211  ASSERT_EQ(pub, pub2);
212  };
213 
214  fn(EccGfp::Type::std_p192r1);
215  fn(EccGfp::Type::std_p224r1);
216  fn(EccGfp::Type::std_p256r1);
217  fn(EccGfp::Type::std_p384r1);
218  fn(EccGfp::Type::std_p521r1);
219  fn(EccGfp::Type::std_p256sm2);
220  //fn(EccGfp::Type::curve_25519);
221  //fn(EccGfp::Type::curve_448);
222 }
223 
224 TEST_F(EccTest, dh_shared_secret)
225 {
226  Bignum key1, key2;
227  EccGfpPoint pub1, pub2;
228 
229  ecc.generate_key_pair(key1, pub1);
230  cout << "***** private key1" << endl;
231  print(key1);
232  cout << "***** public key1" << endl;
233  print(pub1);
234 
235  ecc.generate_key_pair(key2, pub2);
236  cout << "***** private key2" << endl;
237  print(key2);
238  cout << "***** public key2" << endl;
239  print(pub2);
240 
241  Bignum share1, share2;
242 
243  EccGfp::dh_shared_secret(key1, pub2, share1);
244  cout << "***** shared key1" << endl;
245  print(share1);
246 
247  EccGfp::dh_shared_secret(key2, pub1, share2);
248  cout << "***** shared key2" << endl;
249  print(share2);
250 
251  ASSERT_EQ(share1, share2);
252 }
Big number.
Definition: bignum.h:59
int width() const
Number of significant bits.
void reset()
Reset the point to invalid.
Definition: ecc.h:220
void get(scc::crypto::Bignum &, scc::crypto::Bignum &) const
Get the coordinates.
static bool valid(const EccGfpPoint &, const EccGfp &)
Verify the point on a curve.
static bool infinite(const EccGfpPoint &, const EccGfp &)
Test the point for infinity on a curve.
void set(const scc::crypto::Bignum &, const scc::crypto::Bignum &)
Set point.
Elliptic curve cryptography over Galois prime field GF(p) curve.
Definition: ecc.h:77
void generate_key_pair(Bignum &priv_key, EccGfpPoint &pub_key)
Generate a private and public key pair for this curve.
Definition: ecc.h:117
int bit_width() const
Elliptic curve ordinal bit width.
void reset(Type type)
Reset the curve to a new standard type.
void private_key(Bignum &)
Generate a private key.
static bool valid(const EccGfp &)
Verify the curve.
void public_key(const Bignum &, EccGfpPoint &)
Generate a public key corresponding to a private key.
Elliptic curve cryptography.