diff options
Diffstat (limited to 'stack/smp/p_256_multprecision.c')
-rw-r--r-- | stack/smp/p_256_multprecision.c | 704 |
1 files changed, 704 insertions, 0 deletions
diff --git a/stack/smp/p_256_multprecision.c b/stack/smp/p_256_multprecision.c new file mode 100644 index 000000000..f93980957 --- /dev/null +++ b/stack/smp/p_256_multprecision.c @@ -0,0 +1,704 @@ +/****************************************************************************** + * + * Copyright (C) 2006-2015 Broadcom Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + + /****************************************************************************** + * + * This file contains simple pairing algorithms + * + ******************************************************************************/ + +#include <string.h> +#include "bt_target.h" +#include "p_256_ecc_pp.h" +#include "p_256_multprecision.h" + +void multiprecision_init(DWORD *c, uint32_t keyLength) +{ + for (uint32_t i = 0; i < keyLength; i++) + c[i] = 0; +} + +void multiprecision_copy(DWORD *c, DWORD *a, uint32_t keyLength) +{ + for (uint32_t i = 0; i < keyLength; i++) + c[i] = a[i]; +} + +int multiprecision_compare(DWORD *a, DWORD *b, uint32_t keyLength) +{ + for (int i = keyLength - 1; i >= 0; i--) + { + if (a[i] > b[i]) + return 1; + if (a[i] < b[i]) + return -1; + } + return 0; +} + +int multiprecision_iszero(DWORD *a, uint32_t keyLength) +{ + for (uint32_t i = 0; i < keyLength; i++) + if (a[i]) + return 0; + + return 1; +} + +UINT32 multiprecision_dword_bits(DWORD a) +{ + uint32_t i; + for (i = 0; i < DWORD_BITS; i++, a >>= 1) + if (a == 0) + break; + + return i; +} + +UINT32 multiprecision_most_signdwords(DWORD *a, uint32_t keyLength) +{ + int i; + for (i = keyLength - 1; i >= 0; i--) + if (a[i]) + break; + return (i + 1); +} + +UINT32 multiprecision_most_signbits(DWORD *a, uint32_t keyLength) +{ + int aMostSignDWORDs; + + aMostSignDWORDs = multiprecision_most_signdwords(a, keyLength); + if (aMostSignDWORDs == 0) + return 0; + + return (((aMostSignDWORDs-1) << DWORD_BITS_SHIFT) + + multiprecision_dword_bits(a[aMostSignDWORDs-1]) ); +} + +DWORD multiprecision_add(DWORD *c, DWORD *a, DWORD *b, uint32_t keyLength) +{ + DWORD carrier; + DWORD temp; + + carrier=0; + for (uint32_t i = 0; i < keyLength; i++) + { + temp = a[i] + carrier; + carrier = (temp < carrier); + temp += b[i]; + carrier |= (temp < b[i]); + c[i]=temp; + } + + return carrier; +} + +//c=a-b +DWORD multiprecision_sub(DWORD *c, DWORD *a, DWORD *b, uint32_t keyLength) +{ + DWORD borrow; + DWORD temp; + + borrow=0; + for (uint32_t i=0; i < keyLength; i++) + { + temp = a[i] - borrow; + borrow = (temp > a[i]); + c[i] = temp - b[i]; + borrow |= (c[i] > temp); + } + + return borrow; +} + +// c = a << 1 +void multiprecision_lshift_mod(DWORD * c, DWORD * a, uint32_t keyLength) +{ + DWORD carrier; + DWORD *modp; + + if (keyLength == KEY_LENGTH_DWORDS_P192) + { + modp = curve.p; + } + else if (keyLength == KEY_LENGTH_DWORDS_P256) + { + modp = curve_p256.p; + } + else + return; + + carrier = multiprecision_lshift(c, a, keyLength); + if (carrier) + { + multiprecision_sub(c, c, modp, keyLength); + } + else if (multiprecision_compare(c, modp, keyLength)>=0) + { + multiprecision_sub(c, c, modp, keyLength); + } +} + +// c=a>>1 +void multiprecision_rshift(DWORD * c, DWORD * a, uint32_t keyLength) +{ + int j; + DWORD b = 1; + + j = DWORD_BITS - b; + + DWORD carrier = 0; + DWORD temp; + for (int i = keyLength-1; i >= 0; i--) + { + temp = a[i]; // in case of c==a + c[i] = (temp >> b) | carrier; + carrier = temp << j; + } +} + +// Curve specific optimization when p is a pseudo-Mersenns prime, p=2^(KEY_LENGTH_BITS)-omega +void multiprecision_mersenns_mult_mod(DWORD *c, DWORD *a, DWORD *b, uint32_t keyLength) +{ + DWORD cc[2*KEY_LENGTH_DWORDS_P256]; + + multiprecision_mult(cc, a, b, keyLength); + if (keyLength == 6) + { + multiprecision_fast_mod(c, cc); + } + else if (keyLength == 8) + { + multiprecision_fast_mod_P256(c, cc); + } +} + +// Curve specific optimization when p is a pseudo-Mersenns prime +void multiprecision_mersenns_squa_mod(DWORD *c, DWORD *a, uint32_t keyLength) +{ + multiprecision_mersenns_mult_mod(c, a, a, keyLength); +} + +// c=(a+b) mod p, b<p, a<p +void multiprecision_add_mod(DWORD *c, DWORD *a, DWORD *b, uint32_t keyLength) +{ + DWORD carrier; + DWORD *modp; + + if (keyLength == KEY_LENGTH_DWORDS_P192) + { + modp = curve.p; + } + else if (keyLength == KEY_LENGTH_DWORDS_P256) + { + modp = curve_p256.p; + } + else + return; + + carrier = multiprecision_add(c, a, b, keyLength); + if (carrier) + { + multiprecision_sub(c, c, modp, keyLength); + } + else if (multiprecision_compare(c, modp, keyLength) >= 0) + { + multiprecision_sub(c, c, modp, keyLength); + } +} + +// c=(a-b) mod p, a<p, b<p +void multiprecision_sub_mod(DWORD *c, DWORD *a, DWORD *b, uint32_t keyLength) +{ + DWORD borrow; + DWORD *modp; + + if (keyLength == KEY_LENGTH_DWORDS_P192) + { + modp = curve.p; + } + else if(keyLength == KEY_LENGTH_DWORDS_P256) + { + modp = curve_p256.p; + } + else + return; + + borrow = multiprecision_sub(c, a, b, keyLength); + if(borrow) + multiprecision_add(c, c, modp, keyLength); +} + +// c=a<<b, b<DWORD_BITS, c has a buffer size of NumDWORDs+1 +DWORD multiprecision_lshift(DWORD * c, DWORD * a, uint32_t keyLength) +{ + int j; + uint32_t b = 1; + j = DWORD_BITS - b; + + DWORD carrier = 0; + DWORD temp; + + for (uint32_t i = 0; i < keyLength; i++) + { + temp = a[i]; // in case c==a + c[i] = (temp << b) | carrier; + carrier = temp >> j; + } + + return carrier; +} + +// c=a*b; c must have a buffer of 2*Key_LENGTH_DWORDS, c != a != b +void multiprecision_mult(DWORD *c, DWORD *a, DWORD *b, uint32_t keyLength) +{ + DWORD W; + DWORD U; + DWORD V; + + U = V = W = 0; + multiprecision_init(c, keyLength); + + //assume little endian right now + for (uint32_t i = 0; i < keyLength; i++) + { + U = 0; + for (uint32_t j = 0; j < keyLength; j++) + { + uint64_t result; + result = ((UINT64)a[i]) * ((uint64_t) b[j]); + W = result >> 32; + V = a[i] * b[j]; + V = V + U; + U = (V < U); + U += W; + V = V + c[i+j]; + U += (V < c[i+j]); + c[i+j] = V; + } + c[i+keyLength] = U; + } +} + +void multiprecision_fast_mod(DWORD *c, DWORD *a) +{ + DWORD U; + DWORD V; + DWORD *modp = curve.p; + + c[0] = a[0] + a[6]; + U=c[0] < a[0]; + c[0] += a[10]; + U += c[0] < a[10]; + + c[1] = a[1] + U; + U = c[1] < a[1]; + c[1] += a[7]; + U += c[1] < a[7]; + c[1] += a[11]; + U += c[1]< a[11]; + + c[2] = a[2] + U; + U = c[2] < a[2]; + c[2] += a[6]; + U += c[2] < a[6]; + c[2] += a[8]; + U += c[2] < a[8]; + c[2] += a[10]; + U += c[2] < a[10]; + + c[3] = a[3]+U; + U = c[3] < a[3]; + c[3] += a[7]; + U += c[3] < a[7]; + c[3] += a[9]; + U += c[3] < a[9]; + c[3] += a[11]; + U += c[3] < a[11]; + + c[4] = a[4]+U; + U = c[4] < a[4]; + c[4] += a[8]; + U += c[4] < a[8]; + c[4] += a[10]; + U += c[4] < a[10]; + + c[5] = a[5]+U; + U = c[5] < a[5]; + c[5] += a[9]; + U += c[5] < a[9]; + c[5] += a[11]; + U += c[5] < a[11]; + + c[0] += U; + V = c[0] < U; + c[1] += V; + V = c[1] < V; + c[2] += V; + V = c[2] < V; + c[2] += U; + V = c[2] < U; + c[3] += V; + V = c[3] < V; + c[4] += V; + V = c[4] < V; + c[5] += V; + V = c[5] < V; + + if (V) + { + multiprecision_sub(c, c, modp, KEY_LENGTH_DWORDS_P192); + } + else if(multiprecision_compare(c, modp, KEY_LENGTH_DWORDS_P192) >= 0) + { + multiprecision_sub(c, c, modp, KEY_LENGTH_DWORDS_P192); + } +} + +void multiprecision_fast_mod_P256(DWORD *c, DWORD *a) +{ + DWORD A; + DWORD B; + DWORD C; + DWORD D; + DWORD E; + DWORD F; + DWORD G; + uint8_t UA; + uint8_t UB; + uint8_t UC; + uint8_t UD; + uint8_t UE; + uint8_t UF; + uint8_t UG; + DWORD U; + DWORD *modp = curve_p256.p; + + // C = a[13] + a[14] + a[15]; + C = a[13]; + C += a[14]; + UC = (C < a[14]); + C += a[15]; + UC += (C < a[15]); + + // E = a[8] + a[9]; + E = a[8]; + E += a[9]; + UE = (E < a[9]); + + // F = a[9] + a[10]; + F = a[9]; + F += a[10]; + UF = (F < a[10]); + + // G = a[10] + a[11] + G = a[10]; + G += a[11]; + UG = (G < a[11]); + + // B = a[12] + a[13] + a[14] + a[15] == C + a[12] + B = C; + UB = UC; + B += a[12]; + UB += (B < a[12]); + + // A = a[11] + a[12] + a[13] + a[14] == B + a[11] - a[15] + A = B; + UA = UB; + A += a[11]; + UA += (A < a[11]); + UA -= (A < a[15]); + A -= a[15]; + + // D = a[10] + a[11] + a[12] + a[13] == A + a[10] - a[14] + D = A; + UD = UA; + D += a[10]; + UD += (D < a[10]); + UD -= (D < a[14]); + D -= a[14]; + + c[0] = a[0]; + c[0] += E; + U = (c[0] < E); + U += UE; + U -= (c[0] < A); + U -= UA; + c[0] -= A; + + if (U & 0x80000000) + { + DWORD UU; + UU = 0 - U; + U = (a[1] < UU); + c[1] = a[1] - UU; + } + else + { + c[1] = a[1] + U; + U = (c[1] < a[1]); + } + + c[1] += F; + U += (c[1] < F); + U += UF; + U -= (c[1] < B); + U -= UB; + c[1] -= B; + + if (U & 0x80000000) + { + DWORD UU; + UU = 0 - U; + U = (a[2] < UU); + c[2] = a[2] - UU; + } + else + { + c[2] = a[2] + U; + U = (c[2] < a[2]); + } + + c[2] += G; + U += (c[2] < G); + U += UG; + U -= (c[2] < C); + U -= UC; + c[2] -= C; + + if (U & 0x80000000) + { + DWORD UU; + UU = 0 - U; + U = (a[3] < UU); + c[3] = a[3] - UU; + } + else + { + c[3] = a[3] + U; + U = (c[3] < a[3]); + } + + c[3] += A; + U += (c[3] < A); + U += UA; + c[3] += a[11]; + U += (c[3] < a[11]); + c[3] += a[12]; + U += (c[3] < a[12]); + U -= (c[3] < a[14]); + c[3] -= a[14]; + U -= (c[3] < a[15]); + c[3] -= a[15]; + U -= (c[3] < E); + U -= UE; + c[3] -= E; + + if (U & 0x80000000) + { + DWORD UU; + UU = 0 - U; + U = (a[4] < UU); + c[4] = a[4] - UU; + } + else + { + c[4] = a[4] + U; + U = (c[4] < a[4]); + } + + c[4] += B; + U += (c[4] < B); + U += UB; + U -= (c[4] < a[15]); + c[4] -= a[15]; + c[4] += a[12]; + U += (c[4] < a[12]); + c[4] += a[13]; + U += (c[4] < a[13]); + U -= (c[4] < F); + U -= UF; + c[4] -= F; + + if (U & 0x80000000) + { + DWORD UU; + UU = 0 - U; + U = (a[5] < UU); + c[5] = a[5] - UU; + } + else + { + c[5] = a[5] + U; + U = (c[5] < a[5]); + } + + c[5] += C; + U += (c[5] < C); + U += UC; + c[5] += a[13]; + U += (c[5] < a[13]); + c[5] += a[14]; + U += (c[5] < a[14]); + U -= (c[5] < G); + U -= UG; + c[5] -= G; + + if (U & 0x80000000) + { + DWORD UU; + UU = 0 - U; + U = (a[6] < UU); + c[6] = a[6] - UU; + } + else + { + c[6] = a[6] + U; + U = (c[6] < a[6]); + } + + c[6] += C; + U += (c[6] < C); + U += UC; + c[6] += a[14]; + U += (c[6] < a[14]); + c[6] += a[14]; + U += (c[6] < a[14]); + c[6] += a[15]; + U += (c[6] < a[15]); + U -= (c[6] < E); + U -= UE; + c[6] -= E; + + if (U & 0x80000000) + { + DWORD UU; + UU = 0 - U; + U = (a[7] < UU); + c[7] = a[7] - UU; + } + else + { + c[7] = a[7] + U; + U = (c[7] < a[7]); + } + + c[7] += a[15]; + U += (c[7] < a[15]); + c[7] += a[15]; + U += (c[7] < a[15]); + c[7] += a[15]; + U += (c[7] < a[15]); + c[7] += a[8]; + U += (c[7] < a[8]); + U -= (c[7] < D); + U -= UD; + c[7] -= D; + + if (U & 0x80000000) + { + while (U) + { + multiprecision_add(c, c, modp, KEY_LENGTH_DWORDS_P256); + U++; + } + } + else if (U) + { + while (U) + { + multiprecision_sub(c, c, modp, KEY_LENGTH_DWORDS_P256); + U--; + } + } + + if (multiprecision_compare(c, modp, KEY_LENGTH_DWORDS_P256)>=0) + multiprecision_sub(c, c, modp, KEY_LENGTH_DWORDS_P256); + +} + +void multiprecision_inv_mod(DWORD *aminus, DWORD *u, uint32_t keyLength) +{ + DWORD v[KEY_LENGTH_DWORDS_P256]; + DWORD A[KEY_LENGTH_DWORDS_P256+1]; + DWORD C[KEY_LENGTH_DWORDS_P256+1]; + DWORD *modp; + + if(keyLength == KEY_LENGTH_DWORDS_P256) + { + modp = curve_p256.p; + } + else + { + modp = curve.p; + } + + multiprecision_copy(v, modp, keyLength); + multiprecision_init(A, keyLength); + multiprecision_init(C, keyLength); + A[0] = 1; + + while (!multiprecision_iszero(u, keyLength)) + { + while (!(u[0] & 0x01)) // u is even + { + multiprecision_rshift(u, u, keyLength); + if(!(A[0] & 0x01)) // A is even + multiprecision_rshift(A, A, keyLength); + else + { + A[keyLength]=multiprecision_add(A, A, modp, keyLength); // A =A+p + multiprecision_rshift(A, A, keyLength); + A[keyLength-1] |= (A[keyLength]<<31); + } + } + + while (!(v[0] & 0x01)) // v is even + { + multiprecision_rshift(v, v, keyLength); + if (!(C[0] & 0x01)) // C is even + { + multiprecision_rshift(C, C, keyLength); + } + else + { + C[keyLength] = multiprecision_add(C, C, modp, keyLength); // C =C+p + multiprecision_rshift(C, C, keyLength); + C[keyLength-1] |= (C[keyLength] << 31); + } + } + + if (multiprecision_compare(u, v, keyLength) >= 0) + { + multiprecision_sub(u, u, v, keyLength); + multiprecision_sub_mod(A, A, C, keyLength); + } + else + { + multiprecision_sub(v, v, u, keyLength); + multiprecision_sub_mod(C, C, A, keyLength); + } + } + + if (multiprecision_compare(C, modp, keyLength) >= 0) + multiprecision_sub(aminus, C, modp, keyLength); + else + multiprecision_copy(aminus, C, keyLength); +} + |