1 /******************************************************************************
3 * Copyright (C) 2006-2015 Broadcom Corporation
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 ******************************************************************************/
19 /*******************************************************************************
21 * This file contains simple pairing algorithms using Elliptic Curve
22 * Cryptography for private public key
24 ******************************************************************************/
25 #include "p_256_ecc_pp.h"
29 #include "p_256_multprecision.h"
31 elliptic_curve_t curve;
32 elliptic_curve_t curve_p256;
34 static void p_256_init_point(Point* q) { memset(q, 0, sizeof(Point)); }
36 static void p_256_copy_point(Point* q, Point* p) {
37 memcpy(q, p, sizeof(Point));
41 static void ECC_Double(Point* q, Point* p, uint32_t keyLength) {
42 uint32_t t1[KEY_LENGTH_DWORDS_P256];
43 uint32_t t2[KEY_LENGTH_DWORDS_P256];
44 uint32_t t3[KEY_LENGTH_DWORDS_P256];
52 if (multiprecision_iszero(p->z, keyLength)) {
53 multiprecision_init(q->z, keyLength);
54 return; // return infinity
64 multiprecision_mersenns_squa_mod(t1, z1, keyLength); // t1=z1^2
65 multiprecision_sub_mod(t2, x1, t1, keyLength); // t2=x1-t1
66 multiprecision_add_mod(t1, x1, t1, keyLength); // t1=x1+t1
67 multiprecision_mersenns_mult_mod(t2, t1, t2, keyLength); // t2=t2*t1
68 multiprecision_lshift_mod(t3, t2, keyLength);
69 multiprecision_add_mod(t2, t3, t2, keyLength); // t2=3t2
71 multiprecision_mersenns_mult_mod(z3, y1, z1, keyLength); // z3=y1*z1
72 multiprecision_lshift_mod(z3, z3, keyLength);
74 multiprecision_mersenns_squa_mod(y3, y1, keyLength); // y3=y1^2
75 multiprecision_lshift_mod(y3, y3, keyLength);
76 multiprecision_mersenns_mult_mod(t3, y3, x1, keyLength); // t3=y3*x1=x1*y1^2
77 multiprecision_lshift_mod(t3, t3, keyLength);
78 multiprecision_mersenns_squa_mod(y3, y3, keyLength); // y3=y3^2=y1^4
79 multiprecision_lshift_mod(y3, y3, keyLength);
81 multiprecision_mersenns_squa_mod(x3, t2, keyLength); // x3=t2^2
82 multiprecision_lshift_mod(t1, t3, keyLength); // t1=2t3
83 multiprecision_sub_mod(x3, x3, t1, keyLength); // x3=x3-t1
84 multiprecision_sub_mod(t1, t3, x3, keyLength); // t1=t3-x3
85 multiprecision_mersenns_mult_mod(t1, t1, t2, keyLength); // t1=t1*t2
86 multiprecision_sub_mod(y3, t1, y3, keyLength); // y3=t1-y3
89 // q=q+p, zp must be 1
90 static void ECC_Add(Point* r, Point* p, Point* q, uint32_t keyLength) {
91 uint32_t t1[KEY_LENGTH_DWORDS_P256];
92 uint32_t t2[KEY_LENGTH_DWORDS_P256];
113 // if Q=infinity, return p
114 if (multiprecision_iszero(z2, keyLength)) {
115 p_256_copy_point(r, p);
119 // if P=infinity, return q
120 if (multiprecision_iszero(z1, keyLength)) {
121 p_256_copy_point(r, q);
125 multiprecision_mersenns_squa_mod(t1, z1, keyLength); // t1=z1^2
126 multiprecision_mersenns_mult_mod(t2, z1, t1, keyLength); // t2=t1*z1
127 multiprecision_mersenns_mult_mod(t1, x2, t1, keyLength); // t1=t1*x2
128 multiprecision_mersenns_mult_mod(t2, y2, t2, keyLength); // t2=t2*y2
130 multiprecision_sub_mod(t1, t1, x1, keyLength); // t1=t1-x1
131 multiprecision_sub_mod(t2, t2, y1, keyLength); // t2=t2-y1
133 if (multiprecision_iszero(t1, keyLength)) {
134 if (multiprecision_iszero(t2, keyLength)) {
135 ECC_Double(r, q, keyLength);
138 multiprecision_init(z3, keyLength);
139 return; // return infinity
143 multiprecision_mersenns_mult_mod(z3, z1, t1, keyLength); // z3=z1*t1
144 multiprecision_mersenns_squa_mod(y3, t1, keyLength); // t3=t1^2
145 multiprecision_mersenns_mult_mod(z1, y3, t1, keyLength); // t4=t3*t1
146 multiprecision_mersenns_mult_mod(y3, y3, x1, keyLength); // t3=t3*x1
147 multiprecision_lshift_mod(t1, y3, keyLength); // t1=2*t3
148 multiprecision_mersenns_squa_mod(x3, t2, keyLength); // x3=t2^2
149 multiprecision_sub_mod(x3, x3, t1, keyLength); // x3=x3-t1
150 multiprecision_sub_mod(x3, x3, z1, keyLength); // x3=x3-t4
151 multiprecision_sub_mod(y3, y3, x3, keyLength); // t3=t3-x3
152 multiprecision_mersenns_mult_mod(y3, y3, t2, keyLength); // t3=t3*t2
153 multiprecision_mersenns_mult_mod(z1, z1, y1, keyLength); // t4=t4*t1
154 multiprecision_sub_mod(y3, y3, z1, keyLength);
157 // Computing the Non-Adjacent Form of a positive integer
158 static void ECC_NAF(uint8_t* naf, uint32_t* NumNAF, uint32_t* k,
159 uint32_t keyLength) {
165 while ((var = multiprecision_most_signbits(k, keyLength)) >= 1) {
166 if (k[0] & 0x01) // k is odd
168 sign = (k[0] & 0x03); // 1 or 3
172 k[0] = k[0] & 0xFFFFFFFE;
175 if (k[0] == 0) // overflow
180 } while (k[j++] == 0); // overflow
186 multiprecision_rshift(k, k, keyLength);
187 naf[i / 4] |= (sign) << ((i % 4) * 2);
194 // Binary Non-Adjacent Form for point multiplication
195 void ECC_PointMult_Bin_NAF(Point* q, Point* p, uint32_t* n,
196 uint32_t keyLength) {
198 uint8_t naf[256 / 4 + 1];
204 if (keyLength == KEY_LENGTH_DWORDS_P256) {
210 p_256_init_point(&r);
211 multiprecision_init(p->z, keyLength);
218 multiprecision_copy(minus_p.x, p->x, keyLength);
219 multiprecision_sub(minus_p.y, modp, p->y, keyLength);
221 multiprecision_init(minus_p.z, keyLength);
225 memset(naf, 0, sizeof(naf));
226 ECC_NAF(naf, &NumNaf, n, keyLength);
228 for (int i = NumNaf - 1; i >= 0; i--) {
229 p_256_copy_point(&r, q);
230 ECC_Double(q, &r, keyLength);
231 sign = (naf[i / 4] >> ((i % 4) * 2)) & 0x03;
234 p_256_copy_point(&r, q);
235 ECC_Add(q, &r, p, keyLength);
236 } else if (sign == 3) {
237 p_256_copy_point(&r, q);
238 ECC_Add(q, &r, &minus_p, keyLength);
242 multiprecision_inv_mod(minus_p.x, q->z, keyLength);
243 multiprecision_mersenns_squa_mod(q->z, minus_p.x, keyLength);
244 multiprecision_mersenns_mult_mod(q->x, q->x, q->z, keyLength);
245 multiprecision_mersenns_mult_mod(q->z, q->z, minus_p.x, keyLength);
246 multiprecision_mersenns_mult_mod(q->y, q->y, q->z, keyLength);
249 bool ECC_ValidatePoint(const Point& pt) {
250 const size_t kl = KEY_LENGTH_DWORDS_P256;
251 p_256_init_curve(kl);
253 // Ensure y^2 = x^3 + a*x + b (mod p); a = -3
256 uint32_t y2_mod[kl] = {0};
257 multiprecision_mersenns_squa_mod(y2_mod, (uint32_t*)pt.y, kl);
259 // Right hand side calculation
260 uint32_t rhs[kl] = {0};
261 multiprecision_mersenns_squa_mod(rhs, (uint32_t*)pt.x, kl);
262 uint32_t three[kl] = {0};
264 multiprecision_sub_mod(rhs, rhs, three, kl);
265 multiprecision_mersenns_mult_mod(rhs, rhs, (uint32_t*)pt.x, kl);
266 multiprecision_add_mod(rhs, rhs, curve_p256.b, kl);
268 return multiprecision_compare(rhs, y2_mod, kl) == 0;