-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathecc_point_compression.c
121 lines (89 loc) · 3 KB
/
ecc_point_compression.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/*
* This is all about mbedtls_ecp_decompress() and mbedtls_ecp_compress()
*
* Perform X25519 / Curve25519 point compression and decompression for mbedtls.
* As of mbedtls 2.5.1, mbedtls does not support decompression yet.
*
*/
#define MBEDTLS_ALLOW_PRIVATE_ACCESS
#include "ecc_point_compression.h"
int mbedtls_ecp_decompress(
const mbedtls_ecp_group *grp,
const unsigned char *input, size_t ilen,
unsigned char *output, size_t *olen, size_t osize
) {
int ret;
size_t plen;
mbedtls_mpi r;
mbedtls_mpi x;
mbedtls_mpi n;
plen = mbedtls_mpi_size(&grp->P);
*olen = 2 * plen + 1;
if (osize < *olen)
return(MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL);
if (ilen != plen + 1)
return(MBEDTLS_ERR_ECP_BAD_INPUT_DATA);
if (input[0] != 0x02 && input[0] != 0x03)
return(MBEDTLS_ERR_ECP_BAD_INPUT_DATA);
// output will consist of 0x04|X|Y
memcpy(output, input, ilen);
output[0] = 0x04;
mbedtls_mpi_init(&r);
mbedtls_mpi_init(&x);
mbedtls_mpi_init(&n);
// x <= input
MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&x, input + 1, plen));
// r = x^2
MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&r, &x, &x));
// r = x^2 + a
if (grp->A.p == NULL) {
// Special case where a is -3
MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&r, &r, 3));
} else {
MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&r, &r, &grp->A));
}
// r = x^3 + ax
MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&r, &r, &x));
// r = x^3 + ax + b
MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&r, &r, &grp->B));
// Calculate square root of r over finite field P:
// r = sqrt(x^3 + ax + b) = (x^3 + ax + b) ^ ((P + 1) / 4) (mod P)
// n = P + 1
MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(&n, &grp->P, 1));
// n = (P + 1) / 4
MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&n, 2));
// r ^ ((P + 1) / 4) (mod p)
MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&r, &r, &n, &grp->P, NULL));
// Select solution that has the correct "sign" (equals odd/even solution in finite group)
if ((input[0] == 0x03) != mbedtls_mpi_get_bit(&r, 0)) {
// r = p - r
MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&r, &grp->P, &r));
}
// y => output
ret = mbedtls_mpi_write_binary(&r, output + 1 + plen, plen);
cleanup:
mbedtls_mpi_free(&r);
mbedtls_mpi_free(&x);
mbedtls_mpi_free(&n);
return(ret);
}
int mbedtls_ecp_compress(
const mbedtls_ecp_group *grp,
const unsigned char *input, size_t ilen,
unsigned char *output, size_t *olen, size_t osize
) {
size_t plen;
plen = mbedtls_mpi_size(&grp->P);
*olen = plen + 1;
if (osize < *olen)
return(MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL);
if (ilen != 2 * plen + 1)
return (MBEDTLS_ERR_ECP_BAD_INPUT_DATA);
if (input[0] != 0x04)
return(MBEDTLS_ERR_ECP_BAD_INPUT_DATA);
// output will consist of 0x0?|X
memcpy(output, input, *olen);
// Encode even/odd of Y into first byte (either 0x02 or 0x03)
output[0] = 0x02 + (input[2 * plen] & 1);
return(0);
}