Adding the rest of files:

- ASM is disabled
- Neug needs full rewrite
- Flash is based on PiMoroni 4MB flash (needs adjust)

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
This commit is contained in:
Pol Henarejos 2022-01-03 02:02:39 +01:00
parent 0445f587f7
commit 0af5685495
No known key found for this signature in database
GPG Key ID: C0095B7870A4CCD3
52 changed files with 21467 additions and 0 deletions

301
ac.c Normal file
View File

@ -0,0 +1,301 @@
/*
* ac.c -- Check access condition
*
* Copyright (C) 2010, 2012, 2013, 2017 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdint.h>
#include <string.h>
#include "config.h"
#include "gnuk.h"
#include "sha256.h"
#include "random.h"
uint8_t volatile auth_status; /* Initialized to AC_NONE_AUTHORIZED */
int
ac_check_status (uint8_t ac_flag)
{
if (ac_flag == AC_ALWAYS)
return 1;
else if (ac_flag == AC_NEVER)
return 0;
else
return (ac_flag & auth_status)? 1 : 0;
}
void
ac_reset_pso_cds (void)
{
gpg_do_clear_prvkey (GPG_KEY_FOR_SIGNING);
auth_status &= ~AC_PSO_CDS_AUTHORIZED;
}
void
ac_reset_other (void)
{
gpg_do_clear_prvkey (GPG_KEY_FOR_DECRYPTION);
gpg_do_clear_prvkey (GPG_KEY_FOR_AUTHENTICATION);
auth_status &= ~AC_OTHER_AUTHORIZED;
}
int
verify_user_0 (uint8_t access, const uint8_t *pw, int buf_len, int pw_len_known,
const uint8_t *ks_pw1, int save_ks)
{
int pw_len;
int r;
uint8_t keystring[KEYSTRING_MD_SIZE];
const uint8_t *salt;
int salt_len;
if (gpg_pw_locked (PW_ERR_PW1))
return 0;
if (ks_pw1 == NULL)
{
const uint8_t *initial_pw;
salt = NULL;
salt_len = 0;
gpg_do_get_initial_pw_setting (0, &pw_len, &initial_pw);
if ((pw_len_known >= 0 && pw_len_known != pw_len)
|| buf_len < pw_len
|| memcmp (pw, initial_pw, pw_len))
goto failure;
}
else
{
pw_len = ks_pw1[0] & PW_LEN_MASK;
salt = KS_GET_SALT (ks_pw1);
salt_len = SALT_SIZE;
if ((pw_len_known >= 0 && pw_len_known != pw_len)
|| buf_len < pw_len)
goto failure;
}
s2k (salt, salt_len, pw, pw_len, keystring);
if (save_ks)
memcpy (keystring_md_pw3, keystring, KEYSTRING_MD_SIZE);
if (access == AC_PSO_CDS_AUTHORIZED)
r = gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, BY_USER, keystring);
else
{
int r1, r2;
r1 = gpg_do_load_prvkey (GPG_KEY_FOR_DECRYPTION, BY_USER, keystring);
r2 = gpg_do_load_prvkey (GPG_KEY_FOR_AUTHENTICATION, BY_USER, keystring);
if (r1 < 0 || r2 < 0)
r = -1;
else if (r1 == 0)
{
if (r2 == 0)
/* No encryption/authentication keys, then, check signing key. */
r = gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, BY_USER, keystring);
else
r = r2;
}
else if (r2 == 0)
r = r1;
else
r = 1;
}
if (r < 0)
{
failure:
gpg_pw_increment_err_counter (PW_ERR_PW1);
return -1;
}
gpg_pw_reset_err_counter (PW_ERR_PW1);
return pw_len;
}
/*
* Verify for "Perform Security Operation : Compute Digital Signature"
*/
int
verify_pso_cds (const uint8_t *pw, int pw_len)
{
const uint8_t *ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1);
int r;
DEBUG_INFO ("verify_pso_cds\r\n");
DEBUG_BYTE (pw_len);
r = verify_user_0 (AC_PSO_CDS_AUTHORIZED, pw, pw_len, pw_len, ks_pw1, 0);
if (r > 0)
auth_status |= AC_PSO_CDS_AUTHORIZED;
return r;
}
int
verify_other (const uint8_t *pw, int pw_len)
{
const uint8_t *ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1);
int r;
DEBUG_INFO ("verify_other\r\n");
DEBUG_BYTE (pw_len);
r = verify_user_0 (AC_OTHER_AUTHORIZED, pw, pw_len, pw_len, ks_pw1, 0);
if (r > 0)
auth_status |= AC_OTHER_AUTHORIZED;
return r;
}
static int
verify_admin_00 (const uint8_t *pw, int buf_len, int pw_len_known,
const uint8_t *ks, int save_ks)
{
int pw_len;
int r;
uint8_t keystring[KEYSTRING_MD_SIZE];
const uint8_t *salt;
int salt_len;
pw_len = ks[0] & PW_LEN_MASK;
salt = KS_GET_SALT (ks);
salt_len = SALT_SIZE;
if ((pw_len_known >= 0 && pw_len_known != pw_len) || buf_len < pw_len)
return -1;
s2k (salt, salt_len, pw, pw_len, keystring);
if (save_ks)
memcpy (keystring_md_pw3, keystring, KEYSTRING_MD_SIZE);
r = gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, BY_ADMIN, keystring);
if (r < 0)
return -1;
else if (r == 0)
if ((ks[0] & PW_LEN_KEYSTRING_BIT) == 0
|| memcmp (KS_GET_KEYSTRING (ks), keystring, KEYSTRING_MD_SIZE) != 0)
return -1;
return pw_len;
}
uint8_t keystring_md_pw3[KEYSTRING_MD_SIZE];
uint8_t admin_authorized;
int
verify_admin_0 (const uint8_t *pw, int buf_len, int pw_len_known,
const uint8_t *pw3_keystring, int save_ks)
{
int pw_len;
if (pw3_keystring != NULL)
{
if (gpg_pw_locked (PW_ERR_PW3))
return 0;
pw_len = verify_admin_00 (pw, buf_len, pw_len_known, pw3_keystring,
save_ks);
if (pw_len < 0)
{
failure:
gpg_pw_increment_err_counter (PW_ERR_PW3);
return -1;
}
admin_authorized = BY_ADMIN;
success: /* OK, the admin is now authenticated. */
gpg_pw_reset_err_counter (PW_ERR_PW3);
return pw_len;
}
else
{
const uint8_t *initial_pw;
const uint8_t *ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1);
if (ks_pw1 != NULL)
{ /* empty PW3, but PW1 exists */
int r = verify_user_0 (AC_PSO_CDS_AUTHORIZED,
pw, buf_len, pw_len_known, ks_pw1, save_ks);
if (r > 0)
admin_authorized = BY_USER;
return r;
}
if (gpg_pw_locked (PW_ERR_PW3))
return 0;
/*
* For the case of empty PW3 (with empty PW1), passphrase is
* OPENPGP_CARD_INITIAL_PW3, or defined by KDF DO.
*/
gpg_do_get_initial_pw_setting (1, &pw_len, &initial_pw);
if ((pw_len_known >=0 && pw_len_known != pw_len)
|| buf_len < pw_len
|| memcmp (pw, initial_pw, pw_len))
goto failure;
admin_authorized = BY_ADMIN;
if (save_ks)
s2k (NULL, 0, pw, pw_len, keystring_md_pw3);
goto success;
}
}
int
verify_admin (const uint8_t *pw, int pw_len)
{
int r;
const uint8_t *pw3_keystring;
pw3_keystring = gpg_do_read_simple (NR_DO_KEYSTRING_PW3);
r = verify_admin_0 (pw, pw_len, pw_len, pw3_keystring, 1);
if (r <= 0)
return r;
auth_status |= AC_ADMIN_AUTHORIZED;
return 1;
}
void
ac_reset_admin (void)
{
memset (keystring_md_pw3, 0, KEYSTRING_MD_SIZE);
auth_status &= ~AC_ADMIN_AUTHORIZED;
admin_authorized = 0;
}
void
ac_fini (void)
{
memset (keystring_md_pw3, 0, KEYSTRING_MD_SIZE);
gpg_do_clear_prvkey (GPG_KEY_FOR_SIGNING);
gpg_do_clear_prvkey (GPG_KEY_FOR_DECRYPTION);
gpg_do_clear_prvkey (GPG_KEY_FOR_AUTHENTICATION);
auth_status = AC_NONE_AUTHORIZED;
admin_authorized = 0;
}

1352
aes.c Normal file

File diff suppressed because it is too large Load Diff

8
affine.h Normal file
View File

@ -0,0 +1,8 @@
/**
* @brief Affine coordinates
*/
typedef struct
{
bn256 x[1];
bn256 y[1];
} ac;

2561
bignum.c Normal file

File diff suppressed because it is too large Load Diff

427
bn.c Normal file
View File

@ -0,0 +1,427 @@
/*
* bn.c -- 256-bit (and 512-bit) bignum calculation
*
* Copyright (C) 2011, 2013, 2014, 2019
* Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdint.h>
#include <string.h>
#ifndef BN256_NO_RANDOM
#include "random.h"
#endif
#include "bn.h"
uint32_t
bn256_add (bn256 *X, const bn256 *A, const bn256 *B)
{
int i;
uint32_t v;
uint32_t carry = 0;
uint32_t *px;
const uint32_t *pa, *pb;
px = X->word;
pa = A->word;
pb = B->word;
for (i = 0; i < BN256_WORDS; i++)
{
v = *pb;
*px = *pa + carry;
carry = (*px < carry);
*px += v;
carry += (*px < v);
px++;
pa++;
pb++;
}
return carry;
}
uint32_t
bn256_sub (bn256 *X, const bn256 *A, const bn256 *B)
{
int i;
uint32_t v;
uint32_t borrow = 0;
uint32_t *px;
const uint32_t *pa, *pb;
px = X->word;
pa = A->word;
pb = B->word;
for (i = 0; i < BN256_WORDS; i++)
{
uint32_t borrow0 = (*pa < borrow);
v = *pb;
*px = *pa - borrow;
borrow = (*px < v) + borrow0;
*px -= v;
px++;
pa++;
pb++;
}
return borrow;
}
uint32_t
bn256_add_uint (bn256 *X, const bn256 *A, uint32_t w)
{
int i;
uint32_t carry = w;
uint32_t *px;
const uint32_t *pa;
px = X->word;
pa = A->word;
for (i = 0; i < BN256_WORDS; i++)
{
*px = *pa + carry;
carry = (*px < carry);
px++;
pa++;
}
return carry;
}
uint32_t
bn256_sub_uint (bn256 *X, const bn256 *A, uint32_t w)
{
int i;
uint32_t borrow = w;
uint32_t *px;
const uint32_t *pa;
px = X->word;
pa = A->word;
for (i = 0; i < BN256_WORDS; i++)
{
uint32_t borrow0 = (*pa < borrow);
*px = *pa - borrow;
borrow = borrow0;
px++;
pa++;
}
return borrow;
}
#ifndef BN256_C_IMPLEMENTATION
#define ASM_IMPLEMENTATION 0
#endif
void
bn256_mul (bn512 *X, const bn256 *A, const bn256 *B)
{
#if ASM_IMPLEMENTATION
#include "muladd_256.h"
const uint32_t *s;
uint32_t *d;
uint32_t w;
uint32_t c;
memset (X->word, 0, sizeof (uint32_t)*BN256_WORDS*2);
s = A->word; d = &X->word[0]; w = B->word[0]; MULADD_256 (s, d, w, c);
s = A->word; d = &X->word[1]; w = B->word[1]; MULADD_256 (s, d, w, c);
s = A->word; d = &X->word[2]; w = B->word[2]; MULADD_256 (s, d, w, c);
s = A->word; d = &X->word[3]; w = B->word[3]; MULADD_256 (s, d, w, c);
s = A->word; d = &X->word[4]; w = B->word[4]; MULADD_256 (s, d, w, c);
s = A->word; d = &X->word[5]; w = B->word[5]; MULADD_256 (s, d, w, c);
s = A->word; d = &X->word[6]; w = B->word[6]; MULADD_256 (s, d, w, c);
s = A->word; d = &X->word[7]; w = B->word[7]; MULADD_256 (s, d, w, c);
#else
int i, j, k;
int i_beg, i_end;
uint32_t r0, r1, r2;
r0 = r1 = r2 = 0;
for (k = 0; k <= (BN256_WORDS - 1)*2; k++)
{
if (k < BN256_WORDS)
{
i_beg = 0;
i_end = k;
}
else
{
i_beg = k - BN256_WORDS + 1;
i_end = BN256_WORDS - 1;
}
for (i = i_beg; i <= i_end; i++)
{
uint64_t uv;
uint32_t u, v;
uint32_t carry;
j = k - i;
uv = ((uint64_t )A->word[i])*((uint64_t )B->word[j]);
v = uv;
u = (uv >> 32);
r0 += v;
carry = (r0 < v);
r1 += carry;
carry = (r1 < carry);
r1 += u;
carry += (r1 < u);
r2 += carry;
}
X->word[k] = r0;
r0 = r1;
r1 = r2;
r2 = 0;
}
X->word[k] = r0;
#endif
}
void
bn256_sqr (bn512 *X, const bn256 *A)
{
#if ASM_IMPLEMENTATION
int i;
memset (X->word, 0, sizeof (bn512));
for (i = 0; i < BN256_WORDS; i++)
{
uint32_t *wij = &X->word[i*2];
const uint32_t *xj = &A->word[i];
uint32_t x_i = *xj++;
uint32_t c;
asm (/* (C,R4,R5) := w_i_i + x_i*x_i; w_i_i := R5; */
"mov %[c], #0\n\t"
"ldr r5, [%[wij]]\n\t" /* R5 := w_i_i; */
"mov r4, %[c]\n\t"
"umlal r5, r4, %[x_i], %[x_i]\n\t"
"str r5, [%[wij]], #4\n\t"
"cmp %[xj], %[x_max1]\n\t"
"bhi 0f\n\t"
"mov r9, %[c]\n\t" /* R9 := 0, the constant ZERO from here. */
"beq 1f\n"
"2:\n\t"
"ldmia %[xj]!, { r7, r8 }\n\t"
"ldmia %[wij], { r5, r6 }\n\t"
/* (C,R4,R5) := (C,R4) + w_i_j + 2*x_i*x_j; */
"umull r7, r12, %[x_i], r7\n\t"
"adds r5, r5, r4\n\t"
"adc r4, %[c], r9\n\t"
"adds r5, r5, r7\n\t"
"adcs r4, r4, r12\n\t"
"adc %[c], r9, r9\n\t"
"adds r5, r5, r7\n\t"
"adcs r4, r4, r12\n\t"
"adc %[c], %[c], r9\n\t"
/* (C,R4,R6) := (C,R4) + w_i_j + 2*x_i*x_j; */
"adds r6, r6, r4\n\t"
"adc r4, %[c], r9\n\t"
"umull r7, r12, %[x_i], r8\n\t"
"adds r6, r6, r7\n\t"
"adcs r4, r4, r12\n\t"
"adc %[c], r9, r9\n\t"
"adds r6, r6, r7\n\t"
"adcs r4, r4, r12\n\t"
"adc %[c], %[c], r9\n\t"
/**/
"stmia %[wij]!, { r5, r6 }\n\t"
"cmp %[xj], %[x_max1]\n\t"
"bcc 2b\n\t"
"bne 0f\n"
"1:\n\t"
/* (C,R4,R5) := (C,R4) + w_i_j + 2*x_i*x_j; */
"ldr r5, [%[wij]]\n\t"
"ldr r6, [%[xj]], #4\n\t"
"adds r5, r5, r4\n\t"
"adc r4, %[c], r9\n\t"
"umull r7, r12, %[x_i], r6\n\t"
"adds r5, r5, r7\n\t"
"adcs r4, r4, r12\n\t"
"adc %[c], r9, r9\n\t"
"adds r5, r5, r7\n\t"
"adcs r4, r4, r12\n\t"
"adc %[c], %[c], r9\n\t"
"str r5, [%[wij]], #4\n"
"0:\n\t"
"ldr r5, [%[wij]]\n\t"
"adds r4, r4, r5\n\t"
"adc %[c], %[c], #0\n\t"
"str r4, [%[wij]], #4"
: [c] "=&r" (c), [wij] "=r" (wij), [xj] "=r" (xj)
: [x_i] "r" (x_i), [x_max1] "r" (&A->word[BN256_WORDS-1]),
"[wij]" (wij), "[xj]" (xj)
: "r4", "r5", "r6", "r7", "r8", "r9", "r12", "memory", "cc");
if (i < BN256_WORDS - 1)
*wij = c;
}
#else
int i, j, k;
int i_beg, i_end;
uint32_t r0, r1, r2;
r0 = r1 = r2 = 0;
for (k = 0; k <= (BN256_WORDS - 1)*2; k++)
{
if (k < BN256_WORDS)
{
i_beg = 0;
i_end = k/2;
}
else
{
i_beg = k - BN256_WORDS + 1;
i_end = k/2;
}
for (i = i_beg; i <= i_end; i++)
{
uint64_t uv;
uint32_t u, v;
uint32_t carry;
j = k - i;
uv = ((uint64_t )A->word[i])*((uint64_t )A->word[j]);
if (i < j)
{
r2 += ((uv >> 63) != 0);
uv <<= 1;
}
v = uv;
u = (uv >> 32);
r0 += v;
carry = (r0 < v);
r1 += carry;
carry = (r1 < carry);
r1 += u;
carry += (r1 < u);
r2 += carry;
}
X->word[k] = r0;
r0 = r1;
r1 = r2;
r2 = 0;
}
X->word[k] = r0;
#endif
}
uint32_t
bn256_shift (bn256 *X, const bn256 *A, int shift)
{
int i;
uint32_t carry = 0, next_carry;
if (shift > 0)
{
for (i = 0; i < BN256_WORDS; i++)
{
next_carry = A->word[i] >> (32 - shift);
X->word[i] = (A->word[i] << shift) | carry;
carry = next_carry;
}
}
else
{
shift = -shift;
for (i = BN256_WORDS - 1; i >= 0; i--)
{
next_carry = A->word[i] & ((1 << shift) - 1);
X->word[i] = (A->word[i] >> shift) | (carry << (32 - shift));
carry = next_carry;
}
}
return carry;
}
int
bn256_is_zero (const bn256 *X)
{
int i;
int r = 1;
for (i = 0; i < BN256_WORDS; i++)
r &= (X->word[i] == 0);
return r;
}
int
bn256_is_even (const bn256 *X)
{
return !(X->word[0] & 1);
}
int
bn256_is_ge (const bn256 *A, const bn256 *B)
{
uint32_t borrow;
bn256 tmp[1];
borrow = bn256_sub (tmp, A, B);
return borrow == 0;
}
int
bn256_cmp (const bn256 *A, const bn256 *B)
{
uint32_t borrow;
int is_zero;
bn256 tmp[1];
borrow = bn256_sub (tmp, A, B);
is_zero = bn256_is_zero (tmp);
return is_zero ? 0 : (borrow ? -1 : 1);
}
#ifndef BN256_NO_RANDOM
void
bn256_random (bn256 *X)
{
int i, j;
const uint8_t *rand;
for (i = 0; i < 256/256; i++)
{
rand = random_bytes_get ();
for (j = 0; j < BN256_WORDS; j++)
X->word[i*BN256_WORDS+j] = ((uint32_t *)rand)[j];
random_bytes_free (rand);
}
}
#endif

23
bn.h Normal file
View File

@ -0,0 +1,23 @@
#define BN256_WORDS 8
typedef struct bn256 {
uint32_t word[ BN256_WORDS ]; /* Little endian */
} bn256;
#define BN512_WORDS 16
typedef struct bn512 {
uint32_t word[ BN512_WORDS ]; /* Little endian */
} bn512;
uint32_t bn256_add (bn256 *X, const bn256 *A, const bn256 *B);
uint32_t bn256_sub (bn256 *X, const bn256 *A, const bn256 *B);
uint32_t bn256_add_uint (bn256 *X, const bn256 *A, uint32_t w);
uint32_t bn256_sub_uint (bn256 *X, const bn256 *A, uint32_t w);
void bn256_mul (bn512 *X, const bn256 *A, const bn256 *B);
void bn256_sqr (bn512 *X, const bn256 *A);
uint32_t bn256_shift (bn256 *X, const bn256 *A, int shift);
int bn256_is_zero (const bn256 *X);
int bn256_is_even (const bn256 *X);
int bn256_is_ge (const bn256 *A, const bn256 *B);
int bn256_cmp (const bn256 *A, const bn256 *B);
void bn256_random (bn256 *X);

136
call-ec.c Normal file
View File

@ -0,0 +1,136 @@
/*
* call-ec.c - interface between Gnuk and Elliptic curve over GF(prime)
*
* Copyright (C) 2013, 2014, 2017 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "field-group-select.h"
/* We are little-endian in the computation, but the protocol is big-endian. */
#define ECDSA_BYTE_SIZE 32
#define ECDH_BYTE_SIZE 32
int
FUNC(ecdsa_sign) (const uint8_t *hash, uint8_t *output,
const uint8_t *key_data)
{
int i;
bn256 r[1], s[1], z[1], d[1];
uint8_t *p;
p = (uint8_t *)d;
for (i = 0; i < ECDSA_BYTE_SIZE; i++)
p[ECDSA_BYTE_SIZE - i - 1] = key_data[i];
p = (uint8_t *)z;
for (i = 0; i < ECDSA_BYTE_SIZE; i++)
p[ECDSA_BYTE_SIZE - i - 1] = hash[i];
FUNC(ecdsa) (r, s, z, d);
p = (uint8_t *)r;
for (i = 0; i < ECDSA_BYTE_SIZE; i++)
*output++ = p[ECDSA_BYTE_SIZE - i - 1];
p = (uint8_t *)s;
for (i = 0; i < ECDSA_BYTE_SIZE; i++)
*output++ = p[ECDSA_BYTE_SIZE - i - 1];
return 0;
}
int
FUNC(ecc_compute_public) (const uint8_t *key_data, uint8_t *pubkey)
{
uint8_t *p, *p1;
ac q[1];
bn256 k[1];
int i;
p = (uint8_t *)k;
for (i = 0; i < ECDSA_BYTE_SIZE; i++)
p[ECDSA_BYTE_SIZE - i - 1] = key_data[i];
if (FUNC(compute_kG) (q, k) < 0)
return -1;
p = pubkey;
p1 = (uint8_t *)q->x;
for (i = 0; i < ECDSA_BYTE_SIZE; i++)
*p++ = p1[ECDSA_BYTE_SIZE - i - 1];
p1 = (uint8_t *)q->y;
for (i = 0; i < ECDSA_BYTE_SIZE; i++)
*p++ = p1[ECDSA_BYTE_SIZE - i - 1];
return 0;
}
int
FUNC(ecdh_decrypt) (const uint8_t *input, uint8_t *output,
const uint8_t *key_data)
{
bn256 k[1];
ac X[1], P[1];
int i;
uint8_t *p0;
const uint8_t *p1;
int r;
p0 = (uint8_t *)k;
for (i = 0; i < ECDH_BYTE_SIZE; i++)
p0[ECDH_BYTE_SIZE - i - 1] = key_data[i];
p1 = input+1; /* skip '04' */
p0 = (uint8_t *)P->x;
for (i = 0; i < ECDH_BYTE_SIZE; i++)
p0[ECDH_BYTE_SIZE - i - 1] = *p1++;
p0 = (uint8_t *)P->y;
for (i = 0; i < ECDH_BYTE_SIZE; i++)
p0[ECDH_BYTE_SIZE - i - 1] = *p1++;
r = FUNC(compute_kP) (X, k, P);
if (r == 0)
{
p0 = output;
p1 = (const uint8_t *)X->x;
*p0++ = 4;
for (i = 0; i < ECDH_BYTE_SIZE; i++)
*p0++ = p1[ECDH_BYTE_SIZE - i - 1];
p1 = (const uint8_t *)X->y;
for (i = 0; i < ECDH_BYTE_SIZE; i++)
*p0++ = p1[ECDH_BYTE_SIZE - i - 1];
}
return r;
}
/**
* @brief Check if a secret d0 is valid or not
*
* @param D0 scalar D0: secret
* @param D1 scalar D1: secret candidate N-D0
*
* Return 0 on error.
* Return -1 when D1 should be used as the secret
* Return 1 when D0 should be used as the secret
*/
int
FUNC(ecc_check_secret) (const uint8_t *d0, uint8_t *d1)
{
return FUNC(check_secret) ((const bn256 *)d0, (bn256 *)d1);
}

34
call-ec_p256k1.c Normal file
View File

@ -0,0 +1,34 @@
/*
* call-ec_p256k1.c - interface between Gnuk and Elliptic curve over
* GF(p256k1)
*
* Copyright (C) 2014, 2017 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdint.h>
#include <string.h>
#include "bn.h"
#include "affine.h"
#include "jpc-ac_p256k1.h"
#include "ec_p256k1.h"
#define FIELD p256k1
#include "call-ec.c"

267
call-rsa.c Normal file
View File

@ -0,0 +1,267 @@
/*
* call-rsa.c -- Glue code between RSA computation and OpenPGP card protocol
*
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2017
* Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdint.h>
#include <string.h>
//#include <chopstx.h>
#include "config.h"
#include "gnuk.h"
#include "status-code.h"
#include "random.h"
#include "polarssl/config.h"
#include "polarssl/rsa.h"
static rsa_context rsa_ctx;
//static struct chx_cleanup clp;
static void
rsa_cleanup (void *arg)
{
(void)arg;
rsa_free (&rsa_ctx);
}
int
rsa_sign (const uint8_t *raw_message, uint8_t *output, int msg_len,
struct key_data *kd, int pubkey_len)
{
mpi P1, Q1, H;
int ret = 0;
unsigned char temp[pubkey_len];
rsa_init (&rsa_ctx, RSA_PKCS_V15, 0);
mpi_init (&P1); mpi_init (&Q1); mpi_init (&H);
rsa_ctx.len = pubkey_len;
MPI_CHK( mpi_lset (&rsa_ctx.E, 0x10001) );
MPI_CHK( mpi_read_binary (&rsa_ctx.P, &kd->data[0], pubkey_len / 2) );
MPI_CHK( mpi_read_binary (&rsa_ctx.Q, &kd->data[pubkey_len / 2],
pubkey_len / 2) );
#if 0
MPI_CHK( mpi_mul_mpi (&rsa_ctx.N, &rsa_ctx.P, &rsa_ctx.Q) );
#endif
MPI_CHK( mpi_sub_int (&P1, &rsa_ctx.P, 1) );
MPI_CHK( mpi_sub_int (&Q1, &rsa_ctx.Q, 1) );
MPI_CHK( mpi_mul_mpi (&H, &P1, &Q1) );
MPI_CHK( mpi_inv_mod (&rsa_ctx.D , &rsa_ctx.E, &H) );
MPI_CHK( mpi_mod_mpi (&rsa_ctx.DP, &rsa_ctx.D, &P1) );
MPI_CHK( mpi_mod_mpi (&rsa_ctx.DQ, &rsa_ctx.D, &Q1) );
MPI_CHK( mpi_inv_mod (&rsa_ctx.QP, &rsa_ctx.Q, &rsa_ctx.P) );
cleanup:
mpi_free (&P1); mpi_free (&Q1); mpi_free (&H);
if (ret == 0)
{
int cs;
DEBUG_INFO ("RSA sign...");
//clp.next = NULL;
//clp.routine = rsa_cleanup;
//clp.arg = NULL;
//chopstx_cleanup_push (&clp);
//cs = chopstx_setcancelstate (0); /* Allow cancellation. */
ret = rsa_rsassa_pkcs1_v15_sign (&rsa_ctx, NULL, NULL,
RSA_PRIVATE, SIG_RSA_RAW,
msg_len, raw_message, temp);
memcpy (output, temp, pubkey_len);
rsa_cleanup(NULL);
//chopstx_setcancelstate (cs);
//chopstx_cleanup_pop (0);
}
rsa_free (&rsa_ctx);
if (ret != 0)
{
DEBUG_INFO ("fail:");
DEBUG_SHORT (ret);
return -1;
}
else
{
DEBUG_INFO ("done.\r\n");
GPG_SUCCESS ();
return 0;
}
}
/*
* LEN: length in byte
*/
int
modulus_calc (const uint8_t *p, int len, uint8_t *pubkey)
{
mpi P, Q, N;
int ret;
mpi_init (&P); mpi_init (&Q); mpi_init (&N);
MPI_CHK( mpi_read_binary (&P, p, len / 2) );
MPI_CHK( mpi_read_binary (&Q, p + len / 2, len / 2) );
MPI_CHK( mpi_mul_mpi (&N, &P, &Q) );
MPI_CHK( mpi_write_binary (&N, pubkey, len) );
cleanup:
mpi_free (&P); mpi_free (&Q); mpi_free (&N);
if (ret != 0)
return -1;
return 0;
}
int
rsa_decrypt (const uint8_t *input, uint8_t *output, int msg_len,
struct key_data *kd, unsigned int *output_len_p)
{
mpi P1, Q1, H;
int ret;
DEBUG_INFO ("RSA decrypt:");
DEBUG_WORD ((uint32_t)&ret);
rsa_init (&rsa_ctx, RSA_PKCS_V15, 0);
mpi_init (&P1); mpi_init (&Q1); mpi_init (&H);
rsa_ctx.len = msg_len;
DEBUG_WORD (msg_len);
MPI_CHK( mpi_lset (&rsa_ctx.E, 0x10001) );
MPI_CHK( mpi_read_binary (&rsa_ctx.P, &kd->data[0], msg_len / 2) );
MPI_CHK( mpi_read_binary (&rsa_ctx.Q, &kd->data[msg_len / 2], msg_len / 2) );
#if 0
MPI_CHK( mpi_mul_mpi (&rsa_ctx.N, &rsa_ctx.P, &rsa_ctx.Q) );
#endif
MPI_CHK( mpi_sub_int (&P1, &rsa_ctx.P, 1) );
MPI_CHK( mpi_sub_int (&Q1, &rsa_ctx.Q, 1) );
MPI_CHK( mpi_mul_mpi (&H, &P1, &Q1) );
MPI_CHK( mpi_inv_mod (&rsa_ctx.D , &rsa_ctx.E, &H) );
MPI_CHK( mpi_mod_mpi (&rsa_ctx.DP, &rsa_ctx.D, &P1) );
MPI_CHK( mpi_mod_mpi (&rsa_ctx.DQ, &rsa_ctx.D, &Q1) );
MPI_CHK( mpi_inv_mod (&rsa_ctx.QP, &rsa_ctx.Q, &rsa_ctx.P) );
cleanup:
mpi_free (&P1); mpi_free (&Q1); mpi_free (&H);
if (ret == 0)
{
int cs;
DEBUG_INFO ("RSA decrypt ...");
//clp.next = NULL;
//clp.routine = rsa_cleanup;
//clp.arg = NULL;
//chopstx_cleanup_push (&clp);
//cs = chopstx_setcancelstate (0); /* Allow cancellation. */
ret = rsa_rsaes_pkcs1_v15_decrypt (&rsa_ctx, NULL, NULL,
RSA_PRIVATE, output_len_p, input,
output, MAX_RES_APDU_DATA_SIZE);
rsa_cleanup(NULL);
//chopstx_setcancelstate (cs);
//chopstx_cleanup_pop (0);
}
rsa_free (&rsa_ctx);
if (ret != 0)
{
DEBUG_INFO ("fail:");
DEBUG_SHORT (ret);
return -1;
}
else
{
DEBUG_INFO ("done.\r\n");
GPG_SUCCESS ();
return 0;
}
}
int
rsa_verify (const uint8_t *pubkey, int pubkey_len,
const uint8_t *hash, const uint8_t *sig)
{
int ret;
rsa_init (&rsa_ctx, RSA_PKCS_V15, 0);
rsa_ctx.len = pubkey_len;
MPI_CHK( mpi_lset (&rsa_ctx.E, 0x10001) );
MPI_CHK( mpi_read_binary (&rsa_ctx.N, pubkey, pubkey_len) );
DEBUG_INFO ("RSA verify...");
MPI_CHK( rsa_rsassa_pkcs1_v15_verify (&rsa_ctx, NULL, NULL,
RSA_PUBLIC, SIG_RSA_SHA256, 32,
hash, sig) );
cleanup:
rsa_free (&rsa_ctx);
if (ret != 0)
{
DEBUG_INFO ("fail:");
DEBUG_SHORT (ret);
return -1;
}
else
{
DEBUG_INFO ("verified.\r\n");
return 0;
}
}
#define RSA_EXPONENT 0x10001
int
rsa_genkey (int pubkey_len, uint8_t *pubkey, uint8_t *p_q)
{
int ret;
uint8_t index = 0;
uint8_t *p = p_q;
uint8_t *q = p_q + pubkey_len / 2;
int cs;
extern int prng_seed (int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng);
extern void neug_flush (void);
neug_flush ();
prng_seed (random_gen, &index);
rsa_init (&rsa_ctx, RSA_PKCS_V15, 0);
//clp.next = NULL;
//clp.routine = rsa_cleanup;
//clp.arg = NULL;
//chopstx_cleanup_push (&clp);
//cs = chopstx_setcancelstate (0); /* Allow cancellation. */
MPI_CHK( rsa_gen_key (&rsa_ctx, random_gen, &index, pubkey_len * 8,
RSA_EXPONENT) );
MPI_CHK( mpi_write_binary (&rsa_ctx.P, p, pubkey_len / 2) );
MPI_CHK( mpi_write_binary (&rsa_ctx.Q, q, pubkey_len / 2) );
MPI_CHK( mpi_write_binary (&rsa_ctx.N, pubkey, pubkey_len) );
cleanup:
//chopstx_setcancelstate (cs);
//chopstx_cleanup_pop (1);
rsa_cleanup(NULL);
if (ret != 0)
return -1;
else
return 0;
}

17
config.h Normal file
View File

@ -0,0 +1,17 @@
#define DEBUG
#ifdef DEBUG
#define ENABLE_VIRTUAL_COM_PORT 1
#endif
#undef DFU_SUPPORT
#define ORIGIN 0x08000000
#define ORIGIN_REAL 0x08000000
#undef PINPAD_SUPPORT
#define CERTDO_SUPPORT 1
#undef HID_CARD_CHANGE_SUPPORT
#define LIFE_CYCLE_MANAGEMENT_SUPPORT 1
#undef ACKBTN_SUPPORT
#define SERIALNO_STR_LEN 12
#undef KDF_DO_REQUIRED
#define MHZ 133

134
debug.c Normal file
View File

@ -0,0 +1,134 @@
/*
* debug.c -- Debuging with virtual COM port
*
* Copyright (C) 2010 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdint.h>
#include <string.h>
#include "tusb.h"
void my_write (const char *s, int len)
{
if (len == 0)
return;
TU_LOG2(s);
}
static void
put_hex (uint8_t nibble)
{
uint8_t c;
if (nibble < 0x0a)
c = '0' + nibble;
else
c = 'a' + nibble - 0x0a;
my_write ((const char *)&c, 1);
}
void
put_byte (uint8_t b)
{
put_hex (b >> 4);
put_hex (b &0x0f);
my_write ("\r\n", 2);
}
void
put_byte_with_no_nl (uint8_t b)
{
my_write (" ", 1);
put_hex (b >> 4);
put_hex (b &0x0f);
}
void
put_short (uint16_t x)
{
put_hex (x >> 12);
put_hex ((x >> 8)&0x0f);
put_hex ((x >> 4)&0x0f);
put_hex (x & 0x0f);
my_write ("\r\n", 2);
}
void
put_word (uint32_t x)
{
put_hex (x >> 28);
put_hex ((x >> 24)&0x0f);
put_hex ((x >> 20)&0x0f);
put_hex ((x >> 16)&0x0f);
put_hex ((x >> 12)&0x0f);
put_hex ((x >> 8)&0x0f);
put_hex ((x >> 4)&0x0f);
put_hex (x & 0x0f);
my_write ("\r\n", 2);
}
void
put_int (uint32_t x)
{
char s[10];
int i;
for (i = 0; i < 10; i++)
{
s[i] = '0' + (x % 10);
x /= 10;
if (x == 0)
break;
}
while (i)
{
my_write (s+i, 1);
i--;
}
my_write (s, 1);
my_write ("\r\n", 2);
}
void
put_binary (const char *s, int len)
{
int i;
for (i = 0; i < len; i++)
{
put_byte_with_no_nl (s[i]);
if ((i & 0x0f) == 0x0f)
my_write ("\r\n", 2);
}
my_write ("\r\n", 2);
}
void
put_string (const char *s)
{
my_write (s, strlen (s));
}

233
ec_p256k1.c Normal file
View File

@ -0,0 +1,233 @@
/* -*- coding: utf-8 -*-
* ec_p256k1.c - Elliptic curve over GF(p256k1)
*
* Copyright (C) 2014 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Note: we don't take advantage of the specific feature of this curve,
* but use same method of computation as NIST P-256 curve. That's due
* to some software patent(s).
*/
#include <stdint.h>
#include <string.h>
#include "bn.h"
#include "modp256k1.h"
#include "affine.h"
#include "jpc-ac_p256k1.h"
#include "mod.h"
#include "ec_p256k1.h"
#define FIELD p256k1
#define COEFFICIENT_A_IS_ZERO 1
/*
* a = 0, b = 7
*/
#if 0
static const bn256 coefficient_a[1] = {
{{ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }}
};
#endif
static const bn256 coefficient_b[1] = {
{{ 0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }}
};
static const ac precomputed_KG[15] = {
{
{{{ 0x16f81798, 0x59f2815b, 0x2dce28d9, 0x029bfcdb,
0xce870b07, 0x55a06295, 0xf9dcbbac, 0x79be667e }}},
{{{ 0xfb10d4b8, 0x9c47d08f, 0xa6855419, 0xfd17b448,
0x0e1108a8, 0x5da4fbfc, 0x26a3c465, 0x483ada77 }}}
}, {
{{{ 0x42d0e6bd, 0x13b7e0e7, 0xdb0f5e53, 0xf774d163,
0x104d6ecb, 0x82a2147c, 0x243c4e25, 0x3322d401 }}},
{{{ 0x6c28b2a0, 0x24f3a2e9, 0xa2873af6, 0x2805f63e,
0x4ddaf9b7, 0xbfb019bc, 0xe9664ef5, 0x56e70797 }}}
}, {
{{{ 0x829d122a, 0xdca81127, 0x67e99549, 0x8f17f314,
0x6a8a9e73, 0x9b889085, 0x846dd99d, 0x583fdfd9 }}},
{{{ 0x63c4eac4, 0xf3c7719e, 0xb734b37a, 0xb44685a3,
0x572a47a6, 0x9f92d2d6, 0x2ff57d81, 0xabc6232f }}}
}, {
{{{ 0x9ec4c0da, 0x1b7b444c, 0x723ea335, 0xe88c5678,
0x981f162e, 0x9239c1ad, 0xf63b5f33, 0x8f68b9d2 }}},
{{{ 0x501fff82, 0xf23cbf79, 0x95510bfd, 0xbbea2cfe,
0xb6be215d, 0xde1d90c2, 0xba063986, 0x662a9f2d }}}
}, {
{{{ 0x114cbf09, 0x63c5e885, 0x7be77e3e, 0x2f27ce93,
0xf54a3e33, 0xdaa6d12d, 0x3eff872c, 0x8b300e51 }}},
{{{ 0xb3b10a39, 0x26c6ff28, 0x9aaf7169, 0x08f6a7aa,
0x6b8238ea, 0x446f0d46, 0x7f43c0cc, 0x1cec3067 }}}
}, {
{{{ 0x075e9070, 0xba16ce6a, 0x9b5cfe37, 0xbc26893d,
0x9c510774, 0xe1ddadfe, 0xfe3ae2f4, 0x90922d88 }}},
{{{ 0x5c08824a, 0x653943cc, 0xfce8f4bc, 0x06d74475,
0x533c615d, 0x8d101fa7, 0x742108a9, 0x7b1903f6 }}}
}, {
{{{ 0x6ebdc96c, 0x1bcfa45c, 0x1c7584ba, 0xe400bc04,
0x74cf531f, 0x6395e20e, 0xc5131b30, 0x1edd0bb1 }}},
{{{ 0xe358cf9e, 0xa117161b, 0x2724d11c, 0xe490d6f0,
0xee6dd8c9, 0xf75062f6, 0xfba373e4, 0x31e03b2b }}}
}, {
{{{ 0x2120e2b3, 0x7f3b58fa, 0x7f47f9aa, 0x7a58fdce,
0x4ce6e521, 0xe7be4ae3, 0x1f51bdba, 0xeaa649f2 }}},
{{{ 0xba5ad93d, 0xd47a5305, 0xf13f7e59, 0x01a6b965,
0x9879aa5a, 0xc69a80f8, 0x5bbbb03a, 0xbe3279ed }}}
}, {
{{{ 0x27bb4d71, 0xcf291a33, 0x33524832, 0x6caf7d6b,
0x766584ee, 0x6e0ee131, 0xd064c589, 0x160cb0f6 }}},
{{{ 0x17136e8d, 0x9d5de554, 0x1aab720e, 0xe3f2d468,
0xccf75cc2, 0xd1378b49, 0xc4ff16e1, 0x6920c375 }}}
}, {
{{{ 0x1a9ee611, 0x3eef9e96, 0x9cc37faf, 0xfe4d7bf3,
0xb321d965, 0x462aa9b3, 0x208736c5, 0x1702da3e }}},
{{{ 0x3a545ceb, 0xfba57bbf, 0x7ea858f5, 0x6dbcd766,
0x680d92f1, 0x088e897c, 0xbc626c80, 0x468c1fd8 }}}
}, {
{{{ 0xb188660a, 0xb40f85c7, 0x99bc3c36, 0xc5873c19,
0x7f33b54c, 0x3c7b4541, 0x1f8c9bf8, 0x4cd3a93c }}},
{{{ 0x33099cb0, 0xf8dce380, 0x2edd2f33, 0x7a167dd6,
0x0ffe35b7, 0x576d8987, 0xc68ace5c, 0xd2de0386 }}}
}, {
{{{ 0x6658bb08, 0x9a9e0a72, 0xc589607b, 0xe23c5f2a,
0xf2bfb4c8, 0xa048ca14, 0xc62c2291, 0x4d9a0f89 }}},
{{{ 0x0f827294, 0x427b5f31, 0x9f2c35cd, 0x1ea7a8b5,
0x85a3c00f, 0x95442e56, 0x9b57975a, 0x8cb83121 }}}
}, {
{{{ 0x51f5cf67, 0x4333f0da, 0xf4f0d3cb, 0x6d3ea47c,
0xa05a831f, 0x442fda14, 0x016d3e81, 0x6a496013 }}},
{{{ 0xe52e0f48, 0xf647318c, 0x4a0d5ff1, 0x5ff3a66e,
0x61199ba8, 0x046ed81a, 0x3e79c23a, 0x578edf08 }}}
}, {
{{{ 0x3ea01ea7, 0xb8f996f8, 0x7497bb15, 0xc0045d33,
0x6205647c, 0xc4749dc9, 0x0efd22c9, 0xd8946054 }}},
{{{ 0x12774ad5, 0x062dcb09, 0x8be06e3a, 0xcb13f310,
0x235de1a9, 0xca281d35, 0x69c3645c, 0xaf8a7412 }}}
}, {
{{{ 0xbeb8b1e2, 0x8808ca5f, 0xea0dda76, 0x0262b204,
0xddeb356b, 0xb6fffffc, 0xfbb83870, 0x52de253a }}},
{{{ 0x8f8d21ea, 0x961f40c0, 0x002f03ed, 0x89686278,
0x38e421ea, 0x0ff834d7, 0xd36fb8db, 0x3a270d6f }}}
}
};
static const ac precomputed_2E_KG[15] = {
{
{{{ 0x39a48db0, 0xefd7835b, 0x9b3c03bf, 0x9f1215a2,
0x9b7bde45, 0x2791d0a0, 0x696e7167, 0x100f44da }}},
{{{ 0x2bc65a09, 0x0fbd5cd6, 0xff5195ac, 0xb7ff4a18,
0x0c090666, 0x2ec8f330, 0x92a00b77, 0xcdd9e131 }}}
}, {
{{{ 0x40fb27b6, 0x32427e28, 0xbe430576, 0xc76e3db2,
0x61686aa5, 0x10f238ad, 0xbe778b1b, 0xfea74e3d }}},
{{{ 0xf23cb96f, 0x701d3db7, 0x973f7b77, 0x126b596b,
0xccb6af93, 0x7cf674de, 0x9b0b1329, 0x6e0568db }}}
}, {
{{{ 0x2c8118bc, 0x6cac5154, 0x399ddd98, 0x19bd4b34,
0x2e9c8949, 0x47248a8d, 0x2cefa3b1, 0x734cb6a8 }}},
{{{ 0x1e410fd5, 0xf1b340ad, 0xc4873539, 0xa2982bee,
0xd4de4530, 0x7b5a3ea4, 0x42202574, 0xae46e10e }}}
}, {
{{{ 0xac1f98cd, 0xcbfc99c8, 0x4d7f0308, 0x52348905,
0x1cc66021, 0xfaed8a9c, 0x4a474870, 0x9c3919a8 }}},
{{{ 0xd4fc599d, 0xbe7e5e03, 0x6c64c8e6, 0x905326f7,
0xf260e641, 0x584f044b, 0x4a4ddd57, 0xddb84f0f }}}
}, {
{{{ 0xed7cebed, 0xc4aacaa8, 0x4fae424e, 0xb75d2dce,
0xba20735e, 0xa01585a2, 0xba122399, 0x3d75f24b }}},
{{{ 0xd5570dce, 0xcbe4606f, 0x2da192c2, 0x9d00bfd7,
0xa57b7265, 0x9c3ce86b, 0xec4edf5e, 0x987a22f1 }}}
}, {
{{{ 0x73ea0665, 0x211b9715, 0xf3a1abbb, 0x86f485d4,
0xcd076f0e, 0xabd242d8, 0x0ba5dc88, 0x862332ab }}},
{{{ 0x7b784911, 0x09af505c, 0xcaf4fae7, 0xc89544e8,
0xae9a32eb, 0x256625f6, 0x606d1a3f, 0xe2532b72 }}}
}, {
{{{ 0x0deaf885, 0x79e9f313, 0x46df21c9, 0x938ff76e,
0xa953bb2c, 0x1968f5fb, 0x29155f27, 0xdff538bf }}},
{{{ 0x31d5d020, 0xf7bae0b1, 0x1a676a8d, 0x5afdc787,
0xfa9d53ff, 0x11b4f032, 0xc5959167, 0x86ba433e }}}
}, {
{{{ 0x9475b7ba, 0x884fdff0, 0xe4918b3d, 0xe039e730,
0xf5018cdb, 0x3d3e57ed, 0x1943785c, 0x95939698 }}},
{{{ 0x7524f2fd, 0xe9b8abf8, 0xc8709385, 0x9c653f64,
0x4b9cd684, 0x8ba0386a, 0x88c331dd, 0x2e7e5528 }}}
}, {
{{{ 0xeefe79e5, 0x940bef53, 0xbe9b87f3, 0xc518d286,
0x7833042c, 0x9e0c7c76, 0x11fbe152, 0x104e2cb5 }}},
{{{ 0x50bbec83, 0xc0d35e0f, 0x4acd0fcc, 0xee4879be,
0x006085ee, 0xc8d80f5d, 0x72fe1ac1, 0x3c51bc1c }}}
}, {
{{{ 0xb2de976e, 0x06187f61, 0xf5e4b4b6, 0x52869e18,
0x38d332ca, 0x74d4facd, 0xb3a2f8d9, 0x5c1c90b4 }}},
{{{ 0xdaa37893, 0x98644d09, 0xabe39818, 0x682435a8,
0x469c53a0, 0x17e46617, 0x77dc2e64, 0x642f9632 }}}
}, {
{{{ 0x222f6c54, 0xad2101c5, 0xfa74785e, 0xb05c7a58,
0x489bcdaf, 0xce55fa79, 0xffe88d54, 0xc1f920fd }}},
{{{ 0x9065e490, 0x32553ab0, 0x35329f74, 0x7611b9af,
0xab7b24c0, 0x57df19ef, 0x6181c447, 0xb9a78749 }}}
}, {
{{{ 0xa80b7ea8, 0x392f156f, 0x8ae4a8bf, 0x57ab7ca0,
0x50c4b178, 0xac320747, 0x0e781feb, 0x146041b9 }}},
{{{ 0x845279b2, 0xd343f075, 0x7387afa5, 0x2d4fe757,
0xa72f3c39, 0x151e0948, 0x550da168, 0x41a6d54e }}}
}, {
{{{ 0x075a0010, 0xb3134ed3, 0x7ae93e23, 0x9fa76f4b,
0x7bb4daaa, 0xc0db256f, 0x464dd8a3, 0x7668dc27 }}},
{{{ 0x9f5da977, 0x150063f5, 0x05efce00, 0x3acac5c8,
0x884493fe, 0xc8e12ffc, 0x88f06bd2, 0x4ab936d8 }}}
}, {
{{{ 0x5d09ea98, 0x996fde77, 0x4145da58, 0x16ddf512,
0xdc2fb225, 0xa97a6ca8, 0xfbdcdf5a, 0xc7331f30 }}},
{{{ 0x86a86e52, 0x838f99e0, 0x77795edd, 0x68d39b29,
0x9f412aaa, 0xe4e4f97e, 0x30d25352, 0xe5cc2c0a }}}
}, {
{{{ 0x9c21ff71, 0xb3d68650, 0xddbe3884, 0x11e7589d,
0x423bac67, 0x7efd4055, 0x46957425, 0x587a7293 }}},
{{{ 0x8f5a8fc6, 0x360adc2e, 0xbd69f12e, 0x6f8bbafb,
0x0a3f3b4d, 0xf671f423, 0x59942dc3, 0xb49acb47 }}}
}
};
/*
* N: order of G
* 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
*/
static const bn256 N[1] = {
{{ 0xd0364141, 0xbfd25e8c, 0xaf48a03b, 0xbaaedce6,
0xfffffffe, 0xffffffff, 0xffffffff, 0xffffffff }}
};
/*
* MU = 2^512 / N
* MU = ( (1 << 256) | MU_lower )
*/
static const bn256 MU_lower[1] = {
{{ 0x2fc9bec0, 0x402da173, 0x50b75fc4, 0x45512319,
0x1, 0x0, 0x0, 0x0 }}
};
#include "ecc.c"

4
ec_p256k1.h Normal file
View File

@ -0,0 +1,4 @@
int compute_kP_p256k1 (ac *X, const bn256 *K, const ac *P);
int compute_kG_p256k1 (ac *X, const bn256 *K);
void ecdsa_p256k1 (bn256 *r, bn256 *s, const bn256 *z, const bn256 *d);
int check_secret_p256k1 (const bn256 *q, bn256 *d1);

952
ecc-ed25519.c Normal file
View File

@ -0,0 +1,952 @@
/* -*- coding: utf-8 -*-
* ecc-ed25519.c - Elliptic curve computation for
* the twisted Edwards curve: -x^2 + y^2 = 1 + d*x^2*y^2
* d = -121665/121666
*
* Copyright (C) 2014, 2017 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdint.h>
#include <string.h>
#include "bn.h"
#include "mod.h"
#include "mod25638.h"
#include "sha512.h"
/*
* References:
*
* [1] Daniel J. Bernstein, Niels Duif, Tanja Lange, Peter Schwabe, Bo-Yin Yang.
* High-speed high-security signatures.
* Journal of Cryptographic Engineering 2 (2012), 77--89.
* http://cr.yp.to/papers.html#ed25519
*
* [2] Daniel J. Bernstein, Peter Birkner, Marc Joye, Tanja Lange,
* Christiane Peters.
* Twisted Edwards curves.
* Pages 389--405 in Progress in cryptology---AFRICACRYPT 2008.
* http://cr.yp.to/papers.html#twisted
*/
/*
* IMPLEMENTATION NOTE
*
* (0) We assume that the processor has no cache, nor branch target
* prediction. Thus, we don't avoid indexing by secret value.
* We don't avoid conditional jump if both cases have same timing,
* either.
*
* (1) We use Radix-32 field arithmetic. It's a representation like
* 2^256-38, but it's more redundant. For example, "1" can be
* represented in three ways in 256-bit: 1, 2^255-18, and
* 2^256-37.
*
* (2) We use fixed base comb multiplication. Scalar is 252-bit.
* There are various possible choices for 252 = 2 * 2 * 3 * 3 * 7.
* Current choice of total size is 3KB. We use three tables, and
* a table has 16 points (3 * 1KB).
*
* Window size W = 4-bit, E = 21.
* <--21-bit-
* <---42-bit----------
* [ ][########][////////][ ][########][////////]
* <-------63-bit----------------
* <-----------84-bit----------------------
* <--------------105-bit----------------------------
*
* [ ][########][////////][ ][########][////////]
* <-126-bit-
* <-147-bit-
* <----168-bit--------
*
* <-------189-bit---------------
* <----------210-bit----------------------
* <-------------231-bit-----------------------------
*/
/*
* Identity element: (0,1)
* Negation: -(x,y) = (-x,y)
*
* d: -0x2DFC9311D490018C7338BF8688861767FF8FF5B2BEBE27548A14B235ECA6874A
* order:
* 0x1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED
* Gx: 0x216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A
* Gy: 0x6666666666666666666666666666666666666666666666666666666666666658
*/
/* d + 2^255 - 19 */
static const bn256 coefficient_d[1] = {
{{ 0x135978a3, 0x75eb4dca, 0x4141d8ab, 0x00700a4d,
0x7779e898, 0x8cc74079, 0x2b6ffe73, 0x52036cee }} };
/**
* @brief Projective Twisted Coordinates
*/
typedef struct
{
bn256 x[1];
bn256 y[1];
bn256 z[1];
} ptc;
#include "affine.h"
static int
mod25519_is_neg (const bn256 *a)
{
return (a->word[0] & 1);
}
/**
* @brief X = 2 * A
*
* Compute (X3 : Y3 : Z3) = 2 * (X1 : Y1 : Z1)
*/
static void
point_double (ptc *X, const ptc *A)
{
bn256 b[1], d[1], e[1];
/* Compute: B = (X1 + Y1)^2 */
mod25638_add (b, A->x, A->y);
mod25638_sqr (b, b);
/* Compute: C = X1^2 : E */
mod25638_sqr (e, A->x);
/* Compute: D = Y1^2 */
mod25638_sqr (d, A->y);
/* E = aC; where a = -1 */
/* Compute: D - E = D + C : Y3_tmp */
mod25638_add (X->y, e, d);
/* Compute: -F = -(E + D) = C - D; where a = -1 : E */
mod25638_sub (e, e, d);
/* Compute: H = Z1^2 : D */
mod25638_sqr (d, A->z);
/* Compute: -J = 2*H - F : D */
mod25638_add (d, d, d);
mod25638_add (d, d, e);
/* Compute: X3 = (B-C-D)*J = -J*(C+D-B) = -J*(Y3_tmp-B) */
mod25638_sub (X->x, X->y, b);
mod25638_mul (X->x, X->x, d);
/* Compute: Y3 = -F*(D-E) = -F*Y3_tmp */
mod25638_mul (X->y, X->y, e);
/* Z3 = -F*-J */
mod25638_mul (X->z, e, d);
}
/**
* @brief X = A + B
*
* @param X Destination PTC
* @param A PTC
* @param B AC
*
* Compute: (X3 : Y3 : Z3) = (X1 : Y1 : Z1) + (X2 : Y2 : 1)
*/
static void
point_add (ptc *X, const ptc *A, const ac *B)
{
bn256 c[1], d[1], e[1], tmp[1];
/* Compute: C = X1 * X2 */
mod25638_mul (c, A->x, B->x);
/* Compute: D = Y1 * Y2 */
mod25638_mul (d, A->y, B->y);
/* Compute: E = d * C * D */
mod25638_mul (e, c, d);
mod25638_mul (e, coefficient_d, e);
/* Compute: C_1 = C + D */
mod25638_add (c, c, d);
/* Compute: D_1 = Z1^2 : B */
mod25638_sqr (d, A->z);
/* tmp = D_1 - E : F */
mod25638_sub (tmp, d, e);
/* D_2 = D_1 + E : G */
mod25638_add (d, d, e);
/* X3_final = Z1 * tmp * ((X1 + Y1) * (X2 + Y2) - C_1) */
mod25638_add (X->x, A->x, A->y);
mod25638_add (e, B->x, B->y);
mod25638_mul (e, X->x, e);
mod25638_sub (e, e, c);
mod25638_mul (e, tmp, e);
mod25638_mul (X->x, A->z, e);
/* Y3_final = Z1 * D_2 * C_1 */
mod25638_mul (c, d, c);
mod25638_mul (X->y, A->z, c);
/* Z3_final = tmp * D_2 */
mod25638_mul (X->z, tmp, d);
/* A = Z1 */
/* B = A^2 */
/* C = X1 * X2 */
/* D = Y1 * Y2 */
/* E = d * C * D */
/* F = B - E */
/* G = B + E */
/* X3 = A * F * ((X1 + Y1) * (X2 + Y2) - C - D) */
/* Y3 = A * G * (D - aC); where a = -1 */
/* Z3 = F * G */
}
/**
* @brief X = convert A
*
* @param X Destination AC
* @param A PTC
*
* (X1:Y1:Z1) represents the affine point (x=X1/Z1, y=Y1/Z1)
*/
static void
point_ptc_to_ac (ac *X, const ptc *A)
{
bn256 z_inv[1];
/*
* A->z may be bigger than p25519, or two times bigger than p25519.
* But this is no problem for computation of mod_inv.
*/
mod_inv (z_inv, A->z, p25519);
mod25638_mul (X->x, A->x, z_inv);
mod25519_reduce (X->x);
mod25638_mul (X->y, A->y, z_inv);
mod25519_reduce (X->y);
}
static const ac precomputed_KG[16] = {
{ {{{ 0, 0, 0, 0, 0, 0, 0, 0 }}},
{{{ 1, 0, 0, 0, 0, 0, 0, 0 }}} },
{ {{{ 0x8f25d51a, 0xc9562d60, 0x9525a7b2, 0x692cc760,
0xfdd6dc5c, 0xc0a4e231, 0xcd6e53fe, 0x216936d3 }}},
{{{ 0x66666658, 0x66666666, 0x66666666, 0x66666666,
0x66666666, 0x66666666, 0x66666666, 0x66666666 }}} },
{ {{{ 0x3713af22, 0xac7137bd, 0xac634604, 0x25ed77a4,
0xa815e038, 0xce0d0064, 0xbca90151, 0x041c030f }}},
{{{ 0x0780f989, 0xe9b33fcf, 0x3d4445e7, 0xe4e97c2a,
0x655e5c16, 0xc67dc71c, 0xee43fb7a, 0x72467625 }}} },
{ {{{ 0x3ee99893, 0x76a19171, 0x7ba9b065, 0xe647edd9,
0x6aeae260, 0x31f39299, 0x5f4a9bb2, 0x6d9e4545 }}},
{{{ 0x94cae280, 0xc41433da, 0x79061211, 0x8e842de8,
0xa259dc8a, 0xaab95e0b, 0x99013cd0, 0x28bd5fc3 }}} },
{ {{{ 0x7d23ea24, 0x59e22c56, 0x0460850e, 0x1e745a88,
0xda13ef4b, 0x4583ff4c, 0x95083f85, 0x1f13202c }}},
{{{ 0x90275f48, 0xad42025c, 0xb55c4778, 0x0085087e,
0xfdfd7ffa, 0xf21109e7, 0x6c381b7e, 0x66336d35 }}} },
{ {{{ 0xd00851f2, 0xaa9476ab, 0x4a61600b, 0xe7838534,
0x1a52df87, 0x0de65625, 0xbd675870, 0x5f0dd494 }}},
{{{ 0xe23493ba, 0xf20aec1b, 0x3414b0a8, 0x8f7f2741,
0xa80e1eb6, 0x497e74bd, 0xe9365b15, 0x1648eaac }}} },
{ {{{ 0x04ac2b69, 0x5b78dcec, 0x32001a73, 0xecdb66ce,
0xb34cf697, 0xb75832f4, 0x3a2bce94, 0x7aaf57c5 }}},
{{{ 0x60fdfc6f, 0xb32ed2ce, 0x757924c6, 0x77bf20be,
0x48742dd1, 0xaebd15dd, 0x55d38439, 0x6311bb16 }}} },
{ {{{ 0x42ff5c97, 0x139cdd73, 0xdbd82964, 0xee4c359e,
0x70611a3f, 0x91c1cd94, 0x8075dbcb, 0x1d0c34f6 }}},
{{{ 0x5f931219, 0x43eaa549, 0xa23d35a6, 0x3737aba7,
0x46f167bb, 0x54b1992f, 0xb74a9944, 0x01a11f3c }}} },
{ {{{ 0xba46b161, 0x67a5310e, 0xd9d67f6c, 0x790f8527,
0x2f6cc814, 0x359c5b5f, 0x7786383d, 0x7b6a5565 }}},
{{{ 0x663ab0d3, 0xf1431b60, 0x09995826, 0x14a32d8f,
0xeddb8571, 0x61d526f6, 0x0eac739a, 0x0cb7acea }}} },
{ {{{ 0x4a2d009f, 0x5eb1a697, 0xd8df987a, 0xdacb43b4,
0x8397f958, 0x4870f214, 0x8a175fbb, 0x5aa0c67c }}},
{{{ 0x78887db3, 0x27dbbd4c, 0x64e322ab, 0xe327b707,
0x7cbe4e3b, 0x87e293fa, 0xbda72395, 0x17040799 }}} },
{ {{{ 0x99d1e696, 0xc833a5a2, 0x2d9d5877, 0x969bff8e,
0x2216fa67, 0x383a533a, 0x684d3925, 0x338bbe0a }}},
{{{ 0xd6cfb491, 0x35b5aae8, 0xaa12f3f8, 0x4a588279,
0x2e30380e, 0xa7c2e708, 0x9e4b3d62, 0x69f13e09 }}} },
{ {{{ 0x27f1cd56, 0xec0dc2ef, 0xdb11cc97, 0x1af11548,
0x9ebc7613, 0xb642f86a, 0xcb77c3b9, 0x5ce45e73 }}},
{{{ 0x3eddd6de, 0x5d128786, 0x4859eab7, 0x16f9a6b4,
0xd8782345, 0x55c53916, 0xdb7b202a, 0x6b1dfa87 }}} },
{ {{{ 0x19e30528, 0x2461a8ed, 0x665cfb1c, 0xaf756bf9,
0x3a6e8673, 0x0fcafd1d, 0x45d10f48, 0x0d264435 }}},
{{{ 0x5431db67, 0x543fd4c6, 0x60932432, 0xc153a5b3,
0xd2119aa4, 0x41d5b8eb, 0x8b09b6a5, 0x36bd9ab4 }}} },
{ {{{ 0x21e06738, 0x6d39f935, 0x3765dd86, 0x4e6a7c59,
0xa4730880, 0xefc0dd80, 0x4079fe2f, 0x40617e56 }}},
{{{ 0x921439b9, 0xbc83cdff, 0x98833c09, 0xd5cccc06,
0xda13cdcb, 0xe315c425, 0x67ff5370, 0x37bc6e84 }}} },
{ {{{ 0xf643b5f5, 0x65e7f028, 0x0ffbf5a8, 0x5b0d4831,
0xf4085f62, 0x0f540498, 0x0db7bd1b, 0x6f0bb035 }}},
{{{ 0x9733742c, 0x51f65571, 0xf513409f, 0x2fc047a0,
0x355facf6, 0x07f45010, 0x3a989a9c, 0x5cd416a9 }}} },
{ {{{ 0x748f2a67, 0x0bdd7208, 0x415b7f7f, 0x0cf0b80b,
0x57aa0119, 0x44afdd5f, 0x430dc946, 0x05d68802 }}},
{{{ 0x1a60eeb2, 0x420c46e5, 0x665024f5, 0xc60a9b33,
0x48c51347, 0x37520265, 0x00a21bfb, 0x6f4be0af }}} }
};
static const ac precomputed_2E_KG[16] = {
{ {{{ 0, 0, 0, 0, 0, 0, 0, 0 }}},
{{{ 1, 0, 0, 0, 0, 0, 0, 0 }}} },
{ {{{ 0x199c4f7d, 0xec314ac0, 0xb2ebaaf9, 0x66a39c16,
0xedd4d15f, 0xab1c92b8, 0x57d9eada, 0x482a4cdf }}},
{{{ 0x6e4eb04b, 0xbd513b11, 0x25e4fd6a, 0x3f115fa5,
0x14519298, 0x0b3c5fc6, 0x81c2f7a8, 0x7391de43 }}} },
{ {{{ 0x1254fe02, 0xa57dca18, 0x6da34368, 0xa56a2a14,
0x63e7328e, 0x44c6e34f, 0xca63ab3e, 0x3f748617 }}},
{{{ 0x7dc1641e, 0x5a13dc52, 0xee4e9ca1, 0x4cbb2899,
0x1ba9acee, 0x3938a289, 0x420fc47b, 0x0fed89e6 }}} },
{ {{{ 0x49cbad08, 0x3c193f32, 0x15e80ef5, 0xdda71ef1,
0x9d128c33, 0xda44186c, 0xbf98c24f, 0x54183ede }}},
{{{ 0x93d165c1, 0x2cb483f7, 0x177f44aa, 0x51762ace,
0xb4ab035d, 0xb3fe651b, 0xa0b0d4e5, 0x426c99c3 }}} },
{ {{{ 0xef3f3fb1, 0xb3fcf4d8, 0x065060a0, 0x7052292b,
0x24240b15, 0x18795ff8, 0x9989ffcc, 0x13aea184 }}},
{{{ 0xc2b81f44, 0x1930c101, 0x10600555, 0x672d6ca4,
0x1b25e570, 0xfbddbff2, 0x8ca12b70, 0x0884949c }}} },
{ {{{ 0x00564bbf, 0x9983a033, 0xde61b72d, 0x95587d25,
0xeb17ad71, 0xb6719dfb, 0xc0bc3517, 0x46871ad0 }}},
{{{ 0xe95a6693, 0xb034fb61, 0x76eabad9, 0x5b0d8d18,
0x884785dc, 0xad295dd0, 0x74a1276a, 0x359debad }}} },
{ {{{ 0xe89fb5ca, 0x2e5a2686, 0x5656c6c5, 0xd3d200ba,
0x9c969001, 0xef4c051e, 0x02cb45f4, 0x0d4ea946 }}},
{{{ 0x76d6e506, 0xa6f8a422, 0x63209e23, 0x454c768f,
0x2b372386, 0x5c12fd04, 0xdbfee11f, 0x1aedbd3e }}} },
{ {{{ 0x00dbf569, 0x700ab50f, 0xd335b313, 0x9553643c,
0xa17dc97e, 0xeea9bddf, 0x3350a2bd, 0x0d12fe3d }}},
{{{ 0xa16a3dee, 0xe5ac35fe, 0xf81950c3, 0x4ae4664a,
0x3dbbf921, 0x75c63df4, 0x2958a5a6, 0x545b109c }}} },
{ {{{ 0x0a61b29c, 0xd7a52a98, 0x65aca9ee, 0xe21e0acb,
0x5985dcbe, 0x57a69c0f, 0xeb87a534, 0x3c0c1e7b }}},
{{{ 0x6384bd2f, 0xf0a0b50d, 0xc6939e4b, 0xff349a34,
0x6e2f1973, 0x922c4554, 0xf1347631, 0x74e826b2 }}} },
{ {{{ 0xa655803c, 0xd7eaa066, 0x38292c5c, 0x09504e76,
0x2c874953, 0xe298a02e, 0x8932b73f, 0x225093ed }}},
{{{ 0xe69c3efd, 0xf93e2b4d, 0x8a87c799, 0xa2cbd5fc,
0x85dba986, 0xdf41da94, 0xccee8edc, 0x36fe85e7 }}} },
{ {{{ 0x7d742813, 0x78df7dc5, 0x4a193e64, 0x333bcc6d,
0x6a966d2d, 0x8242aa25, 0x4cd36d32, 0x03500a94 }}},
{{{ 0x580505d7, 0xd5d110fc, 0xfa11e1e9, 0xb2f47e16,
0x06eab6b4, 0xd0030f92, 0x62c91d46, 0x2dc80d5f }}} },
{ {{{ 0x2a75e492, 0x5788b01a, 0xbae31352, 0x992acf54,
0x8159db27, 0x4591b980, 0xd3d84740, 0x36c6533c }}},
{{{ 0x103883b5, 0xc44c7c00, 0x515d0820, 0x10329423,
0x71b9dc16, 0xbd306903, 0xf88f8d32, 0x7edd5a95 }}} },
{ {{{ 0x005523d7, 0xfd63b1ac, 0xad70dd21, 0x74482e0d,
0x02b56105, 0x67c9d9d0, 0x5971b456, 0x4d318012 }}},
{{{ 0x841106df, 0xdc9a6f6d, 0xa326987f, 0x7c52ed9d,
0x00607ea0, 0x4dbeaa6f, 0x6959e688, 0x115c221d }}} },
{ {{{ 0xc80f7c16, 0xf8718464, 0xe9930634, 0x05dc8f40,
0xc2e9d5f4, 0xefa699bb, 0x021da209, 0x2469e813 }}},
{{{ 0xc602a3c4, 0x75c02845, 0x0a200f9d, 0x49d1b2ce,
0x2fb3ec8f, 0xd21b75e4, 0xd72a7545, 0x10dd726a }}} },
{ {{{ 0x63ef1a6c, 0xeda58527, 0x051705e0, 0xb3fc0e72,
0x44f1161f, 0xbda6f3ee, 0xf339efe5, 0x7680aebf }}},
{{{ 0xb1b070a7, 0xe8d3fd01, 0xdbfbaaa0, 0xc3ff7dbf,
0xa320c916, 0xd81ef6f2, 0x62a3b54d, 0x3e22a1fb }}} },
{ {{{ 0xb1fa18c8, 0xcdbb9187, 0xcb483a17, 0x8ddb5f6b,
0xea49af98, 0xc0a880b9, 0xf2dfddd0, 0x53bf600b }}},
{{{ 0x9e25b164, 0x4217404c, 0xafb74aa7, 0xfabf06ee,
0x2b9f233c, 0xb17712ae, 0xd0eb909e, 0x71f0b344 }}} }
};
static const ac precomputed_4E_KG[16] = {
{ {{{ 0, 0, 0, 0, 0, 0, 0, 0 }}},
{{{ 1, 0, 0, 0, 0, 0, 0, 0 }}} },
{ {{{ 0xe388a820, 0xbb6ec091, 0x5182278a, 0xa928b283,
0xa9a6eb83, 0x2259174d, 0x45500054, 0x184b48cb }}},
{{{ 0x26e77c33, 0xfe324dba, 0x83faf453, 0x6679a5e3,
0x2380ef73, 0xdd60c268, 0x03dc33a9, 0x3ee0e07a }}} },
{ {{{ 0xce974493, 0x403aff28, 0x9bf6f5c4, 0x84076bf4,
0xecd898fb, 0xec57038c, 0xb663ed49, 0x2898ffaa }}},
{{{ 0xf335163d, 0xf4b3bc46, 0xfa4fb6c6, 0xe613a0f4,
0xb9934557, 0xe759d6bc, 0xab6c9477, 0x094f3b96 }}} },
{ {{{ 0x6afffe9e, 0x168bb5a0, 0xee748c29, 0x950f7ad7,
0xda17203d, 0xa4850a2b, 0x77289e0f, 0x0062f7a7 }}},
{{{ 0x4b3829fa, 0x6265d4e9, 0xbdfcd386, 0x4f155ada,
0x475795f6, 0x9f38bda4, 0xdece4a4c, 0x560ed4b3 }}} },
{ {{{ 0x141e648a, 0xdad4570a, 0x019b965c, 0x8bbf674c,
0xdb08fe30, 0xd7a8d50d, 0xa2851109, 0x7efb45d3 }}},
{{{ 0xd0c28cda, 0x52e818ac, 0xa321d436, 0x792257dd,
0x9d71f8b7, 0x867091c6, 0x11a1bf56, 0x0fe1198b }}} },
{ {{{ 0x06137ab1, 0x4e848339, 0x3e6674cc, 0x5673e864,
0x0140502b, 0xad882043, 0x6ea1e46a, 0x34b5c0cb }}},
{{{ 0x1d70aa7c, 0x29786814, 0x8cdbb8aa, 0x840ae3f9,
0xbd4801fb, 0x78b4d622, 0xcf18ae9a, 0x6cf4e146 }}} },
{ {{{ 0x36297168, 0x95c270ad, 0x942e7812, 0x2303ce80,
0x0205cf0e, 0x71908cc2, 0x32bcd754, 0x0cc15edd }}},
{{{ 0x2c7ded86, 0x1db94364, 0xf141b22c, 0xc694e39b,
0x5e5a9312, 0xf22f64ef, 0x3c5e6155, 0x649b8859 }}} },
{ {{{ 0xb6417945, 0x0d5611c6, 0xac306c97, 0x9643fdbf,
0x0df500ff, 0xe81faaa4, 0x6f50e615, 0x0792c79b }}},
{{{ 0xd2af8c8d, 0xb45bbc49, 0x84f51bfe, 0x16c615ab,
0xc1d02d32, 0xdc57c526, 0x3c8aaa55, 0x5fb9a9a6 }}} },
{ {{{ 0xdee40b98, 0x82faa8db, 0x6d520674, 0xff8a5208,
0x446ac562, 0x1f8c510f, 0x2cc6b66e, 0x4676d381 }}},
{{{ 0x2e7429f4, 0x8f1aa780, 0x8ed6bdf6, 0x2a95c1bf,
0x457fa0eb, 0x051450a0, 0x744c57b1, 0x7d89e2b7 }}} },
{ {{{ 0x3f95ea15, 0xb6bdacd2, 0x2f1a5d69, 0xc9a9d1b1,
0xf4d22d72, 0xd4c2f1a9, 0x4dc516b5, 0x73ecfdf1 }}},
{{{ 0x05391e08, 0xa1ce93cd, 0x7b8aac17, 0x98f1e99e,
0xa098cbb3, 0x9ba84f2e, 0xf9bdd37a, 0x1425aa8b }}} },
{ {{{ 0x966abfc0, 0x8a385bf4, 0xf081a640, 0x55e5e8bc,
0xee26f5ff, 0x835dff85, 0xe509e1ea, 0x4927e622 }}},
{{{ 0x352334b0, 0x164c8dbc, 0xa3fea31f, 0xcac1ad63,
0x682fd457, 0x9b87a676, 0x1a53145f, 0x75f382ff }}} },
{ {{{ 0xc3efcb46, 0x16b944f5, 0x68cb184c, 0x1fb55714,
0x9ccf2dc8, 0xf1c2b116, 0x808283d8, 0x7417e00f }}},
{{{ 0x930199ba, 0x1ea67a22, 0x718990d8, 0x9fbaf765,
0x8f3d5d57, 0x231fc664, 0xe5853194, 0x38141a19 }}} },
{ {{{ 0x2f81290d, 0xb9f00390, 0x04a9ca6c, 0x44877827,
0xe1dbdd65, 0x65d7f9b9, 0xf7c6698a, 0x7133424c }}},
{{{ 0xa7cd250f, 0x604cfb3c, 0x5acc18f3, 0x460c3c4b,
0xb518e3eb, 0xa53e50e0, 0x98a40196, 0x2b4b9267 }}} },
{ {{{ 0xc5dbd06c, 0x591b0672, 0xaa1eeb65, 0x10d43dca,
0xcd2517af, 0x420cdef8, 0x0b695a8a, 0x513a307e }}},
{{{ 0x66503215, 0xee9d6a7b, 0x088fd9a4, 0xdea58720,
0x973afe12, 0x8f3cbbea, 0x872f2538, 0x005c2350 }}} },
{ {{{ 0x35af3291, 0xe5024b70, 0x4f5e669a, 0x1d3eec2d,
0x6e79d539, 0xc1f6d766, 0x795b5248, 0x34ec043f }}},
{{{ 0x400960b6, 0xb2763511, 0x29e57df0, 0xff7a3d84,
0x1666c1f1, 0xaeac7792, 0x66084bc0, 0x72426e97 }}} },
{ {{{ 0x44f826ca, 0x5b1c3199, 0x790aa408, 0x68b00b73,
0x69e9b92b, 0xaf0984b4, 0x3ffe9093, 0x5fe6736f }}},
{{{ 0xffd49312, 0xd67f2889, 0x5cb9ed21, 0x3520d747,
0x3c65a606, 0x94f893b1, 0x2d65496f, 0x2fee5e8c }}} }
};
/**
* @brief X = k * G
*
* @param K scalar k
*
* Return -1 on error.
* Return 0 on success.
*/
static void
compute_kG_25519 (ac *X, const bn256 *K)
{
ptc Q[1];
int i;
/* identity element */
memset (Q, 0, sizeof (ptc));
Q->y->word[0] = 1;
Q->z->word[0] = 1;
for (i = 20; i >= 0; i--)
{
int k0, k1, k2;
k0 = ((K->word[0] >> i) & 1)
| (i < 1 ? ((K->word[1] >> 30) & 2)
: (((K->word[2] >> (i-1)) & 1) << 1))
| (i < 2 ? ((K->word[3] >> (i+28)) & 4)
: (((K->word[4] >> (i-2)) & 1) << 2))
| (i < 3 ? ((K->word[5] >> (i+26)) & 8)
: (((K->word[6] >> (i-3)) & 1) << 3));
k1 = (i < 11 ? ((K->word[0] >> (i+21)) & 1)
: ((K->word[1] >> (i-11)) & 1))
| (i < 12 ? ((K->word[2] >> (i+19)) & 2)
: (((K->word[3] >> (i-12)) & 1) << 1))
| (i < 13 ? ((K->word[4] >> (i+17)) & 4)
: (((K->word[5] >> (i-13)) & 1) << 2))
| (i < 14 ? ((K->word[6] >> (i+15)) & 8)
: (((K->word[7] >> (i-14)) & 1) << 3));
k2 = ((K->word[1] >> (i+10)) & 1)
| ((K->word[3] >> (i+8)) & 2)
| ((K->word[5] >> (i+6)) & 4)
| ((K->word[7] >> (i+4)) & 8);
point_double (Q, Q);
point_add (Q, Q, &precomputed_KG[k0]);
point_add (Q, Q, &precomputed_2E_KG[k1]);
point_add (Q, Q, &precomputed_4E_KG[k2]);
}
point_ptc_to_ac (X, Q);
}
#define BN416_WORDS 13
#define BN128_WORDS 4
/* M: The order of the generator G. */
static const bn256 M[1] = {
{{ 0x5CF5D3ED, 0x5812631A, 0xA2F79CD6, 0x14DEF9DE,
0x00000000, 0x00000000, 0x00000000, 0x10000000 }}
};
#define C ((const uint32_t *)M)
static void
bnX_mul_C (uint32_t *r, const uint32_t *q, int q_size)
{
int i, j, k;
int i_beg, i_end;
uint32_t r0, r1, r2;
r0 = r1 = r2 = 0;
for (k = 0; k <= q_size + BN128_WORDS - 2; k++)
{
if (q_size < BN128_WORDS)
if (k < q_size)
{
i_beg = 0;
i_end = k;
}
else
{
i_beg = k - q_size + 1;
i_end = k;
if (i_end > BN128_WORDS - 1)
i_end = BN128_WORDS - 1;
}
else
if (k < BN128_WORDS)
{
i_beg = 0;
i_end = k;
}
else
{
i_beg = k - BN128_WORDS + 1;
i_end = k;
if (i_end > q_size - 1)
i_end = q_size - 1;
}
for (i = i_beg; i <= i_end; i++)
{
uint64_t uv;
uint32_t u, v;
uint32_t carry;
j = k - i;
if (q_size < BN128_WORDS)
uv = ((uint64_t )q[j])*((uint64_t )C[i]);
else
uv = ((uint64_t )q[i])*((uint64_t )C[j]);
v = uv;
u = (uv >> 32);
r0 += v;
carry = (r0 < v);
r1 += carry;
carry = (r1 < carry);
r1 += u;
carry += (r1 < u);
r2 += carry;
}
r[k] = r0;
r0 = r1;
r1 = r2;
r2 = 0;
}
r[k] = r0;
}
/**
* @brief R = A mod M (using M=2^252+C) (Barret reduction)
*
* See HAC 14.47 and 14.52.
*/
static void
mod_reduce_M (bn256 *R, const bn512 *A)
{
uint32_t q[BN256_WORDS+1];
uint32_t tmp[BN416_WORDS];
bn256 r[1];
uint32_t carry, next_carry;
int i;
#define borrow carry
q[8] = A->word[15]>>28;
carry = A->word[15] & 0x0fffffff;
for (i = BN256_WORDS - 1; i >= 0; i--)
{
next_carry = A->word[i+7] & 0x0fffffff;
q[i] = (A->word[i+7] >> 28) | (carry << 4);
carry = next_carry;
}
memcpy (R, A, sizeof (bn256));
R->word[7] &= 0x0fffffff;
/* Q_size: 9 */
bnX_mul_C (tmp, q, 9); /* TMP = Q*C */
/* Q = tmp / 2^252 */
carry = tmp[12] & 0x0fffffff;
for (i = 4; i >= 0; i--)
{
next_carry = tmp[i+7] & 0x0fffffff;
q[i] = (tmp[i+7] >> 28) | (carry << 4);
carry = next_carry;
}
/* R' = tmp % 2^252 */
memcpy (r, tmp, sizeof (bn256));
r->word[7] &= 0x0fffffff;
/* R -= R' */
borrow = bn256_sub (R, R, r);
if (borrow)
bn256_add (R, R, M);
else
bn256_add ((bn256 *)tmp, R, M);
/* Q_size: 5 */
bnX_mul_C (tmp, q, 5); /* TMP = Q*C */
carry = tmp[8] & 0x0fffffff;
q[0] = (tmp[7] >> 28) | (carry << 4);
/* R' = tmp % 2^252 */
memcpy (r, tmp, sizeof (bn256));
r->word[7] &= 0x0fffffff;
/* R += R' */
bn256_add (R, R, r);
borrow = bn256_sub (R, R, M);
if (borrow)
bn256_add (R, R, M);
else
bn256_add ((bn256 *)tmp, R, M);
/* Q_size: 1 */
bnX_mul_C (tmp, q, 1); /* TMP = Q*C */
/* R' = tmp % 2^252 */
memset (((uint8_t *)r)+(sizeof (uint32_t)*5), 0, sizeof (uint32_t)*3);
memcpy (r, tmp, sizeof (uint32_t)*5);
/* R -= R' */
borrow = bn256_sub (R, R, r);
if (borrow)
bn256_add (R, R, M);
else
bn256_add ((bn256 *)tmp, R, M);
#undef borrow
}
int
eddsa_sign_25519 (const uint8_t *input, size_t ilen, uint32_t *out,
const bn256 *a, const uint8_t *seed, const bn256 *pk)
{
bn256 *r, *s;
sha512_context ctx;
uint8_t hash[64];
bn256 tmp[1];
ac R[1];
uint32_t carry, borrow;
r = (bn256 *)out;
s = (bn256 *)(out+(32/4));
sha512_start (&ctx);
sha512_update (&ctx, seed, sizeof (bn256)); /* It's upper half of the hash */
sha512_update (&ctx, input, ilen);
sha512_finish (&ctx, hash);
mod_reduce_M (r, (bn512 *)hash);
compute_kG_25519 (R, r);
/* EdDSA encoding. */
memcpy (tmp, R->y, sizeof (bn256));
tmp->word[7] ^= mod25519_is_neg (R->x) * 0x80000000;
sha512_start (&ctx);
sha512_update (&ctx, (uint8_t *)tmp, sizeof (bn256));
sha512_update (&ctx, (uint8_t *)pk, sizeof (bn256));
sha512_update (&ctx, input, ilen);
sha512_finish (&ctx, (uint8_t *)hash);
mod_reduce_M (s, (bn512 *)hash);
bn256_mul ((bn512 *)hash, s, a);
mod_reduce_M (s, (bn512 *)hash);
carry = bn256_add (s, s, r);
borrow = bn256_sub (s, s, M);
memcpy (r, tmp, sizeof (bn256));
if ((borrow && !carry))
bn256_add (s, s, M);
else
bn256_add (tmp, s, M);
return 0;
}
static void
eddsa_public_key_25519 (bn256 *pk, const bn256 *a)
{
ac R[1];
ptc X[1];
bn256 a0[1];
bn256_shift (a0, a, -3);
compute_kG_25519 (R, a0);
memcpy (X, R, sizeof (ac));
memset (X->z, 0, sizeof (bn256));
X->z->word[0] = 1;
point_double (X, X);
point_double (X, X);
point_double (X, X);
point_ptc_to_ac (R, X);
/* EdDSA encoding. */
memcpy (pk, R->y, sizeof (bn256));
pk->word[7] ^= mod25519_is_neg (R->x) * 0x80000000;
}
void
eddsa_compute_public_25519 (const uint8_t *kd, uint8_t *pubkey)
{
eddsa_public_key_25519 ((bn256 *)pubkey, (const bn256 *)kd);
}
#if 0
/**
* check if P is on the curve.
*
* Return -1 on error.
* Return 0 on success.
*/
static int
point_is_on_the_curve (const ac *P)
{
bn256 s[1], t[1];
/* Twisted Edwards curve: a*x^2 + y^2 = 1 + d*x^2*y^2 */
}
int
compute_kP_25519 (ac *X, const bn256 *K, const ac *P);
#endif
#ifdef PRINT_OUT_TABLE
static const ptc G[1] = {{
{{{ 0x8f25d51a, 0xc9562d60, 0x9525a7b2, 0x692cc760,
0xfdd6dc5c, 0xc0a4e231, 0xcd6e53fe, 0x216936d3 }}},
{{{ 0x66666658, 0x66666666, 0x66666666, 0x66666666,
0x66666666, 0x66666666, 0x66666666, 0x66666666 }}},
{{{ 1, 0, 0, 0, 0, 0, 0, 0 }}},
}};
#include <stdio.h>
#ifdef TESTING_EDDSA
static void
print_bn256 (const bn256 *X)
{
int i;
for (i = 7; i >= 0; i--)
printf ("%08x", X->word[i]);
puts ("");
}
#endif
#if 0
static void
print_point (const ac *X)
{
int i;
#ifdef PRINT_OUT_TABLE_AS_C
fputs (" { {{{ ", stdout);
for (i = 0; i < 4; i++)
printf ("0x%08x, ", X->x->word[i]);
fputs ("\n ", stdout);
for (; i < 7; i++)
printf ("0x%08x, ", X->x->word[i]);
printf ("0x%08x }}},\n", X->x->word[i]);
fputs (" {{{ ", stdout);
for (i = 0; i < 4; i++)
printf ("0x%08x, ", X->y->word[i]);
fputs ("\n ", stdout);
for (; i < 7; i++)
printf ("0x%08x, ", X->y->word[i]);
printf ("0x%08x }}} },\n", X->y->word[i]);
#else
puts ("--");
for (i = 7; i >= 0; i--)
printf ("%08x", X->x->word[i]);
puts ("");
for (i = 7; i >= 0; i--)
printf ("%08x", X->y->word[i]);
puts ("");
puts ("--");
#endif
}
static void
print_point_ptc (const ptc *X)
{
int i;
puts ("---");
for (i = 7; i >= 0; i--)
printf ("%08x", X->x->word[i]);
puts ("");
for (i = 7; i >= 0; i--)
printf ("%08x", X->y->word[i]);
puts ("");
for (i = 7; i >= 0; i--)
printf ("%08x", X->z->word[i]);
puts ("");
puts ("---");
}
#endif
#ifndef TESTING_EDDSA
static void power_2 (ac *A, ptc *a, int N)
{
int i;
for (i = 0; i < N; i++)
ed_double_25638 (a, a);
ptc_to_ac_25519 (A, a);
}
static void print_table (ac *a0001, ac *a0010, ac *a0100, ac *a1000)
{
int i;
ptc a[1];
ac x[1];
for (i = 1; i < 16; i++)
{
/* A := Identity Element */
memset (a, 0, sizeof (ptc));
a->y->word[0] = 1;
a->z->word[0] = 1;
if ((i & 1))
ed_add_25638 (a, a, a0001);
if ((i & 2))
ed_add_25638 (a, a, a0010);
if ((i & 4))
ed_add_25638 (a, a, a0100);
if ((i & 8))
ed_add_25638 (a, a, a1000);
ptc_to_ac_25519 (x, a);
print_point (x);
}
fputs ("\n", stdout);
}
static void compute_and_print_table (ac *a0001, ac *a0010, ac *a0100, ac *a1000)
{
ptc a[1];
memcpy (a, a0001, sizeof (ac));
memset (a->z, 0, sizeof (bn256));
a->z->word[0] = 1;
power_2 (a0010, a, 63);
power_2 (a0100, a, 63);
power_2 (a1000, a, 63);
print_table (a0001, a0010, a0100, a1000);
}
#endif
int
main (int argc, char *argv[])
{
#ifdef TESTING_EDDSA
uint8_t hash[64];
bn256 a[1];
uint8_t r_s[64];
bn256 pk[1];
bn256 *r, *s;
const bn256 sk[1] = {
{{ 0x9db1619d, 0x605afdef, 0xf44a84ba, 0xc42cec92,
0x69c54944, 0x1969327b, 0x03ac3b70, 0x607fae1c }} };
const bn256 r_expected[1] = {
{{ 0x004356e5, 0x72ac60c3, 0xcce28690, 0x8a826e80,
0x1e7f8784, 0x74d9e5b8, 0x65e073d8, 0x55014922 }} };
const bn256 s_expected[1] = {
{{ 0x1582b85f, 0xac3ba390, 0x70391ec6, 0x6bb4f91c,
0xf0f55bd2, 0x24be5b59, 0x43415165, 0x0b107a8e }} };
r = (bn256 *)r_s;
s = (bn256 *)(r_s+32);
sha512 ((uint8_t *)sk, sizeof (bn256), hash);
hash[0] &= 248;
hash[31] &= 127;
hash[31] |= 64;
memcpy (a, hash, sizeof (bn256));
eddsa_public_key_25519 (pk, a);
eddsa_sign_25519 ((const uint8_t *)"", 0, r_s, a, hash+32, pk);
if (memcmp (r, r_expected, sizeof (bn256)) != 0
|| memcmp (s, s_expected, sizeof (bn256)) != 0)
{
print_bn256 (r);
print_bn256 (s);
return 1;
}
#else
ac a0001[1], a0010[1], a0100[1], a1000[1];
ptc a[1];
memcpy (a, G, sizeof (ptc));
ptc_to_ac_25519 (a0001, a);
compute_and_print_table (a0001, a0010, a0100, a1000);
memcpy (a, a0001, sizeof (ac));
memset (a->z, 0, sizeof (bn256));
a->z->word[0] = 1;
power_2 (a0001, a, 21);
compute_and_print_table (a0001, a0010, a0100, a1000);
memcpy (a, a0001, sizeof (ac));
memset (a->z, 0, sizeof (bn256));
a->z->word[0] = 1;
power_2 (a0001, a, 21);
compute_and_print_table (a0001, a0010, a0100, a1000);
#endif
return 0;
}
#endif

824
ecc-ed448.c Normal file
View File

@ -0,0 +1,824 @@
/* -*- coding: utf-8 -*-
* ecc-ed448.c - Elliptic curve computation for
* the twisted Edwards curve: -x^2 + y^2 = 1 + d*x^2*y^2
* d = -39081
*
* Copyright (C) 2021 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* IMPLEMENTATION NOTE
*
* (0) We assume that the processor has no cache, nor branch target
* prediction. Thus, we don't avoid indexing by secret value.
* We don't avoid conditional jump if both cases have same timing,
* either.
*
* (1) We use fixed base comb multiplication. Scalar is 448-bit.
* We use two tables, and a table has 16 points.
* Window size W = 4-bit, E = 56.
*
*/
#include <stdint.h>
#include <string.h>
#include "p448.h"
#include "shake256.h"
#define C_WORDS 7
#define BN448_WORDS 14
#define BN690_WORDS 22
#define BN896_WORDS 28
#define BN912_WORDS 29 /* 28.5 */
typedef struct bn448 {
uint32_t word[ BN448_WORDS ]; /* Little endian */
} bn448;
typedef struct bn896 {
uint32_t word[ BN896_WORDS ]; /* Little endian */
} bn896;
typedef struct bn912 {
uint32_t word[ BN912_WORDS ]; /* Little endian */
} bn912;
static const bn448 M[1] = {{{
0xab5844f3, 0x2378c292, 0x8dc58f55, 0x216cc272,
0xaed63690, 0xc44edb49, 0x7cca23e9, 0xffffffff,
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
0xffffffff, 0x3fffffff
}}};
static const uint32_t C[C_WORDS] = {
0x54a7bb0d, 0xdc873d6d, 0x723a70aa, 0xde933d8d,
0x5129c96f, 0x3bb124b6, 0x8335dc16
};
static uint32_t
bn448_add (bn448 *X, const bn448 *A, const bn448 *B)
{
int i;
uint32_t v;
uint32_t carry = 0;
uint32_t *px;
const uint32_t *pa, *pb;
px = X->word;
pa = A->word;
pb = B->word;
for (i = 0; i < BN448_WORDS; i++)
{
v = *pb;
*px = *pa + carry;
carry = (*px < carry);
*px += v;
carry += (*px < v);
px++;
pa++;
pb++;
}
return carry;
}
static uint32_t
bn448_sub (bn448 *X, const bn448 *A, const bn448 *B)
{
int i;
uint32_t v;
uint32_t borrow = 0;
uint32_t *px;
const uint32_t *pa, *pb;
px = X->word;
pa = A->word;
pb = B->word;
for (i = 0; i < BN448_WORDS; i++)
{
uint32_t borrow0 = (*pa < borrow);
v = *pb;
*px = *pa - borrow;
borrow = (*px < v) + borrow0;
*px -= v;
px++;
pa++;
pb++;
}
return borrow;
}
static void
bnX_mul_C (uint32_t *r, const uint32_t *q, int q_size)
{
int i, j, k;
int i_beg, i_end;
uint32_t r0, r1, r2;
r0 = r1 = r2 = 0;
for (k = 0; k <= q_size + C_WORDS - 2; k++)
{
if (q_size < C_WORDS)
if (k < q_size)
{
i_beg = 0;
i_end = k;
}
else
{
i_beg = k - q_size + 1;
i_end = k;
if (i_end > C_WORDS - 1)
i_end = C_WORDS - 1;
}
else
if (k < C_WORDS)
{
i_beg = 0;
i_end = k;
}
else
{
i_beg = k - C_WORDS + 1;
i_end = k;
if (i_end > q_size - 1)
i_end = q_size - 1;
}
for (i = i_beg; i <= i_end; i++)
{
uint64_t uv;
uint32_t u, v;
uint32_t carry;
j = k - i;
if (q_size < C_WORDS)
uv = ((uint64_t)q[j])*((uint64_t)C[i]);
else
uv = ((uint64_t)q[i])*((uint64_t)C[j]);
v = uv;
u = (uv >> 32);
r0 += v;
carry = (r0 < v);
r1 += carry;
carry = (r1 < carry);
r1 += u;
carry += (r1 < u);
r2 += carry;
}
r[k] = r0;
r0 = r1;
r1 = r2;
r2 = 0;
}
r[k] = r0;
}
/* X <= X + A when COND!=0 */
/* X <= X when COND==0 */
static void
bn448_add_cond (bn448 *X, const bn448 *A, int cond)
{
int i;
uint32_t v;
uint32_t carry = 0;
uint32_t *px;
const uint32_t *pa;
uint32_t mask = -(!!cond);
px = X->word;
pa = A->word;
for (i = 0; i < BN448_WORDS; i++)
{
v = *px;
*px = (*pa & mask) + carry;
carry = (*px < carry);
*px += v;
carry += (*px < v);
px++;
pa++;
}
}
/* X <= X + A mod M */
static void
bn448_addm (bn448 *X, const bn448 *A)
{
uint32_t borrow;
bn448_add (X, X, A);
borrow = bn448_sub (X, X, M);
bn448_add_cond (X, M, borrow);
}
/**
* @brief R = A mod M (using M=2^446-C) (Barret reduction)
*
* See HAC 14.47.
*/
void
mod_reduce_M (bn448 *R, const bn912 *A)
{
uint32_t q[BN448_WORDS+1];
uint32_t tmp[BN690_WORDS];
bn448 r[1];
uint32_t carry, next_carry;
int i;
/* Q = A / 2^446 *//* 466-bit */
/* Upper half of A->word[28] must be zero. */
q[14] = (A->word[28] << 2) | (A->word[27] >> 30);
carry = A->word[27] & 0x3fffffff;
for (i = BN448_WORDS - 1; i >= 0; i--)
{
next_carry = A->word[i+13] & 0x3fffffff;
q[i] = (A->word[i+13] >> 30) | (carry << 2);
carry = next_carry;
}
memcpy (R, A, sizeof (bn448));
R->word[13] &= 0x3fffffff;
/* Q_size: 15 *//* 466-bit */
bnX_mul_C (tmp, q, 15); /* TMP = Q*C *//* 690-bit */
/* Q = tmp / 2^446 *//* 244-bit */
carry = tmp[21];
for (i = 7; i >= 0; i--)
{
next_carry = tmp[i+13] & 0x3fffffff;
q[i] = (tmp[i+13] >> 30) | (carry << 2);
carry = next_carry;
}
/* R' = tmp % 2^446 */
memcpy (r, tmp, sizeof (bn448));
r->word[13] &= 0x3fffffff;
/* R += R' */
bn448_addm (R, r);
/* Q_size: 8 *//* 244-bit */
bnX_mul_C (tmp, q, 8); /* TMP = Q*C *//* 468-bit */
/* Q = tmp / 2^446 *//* 22-bit */
carry = tmp[14];
q[0] = (tmp[13] >> 30) | (carry << 2);
/* R' = tmp % 2^446 */
memcpy (r, tmp, sizeof (bn448));
r->word[13] &= 0x3fffffff;
/* R += R' */
bn448_addm (R, r);
/* Q_size: 1 */
bnX_mul_C (tmp, q, 1); /* TMP = Q*C *//* 246-bit */
/* R' = tmp % 2^446 */
memset (((uint8_t *)r)+(sizeof (uint32_t)*8), 0, sizeof (uint32_t)*6);
memcpy (r, tmp, sizeof (uint32_t)*8);
/* R += R' */
bn448_addm (R, r);
}
static void
bn448_mul (bn896 *X, const bn448 *A, const bn448 *B)
{
int i, j, k;
int i_beg, i_end;
uint32_t r0, r1, r2;
r0 = r1 = r2 = 0;
for (k = 0; k <= (BN448_WORDS - 1)*2; k++)
{
if (k < BN448_WORDS)
{
i_beg = 0;
i_end = k;
}
else
{
i_beg = k - BN448_WORDS + 1;
i_end = BN448_WORDS - 1;
}
for (i = i_beg; i <= i_end; i++)
{
uint64_t uv;
uint32_t u, v;
uint32_t carry;
j = k - i;
uv = ((uint64_t )A->word[i])*((uint64_t )B->word[j]);
v = uv;
u = (uv >> 32);
r0 += v;
carry = (r0 < v);
r1 += carry;
carry = (r1 < carry);
r1 += u;
carry += (r1 < u);
r2 += carry;
}
X->word[k] = r0;
r0 = r1;
r1 = r2;
r2 = 0;
}
X->word[k] = r0;
}
static const p448_t nGx0[16] = {
{ { 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
{ { 0x070cc05e, 0x026a82bc, 0x00938e26, 0x080e18b0,
0x0511433b, 0x0f72ab66, 0x0412ae1a, 0x0a3d3a46,
0x0a6de324, 0x00f1767e, 0x04657047, 0x036da9e1,
0x05a622bf, 0x0ed221d1, 0x066bed0d, 0x04f1970c } },
{ { 0x0464238e, 0x00079817, 0x00d381ca, 0x02110302,
0x0d9f01b5, 0x01cc4c6e, 0x05a131b1, 0x05e35dc5,
0x006944eb, 0x0b61848d, 0x029631a3, 0x083792a0,
0x0afca0dd, 0x0be1017f, 0x0782fcbb, 0x070aaa01 } },
{ { 0x0e7661f9, 0x0b2f9f62, 0x009fae89, 0x03b99803,
0x066014d2, 0x067900ef, 0x06556c10, 0x0c8eacf3,
0x0ad4a82e, 0x020a44d0, 0x00572f1c, 0x0e7819e7,
0x0fd08cdf, 0x0c0ed140, 0x09aee1da, 0x0a16934a } },
{ { 0x091780c7, 0x0a7ea989, 0x0d2476b6, 0x004e4ecc,
0x0c494b68, 0x00af9f58, 0x0dee64fd, 0x0e0f269f,
0x0021bd26, 0x085a61f6, 0x0b5d284b, 0x0c265c35,
0x03775afd, 0x058755ea, 0x02ecf2c6, 0x0617f174 } },
{ { 0x067f4947, 0x0dbf4eb6, 0x0b8716d9, 0x02206a2a,
0x0e7cad5a, 0x04a148b0, 0x0e483133, 0x0fbf12cd,
0x0c6458f7, 0x0e022d5a, 0x01b7e39d, 0x0a60afe6,
0x05a5208c, 0x0c62f458, 0x03311553, 0x0a08a4c3 } },
{ { 0x0054a90d, 0x0ad5dc54, 0x00ac9fd6, 0x097f2af4,
0x0f4ddbc7, 0x01b0f7b3, 0x0324ce0b, 0x01d5d092,
0x0cd2798f, 0x08cb96e2, 0x0957bc39, 0x0bd045b5,
0x0f76fbfb, 0x046308a9, 0x0ef679ce, 0x0c86d628 } },
{ { 0x0d5d9262, 0x0f251539, 0x0711a956, 0x0240708f,
0x04a0b0bc, 0x07f7e4dd, 0x055b70a8, 0x065dd24f,
0x07ef8979, 0x0e83cec7, 0x09589db8, 0x0f1db2d1,
0x09d93037, 0x0fcc7e8a, 0x04e0b8f4, 0x0cb99f0b } },
{ { 0x04acea57, 0x06f24100, 0x0da68597, 0x0dace1c6,
0x050ce77f, 0x0ea7dd41, 0x01585884, 0x01aecb84,
0x0ea4a85c, 0x092ff208, 0x088eebd2, 0x0de9433c,
0x03f4d289, 0x053cd318, 0x026539af, 0x03970858 } },
{ { 0x0d229665, 0x06e9fd2b, 0x0878dd51, 0x049345aa,
0x0f45bacf, 0x0ccde72a, 0x0be16b6f, 0x0bc249d1,
0x0448a61d, 0x0a25bae9, 0x0d773878, 0x0c93b6ea,
0x02cda508, 0x055f708a, 0x08cf49e6, 0x0fa56852 } },
{ { 0x093bfef9, 0x07bec8db, 0x0fafda3d, 0x0ce4dcdc,
0x06f62ed7, 0x0a75c872, 0x07b3dadd, 0x0c39ac92,
0x0f926d90, 0x0ae1b8d1, 0x048da0a9, 0x0d7dbeca,
0x02a52b3b, 0x0ec13f74, 0x0d4c5ce2, 0x02071cee } },
{ { 0x05a644a6, 0x0e56b0a9, 0x0be6360b, 0x01ecf90e,
0x023b73a8, 0x0c3bbcf7, 0x0292054b, 0x05417d25,
0x07b91b46, 0x0ca1ea05, 0x07ea6c44, 0x01560b21,
0x04f12989, 0x0463cd2a, 0x03d7e086, 0x0092781c } },
{ { 0x0d59796d, 0x0ce08d7e, 0x055bc822, 0x0e464443,
0x0d243cc4, 0x0542002f, 0x098259b3, 0x044fc576,
0x012781de, 0x08650550, 0x0055e6b4, 0x0137f762,
0x0fbf007e, 0x0a391ccc, 0x039fe6f6, 0x0a9c9ad3 } },
{ { 0x01ca2765, 0x0ccddbb0, 0x0563b46c, 0x05d18f4c,
0x0462647e, 0x02ff700d, 0x0822dc83, 0x0670b143,
0x00013963, 0x01627d78, 0x055dbfb9, 0x0435f413,
0x063d41e8, 0x066c95cd, 0x0c797bba, 0x08e27dfb } },
{ { 0x03da4531, 0x01ff4dd6, 0x0cd39a3c, 0x02d0de4c,
0x0bc9da8d, 0x0003561e, 0x033e1e9a, 0x001eea00,
0x078bf710, 0x05458c53, 0x0f56338e, 0x069043ab,
0x061ffba0, 0x0637cf41, 0x039fb551, 0x0fc09757 } },
{ { 0x0256141f, 0x0f1e0e38, 0x00ab2673, 0x0efd5f47,
0x0af4a4af, 0x0b749116, 0x0ac6540b, 0x04242f82,
0x0abaf195, 0x0b26730c, 0x0d06842d, 0x076fbe60,
0x0580cad8, 0x02613d91, 0x0b568ae0, 0x0c2e5b1d } }
};
static const p448_t nGy0[16] = {
{ { 0x00000001, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
{ { 0x0230fa14, 0x008795bf, 0x07c8ad98, 0x0132c4ed,
0x09c4fdbd, 0x01ce67c3, 0x073ad3ff, 0x005a0c2d,
0x07789c1e, 0x0a398408, 0x0a73736c, 0x0c7624be,
0x003756c9, 0x02488762, 0x016eb6bc, 0x0693f467 } },
{ { 0x099945e7, 0x0c63b7a0, 0x0c4486c1, 0x0e9164ec,
0x0885f2c1, 0x0b133e35, 0x0c99ae02, 0x0186f0d3,
0x02bf53e6, 0x02fca492, 0x048a02bc, 0x0f922aa2,
0x00dd3dca, 0x04fe6490, 0x0f6a8207, 0x0e8c313f } },
{ { 0x0579a4e2, 0x0a1ffe8b, 0x0ce472b4, 0x01d006b3,
0x089def96, 0x07c8f689, 0x0a32ae93, 0x079d7bd1,
0x03a02760, 0x0ebb4776, 0x05b4c55e, 0x019b3c6c,
0x07da436f, 0x066ff782, 0x0659536d, 0x0ee40076 } },
{ { 0x05ec556a, 0x050109e2, 0x0fd57e39, 0x0235366b,
0x044b6b2e, 0x07b3c976, 0x0b2b7b9c, 0x0f7f9e82,
0x00ec6409, 0x0b6196ab, 0x00a20d9e, 0x088f1d16,
0x0586f761, 0x0e3be3b4, 0x0e26395d, 0x09983c26 } },
{ { 0x0fab8e56, 0x0ded288e, 0x057277e6, 0x0a4e6f4e,
0x0e949681, 0x0a2a4c4f, 0x0721fdb3, 0x0508a46c,
0x0fb44de2, 0x0f98049e, 0x02fb0f31, 0x071f3724,
0x09067763, 0x0d3fbbb3, 0x0a83faaa, 0x0696ec4a } },
{ { 0x07a04bb0, 0x0f52ae70, 0x0ae14cdb, 0x0784d14b,
0x034acc37, 0x09aa3869, 0x09703f7b, 0x08f79c87,
0x0264026c, 0x0859cde5, 0x0486b035, 0x0b2a45f7,
0x03d5144b, 0x0809740f, 0x0416dc87, 0x0dcf324d } },
{ { 0x0a0c8bc7, 0x04125cec, 0x0eac3f20, 0x0d30ff7e,
0x029ad678, 0x06901f05, 0x04805ff1, 0x033c307d,
0x049d6a79, 0x080f0710, 0x02dece6c, 0x0d1ba22b,
0x0778cccb, 0x01692a0b, 0x02df78fb, 0x0f8c02d3 } },
{ { 0x0b827d87, 0x04b57599, 0x03d77638, 0x0dc82ac0,
0x052f6e61, 0x06943366, 0x0ad5e8a6, 0x0b8fc4b0,
0x0f388642, 0x01b6f7dc, 0x0a74dd57, 0x06f24533,
0x041750cf, 0x0c669378, 0x028a37af, 0x006757eb } },
{ { 0x080128d5, 0x0ef186a8, 0x04a54843, 0x01ceb43b,
0x045be148, 0x0c112a42, 0x01ac9412, 0x0621b93a,
0x05e16552, 0x0a2ca24f, 0x086301c0, 0x0cf3fecf,
0x05c2e2e0, 0x05108805, 0x09e9d8ab, 0x0d2ba341 } },
{ { 0x02138911, 0x0f0d3e4c, 0x0c1a371b, 0x062382ce,
0x05b3a392, 0x09d954e7, 0x0517d2a1, 0x0047d71a,
0x07f70073, 0x09cd1733, 0x0efc3aea, 0x0549d0d1,
0x0df78457, 0x0666e074, 0x0a48e084, 0x0f67e924 } },
{ { 0x0b3114fe, 0x073bec50, 0x0e8b6172, 0x01c5e7b6,
0x0e896bcc, 0x0a1c3ae1, 0x0bcd8cab, 0x0bb3f870,
0x07e9fa9d, 0x0eea8546, 0x0042e2cf, 0x056431f0,
0x0469e8d2, 0x08eb9b9c, 0x0a9adf2c, 0x06856458 } },
{ { 0x07b2cfdd, 0x01855530, 0x073bd43a, 0x01816246,
0x08897062, 0x02f82d12, 0x03563816, 0x06517857,
0x0394a8c7, 0x0529bf2e, 0x075a3141, 0x0660c4f2,
0x018e5a16, 0x0787c8ad, 0x045b679e, 0x0abaec01 } },
{ { 0x06d87d9e, 0x07c9fabb, 0x03b2a99d, 0x0673b28a,
0x068816ee, 0x0efb205e, 0x0dd5e3d5, 0x03d21920,
0x07544f4d, 0x085f40c2, 0x06fb538d, 0x057d045b,
0x05470e4e, 0x028a93c3, 0x063adfd4, 0x0d1cf7a5 } },
{ { 0x06699694, 0x0c83c837, 0x0386dade, 0x0621103f,
0x0f247dc3, 0x06058f43, 0x0aec07c3, 0x0b1ac29a,
0x0bde5d50, 0x06e35e33, 0x078fd31c, 0x0516263c,
0x00a9d127, 0x04a13379, 0x078bec6e, 0x0f39316a } },
{ { 0x0e26ea19, 0x05ecf40e, 0x03bdf1b5, 0x07c284a0,
0x06f461fa, 0x08393462, 0x064a69aa, 0x07d4f6a5,
0x06e88ea4, 0x023059e9, 0x0f92bd0b, 0x0c4a8035,
0x0c5c44a2, 0x0fccec22, 0x07f57ea1, 0x0598207c } }
};
static const p448_t nGx1[16] = {
{ { 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
{ { 0x0528af6f, 0x078c6f13, 0x094b74d9, 0x00001fe2,
0x001aab44, 0x0ae77425, 0x0ef0039c, 0x07cbe937,
0x00fa2a67, 0x0af3e4f0, 0x0da1378e, 0x0e28175f,
0x08ccd90e, 0x072adeed, 0x000af22f, 0x016a8ce1 } },
{ { 0x0fa0459e, 0x0f31f53f, 0x0315cd6b, 0x0f8742a1,
0x0ae64e97, 0x0abe2f50, 0x09b9da48, 0x0bd78741,
0x051e526e, 0x04521a33, 0x0e10ba45, 0x0fa05935,
0x0e8f903c, 0x05c947e1, 0x05a754ee, 0x00aa47d1 } },
{ { 0x00d9a33b, 0x0284f76f, 0x0e4d41e7, 0x09461141,
0x0cc79344, 0x015371b9, 0x03dd8bdd, 0x0173f667,
0x053f866b, 0x0c0d0f83, 0x030b45ea, 0x08b7d59b,
0x0044dc82, 0x02b4cdec, 0x094fa772, 0x0e245b21 } },
{ { 0x04ddc8a8, 0x02fe182d, 0x0ac056bf, 0x088d6e79,
0x00e41e4e, 0x0c3ff2d1, 0x02c3679f, 0x032ec7f9,
0x04e61051, 0x03561f09, 0x06c6250a, 0x04553f5a,
0x0dd25c5b, 0x02b765ef, 0x06a1cd7f, 0x0e3a40a2 } },
{ { 0x05e1f4b2, 0x0e9485c4, 0x070a1e6b, 0x01d85e53,
0x077730a7, 0x0db61fa9, 0x050d418e, 0x0201a6bd,
0x02774433, 0x0e78a475, 0x0622ea3a, 0x016424e5,
0x0d5b9631, 0x01c7734d, 0x0f5064f2, 0x0c7586d3 } },
{ { 0x0af6151d, 0x0c3ed603, 0x0aa19b93, 0x05a5e4a6,
0x0536ff03, 0x07e465ce, 0x0b0be710, 0x0bbb36bf,
0x09249bff, 0x0d15454d, 0x03736654, 0x0ba934d9,
0x0370dc86, 0x0675c04e, 0x0d86eb3b, 0x06cd21cb } },
{ { 0x030c7ce7, 0x04217221, 0x0e9dba4d, 0x0ec314cd,
0x05439062, 0x0d7196cd, 0x0dd96166, 0x0b8295cd,
0x0c15796f, 0x0c767da7, 0x00ab2036, 0x059120e7,
0x0b7d07ec, 0x0e1562a9, 0x0231cdd9, 0x07d5c89f } },
{ { 0x01a82a12, 0x091a5884, 0x080f3a62, 0x0a754175,
0x0f73417a, 0x0399009f, 0x00a8c5cd, 0x02db1fb9,
0x0c046d51, 0x082c8912, 0x08f18274, 0x00a3f577,
0x026ccae2, 0x02ad0ede, 0x08a4e9c2, 0x07d6bd8b } },
{ { 0x0afd28b4, 0x02b7b7be, 0x0298d67e, 0x0e834401,
0x04b11493, 0x0e070d60, 0x063ce6fb, 0x04b67725,
0x0a0cfb04, 0x0d3a0f67, 0x0f08f1b2, 0x0debe82e,
0x0b402b9e, 0x07114482, 0x0b307043, 0x0af532e6 } },
{ { 0x049ab457, 0x0f6483c2, 0x0818ac81, 0x05aced0a,
0x0a900e3a, 0x080916bc, 0x02948675, 0x0145adb9,
0x0d8b7821, 0x04fe2b0e, 0x0b1a62cc, 0x0a9e1bce,
0x096c2408, 0x048f1f80, 0x0ac552fe, 0x0d17e7a0 } },
{ { 0x08ce3344, 0x0ea48915, 0x0434ae70, 0x0c6cf019,
0x0c48f5d2, 0x089d3c0f, 0x0ca7aa7e, 0x0c550a00,
0x017fb3ab, 0x09f8b49f, 0x024844a0, 0x0366a6d5,
0x0ceb4a83, 0x0f1f5bf4, 0x03b782f0, 0x099fd2f7 } },
{ { 0x052daf76, 0x038fbbd7, 0x0bced01d, 0x0ffb0a8b,
0x07c6bd6c, 0x0dc3b0ff, 0x041d595c, 0x03814ee7,
0x01941d44, 0x0e1f8343, 0x0f89b18d, 0x0c083601,
0x0e52ec62, 0x0fc338ff, 0x0e971788, 0x04601008 } },
{ { 0x0add862e, 0x0e8c3a8e, 0x033cea23, 0x06d00cf1,
0x0cdc039a, 0x0d7bda40, 0x0e0a2ac3, 0x04750dcb,
0x0bec4388, 0x0a1bb0bc, 0x0d20c0f9, 0x077a4a7b,
0x0b9e1f0b, 0x02ff072d, 0x07bd3e06, 0x0bd796d7 } },
{ { 0x08e321b4, 0x08757de1, 0x0151699c, 0x06ba6bd4,
0x0a156df0, 0x02ec93a1, 0x0dad4f9e, 0x04e547c5,
0x0ee9310d, 0x01dcc8bf, 0x0f7b5016, 0x0355f710,
0x0ce8f36d, 0x0389d7a9, 0x02b8056d, 0x0ff83804 } },
{ { 0x060f6dcf, 0x0dcaa234, 0x0285b23d, 0x0ec8d56f,
0x083dac2b, 0x01042255, 0x08e1bed7, 0x0c3fe788,
0x0832c0af, 0x07258b0e, 0x02b2affc, 0x0a901bdb,
0x0038f36e, 0x01a28d5f, 0x0dbb618d, 0x080838af } }
};
static const p448_t nGy1[16] = {
{ { 0x00000001, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
{ { 0x0cbf63dd, 0x069fae17, 0x09e39e26, 0x06786172,
0x0f827a18, 0x0e92b3d5, 0x08403682, 0x04d75e41,
0x09056a79, 0x001a4fd9, 0x020008f5, 0x089efb2d,
0x0b78ff15, 0x0a2f6918, 0x0a3437f5, 0x0f41c870 } },
{ { 0x0d814825, 0x0b2849ef, 0x05c9968d, 0x09c2a5d2,
0x004e634c, 0x024dbb26, 0x0db38194, 0x033f3a4c,
0x0c8a2b6b, 0x0e04f609, 0x0abbbfdb, 0x0caefd8e,
0x0404498b, 0x0683119a, 0x08b21cbd, 0x024ab7a9 } },
{ { 0x0ede77b3, 0x0043b728, 0x0a043f1d, 0x003cf736,
0x0ab4e700, 0x0d95a612, 0x0c8fe17c, 0x05ccaac2,
0x0177bd28, 0x0dc3bd14, 0x05360c86, 0x0b3d5c96,
0x04ec7e48, 0x01880c26, 0x04bb47c6, 0x0fd5dba8 } },
{ { 0x05d821dd, 0x0b27309b, 0x0c2c17ca, 0x0950fb8d,
0x08fb0d4c, 0x0feed015, 0x0f550179, 0x0762c479,
0x0e095840, 0x0306cf44, 0x0d379e66, 0x084b413a,
0x0bb2e4f1, 0x0d6e5d5a, 0x094b085d, 0x08bc12b7 } },
{ { 0x0b8a16f6, 0x0b4dacd9, 0x003afc96, 0x0000b9b9,
0x03f19cbf, 0x0ab930b8, 0x0b077171, 0x0541f92e,
0x019baa42, 0x08758d9c, 0x0fea31a2, 0x0299b935,
0x081d9e24, 0x03bc7232, 0x09d91676, 0x0fc081c2 } },
{ { 0x02f05282, 0x04ca6fb6, 0x02e9801e, 0x051928b6,
0x0b609dcb, 0x0c6f37b6, 0x06e32803, 0x06617fd7,
0x0166f0bb, 0x07d1bffb, 0x0ac137d4, 0x0bfdebdd,
0x0df8f3cb, 0x0d558ac9, 0x08fabbb4, 0x00217c7c } },
{ { 0x0f5d72ad, 0x04c71050, 0x008880dd, 0x093209a0,
0x07c3fef0, 0x0e1857c5, 0x022b21d2, 0x07584709,
0x0e52fe8a, 0x039aeffa, 0x0a384e66, 0x0bd7c58b,
0x0bfbbfe2, 0x022fc035, 0x0506e447, 0x0bc96411 } },
{ { 0x04b3de44, 0x0aa0d797, 0x096ac9bb, 0x0f8658b9,
0x05f6c334, 0x031e7be2, 0x04df12c9, 0x023836ce,
0x059eb5c9, 0x0029027b, 0x05b8649d, 0x02f22531,
0x0d907162, 0x0a0fdf03, 0x09e80226, 0x0101d9df } },
{ { 0x05237b19, 0x00d0c997, 0x04a2bcdb, 0x0692bae3,
0x0805b9e0, 0x0a0d3a98, 0x08c7dd07, 0x0a253f11,
0x0e19738e, 0x0c0794d0, 0x019812a1, 0x041a8569,
0x025d360c, 0x078e4ebd, 0x07ee8567, 0x0f02e9d6 } },
{ { 0x00548584, 0x0bb1ee61, 0x0549030f, 0x0026e17a,
0x0b4c52fb, 0x0a4e4e61, 0x0a1ca8f9, 0x0339754c,
0x0ee8806f, 0x03d2a45e, 0x0e2028fa, 0x03c44782,
0x0072e42b, 0x03328ae4, 0x0d21c91f, 0x07e98738 } },
{ { 0x0b9618ad, 0x07f781fa, 0x09cf7662, 0x0855bfab,
0x0c316a14, 0x0d98f9ff, 0x07b3046a, 0x0109f273,
0x042cecfe, 0x0cc21cdc, 0x05be5a36, 0x05236b10,
0x058a0700, 0x0ff2cf95, 0x005ad57d, 0x09cbf152 } },
{ { 0x0ebe90d2, 0x049f0de4, 0x02243779, 0x0221424d,
0x09051808, 0x0b52f44b, 0x0bb9c3fb, 0x0a5d64e3,
0x07690354, 0x0d8bf65d, 0x0bc06e3f, 0x05d039f6,
0x033a3443, 0x04e11c79, 0x04147a83, 0x06a7e42c } },
{ { 0x082e4773, 0x00d276be, 0x0e1b9057, 0x0e9dd324,
0x0369bc97, 0x0b3181ef, 0x002f04fa, 0x01d08726,
0x07c2c5d3, 0x0bf49cbf, 0x09ecb59b, 0x098eae7e,
0x02e09293, 0x052e08b6, 0x0c40f3e6, 0x04096c37 } },
{ { 0x06074e1f, 0x07bc94ed, 0x0790175a, 0x040b2a81,
0x0e307782, 0x0b7958e8, 0x089ff273, 0x07ed27c6,
0x026db869, 0x0b6a32f8, 0x03d2e15c, 0x00446ef9,
0x0777e1ac, 0x0492d2de, 0x01b69b63, 0x06b8dbab } },
{ { 0x07e98bea, 0x0e7c9e7a, 0x02e17335, 0x09302c64,
0x0acc1e93, 0x05dcdcd8, 0x04d90baa, 0x05982bae,
0x0c686ed6, 0x07c08c6c, 0x0fce2c72, 0x04dd3cce,
0x01dc8f12, 0x029ca465, 0x0161cbd7, 0x09324c0a } }
};
static void
compute_kG_448 (uint8_t *out, const uint32_t k[16])
{
int i;
p448_t x0[1], y0[1], z0[1]; /* P0 */
p448_t tmp0[1], tmp1[1];
/* P0 <= O */
memset (x0, 0, sizeof (p448_t));
memset (y0, 0, sizeof (p448_t));
memset (z0, 0, sizeof (p448_t));
y0->limb[0] = 1;
z0->limb[0] = 1;
for (i = 0; i < 56; i++)
{
p448_t b[1], c[1], d[1];
p448_t e[1], f[1], g[1], h[1];
int index0, index1;
if (i < 28)
{
int i0 = 28 - i - 1;
index0 = ((k[1] >> i0) & 1) | (((k[5] >> i0) & 1)<<1)
| (((k[ 9] >> i0) & 1)<<2) | (((k[13] >> i0) & 1)<<3);
index1 = ((k[3] >> i0) & 1) | (((k[7] >> i0) & 1)<<1)
| (((k[11] >> i0) & 1)<<2) | (((k[15] >> i0) & 1)<<3);
}
else
{
int i0 = 56 - i - 1;
index0 = ((k[0] >> i0) & 1) | (((k[4] >> i0) & 1)<<1)
| (((k[ 8] >> i0) & 1)<<2) | (((k[12] >> i0) & 1)<<3);
index1 = ((k[2] >> i0) & 1) | (((k[6] >> i0) & 1)<<1)
| (((k[10] >> i0) & 1)<<2) | (((k[14] >> i0) & 1)<<3);
}
/* Point double P0' <= P0 + P0 */
p448_add (tmp0, x0, y0);
p448_sqr (b, tmp0);
p448_sqr (c, x0);
p448_sqr (d, y0);
p448_add (e, c, d);
p448_sqr (h, z0);
p448_add (tmp0, h, h);
p448_sub (tmp1, e, tmp0);
p448_sub (tmp0, b, e);
p448_mul (x0, tmp0, tmp1);
p448_sub (tmp0, c, d);
p448_mul (y0, e, tmp0);
p448_mul (z0, e, tmp1);
/*
B = (X1+Y1)^2
C = X1^2
D = Y1^2
E = C+D
H = Z1^2
J = E-2*H
X3 = (B-E)*J
Y3 = E*(C-D)
Z3 = E*J
*/
/* Point addition P0' <= P0 + [v0(index0)]G */
p448_sqr (b, z0);
p448_mul (c, x0, &nGx0[index0]);
p448_mul (d, y0, &nGy0[index0]);
p448_mul (tmp0, c, d);
p448_mul_39081 (e, tmp0);
p448_add (f, b, e);
p448_sub (g, b, e);
p448_add (tmp0, x0, y0);
p448_add (tmp1, &nGx0[index0], &nGy0[index0]);
p448_mul (h, tmp0, tmp1);
p448_sub (tmp0, h, c);
p448_sub (tmp1, tmp0, d);
p448_mul (tmp0, f, tmp1);
p448_mul (x0, z0, tmp0);
p448_sub (tmp0, d, c);
p448_mul (tmp1, g, tmp0);
p448_mul (y0, z0, tmp1);
p448_mul (z0, f, g);
/*
A = Z1*Z2
B = A^2
C = X1*X2
D = Y1*Y2
E = d*C*D
F = B-E
G = B+E
H = (X1+Y1)*(X2+Y2)
X3 = A*F*(H-C-D)
Y3 = A*G*(D-C)
Z3 = F*G
*/
/* Point addition P0' <= P0 + [v1(index1)]G */
p448_sqr (b, z0);
p448_mul (c, x0, &nGx1[index1]);
p448_mul (d, y0, &nGy1[index1]);
p448_mul (tmp0, c, d);
p448_mul_39081 (e, tmp0);
p448_add (f, b, e);
p448_sub (g, b, e);
p448_add (tmp0, x0, y0);
p448_add (tmp1, &nGx1[index1], &nGy1[index1]);
p448_mul (h, tmp0, tmp1);
p448_sub (tmp0, h, c);
p448_sub (tmp1, tmp0, d);
p448_mul (tmp0, f, tmp1);
p448_mul (x0, z0, tmp0);
p448_sub (tmp0, d, c);
p448_mul (tmp1, g, tmp0);
p448_mul (y0, z0, tmp1);
p448_mul (z0, f, g);
}
/* Convert to affine coordinate. */
p448_inv (tmp0, z0);
p448_mul (tmp1, x0, tmp0);
p448_serialize (out, tmp1);
/* EdDSA encoding. */
out[56] = (out[0] & 1) << 7;
p448_mul (tmp1, y0, tmp0);
p448_serialize (out, tmp1);
}
#define SEED_SIZE 57
#define DOM448 (const uint8_t *)"SigEd448"
#define DOM448_LEN 8
int
ed448_sign (uint8_t *out, const uint8_t *input, unsigned int ilen,
const uint8_t *a_in, const uint8_t *seed, const uint8_t *pk)
{
bn448 a[1], k[1], s[1];
shake_context ctx;
const unsigned char x_olen[2] = { 0, 0 };
uint32_t hash[BN912_WORDS];
uint8_t r[57];
uint32_t carry, borrow;
p448_t k_redundant[1];
memset (hash, 0, sizeof (hash));
memcpy (a, a_in, sizeof (bn448));
a->word[13] |= 0x80000000;
a->word[0] &= ~3;
shake256_start (&ctx);
shake256_update (&ctx, DOM448, DOM448_LEN);
shake256_update (&ctx, x_olen, 2);
shake256_update (&ctx, seed, 57);
shake256_update (&ctx, input, ilen);
shake256_finish (&ctx, (uint8_t *)hash, 2*57);
mod_reduce_M (k, (const bn912 *)hash);
p448_deserialize (k_redundant, (uint8_t *)k);
compute_kG_448 (r, (uint32_t *)k_redundant);
shake256_start (&ctx);
shake256_update (&ctx, DOM448, DOM448_LEN);
shake256_update (&ctx, x_olen, 2);
shake256_update (&ctx, r, 57);
shake256_update (&ctx, pk, 57);
shake256_update (&ctx, input, ilen);
shake256_finish (&ctx, (uint8_t *)hash, 2*57);
mod_reduce_M (s, (const bn912 *)hash);
memset (hash, 0, sizeof (hash));
bn448_mul ((bn896 *)hash, s, a);
mod_reduce_M (s, (const bn912 *)hash);
carry = bn448_add (s, s, k);
borrow = bn448_sub (s, s, M);
bn448_add_cond (s, M, (borrow && !carry));
memcpy (out, r, 57);
memcpy (out+57, s, 56);
out[114-1] = 0;
return 0;
}
void
ed448_compute_public (uint8_t *pk, const uint8_t *a_in)
{
p448_t a[1];
p448_deserialize (a, a_in);
a->limb[15] |= 0x08000000;
a->limb[0] &= ~3;
compute_kG_448 (pk, (uint32_t *)a);
}

226
ecc-mont.c Normal file
View File

@ -0,0 +1,226 @@
/* -*- coding: utf-8 -*-
* ecc-mont.c - Elliptic curve computation for
* the Montgomery curve: y^2 = x^3 + 486662*x^2 + x.
*
* Copyright (C) 2014, 2015, 2017 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdint.h>
#include <string.h>
#include "bn.h"
#include "mod25638.h"
#include "mod.h"
/*
* References:
*
* [1] D. J. Bernstein. Curve25519: new Diffie-Hellman speed records.
* Proceedings of PKC 2006, to appear.
* http://cr.yp.to/papers.html#curve25519. Date: 2006.02.09.
*
* [2] D. J. Bernstein. Can we avoid tests for zero in fast
* elliptic-curve arithmetic?
* http://cr.yp.to/papers.html#curvezero. Date: 2006.07.26.
*
*/
/*
* IMPLEMENTATION NOTE
*
* (0) We assume that the processor has no cache, nor branch target
* prediction. Thus, we don't avoid indexing by secret value.
* We don't avoid conditional jump if both cases have same timing,
* either.
*
* (1) We use Radix-32 field arithmetic. It's a representation like
* 2^256-38, but it's more redundant. For example, "1" can be
* represented in three ways in 256-bit: 1, 2^255-18, and
* 2^256-37.
*
* (2) We use Montgomery double-and-add.
*
*/
#ifndef BN256_C_IMPLEMENTATION
#define ASM_IMPLEMENTATION 0
#endif
/*
*
* 121665 = 0x1db41
* 1 1101 1011 0100 0001
*/
static void
mod25638_mul_121665 (bn256 *x, const bn256 *a)
{
#if ASM_IMPLEMENTATION
#include "muladd_256.h"
const uint32_t *s;
uint32_t *d;
uint32_t w;
uint32_t c;
s = a->word;
d = x->word;
memset (d, 0, sizeof (bn256));
w = 121665;
MULADD_256_ASM (s, d, w, c);
#else
uint32_t c, c1;
bn256 m[1];
c = c1 = bn256_shift (m, a, 6); c += bn256_add (x, a, m);
c1 <<= 2; c1 |= bn256_shift (m, m, 2); c = c + c1 + bn256_add (x, x, m);
c1 <<= 1; c1 |= bn256_shift (m, m, 1); c = c + c1 + bn256_add (x, x, m);
c1 <<= 2; c1 |= bn256_shift (m, m, 2); c = c + c1 + bn256_add (x, x, m);
c1 <<= 1; c1 |= bn256_shift (m, m, 1); c = c + c1 + bn256_add (x, x, m);
c1 <<= 2; c1 |= bn256_shift (m, m, 2); c = c + c1 + bn256_add (x, x, m);
c1 <<= 1; c1 |= bn256_shift (m, m, 1); c = c + c1 + bn256_add (x, x, m);
c1 <<= 1; c1 |= bn256_shift (m, m, 1); c = c + c1 + bn256_add (x, x, m);
#endif
c = bn256_add_uint (x, x, c*38);
x->word[0] += c * 38;
}
typedef struct
{
bn256 x[1];
bn256 z[1];
} pt;
/**
* @brief Process Montgomery double-and-add
*
* With Q0, Q1, DIF (= Q0 - Q1), compute PRD = 2Q0, SUM = Q0 + Q1
* Q0 and Q1 are clobbered.
*
*/
static void
mont_d_and_a (pt *prd, pt *sum, pt *q0, pt *q1, const bn256 *dif_x)
{
mod25638_add (sum->x, q1->x, q1->z);
mod25638_sub (q1->z, q1->x, q1->z);
mod25638_add (prd->x, q0->x, q0->z);
mod25638_sub (q0->z, q0->x, q0->z);
mod25638_mul (q1->x, q0->z, sum->x);
mod25638_mul (q1->z, prd->x, q1->z);
mod25638_sqr (q0->x, prd->x);
mod25638_sqr (q0->z, q0->z);
mod25638_add (sum->x, q1->x, q1->z);
mod25638_sub (q1->z, q1->x, q1->z);
mod25638_mul (prd->x, q0->x, q0->z);
mod25638_sub (q0->z, q0->x, q0->z);
mod25638_sqr (sum->x, sum->x);
mod25638_sqr (sum->z, q1->z);
mod25638_mul_121665 (prd->z, q0->z);
mod25638_mul (sum->z, sum->z, dif_x);
mod25638_add (prd->z, q0->x, prd->z);
mod25638_mul (prd->z, prd->z, q0->z);
}
/**
* @brief RES = x-coordinate of [n]Q
*
* @param N Scalar N (three least significant bits are 000)
* @param Q_X x-coordinate of Q
*
*/
static void
compute_nQ (bn256 *res, const bn256 *n, const bn256 *q_x)
{
int i, j;
pt p0[1], p1[1], p0_[1], p1_[1];
/* P0 = O = (1:0) */
memset (p0->x, 0, sizeof (bn256));
p0->x->word[0] = 1;
memset (p0->z, 0, sizeof (bn256));
/* P1 = (X:1) */
memcpy (p1->x, q_x, sizeof (bn256));
memset (p1->z, 0, sizeof (bn256));
p1->z->word[0] = 1;
for (i = 0; i < 8; i++)
{
uint32_t u = n->word[7-i];
for (j = 0; j < 16; j++)
{
pt *q0, *q1;
pt *sum_n, *prd_n;
if ((u & 0x80000000))
q0 = p1, q1 = p0, sum_n = p0_, prd_n = p1_;
else
q0 = p0, q1 = p1, sum_n = p1_, prd_n = p0_;
mont_d_and_a (prd_n, sum_n, q0, q1, q_x);
if ((u & 0x40000000))
q0 = p1_, q1 = p0_, sum_n = p0, prd_n = p1;
else
q0 = p0_, q1 = p1_, sum_n = p1, prd_n = p0;
mont_d_and_a (prd_n, sum_n, q0, q1, q_x);
u <<= 2;
}
}
/* We know the LSB of N is always 0. Thus, result is always in P0. */
/*
* p0->z may be zero here, but our mod_inv doesn't raise error for 0,
* but returns 0 (like the implementation of z^(p-2)), thus, RES will
* be 0 in that case, which is correct value.
*/
mod_inv (res, p0->z, p25519);
mod25638_mul (res, res, p0->x);
mod25519_reduce (res);
}
void
ecdh_compute_public_25519 (const uint8_t *key_data, uint8_t *pubkey)
{
bn256 gx[1];
bn256 k[1];
memset (gx, 0, sizeof (bn256));
gx[0].word[0] = 9; /* Gx = 9 */
memcpy (k, key_data, sizeof (bn256));
compute_nQ ((bn256 *)pubkey, k, gx);
}
int
ecdh_decrypt_curve25519 (const uint8_t *input, uint8_t *output,
const uint8_t *key_data)
{
bn256 q_x[1];
bn256 k[1];
bn256 shared[1];
memcpy (q_x, input, sizeof (bn256));
memcpy (k, key_data, sizeof (bn256));
compute_nQ (shared, k, q_x);
memcpy (output, shared, sizeof (bn256));
return 0;
}

177
ecc-x448.c Normal file
View File

@ -0,0 +1,177 @@
/* -*- coding: utf-8 -*-
* ecc-x448.c - Elliptic curve computation for
* the Montgomery curve: y^2 = x^3 + 156326*x^2 + x
*
* Copyright (C) 2021 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* IMPLEMENTATION NOTE
*
* (0) We assume that the processor has no cache, nor branch target
* prediction.
* We don't avoid conditional jump if both cases have same timing,
* either.
*
*/
#include <stdint.h>
#include <string.h>
#include "p448.h"
#define N_LIMBS 14
/**
* @brief Process Montgomery double-and-add
*
* With Q0, Q1, DIF (= Q0 - Q1), compute PRD = 2Q0 into Q0,
* and computute SUM = Q0 + Q1 into Q1
*
*/
static void
mont_d_and_a (p448_t q0_x[1], p448_t q0_z[1], p448_t q1_x[1], p448_t q1_z[1],
const p448_t dif_x[1])
{
p448_t reg0[1], reg1[1];
#define c reg0
#define d reg1
#define a q1_x
#define b q1_z
#define cb q0_x
#define da reg0
#define aa reg1
#define bb q0_z
#define da_plus_cb q1_z
#define da_minus_cb q1_x
#define e reg0
#define dacb_2 q0_z
#define a24_e q1_x
#define aa_ aa /* override is allowed by p448_add */
p448_add (c, q1_x, q1_z);
p448_sub (d, q1_x, q1_z);
p448_add (a, q0_x, q0_z);
p448_sub (b, q0_x, q0_z);
p448_mul (cb, c, b);
p448_mul (da, d, a);
p448_sqr (aa, a);
p448_sqr (bb, b);
p448_add (da_plus_cb, da, cb);
p448_sub (da_minus_cb, da, cb);
p448_mul (q0_x, aa, bb);
p448_sub (e, aa, bb);
p448_sqr (dacb_2, da_minus_cb);
p448_mul_39081 (a24_e, e);
p448_add (aa_, aa, a24_e);
p448_sqr (q1_x, da_plus_cb);
p448_mul (q1_z, dacb_2, dif_x);
p448_mul (q0_z, e, aa_);
}
typedef struct
{
p448_t x[1];
p448_t z[1];
} pt;
/**
* @brief RES = x-coordinate of [n]Q
*
* @param N Scalar N (three least significant bits are 00)
* @param Q_X x-coordinate of Q
*
*/
static void
compute_nQ (uint8_t *res, const uint32_t n[N_LIMBS], const p448_t q_x[1])
{
int i, j;
pt p0[1], p1[1];
#define tmp0 p0->z
#define tmp1 p1->z
/* P0 = O = (1:0) */
memset (p0->x, 0, sizeof (p0->x));
p0->x->limb[0] = 1;
memset (p0->z, 0, sizeof (p0->z));
/* P1 = (X:1) */
memcpy (p1->x, q_x, N_REDUNDANT_LIMBS*4);
memset (p1->z, 0, sizeof (p1->z));
p1->z->limb[0] = 1;
for (i = 0; i < N_LIMBS; i++)
{
uint32_t u = n[N_LIMBS-i-1];
for (j = 0; j < 32; j++)
{
p448_t *q0_x, *q0_z, *q1_x, *q1_z;
if ((u & 0x80000000))
q0_x = p1->x, q0_z = p1->z, q1_x = p0->x, q1_z = p0->z;
else
q0_x = p0->x, q0_z = p0->z, q1_x = p1->x, q1_z = p1->z;
mont_d_and_a (q0_x, q0_z, q1_x, q1_z, q_x);
u <<= 1;
}
}
/* We know the LSB of N is always 0. Thus, result is always in P0. */
/*
* p0->z may be zero here, but our inverse function doesn't raise
* error for 0, but returns 0, thus, RES will be 0 in that case,
* which is correct value.
*/
p448_inv (tmp1, p0->z);
p448_mul (tmp0, tmp1, p0->x);
p448_serialize (res, tmp0);
}
void
ecdh_compute_public_x448 (uint8_t *pubkey, const uint8_t *key_data)
{
const p448_t gx[1] = { { { 5, 0, }, } };
uint32_t k[N_LIMBS];
memcpy (k, key_data, N_LIMBS*4);
k[0] &= ~3;
k[N_LIMBS-1] |= 0x80000000;
compute_nQ (pubkey, k, gx);
}
int
ecdh_decrypt_x448 (uint8_t *output, const uint8_t *input,
const uint8_t *key_data)
{
p448_t q_x[1];
uint32_t k[N_LIMBS];
p448_deserialize (q_x, input);
memcpy (k, key_data, N_LIMBS*4);
k[0] &= ~3;
k[N_LIMBS-1] |= 0x80000000;
compute_nQ (output, k, q_x);
return 0;
}

398
ecc.c Normal file
View File

@ -0,0 +1,398 @@
/* -*- coding: utf-8 -*-
* ecc.c - Elliptic curve over GF(prime)
*
* Copyright (C) 2011, 2013, 2014, 2015
* Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* References:
*
* [1] Suite B Implementer's Guide to FIPS 186-3 (ECDSA), February 3, 2010.
*
* [2] Michael Brown, Darrel Hankerson, Julio López, and Alfred Menezes,
* Software Implementation of the NIST Elliptic Curves Over Prime Fields,
* Proceedings of the 2001 Conference on Topics in Cryptology: The
* Cryptographer's Track at RSA
* Pages 250-265, Springer-Verlag London, UK, 2001
* ISBN:3-540-41898-9
*
* [3] Mustapha Hedabou, Pierre Pinel, Lucien Bénéteau,
* A comb method to render ECC resistant against Side Channel Attacks,
* 2004
*/
#include "field-group-select.h"
/*
* Coefficients
*/
/*
* static const bn256 *coefficient_a;
* static const bn256 *coefficient_b;
*/
/*
* N: order of G
*/
/*
* static const bn256 N[1];
*/
/*
* MU = 2^512 / N
* MU = ( (1 << 256) | MU_lower )
*/
/*
* static const bn256 MU_lower[1];
*/
/*
* w = 4
* m = 256
* d = 64
* e = 32
*/
/*
* static const ac precomputed_KG[15];
* static const ac precomputed_2E_KG[15];
*/
#if TEST
/*
* Generator of Elliptic curve over GF(p256)
*/
const ac *G = &precomputed_KG[0];
#endif
static int
get_vk (const bn256 *K, int i)
{
uint32_t w0, w1, w2, w3;
if (i < 32)
{
w3 = K->word[6]; w2 = K->word[4]; w1 = K->word[2]; w0 = K->word[0];
}
else
{
w3 = K->word[7]; w2 = K->word[5]; w1 = K->word[3]; w0 = K->word[1];
i -= 32;
}
w3 >>= i; w2 >>= i; w1 >>= i; w0 >>= i;
return ((w3 & 1) << 3) | ((w2 & 1) << 2) | ((w1 & 1) << 1) | (w0 & 1);
}
/**
* @brief X = k * G
*
* @param K scalar k
*
* Return -1 on error.
* Return 0 on success.
*/
int
FUNC(compute_kG) (ac *X, const bn256 *K)
{
uint8_t index[64]; /* Lower 4-bit for index absolute value, msb is
for sign (encoded as: 0 means 1, 1 means -1). */
bn256 K_dash[1];
jpc Q[1], tmp[1], *dst;
int i;
int vk;
uint32_t k_is_even = bn256_is_even (K);
bn256_sub_uint (K_dash, K, k_is_even);
/* It keeps the condition: 1 <= K' <= N - 2, and K' is odd. */
/* Fill index. */
vk = get_vk (K_dash, 0);
for (i = 1; i < 64; i++)
{
int vk_next, is_zero;
vk_next = get_vk (K_dash, i);
is_zero = (vk_next == 0);
index[i-1] = (vk - 1) | (is_zero << 7);
vk = (is_zero ? vk : vk_next);
}
index[63] = vk - 1;
memset (Q->z, 0, sizeof (bn256)); /* infinity */
for (i = 31; i >= 0; i--)
{
FUNC(jpc_double) (Q, Q);
FUNC(jpc_add_ac_signed) (Q, Q, &precomputed_2E_KG[index[i+32]&0x0f],
index[i+32] >> 7);
FUNC(jpc_add_ac_signed) (Q, Q, &precomputed_KG[index[i]&0x0f],
index[i] >> 7);
}
dst = k_is_even ? Q : tmp;
FUNC(jpc_add_ac) (dst, Q, &precomputed_KG[0]);
return FUNC(jpc_to_ac) (X, Q);
}
/**
* check if P is on the curve.
*
* Return -1 on error.
* Return 0 on success.
*/
static int
point_is_on_the_curve (const ac *P)
{
bn256 s[1], t[1];
/* Elliptic curve: y^2 = x^3 + a*x + b */
MFNC(sqr) (s, P->x);
MFNC(mul) (s, s, P->x);
#ifndef COEFFICIENT_A_IS_ZERO
MFNC(mul) (t, coefficient_a, P->x);
MFNC(add) (s, s, t);
#endif
MFNC(add) (s, s, coefficient_b);
MFNC(sqr) (t, P->y);
if (bn256_cmp (s, t) == 0)
return 0;
else
return -1;
}
static int
get_vk_kP (const bn256 *K, int i)
{
uint32_t w;
uint8_t blk = i/32;
uint8_t pos = i%32;
uint8_t col = 3*(pos % 11) + (pos >= 11) + (pos >= 22);
uint8_t word_index = (blk * 3) + (pos / 11);
w = ((K->word[word_index] >> col) & 7);
if (word_index < 7 && (pos == 10 || pos == 21))
{
uint8_t mask;
uint8_t shift;
word_index++;
if (pos == 10)
{
shift = 2;
mask = 4;
}
else
{
shift = 1;
mask = 6;
}
w |= ((K->word[word_index] << shift) & mask);
}
return w;
}
/**
* @brief X = k * P
*
* @param K scalar k
* @param P P in affine coordiate
*
* Return -1 on error.
* Return 0 on success.
*
* For the curve (cofactor is 1 and n is prime), possible error cases are:
*
* P is not on the curve.
* P = G, k = n
* Something wrong in the code.
*
* Mathmatically, k=1 and P=O is another possible case, but O cannot be
* represented by affine coordinate.
*/
int
FUNC(compute_kP) (ac *X, const bn256 *K, const ac *P)
{
uint8_t index[86]; /* Lower 2-bit for index absolute value, msb is
for sign (encoded as: 0 means 1, 1 means -1). */
bn256 K_dash[1];
uint32_t k_is_even = bn256_is_even (K);
jpc Q[1], tmp[1], *dst;
int i;
int vk;
ac P3[1], P5[1], P7[1];
const ac *p_Pi[4];
if (point_is_on_the_curve (P) < 0)
return -1;
if (bn256_sub (K_dash, K, N) == 0) /* >= N, it's too big. */
return -1;
bn256_sub_uint (K_dash, K, k_is_even);
/* It keeps the condition: 1 <= K' <= N - 2, and K' is odd. */
p_Pi[0] = P;
p_Pi[1] = P3;
p_Pi[2] = P5;
p_Pi[3] = P7;
{
jpc Q1[1];
memcpy (Q->x, P->x, sizeof (bn256));
memcpy (Q->y, P->y, sizeof (bn256));
memset (Q->z, 0, sizeof (bn256));
Q->z->word[0] = 1;
FUNC(jpc_double) (Q, Q);
FUNC(jpc_add_ac) (Q1, Q, P);
if (FUNC(jpc_to_ac) (P3, Q1) < 0) /* Never occurs, except coding errors. */
return -1;
FUNC(jpc_double) (Q, Q);
FUNC(jpc_add_ac) (Q1, Q, P);
if (FUNC(jpc_to_ac) (P5, Q1) < 0) /* Never occurs, except coding errors. */
return -1;
memcpy (Q->x, P3->x, sizeof (bn256));
memcpy (Q->y, P3->y, sizeof (bn256));
memset (Q->z, 0, sizeof (bn256));
Q->z->word[0] = 1;
FUNC(jpc_double) (Q, Q);
FUNC(jpc_add_ac) (Q1, Q, P);
if (FUNC(jpc_to_ac) (P7, Q1) < 0) /* Never occurs, except coding errors. */
return -1;
}
/* Fill index. */
vk = get_vk_kP (K_dash, 0);
for (i = 1; i < 86; i++)
{
int vk_next, is_even;
vk_next = get_vk_kP (K_dash, i);
is_even = ((vk_next & 1) == 0);
index[i-1] = (is_even << 7) | ((is_even?7-vk:vk-1) >> 1);
vk = vk_next + is_even;
}
index[85] = ((vk - 1) >> 1);
memset (Q->z, 0, sizeof (bn256)); /* infinity */
for (i = 85; i >= 0; i--)
{
FUNC(jpc_double) (Q, Q);
FUNC(jpc_double) (Q, Q);
FUNC(jpc_double) (Q, Q);
FUNC(jpc_add_ac_signed) (Q, Q, p_Pi[index[i]&0x03], index[i] >> 7);
}
dst = k_is_even ? Q : tmp;
FUNC(jpc_add_ac) (dst, Q, P);
return FUNC(jpc_to_ac) (X, Q);
}
/**
* @brief Compute signature (r,s) of hash string z with secret key d
*/
void
FUNC(ecdsa) (bn256 *r, bn256 *s, const bn256 *z, const bn256 *d)
{
bn256 k[1];
ac KG[1];
bn512 tmp[1];
bn256 k_inv[1];
uint32_t carry;
#define borrow carry
#define tmp_k k_inv
do
{
do
{
bn256_random (k);
if (bn256_add_uint (k, k, 1))
continue;
if (bn256_sub (tmp_k, k, N) == 0) /* >= N, it's too big. */
continue;
/* 1 <= k <= N - 1 */
FUNC(compute_kG) (KG, k);
borrow = bn256_sub (r, KG->x, N);
if (borrow)
memcpy (r, KG->x, sizeof (bn256));
else
memcpy (KG->x, r, sizeof (bn256));
}
while (bn256_is_zero (r));
mod_inv (k_inv, k, N);
bn256_mul (tmp, r, d);
mod_reduce (s, tmp, N, MU_lower);
carry = bn256_add (s, s, z);
if (carry)
bn256_sub (s, s, N);
else
bn256_sub ((bn256 *)tmp, s, N);
bn256_mul (tmp, s, k_inv);
mod_reduce (s, tmp, N, MU_lower);
}
while (bn256_is_zero (s));
#undef tmp_k
#undef borrow
}
/**
* @brief Check if a secret d0 is valid or not
*
* @param D0 scalar D0: secret
* @param D1 scalar D1: secret candidate N-D0
*
* Return 0 on error.
* Return -1 when D1 should be used as the secret
* Return 1 when D0 should be used as the secret
*/
int
FUNC(check_secret) (const bn256 *d0, bn256 *d1)
{
ac Q0[1], Q1[1];
if (bn256_is_zero (d0) || bn256_sub (d1, N, d0) != 0)
/* == 0 or >= N, it's not valid. */
return 0;
FUNC(compute_kG) (Q0, d0);
FUNC(compute_kG) (Q1, d1);
/*
* Jivsov compliant key check
*/
return bn256_cmp (Q1[0].y, Q0[0].y);
}

7
field-group-select.h Normal file
View File

@ -0,0 +1,7 @@
#define CONCAT0(a,b) a##b
#define CONCAT1(a,b) CONCAT0(a,b)
#define CONCAT2(a,b,c) CONCAT1(a,b##c)
#define CONCAT3(a,b,c) CONCAT2(a,b,c)
#define FUNC(func) CONCAT1(func##_,FIELD)
#define MFNC(func) CONCAT3(mod,FIELD,_##func)

738
flash.c Normal file
View File

@ -0,0 +1,738 @@
/*
* flash.c -- Data Objects (DO) and GPG Key handling on Flash ROM
*
* Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018
* Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* We assume single DO size is less than 256.
*
* NOTE: "Card holder certificate" (which size is larger than 256) is
* not put into data pool, but is implemented by its own flash
* page(s).
*/
#include <stdint.h>
#include <string.h>
#include "config.h"
#include "sys.h"
#include "gnuk.h"
#include "pico/stdlib.h"
#include "hardware/flash.h"
#include "tusb.h"
/*
* Flash memory map
*
* _text
* .text
* .ctors
* .dtors
* _etext
* .data
* _bss_start
* .bss
* _end
* <alignment to page>
* ch_certificate_startp
* <2048 bytes>
* _keystore_pool
* Three flash pages for keystore
* a page contains a key data of:
* For RSA-2048: 512-byte (p, q and N)
* For RSA-4096: 1024-byte (p, q and N)
* For ECDSA/ECDH and EdDSA, there are padding after public key
* _data_pool
* <two pages>
*/
#define FLASH_DATA_POOL_HEADER_SIZE 2
#define FLASH_DATA_POOL_SIZE (2048*1024)
static uint16_t flash_page_size;
static const uint8_t *data_pool;
static uint8_t *last_p;
/* The first halfword is generation for the data page (little endian) */
const uint8_t flash_data[4] __attribute__ ((section (".gnuk_data"))) = {
0x00, 0x00, 0xff, 0xff
};
#define FLASH_TARGET_OFFSET (4096 * 1024) // DATA starts at the mid of flash
const uint8_t *flash_addr_key_storage_start = (const uint8_t *) (XIP_BASE + FLASH_TARGET_OFFSET);
const uint8_t *flash_addr_data_storage_start = (const uint8_t *) (XIP_BASE + FLASH_TARGET_OFFSET + 2048 * 1024); // 2 MB
const uint8_t *ch_certificate_start = (const uint8_t *) (XIP_BASE + FLASH_TARGET_OFFSET - FLASH_SECTOR_SIZE);
#define FLASH_ADDR_KEY_STORAGE_START flash_addr_key_storage_start
#define FLASH_ADDR_DATA_STORAGE_START flash_addr_data_storage_start
extern int flash_erase_page (uintptr_t addr);
extern int flash_program_halfword (uintptr_t addr, uint16_t data);
extern int flash_check_blank (const uint8_t *p_start, size_t size);
extern int flash_write (uintptr_t dst_addr, const uint8_t *src, size_t len);
static int key_available_at (const uint8_t *k, int key_size)
{
int i;
for (i = 0; i < key_size; i++)
if (k[i])
break;
if (i == key_size) /* It's ZERO. Released key. */
return 0;
for (i = 0; i < key_size; i++)
if (k[i] != 0xff)
break;
if (i == key_size) /* It's FULL. Unused key. */
return 0;
return 1;
}
void
flash_do_storage_init (const uint8_t **p_do_start, const uint8_t **p_do_end)
{
uint16_t gen0, gen1;
uint16_t *gen0_p = (uint16_t *)FLASH_ADDR_DATA_STORAGE_START;
uint16_t *gen1_p;
flash_page_size = FLASH_SECTOR_SIZE;
gen1_p = (uint16_t *)(FLASH_ADDR_DATA_STORAGE_START + flash_page_size);
data_pool = FLASH_ADDR_DATA_STORAGE_START;
/* Check data pool generation and choose the page */
gen0 = *gen0_p;
gen1 = *gen1_p;
if (gen0 == 0xffff && gen1 == 0xffff)
{
/* It's terminated. */
*p_do_start = *p_do_end = NULL;
return;
}
if (gen0 == 0xffff)
/* Use another page if a page is erased. */
data_pool = FLASH_ADDR_DATA_STORAGE_START + flash_page_size;
else if (gen1 == 0xffff)
/* Or use different page if another page is erased. */
data_pool = FLASH_ADDR_DATA_STORAGE_START;
else if ((gen0 == 0xfffe && gen1 == 0) || gen1 > gen0)
/* When both pages have valid header, use newer page. */
data_pool = FLASH_ADDR_DATA_STORAGE_START + flash_page_size;
*p_do_start = data_pool + FLASH_DATA_POOL_HEADER_SIZE;
*p_do_end = data_pool + flash_page_size;
}
static uint8_t *flash_key_getpage (enum kind_of_key kk);
void
flash_terminate (void)
{
int i;
for (i = 0; i < 3; i++)
flash_erase_page ((uintptr_t)flash_key_getpage (i));
flash_erase_page ((uintptr_t)FLASH_ADDR_DATA_STORAGE_START);
flash_erase_page ((uintptr_t)(FLASH_ADDR_DATA_STORAGE_START + flash_page_size));
data_pool = FLASH_ADDR_DATA_STORAGE_START;
last_p = (uint8_t *)FLASH_ADDR_DATA_STORAGE_START + FLASH_DATA_POOL_HEADER_SIZE;
#if defined(CERTDO_SUPPORT)
flash_erase_page ((uintptr_t)ch_certificate_start);
if (FLASH_CH_CERTIFICATE_SIZE > flash_page_size)
flash_erase_page ((uintptr_t)(ch_certificate_start + flash_page_size));
#endif
}
void
flash_activate (void)
{
flash_program_halfword ((uintptr_t)FLASH_ADDR_DATA_STORAGE_START, 0);
}
void
flash_key_storage_init (void)
{
const uint8_t *p;
int i;
/* For each key, find its address. */
p = FLASH_ADDR_KEY_STORAGE_START;
for (i = 0; i < 3; i++)
{
const uint8_t *k;
int key_size = gpg_get_algo_attr_key_size (i, GPG_KEY_STORAGE);
kd[i].pubkey = NULL;
for (k = p; k < p + flash_page_size; k += key_size)
if (key_available_at (k, key_size))
{
int prv_len = gpg_get_algo_attr_key_size (i, GPG_KEY_PRIVATE);
kd[i].pubkey = k + prv_len;
break;
}
p += flash_page_size;
}
}
/*
* Flash data pool managenent
*
* Flash data pool consists of two parts:
* 2-byte header
* contents
*
* Flash data pool objects:
* Data Object (DO) (of smart card)
* Internal objects:
* NONE (0x0000)
* 123-counter
* 14-bit counter
* bool object
* small enum
*
* Format of a Data Object:
* NR: 8-bit tag_number
* LEN: 8-bit length
* DATA: data * LEN
* PAD: optional byte for 16-bit alignment
*/
void
flash_set_data_pool_last (const uint8_t *p)
{
last_p = (uint8_t *)p;
}
/*
* We use two pages
*/
static int
flash_copying_gc (void)
{
uint8_t *src, *dst;
uint16_t generation;
if (data_pool == FLASH_ADDR_DATA_STORAGE_START)
{
src = (uint8_t *)FLASH_ADDR_DATA_STORAGE_START;
dst = (uint8_t *)FLASH_ADDR_DATA_STORAGE_START + flash_page_size;
}
else
{
src = (uint8_t *)FLASH_ADDR_DATA_STORAGE_START + flash_page_size;
dst = (uint8_t *)FLASH_ADDR_DATA_STORAGE_START;
}
generation = *(uint16_t *)src;
data_pool = dst;
gpg_data_copy (data_pool + FLASH_DATA_POOL_HEADER_SIZE);
if (generation == 0xfffe)
generation = 0;
else
generation++;
flash_program_halfword ((uintptr_t)dst, generation);
flash_erase_page ((uintptr_t)src);
return 0;
}
static int
is_data_pool_full (size_t size)
{
return last_p + size > data_pool + flash_page_size;
}
static uint8_t *
flash_data_pool_allocate (size_t size)
{
uint8_t *p;
size = (size + 1) & ~1; /* allocation unit is 1-halfword (2-byte) */
if (is_data_pool_full (size))
if (flash_copying_gc () < 0 || /*still*/ is_data_pool_full (size))
TU_LOG1 ("!!!! FATAL: %d\r\n",FATAL_FLASH);
p = last_p;
last_p += size;
return p;
}
void
flash_do_write_internal (const uint8_t *p, int nr, const uint8_t *data, int len)
{
uint16_t hw;
uintptr_t addr;
int i;
addr = (uintptr_t)p;
hw = nr | (len << 8);
if (flash_program_halfword (addr, hw) != 0)
flash_warning ("DO WRITE ERROR");
addr += 2;
for (i = 0; i < len/2; i++)
{
hw = data[i*2] | (data[i*2+1]<<8);
if (flash_program_halfword (addr, hw) != 0)
flash_warning ("DO WRITE ERROR");
addr += 2;
}
if ((len & 1))
{
hw = data[i*2] | 0xff00;
if (flash_program_halfword (addr, hw) != 0)
flash_warning ("DO WRITE ERROR");
}
}
const uint8_t *
flash_do_write (uint8_t nr, const uint8_t *data, int len)
{
const uint8_t *p;
DEBUG_INFO ("flash DO\r\n");
p = flash_data_pool_allocate (2 + len);
if (p == NULL)
{
DEBUG_INFO ("flash data pool allocation failure.\r\n");
return NULL;
}
flash_do_write_internal (p, nr, data, len);
DEBUG_INFO ("flash DO...done\r\n");
return p + 1;
}
void
flash_warning (const char *msg)
{
(void)msg;
DEBUG_INFO ("FLASH: ");
DEBUG_INFO (msg);
DEBUG_INFO ("\r\n");
}
void
flash_do_release (const uint8_t *do_data)
{
uintptr_t addr = (uintptr_t)do_data - 1;
uintptr_t addr_tag = addr;
int i;
int len = do_data[0];
/* Don't filling zero for data in code (such as ds_count_initial_value) */
if (do_data < FLASH_ADDR_DATA_STORAGE_START
|| do_data > FLASH_ADDR_DATA_STORAGE_START + FLASH_DATA_POOL_SIZE)
return;
addr += 2;
/* Fill zero for content and pad */
for (i = 0; i < len/2; i ++)
{
if (flash_program_halfword (addr, 0) != 0)
flash_warning ("fill-zero failure");
addr += 2;
}
if ((len & 1))
{
if (flash_program_halfword (addr, 0) != 0)
flash_warning ("fill-zero pad failure");
}
/* Fill 0x0000 for "tag_number and length" word */
if (flash_program_halfword (addr_tag, 0) != 0)
flash_warning ("fill-zero tag_nr failure");
}
static uint8_t *
flash_key_getpage (enum kind_of_key kk)
{
/* There is a page for each KK. */
return (uint8_t *)FLASH_ADDR_KEY_STORAGE_START + (flash_page_size * kk);
}
uint8_t *
flash_key_alloc (enum kind_of_key kk)
{
uint8_t *k, *k0 = flash_key_getpage (kk);
int i;
int key_size = gpg_get_algo_attr_key_size (kk, GPG_KEY_STORAGE);
/* Seek free space in the page. */
for (k = k0; k < k0 + flash_page_size; k += key_size)
{
const uint32_t *p = (const uint32_t *)k;
for (i = 0; i < key_size/4; i++)
if (p[i] != 0xffffffff)
break;
if (i == key_size/4) /* Yes, it's empty. */
return k;
}
/* Should not happen as we have enough free space all time, but just
in case. */
return NULL;
}
int
flash_key_write (uint8_t *key_addr,
const uint8_t *key_data, int key_data_len,
const uint8_t *pubkey, int pubkey_len)
{
uint16_t hw;
uintptr_t addr;
int i;
addr = (uintptr_t)key_addr;
for (i = 0; i < key_data_len/2; i ++)
{
hw = key_data[i*2] | (key_data[i*2+1]<<8);
if (flash_program_halfword (addr, hw) != 0)
return -1;
addr += 2;
}
for (i = 0; i < pubkey_len/2; i ++)
{
hw = pubkey[i*2] | (pubkey[i*2+1]<<8);
if (flash_program_halfword (addr, hw) != 0)
return -1;
addr += 2;
}
return 0;
}
static int
flash_check_all_other_keys_released (const uint8_t *key_addr, int key_size)
{
uintptr_t start = (uintptr_t)key_addr & ~(flash_page_size - 1);
const uint32_t *p = (const uint32_t *)start;
while (p < (const uint32_t *)(start + flash_page_size))
if (p == (const uint32_t *)key_addr)
p += key_size/4;
else
if (*p)
return 0;
else
p++;
return 1;
}
static void
flash_key_fill_zero_as_released (uint8_t *key_addr, int key_size)
{
int i;
uintptr_t addr = (uintptr_t)key_addr;
for (i = 0; i < key_size/2; i++)
flash_program_halfword (addr + i*2, 0);
}
void
flash_key_release (uint8_t *key_addr, int key_size)
{
if (flash_check_all_other_keys_released (key_addr, key_size))
flash_erase_page (((uintptr_t)key_addr & ~(flash_page_size - 1)));
else
flash_key_fill_zero_as_released (key_addr, key_size);
}
void
flash_key_release_page (enum kind_of_key kk)
{
flash_erase_page ((uintptr_t)flash_key_getpage (kk));
}
void
flash_clear_halfword (uintptr_t addr)
{
flash_program_halfword (addr, 0);
}
void
flash_put_data_internal (const uint8_t *p, uint16_t hw)
{
flash_program_halfword ((uintptr_t)p, hw);
}
void
flash_put_data (uint16_t hw)
{
uint8_t *p;
p = flash_data_pool_allocate (2);
if (p == NULL)
{
DEBUG_INFO ("data allocation failure.\r\n");
}
flash_program_halfword ((uintptr_t)p, hw);
}
void
flash_bool_clear (const uint8_t **addr_p)
{
const uint8_t *p;
if ((p = *addr_p) == NULL)
return;
flash_program_halfword ((uintptr_t)p, 0);
*addr_p = NULL;
}
void
flash_bool_write_internal (const uint8_t *p, int nr)
{
flash_program_halfword ((uintptr_t)p, nr);
}
const uint8_t *
flash_bool_write (uint8_t nr)
{
uint8_t *p;
uint16_t hw = nr;
p = flash_data_pool_allocate (2);
if (p == NULL)
{
DEBUG_INFO ("bool allocation failure.\r\n");
return NULL;
}
flash_program_halfword ((uintptr_t)p, hw);
return p;
}
void
flash_enum_clear (const uint8_t **addr_p)
{
flash_bool_clear (addr_p);
}
void
flash_enum_write_internal (const uint8_t *p, int nr, uint8_t v)
{
uint16_t hw = nr | (v << 8);
flash_program_halfword ((uintptr_t)p, hw);
}
const uint8_t *
flash_enum_write (uint8_t nr, uint8_t v)
{
uint8_t *p;
uint16_t hw = nr | (v << 8);
p = flash_data_pool_allocate (2);
if (p == NULL)
{
DEBUG_INFO ("enum allocation failure.\r\n");
return NULL;
}
flash_program_halfword ((uintptr_t)p, hw);
return p;
}
int
flash_cnt123_get_value (const uint8_t *p)
{
if (p == NULL)
return 0;
else
{
uint8_t v = *p;
/*
* After erase, a halfword in flash memory becomes 0xffff.
* The halfword can be programmed to any value.
* Then, the halfword can be programmed to zero.
*
* Thus, we can represent value 1, 2, and 3.
*/
if (v == 0xff)
return 1;
else if (v == 0x00)
return 3;
else
return 2;
}
}
void
flash_cnt123_write_internal (const uint8_t *p, int which, int v)
{
uint16_t hw;
hw = NR_COUNTER_123 | (which << 8);
flash_program_halfword ((uintptr_t)p, hw);
if (v == 1)
return;
else if (v == 2)
flash_program_halfword ((uintptr_t)p+2, 0xc3c3);
else /* v == 3 */
flash_program_halfword ((uintptr_t)p+2, 0);
}
void
flash_cnt123_increment (uint8_t which, const uint8_t **addr_p)
{
const uint8_t *p;
uint16_t hw;
if ((p = *addr_p) == NULL)
{
p = flash_data_pool_allocate (4);
if (p == NULL)
{
DEBUG_INFO ("cnt123 allocation failure.\r\n");
return;
}
hw = NR_COUNTER_123 | (which << 8);
flash_program_halfword ((uintptr_t)p, hw);
*addr_p = p + 2;
}
else
{
uint8_t v = *p;
if (v == 0)
return;
if (v == 0xff)
hw = 0xc3c3;
else
hw = 0;
flash_program_halfword ((uintptr_t)p, hw);
}
}
void
flash_cnt123_clear (const uint8_t **addr_p)
{
const uint8_t *p;
if ((p = *addr_p) == NULL)
return;
flash_program_halfword ((uintptr_t)p, 0);
p -= 2;
flash_program_halfword ((uintptr_t)p, 0);
*addr_p = NULL;
}
#if defined(CERTDO_SUPPORT)
int
flash_erase_binary (uint8_t file_id)
{
if (file_id == FILEID_CH_CERTIFICATE)
{
const uint8_t *p = ch_certificate_start;
if (flash_check_blank (p, FLASH_CH_CERTIFICATE_SIZE) == 0)
{
flash_erase_page ((uintptr_t)p);
if (FLASH_CH_CERTIFICATE_SIZE > flash_page_size)
flash_erase_page ((uintptr_t)p + flash_page_size);
}
return 0;
}
return -1;
}
#endif
int
flash_write_binary (uint8_t file_id, const uint8_t *data,
uint16_t len, uint16_t offset)
{
uint16_t maxsize;
const uint8_t *p;
if (file_id == FILEID_SERIAL_NO)
{
maxsize = 6;
p = &openpgpcard_aid[8];
}
#if defined(CERTDO_SUPPORT)
else if (file_id == FILEID_CH_CERTIFICATE)
{
maxsize = FLASH_CH_CERTIFICATE_SIZE;
p = ch_certificate_start;
}
#endif
else
return -1;
if (offset + len > maxsize || (offset&1) || (len&1))
return -1;
else
{
uint16_t hw;
uintptr_t addr;
int i;
if (flash_check_blank (p + offset, len) == 0)
return -1;
addr = (uintptr_t)p + offset;
for (i = 0; i < len/2; i++)
{
hw = data[i*2] | (data[i*2+1]<<8);
if (flash_program_halfword (addr, hw) != 0)
flash_warning ("DO WRITE ERROR");
addr += 2;
}
return 0;
}
}

501
gnuk.h Normal file
View File

@ -0,0 +1,501 @@
/*
* Application layer <-> CCID layer data structure
*/
struct apdu {
uint8_t seq;
/* command APDU */
uint8_t *cmd_apdu_head; /* CLS INS P1 P2 [ internal Lc ] */
uint8_t *cmd_apdu_data;
uint16_t cmd_apdu_data_len; /* Nc, calculated by Lc field */
uint16_t expected_res_size; /* Ne, calculated by Le field */
/* response APDU */
uint16_t sw;
uint16_t res_apdu_data_len;
uint8_t *res_apdu_data;
};
extern struct apdu apdu;
#define CARD_CHANGE_INSERT 0
#define CARD_CHANGE_REMOVE 1
#define CARD_CHANGE_TOGGLE 2
void ccid_card_change_signal (int how);
/* CCID thread */
#define EV_CARD_CHANGE 1
#define EV_TX_FINISHED 2 /* CCID Tx finished */
#define EV_EXEC_ACK_REQUIRED 4 /* OpenPGPcard Execution ACK required */
#define EV_EXEC_FINISHED 8 /* OpenPGPcard Execution finished */
#define EV_RX_DATA_READY 16 /* USB Rx data available */
/* OpenPGPcard thread */
#define EV_MODIFY_CMD_AVAILABLE 1
#define EV_VERIFY_CMD_AVAILABLE 2
#define EV_CMD_AVAILABLE 4
#define EV_EXIT 8
#define EV_PINPAD_INPUT_DONE 16
/* Maximum cmd apdu data is key import 24+4+256+256 (proc_key_import) */
#define MAX_CMD_APDU_DATA_SIZE (24+4+256+256) /* without header */
/* Maximum res apdu data is public key 5+9+512 (gpg_do_public_key) */
#define MAX_RES_APDU_DATA_SIZE (5+9+512) /* without trailer */
#define CCID_MSG_HEADER_SIZE 10
#define res_APDU apdu.res_apdu_data
#define res_APDU_size apdu.res_apdu_data_len
/* USB buffer size of LL (Low-level): size of single Bulk transaction */
#define USB_LL_BUF_SIZE 64
enum ccid_state {
CCID_STATE_NOCARD, /* No card available */
CCID_STATE_START, /* Initial */
CCID_STATE_WAIT, /* Waiting APDU */
CCID_STATE_EXECUTE, /* Executing command */
CCID_STATE_ACK_REQUIRED_0, /* Ack required (executing)*/
CCID_STATE_ACK_REQUIRED_1, /* Waiting user's ACK (execution finished) */
CCID_STATE_EXITED, /* CCID Thread Terminated */
CCID_STATE_EXEC_REQUESTED, /* Exec requested */
};
enum ccid_state ccid_get_ccid_state (void);
extern volatile uint8_t auth_status;
#define AC_NONE_AUTHORIZED 0x00
#define AC_PSO_CDS_AUTHORIZED 0x01 /* PW1 with 0x81 verified */
#define AC_OTHER_AUTHORIZED 0x02 /* PW1 with 0x82 verified */
#define AC_ADMIN_AUTHORIZED 0x04 /* PW3 verified */
#define AC_NEVER 0x80
#define AC_ALWAYS 0xFF
#define PW_ERR_PW1 0
#define PW_ERR_RC 1
#define PW_ERR_PW3 2
int gpg_pw_get_retry_counter (int who);
int gpg_pw_locked (uint8_t which);
void gpg_pw_reset_err_counter (uint8_t which);
void gpg_pw_increment_err_counter (uint8_t which);
int ac_check_status (uint8_t ac_flag);
int verify_pso_cds (const uint8_t *pw, int pw_len);
int verify_other (const uint8_t *pw, int pw_len);
int verify_user_0 (uint8_t access, const uint8_t *pw, int buf_len,
int pw_len_known, const uint8_t *ks_pw1, int saveks);
int verify_admin (const uint8_t *pw, int pw_len);
int verify_admin_0 (const uint8_t *pw, int buf_len, int pw_len_known,
const uint8_t *ks_pw3, int saveks);
void ac_reset_pso_cds (void);
void ac_reset_other (void);
void ac_reset_admin (void);
void ac_fini (void);
void set_res_sw (uint8_t sw1, uint8_t sw2);
extern uint8_t file_selection;
extern const uint8_t historical_bytes[];
extern uint16_t data_objects_number_of_bytes;
#define CHALLENGE_LEN 32
void gpg_data_scan (const uint8_t *start, const uint8_t *end);
void gpg_data_copy (const uint8_t *p);
void gpg_do_terminate (void);
void gpg_do_get_data (uint16_t tag, int with_tag);
void gpg_do_put_data (uint16_t tag, const uint8_t *data, int len);
void gpg_do_public_key (uint8_t kk_byte);
void gpg_do_keygen (uint8_t *buf);
const uint8_t *gpg_get_firmware_update_key (uint8_t keyno);
/* Constants: algo+size */
#define ALGO_RSA4K 0
/* #define ALGO_NISTP256R1 1 */
#define ALGO_SECP256K1 2
#define ALGO_ED25519 3
#define ALGO_CURVE25519 4
#define ALGO_X448 5
#define ALGO_ED448 6
#define ALGO_RSA2K 255
enum kind_of_key {
GPG_KEY_FOR_SIGNING = 0,
GPG_KEY_FOR_DECRYPTION = 1,
GPG_KEY_FOR_AUTHENTICATION = 2,
};
enum size_of_key {
GPG_KEY_STORAGE = 0, /* PUBKEY + PRVKEY rounded to 2^N */
GPG_KEY_PUBLIC,
GPG_KEY_PRIVATE,
};
int gpg_get_algo_attr (enum kind_of_key kk);
int gpg_get_algo_attr_key_size (enum kind_of_key kk, enum size_of_key s);
void flash_do_storage_init (const uint8_t **, const uint8_t **);
void flash_terminate (void);
void flash_activate (void);
void flash_key_storage_init (void);
void flash_do_release (const uint8_t *);
const uint8_t *flash_do_write (uint8_t nr, const uint8_t *data, int len);
uint8_t *flash_key_alloc (enum kind_of_key);
void flash_key_release (uint8_t *, int);
void flash_key_release_page (enum kind_of_key);
int flash_key_write (uint8_t *key_addr,
const uint8_t *key_data, int key_data_len,
const uint8_t *pubkey, int pubkey_len);
void flash_set_data_pool_last (const uint8_t *p);
void flash_clear_halfword (uintptr_t addr);
void flash_increment_counter (uint8_t counter_tag_nr);
void flash_reset_counter (uint8_t counter_tag_nr);
#define FILEID_SERIAL_NO 0
#define FILEID_UPDATE_KEY_0 1
#define FILEID_UPDATE_KEY_1 2
#define FILEID_UPDATE_KEY_2 3
#define FILEID_UPDATE_KEY_3 4
#define FILEID_CH_CERTIFICATE 5
int flash_erase_binary (uint8_t file_id);
int flash_write_binary (uint8_t file_id, const uint8_t *data,
uint16_t len, uint16_t offset);
#define FLASH_CH_CERTIFICATE_SIZE 2048
extern const uint8_t *ch_certificate_start;
#define FIRMWARE_UPDATE_KEY_CONTENT_LEN 256 /* RSA-2048 (p and q) */
#define INITIAL_VECTOR_SIZE 16
#define DATA_ENCRYPTION_KEY_SIZE 16
#define MAX_PRVKEY_LEN 512 /* Maximum is the case for RSA 4096-bit. */
struct key_data {
const uint8_t *pubkey; /* Pointer to public key */
uint8_t data[MAX_PRVKEY_LEN]; /* decrypted private key data content */
};
struct prvkey_data {
/*
* IV: Initial Vector
*/
uint8_t iv[INITIAL_VECTOR_SIZE];
/*
* Checksum
*/
uint8_t checksum_encrypted[DATA_ENCRYPTION_KEY_SIZE];
/*
* DEK (Data Encryption Key) encrypted
*/
uint8_t dek_encrypted_1[DATA_ENCRYPTION_KEY_SIZE]; /* For user */
uint8_t dek_encrypted_2[DATA_ENCRYPTION_KEY_SIZE]; /* For resetcode */
uint8_t dek_encrypted_3[DATA_ENCRYPTION_KEY_SIZE]; /* For admin */
};
#define BY_USER 1
#define BY_RESETCODE 2
#define BY_ADMIN 3
/*
* Maximum length of pass phrase is 127.
* We use the top bit (0x80) to encode if keystring is available within DO.
*/
#define PW_LEN_MAX 127
#define PW_LEN_MASK 0x7f
#define PW_LEN_KEYSTRING_BIT 0x80
#define SALT_SIZE 8
void s2k (const unsigned char *salt, size_t slen,
const unsigned char *input, size_t ilen, unsigned char output[32]);
#define KEYSTRING_PASSLEN_SIZE 1
#define KEYSTRING_SALT_SIZE SALT_SIZE
#define KEYSTRING_MD_SIZE 32
#define KEYSTRING_SIZE (KEYSTRING_PASSLEN_SIZE + KEYSTRING_SALT_SIZE \
+ KEYSTRING_MD_SIZE)
#define KS_META_SIZE (KEYSTRING_PASSLEN_SIZE + KEYSTRING_SALT_SIZE)
#define KS_GET_SALT(ks) (ks + KEYSTRING_PASSLEN_SIZE)
#define KS_GET_KEYSTRING(ks) (ks + KS_META_SIZE)
void gpg_do_clear_prvkey (enum kind_of_key kk);
int gpg_do_load_prvkey (enum kind_of_key kk, int who, const uint8_t *keystring);
int gpg_do_chks_prvkey (enum kind_of_key kk,
int who_old, const uint8_t *old_ks,
int who_new, const uint8_t *new_ks);
int gpg_change_keystring (int who_old, const uint8_t *old_ks,
int who_new, const uint8_t *new_ks);
extern struct key_data kd[3];
#ifdef DEBUG
void stdout_init (void);
#define DEBUG_MORE 1
/*
* Debug functions in debug.c
*/
void put_byte (uint8_t b);
void put_byte_with_no_nl (uint8_t b);
void put_short (uint16_t x);
void put_word (uint32_t x);
void put_int (uint32_t x);
void put_string (const char *s);
void put_binary (const char *s, int len);
#define DEBUG_INFO(msg) put_string (msg)
#define DEBUG_WORD(w) put_word (w)
#define DEBUG_SHORT(h) put_short (h)
#define DEBUG_BYTE(b) put_byte (b)
#define DEBUG_BINARY(s,len) put_binary ((const char *)s,len)
#else
#define DEBUG_INFO(msg)
#define DEBUG_WORD(w)
#define DEBUG_SHORT(h)
#define DEBUG_BYTE(b)
#define DEBUG_BINARY(s,len)
#endif
int rsa_sign (const uint8_t *, uint8_t *, int, struct key_data *, int);
int modulus_calc (const uint8_t *, int, uint8_t *);
int rsa_decrypt (const uint8_t *, uint8_t *, int, struct key_data *,
unsigned int *);
int rsa_verify (const uint8_t *, int, const uint8_t *, const uint8_t *);
int rsa_genkey (int, uint8_t *, uint8_t *);
int ecdsa_sign_p256k1 (const uint8_t *hash, uint8_t *output,
const uint8_t *key_data);
int ecc_compute_public_p256k1 (const uint8_t *key_data, uint8_t *);
int ecc_check_secret_p256k1 (const uint8_t *d0, uint8_t *d1);
int ecdh_decrypt_p256k1 (const uint8_t *input, uint8_t *output,
const uint8_t *key_data);
int eddsa_sign_25519 (const uint8_t *input, size_t ilen, uint32_t *output,
const uint8_t *sk_a, const uint8_t *seed,
const uint8_t *pk);
void eddsa_compute_public_25519 (const uint8_t *a, uint8_t *);
void ecdh_compute_public_25519 (const uint8_t *a, uint8_t *);
int ecdh_decrypt_curve25519 (const uint8_t *input, uint8_t *output,
const uint8_t *key_data);
void ecdh_compute_public_x448 (uint8_t *pubkey, const uint8_t *key_data);
int ecdh_decrypt_x448 (uint8_t *output, const uint8_t *input,
const uint8_t *key_data);
int ed448_sign (uint8_t *out, const uint8_t *input, unsigned int ilen,
const uint8_t *a_in, const uint8_t *seed, const uint8_t *pk);
void ed448_compute_public (uint8_t *pk, const uint8_t *a_in);
const uint8_t *gpg_do_read_simple (uint8_t);
void gpg_do_write_simple (uint8_t, const uint8_t *, int);
void gpg_increment_digital_signature_counter (void);
void gpg_do_get_initial_pw_setting (int is_pw3, int *r_len,
const uint8_t **r_p);
int gpg_do_kdf_check (int len, int how_many);
int gpg_do_get_uif (enum kind_of_key kk);
void fatal (uint8_t code) __attribute__ ((noreturn));
#define FATAL_FLASH 1
#define FATAL_RANDOM 2
#define FATAL_HEAP 3
extern uint8_t keystring_md_pw3[KEYSTRING_MD_SIZE];
extern uint8_t admin_authorized;
/*** Flash memory tag values ***/
/* Data objects */
/*
* Representation of data object:
*
* <-1 halfword-> <--len/2 halfwords->
* <-tag-><-len-> <---data content--->
*/
#define NR_DO_SEX 0x00
#define NR_DO_FP_SIG 0x01
#define NR_DO_FP_DEC 0x02
#define NR_DO_FP_AUT 0x03
#define NR_DO_CAFP_1 0x04
#define NR_DO_CAFP_2 0x05
#define NR_DO_CAFP_3 0x06
#define NR_DO_KGTIME_SIG 0x07
#define NR_DO_KGTIME_DEC 0x08
#define NR_DO_KGTIME_AUT 0x09
#define NR_DO_LOGIN_DATA 0x0a
#define NR_DO_URL 0x0b
#define NR_DO_NAME 0x0c
#define NR_DO_LANGUAGE 0x0d
#define NR_DO_PRVKEY_SIG 0x0e
#define NR_DO_PRVKEY_DEC 0x0f
#define NR_DO_PRVKEY_AUT 0x10
#define NR_DO_KEYSTRING_PW1 0x11
#define NR_DO_KEYSTRING_RC 0x12
#define NR_DO_KEYSTRING_PW3 0x13
#define NR_DO_KDF 0x14
#define NR_DO__LAST__ 21 /* == 0x15 */
/* 14-bit counter for DS: Recorded in flash memory by 1-halfword (2-byte). */
/*
* Representation of 14-bit counter:
* 0: 0x8000
* 1: 0x8001
* ...
* 16383: 0xbfff
*/
#define NR_COUNTER_DS 0x80 /* ..0xbf */
/* 10-bit counter for DS: Recorded in flash memory by 1-halfword (2-byte). */
/*
* Representation of 10-bit counter:
* 0: 0xc000
* 1: 0xc001
* ...
* 1023: 0xc3ff
*/
#define NR_COUNTER_DS_LSB 0xc0 /* ..0xc3 */
/*
* Boolean object, small enum, or 8-bit integer:
* Recorded in flash memory by 1-halfword (2-byte)
*/
/*
* Representation of Boolean object:
* 0: No record in flash memory
* 1: 0xf000
*/
#define NR_BOOL_PW1_LIFETIME 0xf0
/*
* Representation of algorithm attribute object:
* RSA-2048: No record in flash memory
* RSA-4096: 0xf?00
* ECC p256r1: 0xf?01
* ECC p256k1: 0xf?02
* ECC Ed25519: 0xf?03
* ECC Curve25519: 0xf?04
* where <?> == 1 (signature), 2 (decryption) or 3 (authentication)
*/
#define NR_KEY_ALGO_ATTR_SIG 0xf1
#define NR_KEY_ALGO_ATTR_DEC 0xf2
#define NR_KEY_ALGO_ATTR_AUT 0xf3
/*
* Representation of User Interaction Flag:
* 0 (UIF disabled): 0xf?00 or No record in flash memory
* 1 (UIF enabled): 0xf?01
* 2 (UIF permanently enabled): 0xf?02
*
*/
#define NR_DO_UIF_SIG 0xf6
#define NR_DO_UIF_DEC 0xf7
#define NR_DO_UIF_AUT 0xf8
/*
* NR_UINT_SOMETHING could be here... Use 0xf[459abcd]
*/
/* 123-counters: Recorded in flash memory by 2-halfword (4-byte). */
/*
* Representation of 123-counters:
* 0: No record in flash memory
* 1: 0xfe?? 0xffff
* 2: 0xfe?? 0xc3c3
* 3: 0xfe?? 0x0000
* where <counter_id> is placed at second byte <??>
*/
#define NR_COUNTER_123 0xfe
#define NR_EMPTY 0xff
#define SIZE_PW_STATUS_BYTES 7
#define NUM_ALL_PRV_KEYS 3 /* SIG, DEC and AUT */
#if !defined(OPENPGP_CARD_INITIAL_PW1)
#define OPENPGP_CARD_INITIAL_PW1 "123456"
#endif
#if !defined(OPENPGP_CARD_INITIAL_PW3)
#define OPENPGP_CARD_INITIAL_PW3 "12345678"
#endif
extern const uint8_t openpgpcard_aid[14];
void flash_bool_clear (const uint8_t **addr_p);
const uint8_t *flash_bool_write (uint8_t nr);
void flash_enum_clear (const uint8_t **addr_p);
const uint8_t *flash_enum_write (uint8_t nr, uint8_t v);
int flash_cnt123_get_value (const uint8_t *p);
void flash_cnt123_increment (uint8_t which, const uint8_t **addr_p);
void flash_cnt123_clear (const uint8_t **addr_p);
void flash_put_data (uint16_t hw);
void flash_warning (const char *msg);
void flash_put_data_internal (const uint8_t *p, uint16_t hw);
void flash_bool_write_internal (const uint8_t *p, int nr);
void flash_enum_write_internal (const uint8_t *p, int nr, uint8_t v);
void flash_cnt123_write_internal (const uint8_t *p, int which, int v);
void flash_do_write_internal (const uint8_t *p, int nr,
const uint8_t *data, int len);
extern const uint8_t gnuk_string_serial[];
#define LED_ONESHOT 1
#define LED_TWOSHOTS 2
#define LED_SHOW_STATUS 4
#define LED_FATAL 8
#define LED_SYNC 16
#define LED_GNUK_EXEC 32
#define LED_START_COMMAND 64
#define LED_FINISH_COMMAND 128
#define LED_WAIT_FOR_BUTTON 256
#define LED_OFF LED_FINISH_COMMAND
void led_blink (int spec);
#if defined(PINPAD_SUPPORT)
# if defined(PINPAD_CIR_SUPPORT)
void cir_init (void);
# elif defined(PINPAD_DIAL_SUPPORT)
void dial_sw_disable (void);
void dial_sw_enable (void);
# elif defined(PINPAD_DND_SUPPORT)
void msc_init (void);
void msc_media_insert_change (int available);
int msc_scsi_write (uint32_t lba, const uint8_t *buf, size_t size);
int msc_scsi_read (uint32_t lba, const uint8_t **sector_p);
void msc_scsi_stop (uint8_t code);
# endif
#define PIN_INPUT_CURRENT 1
#define PIN_INPUT_NEW 2
#define PIN_INPUT_CONFIRM 3
#define MAX_PIN_CHARS 32
extern uint8_t pin_input_buffer[MAX_PIN_CHARS];
extern uint8_t pin_input_len;
int pinpad_getline (int msg_code, uint32_t timeout_usec);
#endif
extern uint8_t _regnual_start, __heap_end__[];
uint8_t * sram_address (uint32_t offset);
static inline const uint8_t *
unique_device_id (void)
{
/*
* STM32F103 has 96-bit unique device identifier.
* This routine mimics that.
*/
static const uint8_t id[] = { /* My RSA fingerprint */
0x12, 0x41, 0x24, 0xBD, 0x3B, 0x48, 0x62, 0xAF,
0x7A, 0x0A, 0x42, 0xF1, 0x00, 0xB4, 0x5E, 0xBD,
0x4C, 0xA7, 0xBA, 0xBE
};
return id;
}

14
jpc-ac_p256k1.h Normal file
View File

@ -0,0 +1,14 @@
/**
* @brief Jacobian projective coordinates
*/
typedef struct
{
bn256 x[1];
bn256 y[1];
bn256 z[1];
} jpc;
void jpc_double_p256k1 (jpc *X, const jpc *A);
void jpc_add_ac_p256k1 (jpc *X, const jpc *A, const ac *B);
void jpc_add_ac_signed_p256k1 (jpc *X, const jpc *A, const ac *B, int minus);
int jpc_to_ac_p256k1 (ac *X, const jpc *A);

199
jpc.c Normal file
View File

@ -0,0 +1,199 @@
/*
* jpc.c -- arithmetic on Jacobian projective coordinates.
*
* Copyright (C) 2011, 2013 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "field-group-select.h"
/**
* @brief X = 2 * A
*
* @param X Destination JPC
* @param A JPC
*/
void
FUNC(jpc_double) (jpc *X, const jpc *A)
{
bn256 a[1], b[1], c[1], tmp0[1];
bn256 *d;
if (bn256_is_zero (A->z)) /* A is infinite */
return;
d = X->x;
MFNC(sqr) (a, A->y);
memcpy (b, a, sizeof (bn256));
MFNC(mul) (a, a, A->x);
MFNC(shift) (a, a, 2);
MFNC(sqr) (b, b);
MFNC(shift) (b, b, 3);
#if defined(COEFFICIENT_A_IS_MINUS_3)
MFNC(sqr) (tmp0, A->z);
MFNC(sub) (c, A->x, tmp0);
MFNC(add) (tmp0, tmp0, A->x);
MFNC(mul) (tmp0, tmp0, c);
MFNC(shift) (c, tmp0, 1);
MFNC(add) (c, c, tmp0);
#elif defined (COEFFICIENT_A_IS_ZERO)
MFNC(sqr) (tmp0, A->x);
MFNC(shift) (c, tmp0, 1);
MFNC(add) (c, c, tmp0);
#else
#error "not supported."
#endif
MFNC(sqr) (d, c);
MFNC(shift) (tmp0, a, 1);
MFNC(sub) (d, d, tmp0);
MFNC(mul) (X->z, A->y, A->z);
MFNC(shift) (X->z, X->z, 1);
MFNC(sub) (tmp0, a, d);
MFNC(mul) (tmp0, c, tmp0);
MFNC(sub) (X->y, tmp0, b);
}
/**
* @brief X = A + B
*
* @param X Destination JPC
* @param A JPC
* @param B AC
* @param MINUS if 1 subtraction, addition otherwise.
*/
void
FUNC(jpc_add_ac_signed) (jpc *X, const jpc *A, const ac *B, int minus)
{
bn256 a[1], b[1], c[1], d[1], tmp[1];
#define minus_B_y c
#define c_sqr a
#define c_cube b
#define x1_c_sqr c
#define x1_c_sqr_2 c
#define c_cube_plus_x1_c_sqr_2 c
#define x1_c_sqr_copy a
#define y3_tmp c
#define y1_c_cube a
if (bn256_is_zero (A->z)) /* A is infinite */
{
memcpy (X->x, B->x, sizeof (bn256));
if (minus)
{
memcpy (tmp, B->y, sizeof (bn256));
bn256_sub (X->y, CONST_P256, B->y);
}
else
{
memcpy (X->y, B->y, sizeof (bn256));
bn256_sub (tmp, CONST_P256, B->y);
}
memset (X->z, 0, sizeof (bn256));
X->z->word[0] = 1;
return;
}
MFNC(sqr) (a, A->z);
memcpy (b, a, sizeof (bn256));
MFNC(mul) (a, a, B->x);
MFNC(mul) (b, b, A->z);
if (minus)
{
bn256_sub (minus_B_y, CONST_P256, B->y);
MFNC(mul) (b, b, minus_B_y);
}
else
{
bn256_sub (tmp, CONST_P256, B->y);
MFNC(mul) (b, b, B->y);
}
if (bn256_cmp (A->x, a) == 0 && bn256_cmp (A->y, b) == 0)
{
FUNC(jpc_double) (X, A);
return;
}
MFNC(sub) (c, a, A->x);
MFNC(sub) (d, b, A->y);
MFNC(mul) (X->z, A->z, c);
MFNC(sqr) (c_sqr, c);
MFNC(mul) (c_cube, c_sqr, c);
MFNC(mul) (x1_c_sqr, A->x, c_sqr);
MFNC(sqr) (X->x, d);
memcpy (x1_c_sqr_copy, x1_c_sqr, sizeof (bn256));
MFNC(shift) (x1_c_sqr_2, x1_c_sqr, 1);
MFNC(add) (c_cube_plus_x1_c_sqr_2, x1_c_sqr_2, c_cube);
MFNC(sub) (X->x, X->x, c_cube_plus_x1_c_sqr_2);
MFNC(sub) (y3_tmp, x1_c_sqr_copy, X->x);
MFNC(mul) (y3_tmp, y3_tmp, d);
MFNC(mul) (y1_c_cube, A->y, c_cube);
MFNC(sub) (X->y, y3_tmp, y1_c_cube);
}
/**
* @brief X = A + B
*
* @param X Destination JPC
* @param A JPC
* @param B AC
*/
void
FUNC(jpc_add_ac) (jpc *X, const jpc *A, const ac *B)
{
FUNC(jpc_add_ac_signed) (X, A, B, 0);
}
/**
* @brief X = convert A
*
* @param X Destination AC
* @param A JPC
*
* Return -1 on error (infinite).
* Return 0 on success.
*/
int
FUNC(jpc_to_ac) (ac *X, const jpc *A)
{
bn256 z_inv[1], z_inv_sqr[1];
if (bn256_is_zero (A->z))
return -1;
mod_inv (z_inv, A->z, CONST_P256);
MFNC(sqr) (z_inv_sqr, z_inv);
MFNC(mul) (z_inv, z_inv, z_inv_sqr);
MFNC(mul) (X->x, A->x, z_inv_sqr);
MFNC(mul) (X->y, A->y, z_inv);
return 0;
}

36
jpc_p256k1.c Normal file
View File

@ -0,0 +1,36 @@
/*
* jpc_p256k1.c -- arithmetic on Jacobian projective coordinates for p256k1.
*
* Copyright (C) 2014 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdint.h>
#include <string.h>
#include "bn.h"
#include "mod.h"
#include "modp256k1.h"
#include "affine.h"
#include "jpc-ac_p256k1.h"
#define FIELD p256k1
#define CONST_P256 P256K1
#define COEFFICIENT_A_IS_ZERO 1
#include "jpc.c"

54
low_flash.c Normal file
View File

@ -0,0 +1,54 @@
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/flash.h"
#include "hardware/sync.h"
#include <string.h>
int
flash_program_halfword (uintptr_t addr, uint16_t data)
{
off_t offset;
uint8_t buf[FLASH_PAGE_SIZE];
memset(buf, 0, sizeof(uint8_t)*FLASH_PAGE_SIZE);
buf[0] = (data & 0xff);
buf[1] = (data >> 8);
uint32_t ints = save_and_disable_interrupts();
flash_range_program(addr-XIP_BASE, buf, FLASH_PAGE_SIZE);
restore_interrupts (ints);
return 0;
}
static const uint8_t erased[] = { [0 ... 1023 ] = 0xff };
int
flash_erase_page (uintptr_t addr)
{
uint32_t ints = save_and_disable_interrupts();
flash_range_erase(addr-XIP_BASE, FLASH_SECTOR_SIZE);
restore_interrupts (ints);
return 0;
}
int
flash_check_blank (const uint8_t *p_start, size_t size)
{
const uint8_t *p;
for (p = p_start; p < p_start + size; p++)
if (*p != 0xff)
return 0;
return 1;
}
int
flash_write (uintptr_t dst_addr, const uint8_t *src, size_t len)
{
uint32_t ints = save_and_disable_interrupts();
flash_range_program(dst_addr-XIP_BASE, src, (len%FLASH_PAGE_SIZE == 0 ? len : ((size_t)(len/FLASH_PAGE_SIZE)+1)*FLASH_PAGE_SIZE));
restore_interrupts (ints);
}

352
mod.c Normal file
View File

@ -0,0 +1,352 @@
/*
* mod.c -- modulo arithmetic
*
* Copyright (C) 2011, 2014 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdint.h>
#include <string.h>
#include "bn.h"
/**
* @brief X = A mod B (using MU=(1<<(256)+MU_lower)) (Barret reduction)
*
*/
void
mod_reduce (bn256 *X, const bn512 *A, const bn256 *B, const bn256 *MU_lower)
{
bn256 q[1];
bn512 q_big[1], tmp[1];
uint32_t carry;
#define borrow carry
memset (q, 0, sizeof (bn256));
q->word[0] = A->word[15];
bn256_mul (tmp, q, MU_lower);
tmp->word[8] += A->word[15];
carry = (tmp->word[8] < A->word[15]);
tmp->word[9] += carry;
q->word[7] = A->word[14];
q->word[6] = A->word[13];
q->word[5] = A->word[12];
q->word[4] = A->word[11];
q->word[3] = A->word[10];
q->word[2] = A->word[9];
q->word[1] = A->word[8];
q->word[0] = A->word[7];
bn256_mul (q_big, q, MU_lower);
bn256_add ((bn256 *)&q_big->word[8], (bn256 *)&q_big->word[8], q);
q->word[0] = q_big->word[9] + tmp->word[1];
carry = (q->word[0] < tmp->word[1]);
q->word[1] = q_big->word[10] + carry;
carry = (q->word[1] < carry);
q->word[1] += tmp->word[2];
carry += (q->word[1] < tmp->word[2]);
q->word[2] = q_big->word[11] + carry;
carry = (q->word[2] < carry);
q->word[2] += tmp->word[3];
carry += (q->word[2] < tmp->word[3]);
q->word[3] = q_big->word[12] + carry;
carry = (q->word[3] < carry);
q->word[3] += tmp->word[4];
carry += (q->word[3] < tmp->word[4]);
q->word[4] = q_big->word[13] + carry;
carry = (q->word[4] < carry);
q->word[4] += tmp->word[5];
carry += (q->word[4] < tmp->word[5]);
q->word[5] = q_big->word[14] + carry;
carry = (q->word[5] < carry);
q->word[5] += tmp->word[6];
carry += (q->word[5] < tmp->word[6]);
q->word[6] = q_big->word[15] + carry;
carry = (q->word[6] < carry);
q->word[6] += tmp->word[7];
carry += (q->word[6] < tmp->word[7]);
q->word[7] = carry;
q->word[7] += tmp->word[8];
carry = (q->word[7] < tmp->word[8]);
memset (q_big, 0, sizeof (bn512));
q_big->word[8] = A->word[8];
q_big->word[7] = A->word[7];
q_big->word[6] = A->word[6];
q_big->word[5] = A->word[5];
q_big->word[4] = A->word[4];
q_big->word[3] = A->word[3];
q_big->word[2] = A->word[2];
q_big->word[1] = A->word[1];
q_big->word[0] = A->word[0];
bn256_mul (tmp, q, B);
tmp->word[8] += carry * B->word[0];
tmp->word[15] = tmp->word[14] = tmp->word[13] = tmp->word[12]
= tmp->word[11] = tmp->word[10] = tmp->word[9] = 0;
borrow = bn256_sub (X, (bn256 *)&q_big->word[0], (bn256 *)&tmp->word[0]);
q_big->word[8] -= borrow;
q_big->word[8] -= tmp->word[8];
carry = q_big->word[8];
if (carry)
carry -= bn256_sub (X, X, B);
else
bn256_sub (q, X, B);
if (carry)
bn256_sub (X, X, B);
else
bn256_sub (q, X, B);
borrow = bn256_sub (q, X, B);
if (borrow)
memcpy (q, X, sizeof (bn256));
else
memcpy (X, q, sizeof (bn256));
#undef borrow
}
/*
* Reference:
* Donald E. Knuth, The Art of Computer Programming, Vol. 2:
* Seminumerical Algorithms, 3rd ed. Reading, MA: Addison-Wesley, 1998
*
* Max loop: X=0x8000...0000 and N=0xffff...ffff
*/
#define MAX_GCD_STEPS_BN256 (3*256-2)
/**
* @brief C = X^(-1) mod N
*
* Assume X and N are co-prime (or N is prime).
* NOTE: If X==0, it return 0.
*
*/
void
mod_inv (bn256 *C, const bn256 *X, const bn256 *N)
{
bn256 u[1], v[1], tmp[1];
bn256 A[1] = { { { 1, 0, 0, 0, 0, 0, 0, 0 } } };
uint32_t carry;
#define borrow carry
int n = MAX_GCD_STEPS_BN256;
memset (tmp, 0, sizeof (bn256));
memset (C, 0, sizeof (bn256));
memcpy (u, X, sizeof (bn256));
memcpy (v, N, sizeof (bn256));
while (n--)
{
int c = (bn256_is_even (u) << 1) + bn256_is_even (v);
switch (c)
{
case 3:
bn256_shift (u, u, -1);
if (bn256_is_even (A))
{
bn256_add (tmp, A, N);
carry = 0;
}
else
carry = bn256_add (A, A, N);
bn256_shift (A, A, -1);
A->word[7] |= carry * 0x80000000;
bn256_shift (v, v, -1);
if (bn256_is_even (C))
{
bn256_add (tmp, C, N);
carry = 0;
}
else
carry = bn256_add (C, C, N);
bn256_shift (C, C, -1);
C->word[7] |= carry * 0x80000000;
if (bn256_is_ge (tmp, tmp))
{
bn256_sub (tmp, tmp, tmp);
borrow = bn256_sub (tmp, tmp, tmp);
if (borrow)
bn256_add (tmp, tmp, tmp);
else
bn256_add (tmp, A, N);
}
else
{
bn256_sub (tmp, tmp, tmp);
borrow = bn256_sub (tmp, tmp, tmp);
if (borrow)
bn256_add (tmp, tmp, tmp);
else
bn256_add (tmp, tmp, N);
}
break;
case 1:
bn256_shift (tmp, tmp, -1);
if (bn256_is_even (tmp))
{
bn256_add (tmp, tmp, N);
carry = 0;
}
else
carry = bn256_add (tmp, tmp, N);
bn256_shift (tmp, tmp, -1);
tmp->word[7] |= carry * 0x80000000;
bn256_shift (v, v, -1);
if (bn256_is_even (C))
{
bn256_add (tmp, C, N);
carry = 0;
}
else
carry = bn256_add (C, C, N);
bn256_shift (C, C, -1);
C->word[7] |= carry * 0x80000000;
if (bn256_is_ge (tmp, tmp))
{
bn256_sub (tmp, tmp, tmp);
borrow = bn256_sub (tmp, tmp, tmp);
if (borrow)
bn256_add (tmp, tmp, tmp);
else
bn256_add (tmp, A, N);
}
else
{
bn256_sub (tmp, tmp, tmp);
borrow = bn256_sub (tmp, tmp, tmp);
if (borrow)
bn256_add (tmp, tmp, tmp);
else
bn256_add (tmp, tmp, N);
}
break;
case 2:
bn256_shift (u, u, -1);
if (bn256_is_even (A))
{
bn256_add (tmp, A, N);
carry = 0;
}
else
carry = bn256_add (A, A, N);
bn256_shift (A, A, -1);
A->word[7] |= carry * 0x80000000;
bn256_shift (tmp, tmp, -1);
if (bn256_is_even (tmp))
{
bn256_add (tmp, tmp, N);
carry = 0;
}
else
carry = bn256_add (tmp, tmp, N);
bn256_shift (tmp, tmp, -1);
tmp->word[7] |= carry * 0x80000000;
if (bn256_is_ge (tmp, tmp))
{
bn256_sub (tmp, tmp, tmp);
borrow = bn256_sub (tmp, tmp, tmp);
if (borrow)
bn256_add (tmp, tmp, tmp);
else
bn256_add (tmp, A, N);
}
else
{
bn256_sub (tmp, tmp, tmp);
borrow = bn256_sub (tmp, tmp, tmp);
if (borrow)
bn256_add (tmp, tmp, tmp);
else
bn256_add (tmp, tmp, N);
}
break;
case 0:
bn256_shift (tmp, tmp, -1);
if (bn256_is_even (tmp))
{
bn256_add (tmp, tmp, N);
carry = 0;
}
else
carry = bn256_add (tmp, tmp, N);
bn256_shift (tmp, tmp, -1);
tmp->word[7] |= carry * 0x80000000;
bn256_shift (tmp, tmp, -1);
if (bn256_is_even (tmp))
{
bn256_add (tmp, tmp, N);
carry = 0;
}
else
carry = bn256_add (tmp, tmp, N);
bn256_shift (tmp, tmp, -1);
tmp->word[7] |= carry * 0x80000000;
if (bn256_is_ge (u, v))
{
bn256_sub (u, u, v);
borrow = bn256_sub (A, A, C);
if (borrow)
bn256_add (A, A, N);
else
bn256_add (tmp, A, N);
}
else
{
bn256_sub (v, v, u);
borrow = bn256_sub (C, C, A);
if (borrow)
bn256_add (C, C, N);
else
bn256_add (tmp, C, N);
}
break;
}
}
#undef borrow
}

3
mod.h Normal file
View File

@ -0,0 +1,3 @@
void mod_reduce (bn256 *X, const bn512 *A, const bn256 *B,
const bn256 *MU_lower);
void mod_inv (bn256 *X, const bn256 *A, const bn256 *N);

287
mod25638.c Normal file
View File

@ -0,0 +1,287 @@
/*
* mod25638.c -- modulo arithmetic of 2^256-38 for 2^255-19 field
*
* Copyright (C) 2014 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* The field is \Z/(2^255-19)
*
* We use radix-32. During computation, it's not reduced to 2^255-19,
* but it is represented in 256-bit (it is redundant representation),
* that is, something like 2^256-38.
*
* The idea is, keeping within 256-bit until it will be converted to
* affine coordinates.
*/
#include <stdint.h>
#include <string.h>
#include "bn.h"
#include "mod25638.h"
#ifndef BN256_C_IMPLEMENTATION
#define ASM_IMPLEMENTATION 0
#endif
#if ASM_IMPLEMENTATION
#include "muladd_256.h"
#define ADDWORD_256(d_,s_,w_,c_) \
asm ( "ldmia %[s]!, { r4, r5, r6, r7 } \n\t" \
"adds r4, r4, %[w] \n\t" \
"adcs r5, r5, #0 \n\t" \
"adcs r6, r6, #0 \n\t" \
"adcs r7, r7, #0 \n\t" \
"stmia %[d]!, { r4, r5, r6, r7 }\n\t" \
"ldmia %[s]!, { r4, r5, r6, r7 } \n\t" \
"adcs r4, r4, #0 \n\t" \
"adcs r5, r5, #0 \n\t" \
"adcs r6, r6, #0 \n\t" \
"adcs r7, r7, #0 \n\t" \
"stmia %[d]!, { r4, r5, r6, r7 }\n\t" \
"mov %[c], #0 \n\t" \
"adc %[c], %[c], #0" \
: [s] "=&r" (s_), [d] "=&r" (d_), [c] "=&r" (c_) \
: "[s]" (s_), "[d]" (d_), [w] "r" (w_) \
: "r4", "r5", "r6", "r7", "memory", "cc" )
#endif
/*
256 224 192 160 128 96 64 32 0
2^256
1 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
2^256 - 16
0 ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffff0
2^256 - 16 - 2
0 ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffee
2^256 - 16 - 2 - 1
0 ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffed
*/
const bn256 p25519[1] = {
{{ 0xffffffed, 0xffffffff, 0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff, 0xffffffff, 0x7fffffff }} };
/*
* Implementation Note.
*
* It's not always modulo n25638. The representation is redundant
* during computation. For example, when we add the number - 1 and 1,
* it won't overflow to 2^256, and the result is represented within
* 256-bit.
*/
/**
* @brief X = (A + B) mod 2^256-38
*/
void
mod25638_add (bn256 *X, const bn256 *A, const bn256 *B)
{
uint32_t carry;
carry = bn256_add (X, A, B);
carry = bn256_add_uint (X, X, carry*38);
X->word[0] += carry * 38;
}
/**
* @brief X = (A - B) mod 2^256-38
*/
void
mod25638_sub (bn256 *X, const bn256 *A, const bn256 *B)
{
uint32_t borrow;
borrow = bn256_sub (X, A, B);
borrow = bn256_sub_uint (X, X, borrow*38);
X->word[0] -= borrow * 38;
}
/**
* @brief X = A mod 2^256-38
*
* Note that the second argument is not "const bn512 *".
* A is modified during the computation of modulo.
*
* It's not precisely modulo 2^256-38 for all cases,
* but result may be redundant.
*/
static void
mod25638_reduce (bn256 *X, bn512 *A)
{
const uint32_t *s;
uint32_t *d;
uint32_t w;
#if ASM_IMPLEMENTATION
uint32_t c, c0;
s = &A->word[8]; d = &A->word[0]; w = 38; MULADD_256 (s, d, w, c);
c0 = A->word[8] * 38;
d = &X->word[0];
s = &A->word[0];
ADDWORD_256 (d, s, c0, c);
X->word[0] += c * 38;
#else
s = &A->word[8]; d = &A->word[0]; w = 38;
{
int i;
uint64_t r;
uint32_t carry;
r = 0;
for (i = 0; i < BN256_WORDS; i++)
{
uint64_t uv;
r += d[i];
carry = (r < d[i]);
uv = ((uint64_t)s[i])*w;
r += uv;
carry += (r < uv);
d[i] = (uint32_t)r;
r = ((r >> 32) | ((uint64_t)carry << 32));
}
carry = bn256_add_uint (X, (bn256 *)A, r * 38);
X->word[0] += carry * 38;
}
#endif
}
/**
* @brief X = (A * B) mod 2^256-38
*/
void
mod25638_mul (bn256 *X, const bn256 *A, const bn256 *B)
{
bn512 tmp[1];
bn256_mul (tmp, A, B);
mod25638_reduce (X, tmp);
}
/**
* @brief X = A * A mod 2^256-38
*/
void
mod25638_sqr (bn256 *X, const bn256 *A)
{
bn512 tmp[1];
bn256_sqr (tmp, A);
mod25638_reduce (X, tmp);
}
/**
* @brief X = (A << shift) mod 2^256-38
* @note shift < 32
*/
void
mod25638_shift (bn256 *X, const bn256 *A, int shift)
{
uint32_t carry;
bn256 tmp[1];
carry = bn256_shift (X, A, shift);
if (shift < 0)
return;
memset (tmp, 0, sizeof (bn256));
tmp->word[0] = (carry << 1);
/* tmp->word[1] = (carry >> 31); always zero. */
tmp->word[0] = tmp->word[0] + (carry << 2);
tmp->word[1] = (tmp->word[0] < (carry << 2)) + (carry >> 30);
tmp->word[0] = tmp->word[0] + (carry << 5);
tmp->word[1] = tmp->word[1] + (tmp->word[0] < (carry << 5)) + (carry >> 27);
mod25638_add (X, X, tmp);
}
/*
* @brief X = A mod 2^255-19
*
* It's precisely modulo 2^255-19 (unlike mod25638_reduce).
*/
void
mod25519_reduce (bn256 *X)
{
uint32_t q;
bn256 r0[1], r1[1];
int flag;
memcpy (r0, X, sizeof (bn256));
q = (r0->word[7] >> 31);
r0->word[7] &= 0x7fffffff;
if (q)
{
bn256_add_uint (r0, r0, 19);
q = (r0->word[7] >> 31);
r0->word[7] &= 0x7fffffff;
if (q)
{
bn256_add_uint (r1, r0, 19);
q = (r1->word[7] >> 31);
r1->word[7] &= 0x7fffffff;
flag = 0;
}
else
flag = 1;
}
else
{
bn256_add_uint (r1, r0, 19);
q = (r1->word[7] >> 31); /* dummy */
r1->word[7] &= 0x7fffffff; /* dummy */
if (q)
flag = 2;
else
flag = 3;
}
if (flag)
{
bn256_add_uint (r1, r0, 19);
q = (r1->word[7] >> 31);
r1->word[7] &= 0x7fffffff;
if (q)
memcpy (X, r1, sizeof (bn256));
else
memcpy (X, r0, sizeof (bn256));
}
else
{
if (q)
{
asm volatile ("" : : "r" (q) : "memory");
memcpy (X, r1, sizeof (bn256));
asm volatile ("" : : "r" (q) : "memory");
}
else
memcpy (X, r1, sizeof (bn256));
}
}

7
mod25638.h Normal file
View File

@ -0,0 +1,7 @@
extern const bn256 p25519[1];
void mod25638_add (bn256 *X, const bn256 *A, const bn256 *B);
void mod25638_sub (bn256 *X, const bn256 *A, const bn256 *B);
void mod25638_mul (bn256 *X, const bn256 *A, const bn256 *B);
void mod25638_sqr (bn256 *X, const bn256 *A);
void mod25519_reduce (bn256 *X);

315
modp256k1.c Normal file
View File

@ -0,0 +1,315 @@
/*
* modp256k1.c -- modulo arithmetic for p256k1
*
* Copyright (C) 2014, 2016, 2020 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* p256k1 = 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1
*/
#include <stdint.h>
#include <string.h>
#include "bn.h"
#include "modp256k1.h"
/*
256 224 192 160 128 96 64 32 0
2^256
1 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
2^256 - 2^32
0 ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff 00000000
2^256 - 2^32 - 2^9
0 ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffe00
2^256 - 2^32 - 2^9 - 2^8
0 ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffd00
2^256 - 2^32 - 2^9 - 2^8 - 2^7
0 ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc80
2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6
0 ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc40
2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4
0 ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc30
2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1
0 ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f
*/
const bn256 p256k1 = { {0xfffffc2f, 0xfffffffe, 0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff } };
/*
* Implementation Note.
*
* It's always modulo p256k1.
*
* Once, I tried redundant representation which caused wrong
* calculation. Implementation could be correct with redundant
* representation, but it found that it's more expensive.
*
*/
/**
* @brief X = (A + B) mod p256k1
*/
void
modp256k1_add (bn256 *X, const bn256 *A, const bn256 *B)
{
uint32_t cond;
bn256 tmp[1];
bn256 dummy[1];
cond = (bn256_add (X, A, B) == 0);
cond &= bn256_sub (tmp, X, P256K1);
memcpy (cond?dummy:X, tmp, sizeof (bn256));
asm ("" : "=m" (dummy) : "m" (dummy) : "memory");
}
/**
* @brief X = (A - B) mod p256
*/
void
modp256k1_sub (bn256 *X, const bn256 *A, const bn256 *B)
{
uint32_t borrow;
bn256 tmp[1];
bn256 dummy[1];
borrow = bn256_sub (X, A, B);
bn256_add (tmp, X, P256K1);
memcpy (borrow?X:dummy, tmp, sizeof (bn256));
asm ("" : "=m" (dummy) : "m" (dummy) : "memory");
}
/**
* @brief X = A mod p256k1
*/
void
modp256k1_reduce (bn256 *X, const bn512 *A)
{
bn256 tmp[1];
uint32_t carry;
#define borrow carry
uint32_t s0, s1;
#define s00 tmp->word[0]
#define s01 tmp->word[1]
#define s02 tmp->word[2]
#define W0 X
#define W1 tmp
#define W2 tmp
#define W3 tmp
#define W4 tmp
#define W5 tmp
#define W6 tmp
#define W7 tmp
#define S tmp
/*
* Suppose: P256K1 = 2^256 - CONST
* Then, compute: W = A_low + A_high * CONST
* 256-bit W0 = W mod 2^256
* 64-bit (S1, S0) = W / 2^256
* where: CONST = 2^32 + 2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1
*/
/* W0 = A_low */
/* W7 = A_high */
/* W0 += W7 */
carry = bn256_add (W0, (const bn256 *)&A->word[8], (const bn256 *)A);
/* W6 = W7 << 4 */
/* W0 += W6 */
bn256_shift (W6, (const bn256 *)&A->word[8], 4);
carry += bn256_add (W0, W0, W6);
/* W5 = W6 << 2 */
/* W0 += W5 */
bn256_shift (W5, W6, 2);
carry += bn256_add (W0, W0, W5);
/* W4 = W5 << 1 */
/* W0 += W4 */
bn256_shift (W4, W5, 1);
carry += bn256_add (W0, W0, W4);
/* W3 = W4 << 1 */
/* W0 += W3 */
bn256_shift (W3, W4, 1);
carry += bn256_add (W0, W0, W3);
/* W2 = W3 << 1 */
/* W0 += W2 */
bn256_shift (W2, W3, 1);
carry += bn256_add (W0, W0, W2);
/* W1 = A_high << 32 */
/* W0 += W1 */
W1->word[7] = A->word[14];
W1->word[6] = A->word[13];
W1->word[5] = A->word[12];
W1->word[4] = A->word[11];
W1->word[3] = A->word[10];
W1->word[2] = A->word[9];
W1->word[1] = A->word[8];
W1->word[0] = 0;
carry += bn256_add (W0, W0, W1);
/* (S1, S0) = W / 2^256 */
s0 = A->word[15];
carry += (s0 >> 28) + (s0 >> 26) + (s0 >> 25) + (s0 >> 24) + (s0 >> 23);
carry += s0;
s1 = (carry < s0) ? 1 : 0;
s0 = carry;
/*
* Compute: S:=(S02, S01, S00), S = (S1,S0)*CONST
*/
S->word[7] = S->word[6] = S->word[5] = S->word[4] = S->word[3] = 0;
/* (S02, S01, S00) = (S1, S0) + (S1, S0)*2^32 */
s00 = s0;
s01 = s0 + s1;
s02 = s1 + ((s01 < s0)? 1 : 0);
/* (S02, S01, S00) += (S1, S0)*2^9 */
carry = (s0 >> 23) + s01;
s02 += (s1 >> 23) + ((carry < s01)? 1 : 0);
s01 = (s1 << 9) + carry;
s02 += ((s01 < carry)? 1 : 0);
s00 += (s0 << 9);
carry = ((s00 < (s0 << 9))? 1 : 0);
s01 += carry;
s02 += ((s01 < carry)? 1 : 0);
/* (S02, S01, S00) += (S1, S0)*2^8 */
carry = (s0 >> 24) + s01;
s02 += (s1 >> 24) + ((carry < s01)? 1 : 0);
s01 = (s1 << 8) + carry;
s02 += ((s01 < carry)? 1 : 0);
s00 += (s0 << 8);
carry = ((s00 < (s0 << 8))? 1 : 0);
s01 += carry;
s02 += ((s01 < carry)? 1 : 0);
/* (S02, S01, S00) += (S1, S0)*2^7 */
carry = (s0 >> 25) + s01;
s02 += (s1 >> 25) + ((carry < s01)? 1 : 0);
s01 = (s1 << 7) + carry;
s02 += ((s01 < carry)? 1 : 0);
s00 += (s0 << 7);
carry = ((s00 < (s0 << 7))? 1 : 0);
s01 += carry;
s02 += ((s01 < carry)? 1 : 0);
/* (S02, S01, S00) += (S1, S0)*2^6 */
carry = (s0 >> 26) + s01;
s02 += (s1 >> 26) + ((carry < s01)? 1 : 0);
s01 = (s1 << 6) + carry;
s02 += ((s01 < carry)? 1 : 0);
s00 += (s0 << 6);
carry = ((s00 < (s0 << 6))? 1 : 0);
s01 += carry;
s02 += ((s01 < carry)? 1 : 0);
/* (S02, S01, S00) += (S1, S0)*2^4 */
carry = (s0 >> 28) + s01;
s02 += (s1 >> 28) + ((carry < s01)? 1 : 0);
s01 = (s1 << 4) + carry;
s02 += ((s01 < carry)? 1 : 0);
s00 += (s0 << 4);
carry = ((s00 < (s0 << 4))? 1 : 0);
s01 += carry;
s02 += ((s01 < carry)? 1 : 0);
/* W0 += S */
modp256k1_add (W0, W0, S);
borrow = bn256_sub (tmp, W0, P256K1);
if (borrow)
memcpy (tmp, W0, sizeof (bn256));
else
memcpy (W0, tmp, sizeof (bn256));
#undef W0
#undef W1
#undef W2
#undef W3
#undef W4
#undef W5
#undef W6
#undef W7
#undef S
#undef s00
#undef s01
#undef s02
#undef borrow
}
/**
* @brief X = (A * B) mod p256k1
*/
void
modp256k1_mul (bn256 *X, const bn256 *A, const bn256 *B)
{
bn512 AB[1];
bn256_mul (AB, A, B);
modp256k1_reduce (X, AB);
}
/**
* @brief X = A * A mod p256k1
*/
void
modp256k1_sqr (bn256 *X, const bn256 *A)
{
bn512 AA[1];
bn256_sqr (AA, A);
modp256k1_reduce (X, AA);
}
/**
* @brief X = (A << shift) mod p256k1
* @note shift < 32
*/
void
modp256k1_shift (bn256 *X, const bn256 *A, int shift)
{
uint32_t carry;
bn256 tmp[1];
carry = bn256_shift (X, A, shift);
if (shift < 0)
return;
memset (tmp, 0, sizeof (bn256));
tmp->word[0] = carry + (carry << 9);
tmp->word[1] = carry + (tmp->word[0] < (carry << 9)) + (carry >> 23);
tmp->word[0] = tmp->word[0] + (carry << 8);
tmp->word[1] = tmp->word[1] + (tmp->word[0] < (carry << 8)) + (carry >> 24);
tmp->word[0] = tmp->word[0] + (carry << 7);
tmp->word[1] = tmp->word[1] + (tmp->word[0] < (carry << 7)) + (carry >> 25);
tmp->word[0] = tmp->word[0] + (carry << 6);
tmp->word[1] = tmp->word[1] + (tmp->word[0] < (carry << 6)) + (carry >> 26);
tmp->word[0] = tmp->word[0] + (carry << 4);
tmp->word[1] = tmp->word[1] + (tmp->word[0] < (carry << 4)) + (carry >> 28);
modp256k1_add (X, X, tmp);
}

9
modp256k1.h Normal file
View File

@ -0,0 +1,9 @@
extern const bn256 p256k1;
#define P256K1 (&p256k1)
void modp256k1_add (bn256 *X, const bn256 *A, const bn256 *B);
void modp256k1_sub (bn256 *X, const bn256 *A, const bn256 *B);
void modp256k1_reduce (bn256 *X, const bn512 *A);
void modp256k1_mul (bn256 *X, const bn256 *A, const bn256 *B);
void modp256k1_sqr (bn256 *X, const bn256 *A);
void modp256k1_shift (bn256 *X, const bn256 *A, int shift);

50
muladd_256.h Normal file
View File

@ -0,0 +1,50 @@
#define MULADD_256_ASM(s_,d_,w_,c_) \
asm ( "ldmia %[s]!, { r8, r9, r10 } \n\t" \
"ldmia %[d], { r5, r6, r7 } \n\t" \
"umull r4, r8, %[w], r8 \n\t" \
"adds r5, r5, r4 \n\t" \
"adcs r6, r6, r8 \n\t" \
"umull r4, r8, %[w], r9 \n\t" \
"adc %[c], r8, #0 \n\t" \
"adds r6, r6, r4 \n\t" \
"adcs r7, r7, %[c] \n\t" \
"umull r4, r8, %[w], r10 \n\t" \
"adc %[c], r8, #0 \n\t" \
"adds r7, r7, r4 \n\t" \
"stmia %[d]!, { r5, r6, r7 } \n\t" \
"ldmia %[s]!, { r8, r9, r10 } \n\t" \
"ldmia %[d], { r5, r6, r7 } \n\t" \
"adcs r5, r5, %[c] \n\t" \
"umull r4, r8, %[w], r8 \n\t" \
"adc %[c], r8, #0 \n\t" \
"adds r5, r5, r4 \n\t" \
"adcs r6, r6, %[c] \n\t" \
"umull r4, r8, %[w], r9 \n\t" \
"adc %[c], r8, #0 \n\t" \
"adds r6, r6, r4 \n\t" \
"adcs r7, r7, %[c] \n\t" \
"umull r4, r8, %[w], r10 \n\t" \
"adc %[c], r8, #0 \n\t" \
"adds r7, r7, r4 \n\t" \
"stmia %[d]!, { r5, r6, r7 } \n\t" \
"ldmia %[s]!, { r8, r9 } \n\t" \
"ldmia %[d], { r5, r6 } \n\t" \
"adcs r5, r5, %[c] \n\t" \
"umull r4, r8, %[w], r8 \n\t" \
"adc %[c], r8, #0 \n\t" \
"adds r5, r5, r4 \n\t" \
"adcs r6, r6, %[c] \n\t" \
"umull r4, r8, %[w], r9 \n\t" \
"adc %[c], r8, #0 \n\t" \
"adds r6, r6, r4 \n\t" \
"adc %[c], %[c], #0 \n\t" \
"stmia %[d]!, { r5, r6 }" \
: [s] "=&r" (s_), [d] "=&r" (d_), [c] "=&r" (c_) \
: "[s]" (s_), "[d]" (d_), [w] "r" (w_) \
: "r4", "r5", "r6", "r7", "r8", "r9", "r10", \
"memory", "cc" )
#define MULADD_256(s__,d__,w__,c__) do { \
MULADD_256_ASM(s__,d__,w__,c__); \
*d__ = c__; \
} while (0)

2637
openpgp-do.c Normal file

File diff suppressed because it is too large Load Diff

1704
openpgp.c Normal file

File diff suppressed because it is too large Load Diff

666
p448.c Normal file
View File

@ -0,0 +1,666 @@
/* -*- coding: utf-8 -*-
* p448.c - Modular calculation with p448: 2^448 - 2^224 - 1
*
* Copyright (C) 2021 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdint.h>
#include "p448.h"
#define MASK_28BITS 0x0fffffff
static void
p448_add_raw (p448_t *x, const p448_t *a, const p448_t *b)
{
int i;
for (i = 0; i < N_REDUNDANT_LIMBS; i++)
x->limb[i] = a->limb[i] + b->limb[i];
}
static void
p448_sub_raw (p448_t *x, const p448_t *a, const p448_t *b)
{
int i;
for (i = 0; i < N_REDUNDANT_LIMBS; i++)
x->limb[i] = a->limb[i] - b->limb[i];
}
static uint64_t
mul64_32x32 (const uint32_t a, const uint32_t b)
{
return ((uint64_t)a) * b;
}
/**
* Compute X = A * B mod p448
*/
/*
* When we set phi = 2^224, p448 can be expressed as:
*
* p448 = phi^2 - phy - 1
*
* Here, using the right hand side and make a fomula
*
* phi^2 - phy - 1 = 0
*
* it is the fomula where it's solution is golden ratio.
*
* By analogy, so, p448 is called "golden-ratio prime".
*
* When we set phi = 2^224, Karatsuba multiplication goes like:
*
* (p + q * phi) * (r + s * phi)
* = pr + (ps + qr)*phy + qs*phi^2
* == (pr + qs) + (ps + qr + qs) * phy (mod p448)
* = (pr + qs) + ((p + q)*(r + s) - pr) * phy
*
* That is, it can be done by three times of 224-bit multiplications
* (instead of four).
*
* Let us see more detail.
*
* The formula above is calculated to:
* = lower224(pr + qs) + upper224(pr + qs)*phy
* + lower224((p + q)*(r + s) - pr)*phy
* + upper224((p + q)*(r + s) - pr)*phy^2 (mod p448)
* == lower224(pr + qs)
* + upper224((p + q)*(r + s) - pr)
* + (upper224(pr + qs)
* + lower224((p + q)*(r + s) - pr)
* + upper224((p + q)*(r + s) - pr))*phy (mod p448)
* = lower224(pr + qs)
* + upper224((p + q)*(r + s) - pr)
* + (lower224((p + q)*(r + s) - pr)
* + upper224((p + q)*(r + s) + qs)) * phy
*
*/
/*
Here is a figure of: multiplication by 8-limb * 8-limb
a b c d e f g h
* i j k l m n o p
---------------------------------------------
ap bp cp dp ep fp gp hp
ao bo co do eo fo go ho
an bn cn dn en fn gn hn
am bm cm dm em fm gm hm
al bl cl dl el fl gl hl
ak bk ck dk ek fk gk hk
aj bj cj dj ej fj gj hj
ai bi ci di ei fi gi hi
Considering lower224, it's:
ap bp cp dp ep fp gp hp
bo co do eo fo go ho
cn dn en fn gn hn
dm em fm gm hm
el fl gl hl
fk gk hk
gj hj
hi
Considering upper224, it's:
ao
an bn
am bm cm
al bl cl dl
ak bk ck dk ek
aj bj cj dj ej fj
ai bi ci di ei fi gi
*/
void
p448_mul (p448_t *__restrict__ x, const p448_t *a, const p448_t *b)
{
int i, j;
uint64_t v64_0, v64_1, v64_2;
uint32_t p_q[8], r_s[8];
uint32_t *px;
const uint32_t *pa, *pb;
px = x->limb;
pa = a->limb;
pb = b->limb;
/* Firstly, we do Karatsuba preparation. */
for (i = 0; i < 8; i++)
{
p_q[i] = pa[i] + pa[i+8];
r_s[i] = pb[i] + pb[i+8];
}
v64_0 = v64_1 = 0;
for (j = 0; j < 8; j++)
{
v64_2 = 0;
/* Compute lower half of limbs (lower224) */
/* __ <-- j
* | / |
* |/ v i
*
*/
for (i = 0; i <= j; i++)
{
v64_0 += mul64_32x32 (pa[8+j-i], pb[8+i]);/* accumulating q*s */
v64_1 += mul64_32x32 (p_q[j-i], r_s[i]); /* accumulating p_q*r_s */
v64_2 += mul64_32x32 (pa[j-i], pb[i]); /* accumulating p*r */
}
v64_0 += v64_2; /* Compute pr+qs. */
v64_1 -= v64_2; /* Compute p_q*r_s - pr. */
v64_2 = 0;
/* Compute upper half of limbs (upper224) */
/* <-- j
* /| |
* /_| v i
*
*/
for (; i < 8; i++)
{
v64_0 -= mul64_32x32 (pa[8+j-i], pb[i]); /* accumulating -p*r */
v64_1 += mul64_32x32 (pa[16+j-i], pb[8+i]);/* accumulating q*s */
v64_2 += mul64_32x32 (p_q[8+j-i], r_s[i]); /* accumulating p_q*r_s */
}
v64_0 += v64_2; /* Compute p_q*r_s - pr. */
v64_1 += v64_2; /* Compute p_q*r_s + qs. */
px[j] = v64_0 & MASK_28BITS;
px[j+8] = v64_1 & MASK_28BITS;
v64_0 >>= 28;
v64_1 >>= 28;
}
/* "Carry" remains as: 2^448 * v64_1 + 2^224 * v64_0 */
/*
* Subtract p448 times v64_1 to clear msbs, meaning, clear those
* bits and adding v64_1 to px[0] and px[8] (in mod p448
* calculation).
*/
v64_0 += v64_1;
v64_0 += px[8];
v64_1 += px[0];
px[8] = v64_0 & MASK_28BITS;
px[0] = v64_1 & MASK_28BITS;
/* Still, it carries to... */
v64_0 >>= 28;
v64_1 >>= 28;
px[9] += v64_0;
px[1] += v64_1;
/* DONE. */
}
/**
* Compute X = A * 39081
*/
void
p448_mul_39081 (p448_t *x, const p448_t *a)
{
int i;
const uint32_t w = 39081;
uint32_t *px;
const uint32_t *pa;
uint64_t v64;
uint32_t carry;
px = x->limb;
pa = a->limb;
v64 = 0;
for (i = 0; i < N_REDUNDANT_LIMBS; i++)
{
v64 += mul64_32x32 (w, pa[i]);
px[i] = v64 & MASK_28BITS;
v64 >>= 28;
}
carry = v64;
carry += px[0];
px[0] = carry & MASK_28BITS;
px[1] += carry >> 28;
carry = v64;
carry += px[8];
px[8] = carry & MASK_28BITS;
px[9] += carry >> 28;
}
/*
ah bh ch dh eh fh gh HH
bg cg dg eg fg GG
cf df ef FF
de EE
DD
CC dc ec
BB cb db eb fb
AA ba ca da ea fa ga
*/
/**
* Compute X = A^2 mod p448
*/
void
p448_sqr (p448_t *__restrict__ x, const p448_t *a)
{
int i, j;
uint64_t v64_0, v64_1, v64_2, v64_3;
uint32_t p_q[8];
uint32_t *px;
const uint32_t *pa;
px = x->limb;
pa = a->limb;
/* Firstly, we do Karatsuba preparation. */
for (i = 0; i < 8; i++)
p_q[i] = pa[i] + pa[i+8];
v64_0 = v64_1 = 0;
for (j = 0; j < 8; j++)
{
v64_2 = 0;
/* Compute lower half of limbs (lower224) */
/* __ <-- j
* | / |
* |/ v i
*
*/
for (i = 0; i <= j/2; i++)
{
int cond = ((j & 1) || i != j/2);
v64_3 = mul64_32x32 (pa[8+j-i], pa[8+i]);/* accumulating q*q */
v64_0 += (v64_3 << cond);
v64_3 = mul64_32x32 (p_q[j-i], p_q[i]); /* accumulating p_q^2 */
v64_1 += (v64_3 << cond);
v64_3 = mul64_32x32 (pa[j-i], pa[i]); /* accumulating p*p */
v64_2 += (v64_3 << cond);
}
v64_0 += v64_2; /* Compute pp+qq. */
v64_1 -= v64_2; /* Compute p_q^2 - pp. */
v64_2 = 0;
/* Compute upper half of limbs (upper224) */
/* <-- j
* /| |
* /_| v i
*
*/
if (!(j & 1))
{
v64_0 -= mul64_32x32 (pa[4+i-1], pa[4+i-1]); /* accumulating -p*p */
v64_1 += mul64_32x32 (pa[12+i-1], pa[12+i-1]);/* accumulating q*q */
v64_2 += mul64_32x32 (p_q[4+i-1], p_q[4+i-1]);/* accumulating p_q^2 */
}
for (; i < 4; i++)
{
v64_3 = mul64_32x32 (pa[4+j-i], pa[4+i]);
v64_0 -= (v64_3 << 1); /* accumulating -p*p */
v64_3 = mul64_32x32 (pa[12+j-i], pa[12+i]);
v64_1 += (v64_3 << 1); /* accumulating q*q */
v64_3 = mul64_32x32 (p_q[4+j-i], p_q[4+i]);
v64_2 += (v64_3 << 1); /* accumulating p_q^2 */
}
v64_0 += v64_2; /* Compute p_q^2 - p^2. */
v64_1 += v64_2; /* Compute p_q^2 + q^2. */
px[j] = v64_0 & MASK_28BITS;
px[j+8] = v64_1 & MASK_28BITS;
v64_0 >>= 28;
v64_1 >>= 28;
}
/* "Carry" remains as: 2^448 * v64_1 + 2^224 * v64_0 */
/*
* Subtract p448 times v64_1 to clear msbs, meaning, clear those
* bits and adding v64_1 to px[0] and px[8] (in mod p448
* calculation).
*/
v64_0 += v64_1;
v64_0 += px[8];
v64_1 += px[0];
px[8] = v64_0 & MASK_28BITS;
px[0] = v64_1 & MASK_28BITS;
/* Still, it carries to... */
v64_0 >>= 28;
v64_1 >>= 28;
px[9] += v64_0;
px[1] += v64_1;
/* DONE. */
}
/**
* Weak reduce - Make each limb of redundunt representation smaller.
* Do our best weakly to zeroing most significant 4-bit.
*
* Note that: p448 = 2^448 - 2^224 - 1
*
* Subtracting p448 means that subtracting 2^448 then adding 2^224 + 1.
*/
void
p448_weak_reduce (p448_t *a)
{
int i;
uint32_t tmp = a->limb[15] >> 28;
a->limb[8] += tmp; /* Adding TMP * 2^224 (28 * 8 = 224) */
/* Compute top to bottom. */
for (i = 0; i < N_REDUNDANT_LIMBS - 1; i++)
a->limb[N_REDUNDANT_LIMBS - i - 1] =
(a->limb[N_REDUNDANT_LIMBS - i - 1] & MASK_28BITS)
+ (a->limb[N_REDUNDANT_LIMBS - i - 2] >> 28);
a->limb[0] = (a->limb[0] & MASK_28BITS) + tmp;
}
static const p448_t p448[1] = {
{
{
0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff,
0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff,
0x0ffffffe, 0x0fffffff, 0x0fffffff, 0x0fffffff,
0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff
}
}
};
static uint32_t
p448_add_carry_cond (p448_t *x, const p448_t *a, const p448_t *b,
uint32_t cond)
{
int i;
uint32_t v;
uint32_t carry = 0;
uint32_t *px;
const uint32_t *pa, *pb;
cond = cond * MASK_28BITS;
px = x->limb;
pa = a->limb;
pb = b->limb;
for (i = 0; i < N_REDUNDANT_LIMBS; i++)
{
v = *pb & cond;
*px = *pa + carry;
carry = (*px < carry);
*px = (*px + v) & MASK_28BITS;
carry += (*px < v);
px++;
pa++;
pb++;
}
return carry;
}
static uint32_t
p448_sub_borrow (p448_t *x, const p448_t *a, const p448_t *b)
{
int i;
uint32_t v;
uint32_t borrow = 0;
uint32_t *px;
const uint32_t *pa, *pb;
px = x->limb;
pa = a->limb;
pb = b->limb;
for (i = 0; i < N_REDUNDANT_LIMBS; i++)
{
uint32_t borrow0 = (*pa < borrow);
v = *pb;
*px = *pa - borrow;
borrow = (*px < v) + borrow0;
*px = (*px - v) & MASK_28BITS;
px++;
pa++;
pb++;
}
return borrow;
}
/**
* Strong reduce - Make sure that each limb of redundunt
* representation has zeros of significant 4-bit.
*/
void
p448_strong_reduce (p448_t *a)
{
uint32_t tmp;
uint32_t is_negative;
/*
* Clear the 4-bit of the last (top) limb. As stated in the comment
* of weak_reduce, subtracting p448 means that subtracting 2^448
* then adding 2^224 + 1.
*/
tmp = a->limb[15] >> 28;
a->limb[8] += tmp;
a->limb[0] += tmp;
a->limb[15] &= MASK_28BITS;
/*
* Here, it's: 0 <= v < 2*p448
*
* When v > p448, subtract p448 from v, then it becomes strongly reduced.
* Otherwise, it's already strongly reduced.
*/
/* Subtract p448 */
is_negative = p448_sub_borrow (a, a, p448);
/* Add p448 conditionally, when it becomes negative. */
p448_add_carry_cond (a, a, p448, is_negative);
}
/**
* Convert to wire-format from internal redundant representation.
*/
void
p448_serialize (uint8_t serial[56], const struct p448_t *x)
{
int i;
p448_t tmp[1];
uint8_t *p = serial;
*tmp = *x;
p448_strong_reduce (tmp);
for (i = 0; i < 8; i++)
{
uint32_t limb0 = tmp->limb[2*i];
uint32_t limb1 = tmp->limb[2*i+1];
*p++ = limb0;
*p++ = (limb0 >> 8);
*p++ = (limb0 >> 16);
*p++ = ((limb0 >> 24) & 0x0f) | ((limb1 & 0x0f )<< 4);
*p++ = (limb1 >> 4);
*p++ = (limb1 >> 12);
*p++ = (limb1 >> 20);
}
}
/**
* Convert from wire-format to internal redundant representation.
*/
void
p448_deserialize (p448_t *x, const uint8_t serial[56])
{
int i;
const uint8_t *p = serial + 56;
for (i = 0; i < 8; i++)
{
uint32_t v;
v = *--p;
v <<= 8;
v |= *--p;
v <<= 8;
v |= *--p;
v <<= 8;
v |= *--p;
x->limb[N_REDUNDANT_LIMBS-2*i-1] = (v >> 4);
v = (v & 0x0f);
v <<= 8;
v |= *--p;
v <<= 8;
v |= *--p;
v <<= 8;
v |= *--p;
x->limb[N_REDUNDANT_LIMBS-2*i-2] = v & MASK_28BITS;
}
}
/* X = A^(2*N) */
static void
p448_sqrn (p448_t *__restrict__ x, const p448_t *a, int n)
{
p448_t tmp[1];
if ((n&1))
{
p448_sqr (x, a);
n--;
}
else
{
p448_sqr (tmp, a);
p448_sqr (x, tmp);
n -= 2;
}
for (; n; n -= 2)
{
p448_sqr (tmp, x);
p448_sqr (x, tmp);
}
}
/**
* Compute X = A^(-1) mod p448 (if A=0, return X = 0)
*
* Internally, do A^(p448 - 2) to get A^(-1).
*/
void
p448_inv (p448_t *__restrict__ x, const p448_t *a)
{
p448_t t[1], u[1];
/*
* Bit pattern of p448-2: 1{223} 0 1{222}01
*
* 222-bit can be composed by 3-bit three times to get 9-bit, 9-bit
* two times to get 18-bit, 18-bit two times plus 1-bit to get 37-bit.
* 37-bit three times to get 111-bit, and lastly 111-bit two times.
* 222 = 111*2 = 37*3*2 = (18*2+1)*3*2 = (9*2*2+1)*3*2 = (3*3*2*2+1)*3*2
*/
p448_sqr ( x, a ); /* 10 */
p448_mul ( t, a, x ); /* 11 */
p448_sqr ( x, t ); /* 110 */
p448_mul ( t, a, x ); /* 111 */
p448_sqrn ( x, t, 3 ); /* 111000 */
p448_mul ( u, t, x ); /* 111111 */
p448_sqrn ( x, u, 3 ); /* 111111000 */
p448_mul ( u, t, x ); /* 111111111 */
p448_sqrn ( t, u, 9 ); /* 1{9} 0{9} */
p448_mul ( x, u, t ); /* 1{18} */
p448_sqr ( t, x ); /* 1{18} 0 */
p448_mul ( u, a, t ); /* 1{19} */
p448_sqrn ( t, u, 18 ); /* 1{19} 0{18} */
p448_mul ( u, x, t ); /* 1{37} */
p448_sqrn ( t, u, 37 ); /* 1{37} 0{37} */
p448_mul ( x, u, t ); /* 1{74} */
p448_sqrn ( t, x, 37 ); /* 1{74} 0{37} */
p448_mul ( x, u, t ); /* 1{111} */
p448_sqrn ( t, x, 111 ); /* 1{111} 0{111} */
p448_mul ( u, x, t ); /* 1{222} */
p448_sqr ( t, u ); /* 1{222} 0 */
p448_mul ( x, a, t ); /* 1{223} */
p448_sqrn ( u, x, 224 ); /* 1{223} 0{224} */
p448_mul ( x, u, t ); /* 1{223} 0 1{222}0 */
p448_sqr ( t, x ); /* 1{223} 0 1{222}00 */
p448_mul ( x, a, t ); /* 1{223} 0 1{222}01 */
}
static const p448_t p448_times_2[1] = {
{
{
0x1ffffffe, 0x1ffffffe, 0x1ffffffe, 0x1ffffffe,
0x1ffffffe, 0x1ffffffe, 0x1ffffffe, 0x1ffffffe,
0x1ffffffc, 0x1ffffffe, 0x1ffffffe, 0x1ffffffe,
0x1ffffffe, 0x1ffffffe, 0x1ffffffe, 0x1ffffffe
}
}
};
/**
* Compute X = A + B mod p448, result is weakly reduced.
*
*/
void
p448_add (p448_t *x, const p448_t *a, const p448_t *b)
{
p448_add_raw (x, a, b);
p448_weak_reduce (x);
}
/**
* Compute X = A - B mod p448, result is weakly reduced.
*
*/
void
p448_sub (p448_t *x, const p448_t *a, const p448_t *b)
{
p448_t tmp[1];
p448_sub_raw (tmp, a, b);
p448_add_raw (x, p448_times_2, tmp);
p448_weak_reduce (x);
}

15
p448.h Normal file
View File

@ -0,0 +1,15 @@
#define N_REDUNDANT_LIMBS 16
typedef struct p448_t
{
uint32_t limb[N_REDUNDANT_LIMBS];
} p448_t;
void p448_add (p448_t *x, const p448_t *a, const p448_t *b);
void p448_sub (p448_t *x, const p448_t *a, const p448_t *b);
void p448_mul (p448_t *__restrict__ x, const p448_t *a, const p448_t *b);
void p448_mul_39081 (p448_t *x, const p448_t *a);
void p448_sqr (p448_t *__restrict__ c, const p448_t *a);
void p448_inv (p448_t *__restrict__ x, const p448_t *a);
void p448_serialize (uint8_t serial[56], const p448_t *x);
void p448_deserialize (p448_t *x, const uint8_t serial[56]);
void p448_strong_reduce (p448_t *a);

204
polarssl/aes.h Normal file
View File

@ -0,0 +1,204 @@
/**
* \file aes.h
*
* \brief AES block cipher
*
* Copyright (C) 2006-2013, Brainspark B.V.
*
* This file is part of PolarSSL (http://www.polarssl.org)
* Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef POLARSSL_AES_H
#define POLARSSL_AES_H
#include "config.h"
#include <string.h>
#ifdef _MSC_VER
#include <basetsd.h>
typedef UINT32 uint32_t;
#else
#include <inttypes.h>
#endif
#define AES_ENCRYPT 1
#define AES_DECRYPT 0
#define POLARSSL_ERR_AES_INVALID_KEY_LENGTH -0x0020 /**< Invalid key length. */
#define POLARSSL_ERR_AES_INVALID_INPUT_LENGTH -0x0022 /**< Invalid data input length. */
#if !defined(POLARSSL_AES_ALT)
// Regular implementation
//
/**
* \brief AES context structure
*/
typedef struct
{
int nr; /*!< number of rounds */
uint32_t *rk; /*!< AES round keys */
uint32_t buf[68]; /*!< unaligned data */
}
aes_context;
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief AES key schedule (encryption)
*
* \param ctx AES context to be initialized
* \param key encryption key
* \param keysize must be 128, 192 or 256
*
* \return 0 if successful, or POLARSSL_ERR_AES_INVALID_KEY_LENGTH
*/
int aes_setkey_enc( aes_context *ctx, const unsigned char *key, unsigned int keysize );
/**
* \brief AES key schedule (decryption)
*
* \param ctx AES context to be initialized
* \param key decryption key
* \param keysize must be 128, 192 or 256
*
* \return 0 if successful, or POLARSSL_ERR_AES_INVALID_KEY_LENGTH
*/
int aes_setkey_dec( aes_context *ctx, const unsigned char *key, unsigned int keysize );
/**
* \brief AES-ECB block encryption/decryption
*
* \param ctx AES context
* \param mode AES_ENCRYPT or AES_DECRYPT
* \param input 16-byte input block
* \param output 16-byte output block
*
* \return 0 if successful
*/
int aes_crypt_ecb( aes_context *ctx,
int mode,
const unsigned char input[16],
unsigned char output[16] );
#if 0
/**
* \brief AES-CBC buffer encryption/decryption
* Length should be a multiple of the block
* size (16 bytes)
*
* \param ctx AES context
* \param mode AES_ENCRYPT or AES_DECRYPT
* \param length length of the input data
* \param iv initialization vector (updated after use)
* \param input buffer holding the input data
* \param output buffer holding the output data
*
* \return 0 if successful, or POLARSSL_ERR_AES_INVALID_INPUT_LENGTH
*/
int aes_crypt_cbc( aes_context *ctx,
int mode,
size_t length,
unsigned char iv[16],
const unsigned char *input,
unsigned char *output );
#endif
/**
* \brief AES-CFB128 buffer encryption/decryption.
*
* Note: Due to the nature of CFB you should use the same key schedule for
* both encryption and decryption. So a context initialized with
* aes_setkey_enc() for both AES_ENCRYPT and AES_DECRYPT.
*
* both
* \param ctx AES context
* \param mode AES_ENCRYPT or AES_DECRYPT
* \param length length of the input data
* \param iv_off offset in IV (updated after use)
* \param iv initialization vector (updated after use)
* \param input buffer holding the input data
* \param output buffer holding the output data
*
* \return 0 if successful
*/
int aes_crypt_cfb128( aes_context *ctx,
int mode,
size_t length,
size_t *iv_off,
unsigned char iv[16],
const unsigned char *input,
unsigned char *output );
/**
* \brief AES-CTR buffer encryption/decryption
*
* Warning: You have to keep the maximum use of your counter in mind!
*
* Note: Due to the nature of CTR you should use the same key schedule for
* both encryption and decryption. So a context initialized with
* aes_setkey_enc() for both AES_ENCRYPT and AES_DECRYPT.
*
* \param length The length of the data
* \param nc_off The offset in the current stream_block (for resuming
* within current cipher stream). The offset pointer to
* should be 0 at the start of a stream.
* \param nonce_counter The 128-bit nonce and counter.
* \param stream_block The saved stream-block for resuming. Is overwritten
* by the function.
* \param input The input data stream
* \param output The output data stream
*
* \return 0 if successful
*/
int aes_crypt_ctr( aes_context *ctx,
size_t length,
size_t *nc_off,
unsigned char nonce_counter[16],
unsigned char stream_block[16],
const unsigned char *input,
unsigned char *output );
#ifdef __cplusplus
}
#endif
#else /* POLARSSL_AES_ALT */
#include "aes_alt.h"
#endif /* POLARSSL_AES_ALT */
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief Checkup routine
*
* \return 0 if successful, or 1 if the test failed
*/
int aes_self_test( int verbose );
#ifdef __cplusplus
}
#endif
#endif /* aes.h */

687
polarssl/bignum.h Normal file
View File

@ -0,0 +1,687 @@
/**
* \file bignum.h
*
* \brief Multi-precision integer library
*
* Copyright (C) 2006-2013, Brainspark B.V.
*
* This file is part of PolarSSL (http://www.polarssl.org)
* Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef POLARSSL_BIGNUM_H
#define POLARSSL_BIGNUM_H
#include <stdio.h>
#include <string.h>
#include "config.h"
#ifdef _MSC_VER
#include <basetsd.h>
#if (_MSC_VER <= 1200)
typedef signed short int16_t;
typedef unsigned short uint16_t;
#else
typedef INT16 int16_t;
typedef UINT16 uint16_t;
#endif
typedef INT32 int32_t;
typedef INT64 int64_t;
typedef UINT32 uint32_t;
typedef UINT64 uint64_t;
#else
#include <inttypes.h>
#endif
#define POLARSSL_ERR_MPI_FILE_IO_ERROR -0x0002 /**< An error occurred while reading from or writing to a file. */
#define POLARSSL_ERR_MPI_BAD_INPUT_DATA -0x0004 /**< Bad input parameters to function. */
#define POLARSSL_ERR_MPI_INVALID_CHARACTER -0x0006 /**< There is an invalid character in the digit string. */
#define POLARSSL_ERR_MPI_BUFFER_TOO_SMALL -0x0008 /**< The buffer is too small to write to. */
#define POLARSSL_ERR_MPI_NEGATIVE_VALUE -0x000A /**< The input arguments are negative or result in illegal output. */
#define POLARSSL_ERR_MPI_DIVISION_BY_ZERO -0x000C /**< The input argument for division is zero, which is not allowed. */
#define POLARSSL_ERR_MPI_NOT_ACCEPTABLE -0x000E /**< The input arguments are not acceptable. */
#define POLARSSL_ERR_MPI_MALLOC_FAILED -0x0010 /**< Memory allocation failed. */
#define MPI_CHK(f) if( ( ret = f ) != 0 ) goto cleanup
/*
* Maximum size MPIs are allowed to grow to in number of limbs.
*/
#define POLARSSL_MPI_MAX_LIMBS 10000
#if !defined(POLARSSL_CONFIG_OPTIONS)
/*
* Maximum window size used for modular exponentiation. Default: 6
* Minimum value: 1. Maximum value: 6.
*
* Result is an array of ( 2 << POLARSSL_MPI_WINDOW_SIZE ) MPIs used
* for the sliding window calculation. (So 64 by default)
*
* Reduction in size, reduces speed.
*/
#define POLARSSL_MPI_WINDOW_SIZE 6 /**< Maximum windows size used. */
/*
* Maximum size of MPIs allowed in bits and bytes for user-MPIs.
* ( Default: 512 bytes => 4096 bits, Maximum tested: 2048 bytes => 16384 bits )
*
* Note: Calculations can results temporarily in larger MPIs. So the number
* of limbs required (POLARSSL_MPI_MAX_LIMBS) is higher.
*/
#define POLARSSL_MPI_MAX_SIZE 256 /**< Maximum number of bytes for usable MPIs. */
#endif /* !POLARSSL_CONFIG_OPTIONS */
#define POLARSSL_MPI_MAX_BITS ( 8 * POLARSSL_MPI_MAX_SIZE ) /**< Maximum number of bits for usable MPIs. */
/*
* When reading from files with mpi_read_file() and writing to files with
* mpi_write_file() the buffer should have space
* for a (short) label, the MPI (in the provided radix), the newline
* characters and the '\0'.
*
* By default we assume at least a 10 char label, a minimum radix of 10
* (decimal) and a maximum of 4096 bit numbers (1234 decimal chars).
* Autosized at compile time for at least a 10 char label, a minimum radix
* of 10 (decimal) for a number of POLARSSL_MPI_MAX_BITS size.
*
* This used to be statically sized to 1250 for a maximum of 4096 bit
* numbers (1234 decimal chars).
*
* Calculate using the formula:
* POLARSSL_MPI_RW_BUFFER_SIZE = ceil(POLARSSL_MPI_MAX_BITS / ln(10) * ln(2)) +
* LabelSize + 6
*/
#define POLARSSL_MPI_MAX_BITS_SCALE100 ( 100 * POLARSSL_MPI_MAX_BITS )
#define LN_2_DIV_LN_10_SCALE100 332
#define POLARSSL_MPI_RW_BUFFER_SIZE ( ((POLARSSL_MPI_MAX_BITS_SCALE100 + LN_2_DIV_LN_10_SCALE100 - 1) / LN_2_DIV_LN_10_SCALE100) + 10 + 6 )
/*
* Define the base integer type, architecture-wise
*/
#if defined(POLARSSL_HAVE_INT8)
typedef signed char t_sint;
typedef unsigned char t_uint;
typedef uint16_t t_udbl;
#define POLARSSL_HAVE_UDBL
#else
#if defined(POLARSSL_HAVE_INT16)
typedef int16_t t_sint;
typedef uint16_t t_uint;
typedef uint32_t t_udbl;
#define POLARSSL_HAVE_UDBL
#else
#if ( defined(_MSC_VER) && defined(_M_AMD64) )
typedef int64_t t_sint;
typedef uint64_t t_uint;
#else
#if ( defined(__GNUC__) && ( \
defined(__amd64__) || defined(__x86_64__) || \
defined(__ppc64__) || defined(__powerpc64__) || \
defined(__ia64__) || defined(__alpha__) || \
(defined(__sparc__) && defined(__arch64__)) || \
defined(__s390x__) ) )
typedef int64_t t_sint;
typedef uint64_t t_uint;
typedef unsigned int t_udbl __attribute__((mode(TI)));
#define POLARSSL_HAVE_UDBL
#else
typedef int32_t t_sint;
typedef uint32_t t_uint;
#if ( defined(_MSC_VER) && defined(_M_IX86) )
typedef uint64_t t_udbl;
#define POLARSSL_HAVE_UDBL
#else
#if defined( POLARSSL_HAVE_LONGLONG )
typedef unsigned long long t_udbl;
#define POLARSSL_HAVE_UDBL
#endif
#endif
#endif
#endif
#endif /* POLARSSL_HAVE_INT16 */
#endif /* POLARSSL_HAVE_INT8 */
/**
* \brief MPI structure
*/
typedef struct
{
int s; /*!< integer sign */
size_t n; /*!< total # of limbs */
t_uint *p; /*!< pointer to limbs */
}
mpi;
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief Initialize one MPI
*
* \param X One MPI to initialize.
*/
void mpi_init( mpi *X );
/**
* \brief Unallocate one MPI
*
* \param X One MPI to unallocate.
*/
void mpi_free( mpi *X );
/**
* \brief Enlarge to the specified number of limbs
*
* \param X MPI to grow
* \param nblimbs The target number of limbs
*
* \return 0 if successful,
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
*/
int mpi_grow( mpi *X, size_t nblimbs );
/**
* \brief Copy the contents of Y into X
*
* \param X Destination MPI
* \param Y Source MPI
*
* \return 0 if successful,
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
*/
int mpi_copy( mpi *X, const mpi *Y );
/**
* \brief Swap the contents of X and Y
*
* \param X First MPI value
* \param Y Second MPI value
*/
void mpi_swap( mpi *X, mpi *Y );
/**
* \brief Set value from integer
*
* \param X MPI to set
* \param z Value to use
*
* \return 0 if successful,
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
*/
int mpi_lset( mpi *X, t_sint z );
/**
* \brief Get a specific bit from X
*
* \param X MPI to use
* \param pos Zero-based index of the bit in X
*
* \return Either a 0 or a 1
*/
int mpi_get_bit( const mpi *X, size_t pos );
/**
* \brief Set a bit of X to a specific value of 0 or 1
*
* \note Will grow X if necessary to set a bit to 1 in a not yet
* existing limb. Will not grow if bit should be set to 0
*
* \param X MPI to use
* \param pos Zero-based index of the bit in X
* \param val The value to set the bit to (0 or 1)
*
* \return 0 if successful,
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed,
* POLARSSL_ERR_MPI_BAD_INPUT_DATA if val is not 0 or 1
*/
int mpi_set_bit( mpi *X, size_t pos, unsigned char val );
/**
* \brief Return the number of zero-bits before the least significant
* '1' bit
*
* Note: Thus also the zero-based index of the least significant '1' bit
*
* \param X MPI to use
*/
size_t mpi_lsb( const mpi *X );
/**
* \brief Return the number of bits up to and including the most
* significant '1' bit'
*
* Note: Thus also the one-based index of the most significant '1' bit
*
* \param X MPI to use
*/
size_t mpi_msb( const mpi *X );
/**
* \brief Return the total size in bytes
*
* \param X MPI to use
*/
size_t mpi_size( const mpi *X );
/**
* \brief Import from an ASCII string
*
* \param X Destination MPI
* \param radix Input numeric base
* \param s Null-terminated string buffer
*
* \return 0 if successful, or a POLARSSL_ERR_MPI_XXX error code
*/
int mpi_read_string( mpi *X, int radix, const char *s );
/**
* \brief Export into an ASCII string
*
* \param X Source MPI
* \param radix Output numeric base
* \param s String buffer
* \param slen String buffer size
*
* \return 0 if successful, or a POLARSSL_ERR_MPI_XXX error code.
* *slen is always updated to reflect the amount
* of data that has (or would have) been written.
*
* \note Call this function with *slen = 0 to obtain the
* minimum required buffer size in *slen.
*/
int mpi_write_string( const mpi *X, int radix, char *s, size_t *slen );
#if defined(POLARSSL_FS_IO)
/**
* \brief Read X from an opened file
*
* \param X Destination MPI
* \param radix Input numeric base
* \param fin Input file handle
*
* \return 0 if successful, POLARSSL_ERR_MPI_BUFFER_TOO_SMALL if
* the file read buffer is too small or a
* POLARSSL_ERR_MPI_XXX error code
*/
int mpi_read_file( mpi *X, int radix, FILE *fin );
/**
* \brief Write X into an opened file, or stdout if fout is NULL
*
* \param p Prefix, can be NULL
* \param X Source MPI
* \param radix Output numeric base
* \param fout Output file handle (can be NULL)
*
* \return 0 if successful, or a POLARSSL_ERR_MPI_XXX error code
*
* \note Set fout == NULL to print X on the console.
*/
int mpi_write_file( const char *p, const mpi *X, int radix, FILE *fout );
#endif /* POLARSSL_FS_IO */
/**
* \brief Import X from unsigned binary data, big endian
*
* \param X Destination MPI
* \param buf Input buffer
* \param buflen Input buffer size
*
* \return 0 if successful,
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
*/
int mpi_read_binary( mpi *X, const unsigned char *buf, size_t buflen );
/**
* \brief Export X into unsigned binary data, big endian
*
* \param X Source MPI
* \param buf Output buffer
* \param buflen Output buffer size
*
* \return 0 if successful,
* POLARSSL_ERR_MPI_BUFFER_TOO_SMALL if buf isn't large enough
*/
int mpi_write_binary( const mpi *X, unsigned char *buf, size_t buflen );
/**
* \brief Left-shift: X <<= count
*
* \param X MPI to shift
* \param count Amount to shift
*
* \return 0 if successful,
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
*/
int mpi_shift_l( mpi *X, size_t count );
/**
* \brief Right-shift: X >>= count
*
* \param X MPI to shift
* \param count Amount to shift
*
* \return 0 if successful,
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
*/
int mpi_shift_r( mpi *X, size_t count );
/**
* \brief Compare unsigned values
*
* \param X Left-hand MPI
* \param Y Right-hand MPI
*
* \return 1 if |X| is greater than |Y|,
* -1 if |X| is lesser than |Y| or
* 0 if |X| is equal to |Y|
*/
int mpi_cmp_abs( const mpi *X, const mpi *Y );
/**
* \brief Compare signed values
*
* \param X Left-hand MPI
* \param Y Right-hand MPI
*
* \return 1 if X is greater than Y,
* -1 if X is lesser than Y or
* 0 if X is equal to Y
*/
int mpi_cmp_mpi( const mpi *X, const mpi *Y );
/**
* \brief Compare signed values
*
* \param X Left-hand MPI
* \param z The integer value to compare to
*
* \return 1 if X is greater than z,
* -1 if X is lesser than z or
* 0 if X is equal to z
*/
int mpi_cmp_int( const mpi *X, t_sint z );
/**
* \brief Unsigned addition: X = |A| + |B|
*
* \param X Destination MPI
* \param A Left-hand MPI
* \param B Right-hand MPI
*
* \return 0 if successful,
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
*/
int mpi_add_abs( mpi *X, const mpi *A, const mpi *B );
/**
* \brief Unsigned substraction: X = |A| - |B|
*
* \param X Destination MPI
* \param A Left-hand MPI
* \param B Right-hand MPI
*
* \return 0 if successful,
* POLARSSL_ERR_MPI_NEGATIVE_VALUE if B is greater than A
*/
int mpi_sub_abs( mpi *X, const mpi *A, const mpi *B );
/**
* \brief Signed addition: X = A + B
*
* \param X Destination MPI
* \param A Left-hand MPI
* \param B Right-hand MPI
*
* \return 0 if successful,
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
*/
int mpi_add_mpi( mpi *X, const mpi *A, const mpi *B );
/**
* \brief Signed substraction: X = A - B
*
* \param X Destination MPI
* \param A Left-hand MPI
* \param B Right-hand MPI
*
* \return 0 if successful,
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
*/
int mpi_sub_mpi( mpi *X, const mpi *A, const mpi *B );
/**
* \brief Signed addition: X = A + b
*
* \param X Destination MPI
* \param A Left-hand MPI
* \param b The integer value to add
*
* \return 0 if successful,
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
*/
int mpi_add_int( mpi *X, const mpi *A, t_sint b );
/**
* \brief Signed substraction: X = A - b
*
* \param X Destination MPI
* \param A Left-hand MPI
* \param b The integer value to subtract
*
* \return 0 if successful,
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
*/
int mpi_sub_int( mpi *X, const mpi *A, t_sint b );
/**
* \brief Baseline multiplication: X = A * B
*
* \param X Destination MPI
* \param A Left-hand MPI
* \param B Right-hand MPI
*
* \return 0 if successful,
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
*/
int mpi_mul_mpi( mpi *X, const mpi *A, const mpi *B );
/**
* \brief Baseline multiplication: X = A * b
* Note: b is an unsigned integer type, thus
* Negative values of b are ignored.
*
* \param X Destination MPI
* \param A Left-hand MPI
* \param b The integer value to multiply with
*
* \return 0 if successful,
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
*/
int mpi_mul_int( mpi *X, const mpi *A, t_sint b );
/**
* \brief Division by mpi: A = Q * B + R
*
* \param Q Destination MPI for the quotient
* \param R Destination MPI for the rest value
* \param A Left-hand MPI
* \param B Right-hand MPI
*
* \return 0 if successful,
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed,
* POLARSSL_ERR_MPI_DIVISION_BY_ZERO if B == 0
*
* \note Either Q or R can be NULL.
*/
int mpi_div_mpi( mpi *Q, mpi *R, const mpi *A, const mpi *B );
/**
* \brief Division by int: A = Q * b + R
*
* \param Q Destination MPI for the quotient
* \param R Destination MPI for the rest value
* \param A Left-hand MPI
* \param b Integer to divide by
*
* \return 0 if successful,
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed,
* POLARSSL_ERR_MPI_DIVISION_BY_ZERO if b == 0
*
* \note Either Q or R can be NULL.
*/
int mpi_div_int( mpi *Q, mpi *R, const mpi *A, t_sint b );
/**
* \brief Modulo: R = A mod B
*
* \param R Destination MPI for the rest value
* \param A Left-hand MPI
* \param B Right-hand MPI
*
* \return 0 if successful,
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed,
* POLARSSL_ERR_MPI_DIVISION_BY_ZERO if B == 0,
* POLARSSL_ERR_MPI_NEGATIVE_VALUE if B < 0
*/
int mpi_mod_mpi( mpi *R, const mpi *A, const mpi *B );
/**
* \brief Modulo: r = A mod b
*
* \param r Destination t_uint
* \param A Left-hand MPI
* \param b Integer to divide by
*
* \return 0 if successful,
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed,
* POLARSSL_ERR_MPI_DIVISION_BY_ZERO if b == 0,
* POLARSSL_ERR_MPI_NEGATIVE_VALUE if b < 0
*/
int mpi_mod_int( t_uint *r, const mpi *A, t_sint b );
/**
* \brief Sliding-window exponentiation: X = A^E mod N
*
* \param X Destination MPI
* \param A Left-hand MPI
* \param E Exponent MPI
* \param N Modular MPI
* \param _RR Speed-up MPI used for recalculations
*
* \return 0 if successful,
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed,
* POLARSSL_ERR_MPI_BAD_INPUT_DATA if N is negative or even or if
* E is negative
*
* \note _RR is used to avoid re-computing R*R mod N across
* multiple calls, which speeds up things a bit. It can
* be set to NULL if the extra performance is unneeded.
*/
int mpi_exp_mod( mpi *X, const mpi *A, const mpi *E, const mpi *N, mpi *_RR );
/**
* \brief Fill an MPI X with size bytes of random
*
* \param X Destination MPI
* \param size Size in bytes
* \param f_rng RNG function
* \param p_rng RNG parameter
*
* \return 0 if successful,
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
*/
int mpi_fill_random( mpi *X, size_t size,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng );
/**
* \brief Greatest common divisor: G = gcd(A, B)
*
* \param G Destination MPI
* \param A Left-hand MPI
* \param B Right-hand MPI
*
* \return 0 if successful,
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed
*/
int mpi_gcd( mpi *G, const mpi *A, const mpi *B );
/**
* \brief Modular inverse: X = A^-1 mod N
*
* \param X Destination MPI
* \param A Left-hand MPI
* \param N Right-hand MPI
*
* \return 0 if successful,
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed,
* POLARSSL_ERR_MPI_BAD_INPUT_DATA if N is negative or nil
POLARSSL_ERR_MPI_NOT_ACCEPTABLE if A has no inverse mod N
*/
int mpi_inv_mod( mpi *X, const mpi *A, const mpi *N );
#if 0
/**
* \brief Miller-Rabin primality test
*
* \param X MPI to check
* \param f_rng RNG function
* \param p_rng RNG parameter
*
* \return 0 if successful (probably prime),
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed,
* POLARSSL_ERR_MPI_NOT_ACCEPTABLE if X is not prime
*/
int mpi_is_prime( mpi *X,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng );
#endif
/**
* \brief Prime number generation
*
* \param X Destination MPI
* \param nbits Required size of X in bits ( 3 <= nbits <= POLARSSL_MPI_MAX_BITS )
* \param dh_flag If 1, then (X-1)/2 will be prime too
* \param f_rng RNG function
* \param p_rng RNG parameter
*
* \return 0 if successful (probably prime),
* POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed,
* POLARSSL_ERR_MPI_BAD_INPUT_DATA if nbits is < 3
*/
int mpi_gen_prime( mpi *X, size_t nbits, int dh_flag,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng );
/**
* \brief Checkup routine
*
* \return 0 if successful, or 1 if the test failed
*/
int mpi_self_test( int verbose );
#ifdef __cplusplus
}
#endif
#endif /* bignum.h */

901
polarssl/bn_mul.h Normal file
View File

@ -0,0 +1,901 @@
/**
* \file bn_mul.h
*
* Copyright (C) 2006-2010, Brainspark B.V.
*
* This file is part of PolarSSL (http://www.polarssl.org)
* Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*
* Multiply source vector [s] with b, add result
* to destination vector [d] and set carry c.
*
* Currently supports:
*
* . IA-32 (386+) . AMD64 / EM64T
* . IA-32 (SSE2) . Motorola 68000
* . PowerPC, 32-bit . MicroBlaze
* . PowerPC, 64-bit . TriCore
* . SPARC v8 . ARM v3+
* . Alpha . MIPS32
* . C, longlong . C, generic
*/
#ifndef POLARSSL_BN_MUL_H
#define POLARSSL_BN_MUL_H
#include "polarssl/config.h"
#if defined(POLARSSL_HAVE_ASM)
#if defined(__GNUC__)
#if defined(__i386__)
#define MULADDC_INIT \
asm( " \
movl %%ebx, %0; \
movl %5, %%esi; \
movl %6, %%edi; \
movl %7, %%ecx; \
movl %8, %%ebx; \
"
#define MULADDC_CORE \
" \
lodsl; \
mull %%ebx; \
addl %%ecx, %%eax; \
adcl $0, %%edx; \
addl (%%edi), %%eax; \
adcl $0, %%edx; \
movl %%edx, %%ecx; \
stosl; \
"
#if defined(POLARSSL_HAVE_SSE2)
#define MULADDC_HUIT \
" \
movd %%ecx, %%mm1; \
movd %%ebx, %%mm0; \
movd (%%edi), %%mm3; \
paddq %%mm3, %%mm1; \
movd (%%esi), %%mm2; \
pmuludq %%mm0, %%mm2; \
movd 4(%%esi), %%mm4; \
pmuludq %%mm0, %%mm4; \
movd 8(%%esi), %%mm6; \
pmuludq %%mm0, %%mm6; \
movd 12(%%esi), %%mm7; \
pmuludq %%mm0, %%mm7; \
paddq %%mm2, %%mm1; \
movd 4(%%edi), %%mm3; \
paddq %%mm4, %%mm3; \
movd 8(%%edi), %%mm5; \
paddq %%mm6, %%mm5; \
movd 12(%%edi), %%mm4; \
paddq %%mm4, %%mm7; \
movd %%mm1, (%%edi); \
movd 16(%%esi), %%mm2; \
pmuludq %%mm0, %%mm2; \
psrlq $32, %%mm1; \
movd 20(%%esi), %%mm4; \
pmuludq %%mm0, %%mm4; \
paddq %%mm3, %%mm1; \
movd 24(%%esi), %%mm6; \
pmuludq %%mm0, %%mm6; \
movd %%mm1, 4(%%edi); \
psrlq $32, %%mm1; \
movd 28(%%esi), %%mm3; \
pmuludq %%mm0, %%mm3; \
paddq %%mm5, %%mm1; \
movd 16(%%edi), %%mm5; \
paddq %%mm5, %%mm2; \
movd %%mm1, 8(%%edi); \
psrlq $32, %%mm1; \
paddq %%mm7, %%mm1; \
movd 20(%%edi), %%mm5; \
paddq %%mm5, %%mm4; \
movd %%mm1, 12(%%edi); \
psrlq $32, %%mm1; \
paddq %%mm2, %%mm1; \
movd 24(%%edi), %%mm5; \
paddq %%mm5, %%mm6; \
movd %%mm1, 16(%%edi); \
psrlq $32, %%mm1; \
paddq %%mm4, %%mm1; \
movd 28(%%edi), %%mm5; \
paddq %%mm5, %%mm3; \
movd %%mm1, 20(%%edi); \
psrlq $32, %%mm1; \
paddq %%mm6, %%mm1; \
movd %%mm1, 24(%%edi); \
psrlq $32, %%mm1; \
paddq %%mm3, %%mm1; \
movd %%mm1, 28(%%edi); \
addl $32, %%edi; \
addl $32, %%esi; \
psrlq $32, %%mm1; \
movd %%mm1, %%ecx; \
"
#define MULADDC_STOP \
" \
emms; \
movl %4, %%ebx; \
movl %%ecx, %1; \
movl %%edi, %2; \
movl %%esi, %3; \
" \
: "=m" (t), "=m" (c), "=m" (d), "=m" (s) \
: "m" (t), "m" (s), "m" (d), "m" (c), "m" (b) \
: "eax", "ecx", "edx", "esi", "edi" \
);
#else
#define MULADDC_STOP \
" \
movl %4, %%ebx; \
movl %%ecx, %1; \
movl %%edi, %2; \
movl %%esi, %3; \
" \
: "=m" (t), "=m" (c), "=m" (d), "=m" (s) \
: "m" (t), "m" (s), "m" (d), "m" (c), "m" (b) \
: "eax", "ecx", "edx", "esi", "edi" \
);
#endif /* SSE2 */
#endif /* i386 */
#if defined(__amd64__) || defined (__x86_64__)
#define MULADDC_INIT \
asm( "movq %0, %%rsi " :: "m" (s)); \
asm( "movq %0, %%rdi " :: "m" (d)); \
asm( "movq %0, %%rcx " :: "m" (c)); \
asm( "movq %0, %%rbx " :: "m" (b)); \
asm( "xorq %r8, %r8 " );
#define MULADDC_CORE \
asm( "movq (%rsi),%rax " ); \
asm( "mulq %rbx " ); \
asm( "addq $8, %rsi " ); \
asm( "addq %rcx, %rax " ); \
asm( "movq %r8, %rcx " ); \
asm( "adcq $0, %rdx " ); \
asm( "nop " ); \
asm( "addq %rax, (%rdi) " ); \
asm( "adcq %rdx, %rcx " ); \
asm( "addq $8, %rdi " );
#define MULADDC_STOP \
asm( "movq %%rcx, %0 " : "=m" (c)); \
asm( "movq %%rdi, %0 " : "=m" (d)); \
asm( "movq %%rsi, %0 " : "=m" (s) :: \
"rax", "rcx", "rdx", "rbx", "rsi", "rdi", "r8" );
#endif /* AMD64 */
#if defined(__mc68020__) || defined(__mcpu32__)
#define MULADDC_INIT \
asm( "movl %0, %%a2 " :: "m" (s)); \
asm( "movl %0, %%a3 " :: "m" (d)); \
asm( "movl %0, %%d3 " :: "m" (c)); \
asm( "movl %0, %%d2 " :: "m" (b)); \
asm( "moveq #0, %d0 " );
#define MULADDC_CORE \
asm( "movel %a2@+, %d1 " ); \
asm( "mulul %d2, %d4:%d1 " ); \
asm( "addl %d3, %d1 " ); \
asm( "addxl %d0, %d4 " ); \
asm( "moveq #0, %d3 " ); \
asm( "addl %d1, %a3@+ " ); \
asm( "addxl %d4, %d3 " );
#define MULADDC_STOP \
asm( "movl %%d3, %0 " : "=m" (c)); \
asm( "movl %%a3, %0 " : "=m" (d)); \
asm( "movl %%a2, %0 " : "=m" (s) :: \
"d0", "d1", "d2", "d3", "d4", "a2", "a3" );
#define MULADDC_HUIT \
asm( "movel %a2@+, %d1 " ); \
asm( "mulul %d2, %d4:%d1 " ); \
asm( "addxl %d3, %d1 " ); \
asm( "addxl %d0, %d4 " ); \
asm( "addl %d1, %a3@+ " ); \
asm( "movel %a2@+, %d1 " ); \
asm( "mulul %d2, %d3:%d1 " ); \
asm( "addxl %d4, %d1 " ); \
asm( "addxl %d0, %d3 " ); \
asm( "addl %d1, %a3@+ " ); \
asm( "movel %a2@+, %d1 " ); \
asm( "mulul %d2, %d4:%d1 " ); \
asm( "addxl %d3, %d1 " ); \
asm( "addxl %d0, %d4 " ); \
asm( "addl %d1, %a3@+ " ); \
asm( "movel %a2@+, %d1 " ); \
asm( "mulul %d2, %d3:%d1 " ); \
asm( "addxl %d4, %d1 " ); \
asm( "addxl %d0, %d3 " ); \
asm( "addl %d1, %a3@+ " ); \
asm( "movel %a2@+, %d1 " ); \
asm( "mulul %d2, %d4:%d1 " ); \
asm( "addxl %d3, %d1 " ); \
asm( "addxl %d0, %d4 " ); \
asm( "addl %d1, %a3@+ " ); \
asm( "movel %a2@+, %d1 " ); \
asm( "mulul %d2, %d3:%d1 " ); \
asm( "addxl %d4, %d1 " ); \
asm( "addxl %d0, %d3 " ); \
asm( "addl %d1, %a3@+ " ); \
asm( "movel %a2@+, %d1 " ); \
asm( "mulul %d2, %d4:%d1 " ); \
asm( "addxl %d3, %d1 " ); \
asm( "addxl %d0, %d4 " ); \
asm( "addl %d1, %a3@+ " ); \
asm( "movel %a2@+, %d1 " ); \
asm( "mulul %d2, %d3:%d1 " ); \
asm( "addxl %d4, %d1 " ); \
asm( "addxl %d0, %d3 " ); \
asm( "addl %d1, %a3@+ " ); \
asm( "addxl %d0, %d3 " );
#endif /* MC68000 */
#if defined(__powerpc__) || defined(__ppc__)
#if defined(__powerpc64__) || defined(__ppc64__)
#if defined(__MACH__) && defined(__APPLE__)
#define MULADDC_INIT \
asm( "ld r3, %0 " :: "m" (s)); \
asm( "ld r4, %0 " :: "m" (d)); \
asm( "ld r5, %0 " :: "m" (c)); \
asm( "ld r6, %0 " :: "m" (b)); \
asm( "addi r3, r3, -8 " ); \
asm( "addi r4, r4, -8 " ); \
asm( "addic r5, r5, 0 " );
#define MULADDC_CORE \
asm( "ldu r7, 8(r3) " ); \
asm( "mulld r8, r7, r6 " ); \
asm( "mulhdu r9, r7, r6 " ); \
asm( "adde r8, r8, r5 " ); \
asm( "ld r7, 8(r4) " ); \
asm( "addze r5, r9 " ); \
asm( "addc r8, r8, r7 " ); \
asm( "stdu r8, 8(r4) " );
#define MULADDC_STOP \
asm( "addze r5, r5 " ); \
asm( "addi r4, r4, 8 " ); \
asm( "addi r3, r3, 8 " ); \
asm( "std r5, %0 " : "=m" (c)); \
asm( "std r4, %0 " : "=m" (d)); \
asm( "std r3, %0 " : "=m" (s) :: \
"r3", "r4", "r5", "r6", "r7", "r8", "r9" );
#else
#define MULADDC_INIT \
asm( "ld %%r3, %0 " :: "m" (s)); \
asm( "ld %%r4, %0 " :: "m" (d)); \
asm( "ld %%r5, %0 " :: "m" (c)); \
asm( "ld %%r6, %0 " :: "m" (b)); \
asm( "addi %r3, %r3, -8 " ); \
asm( "addi %r4, %r4, -8 " ); \
asm( "addic %r5, %r5, 0 " );
#define MULADDC_CORE \
asm( "ldu %r7, 8(%r3) " ); \
asm( "mulld %r8, %r7, %r6 " ); \
asm( "mulhdu %r9, %r7, %r6 " ); \
asm( "adde %r8, %r8, %r5 " ); \
asm( "ld %r7, 8(%r4) " ); \
asm( "addze %r5, %r9 " ); \
asm( "addc %r8, %r8, %r7 " ); \
asm( "stdu %r8, 8(%r4) " );
#define MULADDC_STOP \
asm( "addze %r5, %r5 " ); \
asm( "addi %r4, %r4, 8 " ); \
asm( "addi %r3, %r3, 8 " ); \
asm( "std %%r5, %0 " : "=m" (c)); \
asm( "std %%r4, %0 " : "=m" (d)); \
asm( "std %%r3, %0 " : "=m" (s) :: \
"r3", "r4", "r5", "r6", "r7", "r8", "r9" );
#endif
#else /* PPC32 */
#if defined(__MACH__) && defined(__APPLE__)
#define MULADDC_INIT \
asm( "lwz r3, %0 " :: "m" (s)); \
asm( "lwz r4, %0 " :: "m" (d)); \
asm( "lwz r5, %0 " :: "m" (c)); \
asm( "lwz r6, %0 " :: "m" (b)); \
asm( "addi r3, r3, -4 " ); \
asm( "addi r4, r4, -4 " ); \
asm( "addic r5, r5, 0 " );
#define MULADDC_CORE \
asm( "lwzu r7, 4(r3) " ); \
asm( "mullw r8, r7, r6 " ); \
asm( "mulhwu r9, r7, r6 " ); \
asm( "adde r8, r8, r5 " ); \
asm( "lwz r7, 4(r4) " ); \
asm( "addze r5, r9 " ); \
asm( "addc r8, r8, r7 " ); \
asm( "stwu r8, 4(r4) " );
#define MULADDC_STOP \
asm( "addze r5, r5 " ); \
asm( "addi r4, r4, 4 " ); \
asm( "addi r3, r3, 4 " ); \
asm( "stw r5, %0 " : "=m" (c)); \
asm( "stw r4, %0 " : "=m" (d)); \
asm( "stw r3, %0 " : "=m" (s) :: \
"r3", "r4", "r5", "r6", "r7", "r8", "r9" );
#else
#define MULADDC_INIT \
asm( "lwz %%r3, %0 " :: "m" (s)); \
asm( "lwz %%r4, %0 " :: "m" (d)); \
asm( "lwz %%r5, %0 " :: "m" (c)); \
asm( "lwz %%r6, %0 " :: "m" (b)); \
asm( "addi %r3, %r3, -4 " ); \
asm( "addi %r4, %r4, -4 " ); \
asm( "addic %r5, %r5, 0 " );
#define MULADDC_CORE \
asm( "lwzu %r7, 4(%r3) " ); \
asm( "mullw %r8, %r7, %r6 " ); \
asm( "mulhwu %r9, %r7, %r6 " ); \
asm( "adde %r8, %r8, %r5 " ); \
asm( "lwz %r7, 4(%r4) " ); \
asm( "addze %r5, %r9 " ); \
asm( "addc %r8, %r8, %r7 " ); \
asm( "stwu %r8, 4(%r4) " );
#define MULADDC_STOP \
asm( "addze %r5, %r5 " ); \
asm( "addi %r4, %r4, 4 " ); \
asm( "addi %r3, %r3, 4 " ); \
asm( "stw %%r5, %0 " : "=m" (c)); \
asm( "stw %%r4, %0 " : "=m" (d)); \
asm( "stw %%r3, %0 " : "=m" (s) :: \
"r3", "r4", "r5", "r6", "r7", "r8", "r9" );
#endif
#endif /* PPC32 */
#endif /* PPC64 */
#if defined(__sparc__)
#define MULADDC_INIT \
asm( "ld %0, %%o0 " :: "m" (s)); \
asm( "ld %0, %%o1 " :: "m" (d)); \
asm( "ld %0, %%o2 " :: "m" (c)); \
asm( "ld %0, %%o3 " :: "m" (b));
#define MULADDC_CORE \
asm( "ld [%o0], %o4 " ); \
asm( "inc 4, %o0 " ); \
asm( "ld [%o1], %o5 " ); \
asm( "umul %o3, %o4, %o4 " ); \
asm( "addcc %o4, %o2, %o4 " ); \
asm( "rd %y, %g1 " ); \
asm( "addx %g1, 0, %g1 " ); \
asm( "addcc %o4, %o5, %o4 " ); \
asm( "st %o4, [%o1] " ); \
asm( "addx %g1, 0, %o2 " ); \
asm( "inc 4, %o1 " );
#define MULADDC_STOP \
asm( "st %%o2, %0 " : "=m" (c)); \
asm( "st %%o1, %0 " : "=m" (d)); \
asm( "st %%o0, %0 " : "=m" (s) :: \
"g1", "o0", "o1", "o2", "o3", "o4", "o5" );
#endif /* SPARCv8 */
#if defined(__microblaze__) || defined(microblaze)
#define MULADDC_INIT \
asm( "lwi r3, %0 " :: "m" (s)); \
asm( "lwi r4, %0 " :: "m" (d)); \
asm( "lwi r5, %0 " :: "m" (c)); \
asm( "lwi r6, %0 " :: "m" (b)); \
asm( "andi r7, r6, 0xffff" ); \
asm( "bsrli r6, r6, 16 " );
#define MULADDC_CORE \
asm( "lhui r8, r3, 0 " ); \
asm( "addi r3, r3, 2 " ); \
asm( "lhui r9, r3, 0 " ); \
asm( "addi r3, r3, 2 " ); \
asm( "mul r10, r9, r6 " ); \
asm( "mul r11, r8, r7 " ); \
asm( "mul r12, r9, r7 " ); \
asm( "mul r13, r8, r6 " ); \
asm( "bsrli r8, r10, 16 " ); \
asm( "bsrli r9, r11, 16 " ); \
asm( "add r13, r13, r8 " ); \
asm( "add r13, r13, r9 " ); \
asm( "bslli r10, r10, 16 " ); \
asm( "bslli r11, r11, 16 " ); \
asm( "add r12, r12, r10 " ); \
asm( "addc r13, r13, r0 " ); \
asm( "add r12, r12, r11 " ); \
asm( "addc r13, r13, r0 " ); \
asm( "lwi r10, r4, 0 " ); \
asm( "add r12, r12, r10 " ); \
asm( "addc r13, r13, r0 " ); \
asm( "add r12, r12, r5 " ); \
asm( "addc r5, r13, r0 " ); \
asm( "swi r12, r4, 0 " ); \
asm( "addi r4, r4, 4 " );
#define MULADDC_STOP \
asm( "swi r5, %0 " : "=m" (c)); \
asm( "swi r4, %0 " : "=m" (d)); \
asm( "swi r3, %0 " : "=m" (s) :: \
"r3", "r4" , "r5" , "r6" , "r7" , "r8" , \
"r9", "r10", "r11", "r12", "r13" );
#endif /* MicroBlaze */
#if defined(__tricore__)
#define MULADDC_INIT \
asm( "ld.a %%a2, %0 " :: "m" (s)); \
asm( "ld.a %%a3, %0 " :: "m" (d)); \
asm( "ld.w %%d4, %0 " :: "m" (c)); \
asm( "ld.w %%d1, %0 " :: "m" (b)); \
asm( "xor %d5, %d5 " );
#define MULADDC_CORE \
asm( "ld.w %d0, [%a2+] " ); \
asm( "madd.u %e2, %e4, %d0, %d1 " ); \
asm( "ld.w %d0, [%a3] " ); \
asm( "addx %d2, %d2, %d0 " ); \
asm( "addc %d3, %d3, 0 " ); \
asm( "mov %d4, %d3 " ); \
asm( "st.w [%a3+], %d2 " );
#define MULADDC_STOP \
asm( "st.w %0, %%d4 " : "=m" (c)); \
asm( "st.a %0, %%a3 " : "=m" (d)); \
asm( "st.a %0, %%a2 " : "=m" (s) :: \
"d0", "d1", "e2", "d4", "a2", "a3" );
#endif /* TriCore */
#if defined(__arm__)
#if defined(__ARM_FEATURE_DSP)
/* The ARM DSP instructions are available on Cortex M4, M7 and
Cortex A CPUs */
#define MULADDC_1024_CORE \
"ldmia %[s]!, { r7, r8, r9, r10 } \n\t" \
"ldmia %[d], { r3, r4, r5, r6 } \n\t" \
"umaal r3, %2, %[b], r7 \n\t" \
"umaal r4, %2, %[b], r8 \n\t" \
"umaal r5, %2, %[b], r9 \n\t" \
"umaal r6, %2, %[b], r10 \n\t" \
"stmia %[d]!, {r3, r4, r5, r6} \n\t"
#define MULADDC_1024_LOOP \
asm( "tst %[i], #0xfe0 \n\t" \
"beq 0f \n" \
"1: sub %[i], %[i], #32 \n\t" \
MULADDC_1024_CORE MULADDC_1024_CORE \
MULADDC_1024_CORE MULADDC_1024_CORE \
MULADDC_1024_CORE MULADDC_1024_CORE \
MULADDC_1024_CORE MULADDC_1024_CORE \
"tst %[i], #0xfe0 \n\t" \
"bne 1b \n" \
"0:" \
: [s] "=r" (s), [d] "=r" (d), [c] "=r" (c), [i] "=r" (i) \
: [b] "r" (b), "[s]" (s), "[d]" (d), "[c]" (c), "[i]" (i) \
: "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "memory", "cc" );
#define MULADDC_INIT \
asm(
#define MULADDC_CORE \
"ldr r0, [%0], #4 \n\t" \
"ldr r1, [%1] \n\t" \
"umaal r1, %2, %3, r0 \n\t" \
"str r1, [%1], #4 \n\t"
#define MULADDC_HUIT \
"ldmia %0!, {r0, r1, r2, r3} \n\t" \
"ldmia %1, {r4, r5, r6, r7} \n\t" \
"umaal r4, %2, %3, r0 \n\t" \
"umaal r5, %2, %3, r1 \n\t" \
"umaal r6, %2, %3, r2 \n\t" \
"umaal r7, %2, %3, r3 \n\t" \
"stmia %1!, {r4, r5, r6, r7} \n\t" \
"ldmia %0!, {r0, r1, r2, r3} \n\t" \
"ldmia %1, {r4, r5, r6, r7} \n\t" \
"umaal r4, %2, %3, r0 \n\t" \
"umaal r5, %2, %3, r1 \n\t" \
"umaal r6, %2, %3, r2 \n\t" \
"umaal r7, %2, %3, r3 \n\t" \
"stmia %1!, {r4, r5, r6, r7} \n\t"
#define MULADDC_STOP \
: "=r" (s), "=r" (d), "=r" (c) \
: "r" (b), "0" (s), "1" (d), "2" (c) \
: "r0", "r1", "r2", "r3", "r4", "r5", \
"r6", "r7", "memory");
#else /* __ARM_FEATURE_DSP */
#define MULADDC_1024_CORE \
"ldmia %[s]!, { r8, r9, r10 } \n\t" \
"ldmia %[d], { r5, r6, r7 } \n\t" \
"adcs r5, r5, %[c] \n\t" \
"umull r4, r8, r8, %[b] \n\t" \
"adc %[c], r8, #0 \n\t" \
"adds r5, r5, r4 \n\t" \
"adcs r6, r6, %[c] \n\t" \
"umull r4, r8, r9, %[b] \n\t" \
"adc %[c], r8, #0 \n\t" \
"adds r6, r6, r4 \n\t" \
"adcs r7, r7, %[c] \n\t" \
"umull r4, r8, r10, %[b] \n\t" \
"adc %[c], r8, #0 \n\t" \
"adds r7, r7, r4 \n\t" \
"stmia %[d]!, { r5, r6, r7 } \n\t"
#define MULADDC_1024_LOOP \
asm( "tst %[i], #0xfe0 \n\t" \
"beq 0f \n" \
"1: ldmia %[s]!, { r8, r9, r10 } \n\t" \
"ldmia %[d], { r5, r6, r7 } \n\t" \
"sub %[i], %[i], #32 \n\t" \
"adds r5, r5, %[c] \n\t" \
"umull r4, r8, %[b], r8 \n\t" \
"adc %[c], r8, #0 \n\t" \
"adds r5, r5, r4 \n\t" \
"adcs r6, r6, %[c] \n\t" \
"umull r4, r8, %[b], r9 \n\t" \
"adc %[c], r8, #0 \n\t" \
"adds r6, r6, r4 \n\t" \
"adcs r7, r7, %[c] \n\t" \
"umull r4, r8, %[b], r10 \n\t" \
"adc %[c], r8, #0 \n\t" \
"adds r7, r7, r4 \n\t" \
"stmia %[d]!, { r5, r6, r7 } \n\t" \
MULADDC_1024_CORE MULADDC_1024_CORE \
MULADDC_1024_CORE MULADDC_1024_CORE \
MULADDC_1024_CORE MULADDC_1024_CORE \
MULADDC_1024_CORE MULADDC_1024_CORE \
MULADDC_1024_CORE \
"ldmia %[s]!, { r8, r9 } \n\t" \
"ldmia %[d], { r5, r6 } \n\t" \
"adcs r5, r5, %[c] \n\t" \
"umull r4, r8, %[b], r8 \n\t" \
"adc %[c], r8, #0 \n\t" \
"adds r5, r5, r4 \n\t" \
"adcs r6, r6, %[c] \n\t" \
"umull r4, r8, %[b], r9 \n\t" \
"adc %[c], r8, #0 \n\t" \
"adds r6, r6, r4 \n\t" \
"adc %[c], %[c], #0 \n\t" \
"stmia %[d]!, { r5, r6 } \n\t" \
"tst %[i], #0xfe0 \n\t" \
"bne 1b \n" \
"0:" \
: [s] "=r" (s), [d] "=r" (d), [c] "=r" (c), [i] "=r" (i) \
: [b] "r" (b), "[s]" (s), "[d]" (d), "[c]" (c), "[i]" (i) \
: "r4", "r5", "r6", "r7", "r8", "r9", "r10", "memory", "cc" );
/* Just for reference (dead code) */
#define MULADDC_HUIT_DEAD \
"ldmia %0!, { r4, r5 } \n\t" \
"ldmia %1, { r8, r9 } \n\t" \
"umull r6, r7, %3, r4 \n\t" \
"adcs r6, r6, %2 \n\t" \
"adc %2, r7, #0 \n\t" \
"adds r8, r8, r6 \n\t" \
"umull r6, r7, %3, r5 \n\t" \
"adcs r6, r6, %2 \n\t" \
"adc %2, r7, #0 \n\t" \
"adds r9, r9, r6 \n\t" \
"stmia %1!, { r8, r9 } \n\t" \
"ldmia %0!, { r4, r5 } \n\t" \
"ldmia %1, { r8, r9 } \n\t" \
"umull r6, r7, %3, r4 \n\t" \
"adcs r6, r6, %2 \n\t" \
"adc %2, r7, #0 \n\t" \
"adds r8, r8, r6 \n\t" \
"umull r6, r7, %3, r5 \n\t" \
"adcs r6, r6, %2 \n\t" \
"adc %2, r7, #0 \n\t" \
"adds r9, r9, r6 \n\t" \
"stmia %1!, { r8, r9 } \n\t" \
"ldmia %0!, { r4, r5 } \n\t" \
"ldmia %1, { r8, r9 } \n\t" \
"umull r6, r7, %3, r4 \n\t" \
"adcs r6, r6, %2 \n\t" \
"adc %2, r7, #0 \n\t" \
"adds r8, r8, r6 \n\t" \
"umull r6, r7, %3, r5 \n\t" \
"adcs r6, r6, %2 \n\t" \
"adc %2, r7, #0 \n\t" \
"adds r9, r9, r6 \n\t" \
"stmia %1!, { r8, r9 } \n\t" \
"ldmia %0!, { r4, r5 } \n\t" \
"ldmia %1, { r8, r9 } \n\t" \
"umull r6, r7, %3, r4 \n\t" \
"adcs r6, r6, %2 \n\t" \
"adc %2, r7, #0 \n\t" \
"adds r8, r8, r6 \n\t" \
"umull r6, r7, %3, r5 \n\t" \
"adcs r6, r6, %2 \n\t" \
"adc %2, r7, #0 \n\t" \
"adds r9, r9, r6 \n\t" \
"stmia %1!, { r8, r9 } \n\t"
#define MULADDC_INIT \
asm( "adds %0, #0 \n\t"
#define MULADDC_CORE \
"ldr r5, [%1] \n\t" \
"ldr r4, [%0], #4 \n\t" \
"adcs r5, r5, %2 \n\t" \
"umull r6, r7, %3, r4 \n\t" \
"adc %2, r7, #0 \n\t" \
"adds r5, r5, r6 \n\t" \
"str r5, [%1], #4 \n\t"
#define MULADDC_STOP \
"adc %2, %2, #0 " \
: "=r" (s), "=r" (d), "=r" (c) \
: "r" (b), "0" (s), "1" (d), "2" (c) \
: "r4", "r5", "r6", "r7", "memory", "cc" );
#endif /* __ARM_FEATURE_DSP */
#endif /* ARMv3 */
#if defined(__alpha__)
#define MULADDC_INIT \
asm( "ldq $1, %0 " :: "m" (s)); \
asm( "ldq $2, %0 " :: "m" (d)); \
asm( "ldq $3, %0 " :: "m" (c)); \
asm( "ldq $4, %0 " :: "m" (b));
#define MULADDC_CORE \
asm( "ldq $6, 0($1) " ); \
asm( "addq $1, 8, $1 " ); \
asm( "mulq $6, $4, $7 " ); \
asm( "umulh $6, $4, $6 " ); \
asm( "addq $7, $3, $7 " ); \
asm( "cmpult $7, $3, $3 " ); \
asm( "ldq $5, 0($2) " ); \
asm( "addq $7, $5, $7 " ); \
asm( "cmpult $7, $5, $5 " ); \
asm( "stq $7, 0($2) " ); \
asm( "addq $2, 8, $2 " ); \
asm( "addq $6, $3, $3 " ); \
asm( "addq $5, $3, $3 " );
#define MULADDC_STOP \
asm( "stq $3, %0 " : "=m" (c)); \
asm( "stq $2, %0 " : "=m" (d)); \
asm( "stq $1, %0 " : "=m" (s) :: \
"$1", "$2", "$3", "$4", "$5", "$6", "$7" );
#endif /* Alpha */
#if defined(__mips__)
#define MULADDC_INIT \
asm( "lw $10, %0 " :: "m" (s)); \
asm( "lw $11, %0 " :: "m" (d)); \
asm( "lw $12, %0 " :: "m" (c)); \
asm( "lw $13, %0 " :: "m" (b));
#define MULADDC_CORE \
asm( "lw $14, 0($10) " ); \
asm( "multu $13, $14 " ); \
asm( "addi $10, $10, 4 " ); \
asm( "mflo $14 " ); \
asm( "mfhi $9 " ); \
asm( "addu $14, $12, $14 " ); \
asm( "lw $15, 0($11) " ); \
asm( "sltu $12, $14, $12 " ); \
asm( "addu $15, $14, $15 " ); \
asm( "sltu $14, $15, $14 " ); \
asm( "addu $12, $12, $9 " ); \
asm( "sw $15, 0($11) " ); \
asm( "addu $12, $12, $14 " ); \
asm( "addi $11, $11, 4 " );
#define MULADDC_STOP \
asm( "sw $12, %0 " : "=m" (c)); \
asm( "sw $11, %0 " : "=m" (d)); \
asm( "sw $10, %0 " : "=m" (s) :: \
"$9", "$10", "$11", "$12", "$13", "$14", "$15" );
#endif /* MIPS */
#endif /* GNUC */
#if (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
#define MULADDC_INIT \
__asm mov esi, s \
__asm mov edi, d \
__asm mov ecx, c \
__asm mov ebx, b
#define MULADDC_CORE \
__asm lodsd \
__asm mul ebx \
__asm add eax, ecx \
__asm adc edx, 0 \
__asm add eax, [edi] \
__asm adc edx, 0 \
__asm mov ecx, edx \
__asm stosd
#if defined(POLARSSL_HAVE_SSE2)
#define EMIT __asm _emit
#define MULADDC_HUIT \
EMIT 0x0F EMIT 0x6E EMIT 0xC9 \
EMIT 0x0F EMIT 0x6E EMIT 0xC3 \
EMIT 0x0F EMIT 0x6E EMIT 0x1F \
EMIT 0x0F EMIT 0xD4 EMIT 0xCB \
EMIT 0x0F EMIT 0x6E EMIT 0x16 \
EMIT 0x0F EMIT 0xF4 EMIT 0xD0 \
EMIT 0x0F EMIT 0x6E EMIT 0x66 EMIT 0x04 \
EMIT 0x0F EMIT 0xF4 EMIT 0xE0 \
EMIT 0x0F EMIT 0x6E EMIT 0x76 EMIT 0x08 \
EMIT 0x0F EMIT 0xF4 EMIT 0xF0 \
EMIT 0x0F EMIT 0x6E EMIT 0x7E EMIT 0x0C \
EMIT 0x0F EMIT 0xF4 EMIT 0xF8 \
EMIT 0x0F EMIT 0xD4 EMIT 0xCA \
EMIT 0x0F EMIT 0x6E EMIT 0x5F EMIT 0x04 \
EMIT 0x0F EMIT 0xD4 EMIT 0xDC \
EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x08 \
EMIT 0x0F EMIT 0xD4 EMIT 0xEE \
EMIT 0x0F EMIT 0x6E EMIT 0x67 EMIT 0x0C \
EMIT 0x0F EMIT 0xD4 EMIT 0xFC \
EMIT 0x0F EMIT 0x7E EMIT 0x0F \
EMIT 0x0F EMIT 0x6E EMIT 0x56 EMIT 0x10 \
EMIT 0x0F EMIT 0xF4 EMIT 0xD0 \
EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \
EMIT 0x0F EMIT 0x6E EMIT 0x66 EMIT 0x14 \
EMIT 0x0F EMIT 0xF4 EMIT 0xE0 \
EMIT 0x0F EMIT 0xD4 EMIT 0xCB \
EMIT 0x0F EMIT 0x6E EMIT 0x76 EMIT 0x18 \
EMIT 0x0F EMIT 0xF4 EMIT 0xF0 \
EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x04 \
EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \
EMIT 0x0F EMIT 0x6E EMIT 0x5E EMIT 0x1C \
EMIT 0x0F EMIT 0xF4 EMIT 0xD8 \
EMIT 0x0F EMIT 0xD4 EMIT 0xCD \
EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x10 \
EMIT 0x0F EMIT 0xD4 EMIT 0xD5 \
EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x08 \
EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \
EMIT 0x0F EMIT 0xD4 EMIT 0xCF \
EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x14 \
EMIT 0x0F EMIT 0xD4 EMIT 0xE5 \
EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x0C \
EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \
EMIT 0x0F EMIT 0xD4 EMIT 0xCA \
EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x18 \
EMIT 0x0F EMIT 0xD4 EMIT 0xF5 \
EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x10 \
EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \
EMIT 0x0F EMIT 0xD4 EMIT 0xCC \
EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x1C \
EMIT 0x0F EMIT 0xD4 EMIT 0xDD \
EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x14 \
EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \
EMIT 0x0F EMIT 0xD4 EMIT 0xCE \
EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x18 \
EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \
EMIT 0x0F EMIT 0xD4 EMIT 0xCB \
EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x1C \
EMIT 0x83 EMIT 0xC7 EMIT 0x20 \
EMIT 0x83 EMIT 0xC6 EMIT 0x20 \
EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \
EMIT 0x0F EMIT 0x7E EMIT 0xC9
#define MULADDC_STOP \
EMIT 0x0F EMIT 0x77 \
__asm mov c, ecx \
__asm mov d, edi \
__asm mov s, esi \
#else
#define MULADDC_STOP \
__asm mov c, ecx \
__asm mov d, edi \
__asm mov s, esi \
#endif /* SSE2 */
#endif /* MSVC */
#endif /* POLARSSL_HAVE_ASM */
#if !defined(MULADDC_CORE)
#if defined(POLARSSL_HAVE_LONGLONG)
#define MULADDC_INIT \
{ \
t_dbl r; \
t_int r0, r1;
#define MULADDC_CORE \
r = *(s++) * (t_dbl) b; \
r0 = r; \
r1 = r >> biL; \
r0 += c; r1 += (r0 < c); \
r0 += *d; r1 += (r0 < *d); \
c = r1; *(d++) = r0;
#define MULADDC_STOP \
}
#else
#define MULADDC_INIT \
{ \
t_uint s0, s1, b0, b1; \
t_uint r0, r1, rx, ry; \
b0 = ( b << biH ) >> biH; \
b1 = ( b >> biH );
#define MULADDC_CORE \
s0 = ( *s << biH ) >> biH; \
s1 = ( *s >> biH ); s++; \
rx = s0 * b1; r0 = s0 * b0; \
ry = s1 * b0; r1 = s1 * b1; \
r1 += ( rx >> biH ); \
r1 += ( ry >> biH ); \
rx <<= biH; ry <<= biH; \
r0 += rx; r1 += (r0 < rx); \
r0 += ry; r1 += (r0 < ry); \
r0 += c; r1 += (r0 < c); \
r0 += *d; r1 += (r0 < *d); \
c = r1; *(d++) = r0;
#define MULADDC_STOP \
}
#endif /* C (generic) */
#endif /* C (longlong) */
#endif /* bn_mul.h */

1018
polarssl/config.h Normal file

File diff suppressed because it is too large Load Diff

633
polarssl/rsa.h Normal file
View File

@ -0,0 +1,633 @@
/**
* \file rsa.h
*
* \brief The RSA public-key cryptosystem
*
* Copyright (C) 2006-2010, Brainspark B.V.
*
* This file is part of PolarSSL (http://www.polarssl.org)
* Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef POLARSSL_RSA_H
#define POLARSSL_RSA_H
#include "bignum.h"
/*
* RSA Error codes
*/
#define POLARSSL_ERR_RSA_BAD_INPUT_DATA -0x4080 /**< Bad input parameters to function. */
#define POLARSSL_ERR_RSA_INVALID_PADDING -0x4100 /**< Input data contains invalid padding and is rejected. */
#define POLARSSL_ERR_RSA_KEY_GEN_FAILED -0x4180 /**< Something failed during generation of a key. */
#define POLARSSL_ERR_RSA_KEY_CHECK_FAILED -0x4200 /**< Key failed to pass the libraries validity check. */
#define POLARSSL_ERR_RSA_PUBLIC_FAILED -0x4280 /**< The public key operation failed. */
#define POLARSSL_ERR_RSA_PRIVATE_FAILED -0x4300 /**< The private key operation failed. */
#define POLARSSL_ERR_RSA_VERIFY_FAILED -0x4380 /**< The PKCS#1 verification failed. */
#define POLARSSL_ERR_RSA_OUTPUT_TOO_LARGE -0x4400 /**< The output buffer for decryption is not large enough. */
#define POLARSSL_ERR_RSA_RNG_FAILED -0x4480 /**< The random generator failed to generate non-zeros. */
/*
* PKCS#1 constants
*/
#define SIG_RSA_RAW 0
#define SIG_RSA_MD2 2
#define SIG_RSA_MD4 3
#define SIG_RSA_MD5 4
#define SIG_RSA_SHA1 5
#define SIG_RSA_SHA224 14
#define SIG_RSA_SHA256 11
#define SIG_RSA_SHA384 12
#define SIG_RSA_SHA512 13
#define RSA_PUBLIC 0
#define RSA_PRIVATE 1
#define RSA_PKCS_V15 0
#define RSA_PKCS_V21 1
#define RSA_SIGN 1
#define RSA_CRYPT 2
#define ASN1_STR_CONSTRUCTED_SEQUENCE "\x30"
#define ASN1_STR_NULL "\x05"
#define ASN1_STR_OID "\x06"
#define ASN1_STR_OCTET_STRING "\x04"
#define OID_DIGEST_ALG_MDX "\x2A\x86\x48\x86\xF7\x0D\x02\x00"
#define OID_HASH_ALG_SHA1 "\x2b\x0e\x03\x02\x1a"
#define OID_HASH_ALG_SHA2X "\x60\x86\x48\x01\x65\x03\x04\x02\x00"
#define OID_ISO_MEMBER_BODIES "\x2a"
#define OID_ISO_IDENTIFIED_ORG "\x2b"
/*
* ISO Member bodies OID parts
*/
#define OID_COUNTRY_US "\x86\x48"
#define OID_RSA_DATA_SECURITY "\x86\xf7\x0d"
/*
* ISO Identified organization OID parts
*/
#define OID_OIW_SECSIG_SHA1 "\x0e\x03\x02\x1a"
/*
* DigestInfo ::= SEQUENCE {
* digestAlgorithm DigestAlgorithmIdentifier,
* digest Digest }
*
* DigestAlgorithmIdentifier ::= AlgorithmIdentifier
*
* Digest ::= OCTET STRING
*/
#define ASN1_HASH_MDX \
( \
ASN1_STR_CONSTRUCTED_SEQUENCE "\x20" \
ASN1_STR_CONSTRUCTED_SEQUENCE "\x0C" \
ASN1_STR_OID "\x08" \
OID_DIGEST_ALG_MDX \
ASN1_STR_NULL "\x00" \
ASN1_STR_OCTET_STRING "\x10" \
)
#define ASN1_HASH_SHA1 \
ASN1_STR_CONSTRUCTED_SEQUENCE "\x21" \
ASN1_STR_CONSTRUCTED_SEQUENCE "\x09" \
ASN1_STR_OID "\x05" \
OID_HASH_ALG_SHA1 \
ASN1_STR_NULL "\x00" \
ASN1_STR_OCTET_STRING "\x14"
#define ASN1_HASH_SHA1_ALT \
ASN1_STR_CONSTRUCTED_SEQUENCE "\x1F" \
ASN1_STR_CONSTRUCTED_SEQUENCE "\x07" \
ASN1_STR_OID "\x05" \
OID_HASH_ALG_SHA1 \
ASN1_STR_OCTET_STRING "\x14"
#define ASN1_HASH_SHA2X \
ASN1_STR_CONSTRUCTED_SEQUENCE "\x11" \
ASN1_STR_CONSTRUCTED_SEQUENCE "\x0d" \
ASN1_STR_OID "\x09" \
OID_HASH_ALG_SHA2X \
ASN1_STR_NULL "\x00" \
ASN1_STR_OCTET_STRING "\x00"
/**
* \brief RSA context structure
*/
typedef struct
{
int ver; /*!< always 0 */
size_t len; /*!< size(N) in chars */
mpi N; /*!< public modulus */
mpi E; /*!< public exponent */
mpi D; /*!< private exponent */
mpi P; /*!< 1st prime factor */
mpi Q; /*!< 2nd prime factor */
mpi DP; /*!< D % (P - 1) */
mpi DQ; /*!< D % (Q - 1) */
mpi QP; /*!< 1 / (Q % P) */
mpi RN; /*!< cached R^2 mod N */
mpi RP; /*!< cached R^2 mod P */
mpi RQ; /*!< cached R^2 mod Q */
int padding; /*!< RSA_PKCS_V15 for 1.5 padding and
RSA_PKCS_v21 for OAEP/PSS */
int hash_id; /*!< Hash identifier of md_type_t as
specified in the md.h header file
for the EME-OAEP and EMSA-PSS
encoding */
}
rsa_context;
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief Initialize an RSA context
*
* Note: Set padding to RSA_PKCS_V21 for the RSAES-OAEP
* encryption scheme and the RSASSA-PSS signature scheme.
*
* \param ctx RSA context to be initialized
* \param padding RSA_PKCS_V15 or RSA_PKCS_V21
* \param hash_id RSA_PKCS_V21 hash identifier
*
* \note The hash_id parameter is actually ignored
* when using RSA_PKCS_V15 padding.
*/
void rsa_init( rsa_context *ctx,
int padding,
int hash_id);
/**
* \brief Generate an RSA keypair
*
* \param ctx RSA context that will hold the key
* \param f_rng RNG function
* \param p_rng RNG parameter
* \param nbits size of the public key in bits
* \param exponent public exponent (e.g., 65537)
*
* \note rsa_init() must be called beforehand to setup
* the RSA context.
*
* \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code
*/
int rsa_gen_key( rsa_context *ctx,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng,
unsigned int nbits, int exponent );
/**
* \brief Check a public RSA key
*
* \param ctx RSA context to be checked
*
* \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code
*/
int rsa_check_pubkey( const rsa_context *ctx );
/**
* \brief Check a private RSA key
*
* \param ctx RSA context to be checked
*
* \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code
*/
int rsa_check_privkey( const rsa_context *ctx );
/**
* \brief Do an RSA public key operation
*
* \param ctx RSA context
* \param input input buffer
* \param output output buffer
*
* \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code
*
* \note This function does NOT take care of message
* padding. Also, be sure to set input[0] = 0 or assure that
* input is smaller than N.
*
* \note The input and output buffers must be large
* enough (eg. 128 bytes if RSA-1024 is used).
*/
int rsa_public( rsa_context *ctx,
const unsigned char *input,
unsigned char *output );
/**
* \brief Do an RSA private key operation
*
* \param ctx RSA context
* \param f_rng RNG function (Needed for blinding)
* \param p_rng RNG parameter
* \param input input buffer
* \param output output buffer
*
* \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code
*
* \note The input and output buffers must be large
* enough (eg. 128 bytes if RSA-1024 is used).
*/
int rsa_private( rsa_context *ctx,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng,
const unsigned char *input,
unsigned char *output );
/**
* \brief Generic wrapper to perform a PKCS#1 encryption using the
* mode from the context. Add the message padding, then do an
* RSA operation.
*
* \param ctx RSA context
* \param f_rng RNG function (Needed for padding and PKCS#1 v2.1 encoding
* and RSA_PRIVATE)
* \param p_rng RNG parameter
* \param mode RSA_PUBLIC or RSA_PRIVATE
* \param ilen contains the plaintext length
* \param input buffer holding the data to be encrypted
* \param output buffer that will hold the ciphertext
*
* \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code
*
* \note The output buffer must be as large as the size
* of ctx->N (eg. 128 bytes if RSA-1024 is used).
*/
int rsa_pkcs1_encrypt( rsa_context *ctx,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng,
int mode, size_t ilen,
const unsigned char *input,
unsigned char *output );
/**
* \brief Perform a PKCS#1 v1.5 encryption (RSAES-PKCS1-v1_5-ENCRYPT)
*
* \param ctx RSA context
* \param f_rng RNG function (Needed for padding and RSA_PRIVATE)
* \param p_rng RNG parameter
* \param mode RSA_PUBLIC or RSA_PRIVATE
* \param ilen contains the plaintext length
* \param input buffer holding the data to be encrypted
* \param output buffer that will hold the ciphertext
*
* \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code
*
* \note The output buffer must be as large as the size
* of ctx->N (eg. 128 bytes if RSA-1024 is used).
*/
int rsa_rsaes_pkcs1_v15_encrypt( rsa_context *ctx,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng,
int mode, size_t ilen,
const unsigned char *input,
unsigned char *output );
/**
* \brief Perform a PKCS#1 v2.1 OAEP encryption (RSAES-OAEP-ENCRYPT)
*
* \param ctx RSA context
* \param f_rng RNG function (Needed for padding and PKCS#1 v2.1 encoding
* and RSA_PRIVATE)
* \param p_rng RNG parameter
* \param mode RSA_PUBLIC or RSA_PRIVATE
* \param label buffer holding the custom label to use
* \param label_len contains the label length
* \param ilen contains the plaintext length
* \param input buffer holding the data to be encrypted
* \param output buffer that will hold the ciphertext
*
* \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code
*
* \note The output buffer must be as large as the size
* of ctx->N (eg. 128 bytes if RSA-1024 is used).
*/
int rsa_rsaes_oaep_encrypt( rsa_context *ctx,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng,
int mode,
const unsigned char *label, size_t label_len,
size_t ilen,
const unsigned char *input,
unsigned char *output );
/**
* \brief Generic wrapper to perform a PKCS#1 decryption using the
* mode from the context. Do an RSA operation, then remove
* the message padding
*
* \param ctx RSA context
* \param f_rng RNG function (Only needed for RSA_PRIVATE)
* \param p_rng RNG parameter
* \param mode RSA_PUBLIC or RSA_PRIVATE
* \param olen will contain the plaintext length
* \param input buffer holding the encrypted data
* \param output buffer that will hold the plaintext
* \param output_max_len maximum length of the output buffer
*
* \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code
*
* \note The output buffer must be as large as the size
* of ctx->N (eg. 128 bytes if RSA-1024 is used) otherwise
* an error is thrown.
*/
int rsa_pkcs1_decrypt( rsa_context *ctx,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng,
int mode, size_t *olen,
const unsigned char *input,
unsigned char *output,
size_t output_max_len );
/**
* \brief Perform a PKCS#1 v1.5 decryption (RSAES-PKCS1-v1_5-DECRYPT)
*
* \param ctx RSA context
* \param f_rng RNG function (Only needed for RSA_PRIVATE)
* \param p_rng RNG parameter
* \param mode RSA_PUBLIC or RSA_PRIVATE
* \param olen will contain the plaintext length
* \param input buffer holding the encrypted data
* \param output buffer that will hold the plaintext
* \param output_max_len maximum length of the output buffer
*
* \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code
*
* \note The output buffer must be as large as the size
* of ctx->N (eg. 128 bytes if RSA-1024 is used) otherwise
* an error is thrown.
*/
int rsa_rsaes_pkcs1_v15_decrypt( rsa_context *ctx,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng,
int mode, size_t *olen,
const unsigned char *input,
unsigned char *output,
size_t output_max_len );
/**
* \brief Perform a PKCS#1 v2.1 OAEP decryption (RSAES-OAEP-DECRYPT)
*
* \param ctx RSA context
* \param f_rng RNG function (Only needed for RSA_PRIVATE)
* \param p_rng RNG parameter
* \param mode RSA_PUBLIC or RSA_PRIVATE
* \param label buffer holding the custom label to use
* \param label_len contains the label length
* \param olen will contain the plaintext length
* \param input buffer holding the encrypted data
* \param output buffer that will hold the plaintext
* \param output_max_len maximum length of the output buffer
*
* \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code
*
* \note The output buffer must be as large as the size
* of ctx->N (eg. 128 bytes if RSA-1024 is used) otherwise
* an error is thrown.
*/
int rsa_rsaes_oaep_decrypt( rsa_context *ctx,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng,
int mode,
const unsigned char *label, size_t label_len,
size_t *olen,
const unsigned char *input,
unsigned char *output,
size_t output_max_len );
/**
* \brief Generic wrapper to perform a PKCS#1 signature using the
* mode from the context. Do a private RSA operation to sign
* a message digest
*
* \param ctx RSA context
* \param f_rng RNG function (Needed for PKCS#1 v2.1 encoding and for
* RSA_PRIVATE)
* \param p_rng RNG parameter
* \param mode RSA_PUBLIC or RSA_PRIVATE
* \param hash_id SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512}
* \param hashlen message digest length (for SIG_RSA_RAW only)
* \param hash buffer holding the message digest
* \param sig buffer that will hold the ciphertext
*
* \return 0 if the signing operation was successful,
* or an POLARSSL_ERR_RSA_XXX error code
*
* \note The "sig" buffer must be as large as the size
* of ctx->N (eg. 128 bytes if RSA-1024 is used).
*
* \note In case of PKCS#1 v2.1 encoding keep in mind that
* the hash_id in the RSA context is the one used for the
* encoding. hash_id in the function call is the type of hash
* that is encoded. According to RFC 3447 it is advised to
* keep both hashes the same.
*/
int rsa_pkcs1_sign( rsa_context *ctx,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng,
int mode,
int hash_id,
unsigned int hashlen,
const unsigned char *hash,
unsigned char *sig );
/**
* \brief Perform a PKCS#1 v1.5 signature (RSASSA-PKCS1-v1_5-SIGN)
*
* \param ctx RSA context
* \param f_rng RNG function (Only needed for RSA_PRIVATE)
* \param p_rng RNG parameter
* \param mode RSA_PUBLIC or RSA_PRIVATE
* \param hash_id SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512}
* \param hashlen message digest length (for SIG_RSA_RAW only)
* \param hash buffer holding the message digest
* \param sig buffer that will hold the ciphertext
*
* \return 0 if the signing operation was successful,
* or an POLARSSL_ERR_RSA_XXX error code
*
* \note The "sig" buffer must be as large as the size
* of ctx->N (eg. 128 bytes if RSA-1024 is used).
*/
int rsa_rsassa_pkcs1_v15_sign( rsa_context *ctx,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng,
int mode,
int hash_id,
unsigned int hashlen,
const unsigned char *hash,
unsigned char *sig );
/**
* \brief Perform a PKCS#1 v2.1 PSS signature (RSASSA-PSS-SIGN)
*
* \param ctx RSA context
* \param f_rng RNG function (Needed for PKCS#1 v2.1 encoding and for
* RSA_PRIVATE)
* \param p_rng RNG parameter
* \param mode RSA_PUBLIC or RSA_PRIVATE
* \param hash_id SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512}
* \param hashlen message digest length (for SIG_RSA_RAW only)
* \param hash buffer holding the message digest
* \param sig buffer that will hold the ciphertext
*
* \return 0 if the signing operation was successful,
* or an POLARSSL_ERR_RSA_XXX error code
*
* \note The "sig" buffer must be as large as the size
* of ctx->N (eg. 128 bytes if RSA-1024 is used).
*
* \note In case of PKCS#1 v2.1 encoding keep in mind that
* the hash_id in the RSA context is the one used for the
* encoding. hash_id in the function call is the type of hash
* that is encoded. According to RFC 3447 it is advised to
* keep both hashes the same.
*/
int rsa_rsassa_pss_sign( rsa_context *ctx,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng,
int mode,
int hash_id,
unsigned int hashlen,
const unsigned char *hash,
unsigned char *sig );
/**
* \brief Generic wrapper to perform a PKCS#1 verification using the
* mode from the context. Do a public RSA operation and check
* the message digest
*
* \param ctx points to an RSA public key
* \param f_rng RNG function (Only needed for RSA_PRIVATE)
* \param p_rng RNG parameter
* \param mode RSA_PUBLIC or RSA_PRIVATE
* \param hash_id SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512}
* \param hashlen message digest length (for SIG_RSA_RAW only)
* \param hash buffer holding the message digest
* \param sig buffer holding the ciphertext
*
* \return 0 if the verify operation was successful,
* or an POLARSSL_ERR_RSA_XXX error code
*
* \note The "sig" buffer must be as large as the size
* of ctx->N (eg. 128 bytes if RSA-1024 is used).
*
* \note In case of PKCS#1 v2.1 encoding keep in mind that
* the hash_id in the RSA context is the one used for the
* verification. hash_id in the function call is the type of hash
* that is verified. According to RFC 3447 it is advised to
* keep both hashes the same.
*/
int rsa_pkcs1_verify( rsa_context *ctx,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng,
int mode,
int hash_id,
unsigned int hashlen,
const unsigned char *hash,
const unsigned char *sig );
/**
* \brief Perform a PKCS#1 v1.5 verification (RSASSA-PKCS1-v1_5-VERIFY)
*
* \param ctx points to an RSA public key
* \param f_rng RNG function (Only needed for RSA_PRIVATE)
* \param p_rng RNG parameter
* \param mode RSA_PUBLIC or RSA_PRIVATE
* \param hash_id SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512}
* \param hashlen message digest length (for SIG_RSA_RAW only)
* \param hash buffer holding the message digest
* \param sig buffer holding the ciphertext
*
* \return 0 if the verify operation was successful,
* or an POLARSSL_ERR_RSA_XXX error code
*
* \note The "sig" buffer must be as large as the size
* of ctx->N (eg. 128 bytes if RSA-1024 is used).
*/
int rsa_rsassa_pkcs1_v15_verify( rsa_context *ctx,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng,
int mode,
int hash_id,
unsigned int hashlen,
const unsigned char *hash,
const unsigned char *sig );
/**
* \brief Perform a PKCS#1 v2.1 PSS verification (RSASSA-PSS-VERIFY)
* \brief Do a public RSA and check the message digest
*
* \param ctx points to an RSA public key
* \param f_rng RNG function (Only needed for RSA_PRIVATE)
* \param p_rng RNG parameter
* \param mode RSA_PUBLIC or RSA_PRIVATE
* \param hash_id SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512}
* \param hashlen message digest length (for SIG_RSA_RAW only)
* \param hash buffer holding the message digest
* \param sig buffer holding the ciphertext
*
* \return 0 if the verify operation was successful,
* or an POLARSSL_ERR_RSA_XXX error code
*
* \note The "sig" buffer must be as large as the size
* of ctx->N (eg. 128 bytes if RSA-1024 is used).
*
* \note In case of PKCS#1 v2.1 encoding keep in mind that
* the hash_id in the RSA context is the one used for the
* verification. hash_id in the function call is the type of hash
* that is verified. According to RFC 3447 it is advised to
* keep both hashes the same.
*/
int rsa_rsassa_pss_verify( rsa_context *ctx,
int (*f_rng)(void *, unsigned char *, size_t),
void *p_rng,
int mode,
int hash_id,
unsigned int hashlen,
const unsigned char *hash,
unsigned char *sig );
/**
* \brief Free the components of an RSA key
*
* \param ctx RSA Context to free
*/
void rsa_free( rsa_context *ctx );
/**
* \brief Checkup routine
*
* \return 0 if successful, or 1 if the test failed
*/
int rsa_self_test( int verbose );
#ifdef __cplusplus
}
#endif
#endif /* rsa.h */

120
random.c Normal file
View File

@ -0,0 +1,120 @@
/*
* random.c -- get random bytes
*
* Copyright (C) 2010, 2011, 2012, 2013, 2015
* Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdint.h>
#include <string.h>
#include "gnuk.h"
#include "neug.h"
#define RANDOM_BYTES_LENGTH 32
static uint32_t random_word[RANDOM_BYTES_LENGTH/sizeof (uint32_t)];
void
random_init (void)
{
int i;
neug_init (random_word, RANDOM_BYTES_LENGTH/sizeof (uint32_t));
for (i = 0; i < NEUG_PRE_LOOP; i++)
(void)neug_get (NEUG_KICK_FILLING);
}
void
random_fini (void)
{
neug_fini ();
}
/*
* Return pointer to random 32-byte
*/
const uint8_t *
random_bytes_get (void)
{
neug_wait_full ();
return (const uint8_t *)random_word;
}
/*
* Free pointer to random 32-byte
*/
void
random_bytes_free (const uint8_t *p)
{
(void)p;
memset (random_word, 0, RANDOM_BYTES_LENGTH);
neug_flush ();
}
/*
* Return 4-byte salt
*/
void
random_get_salt (uint8_t *p)
{
uint32_t rnd;
rnd = neug_get (NEUG_KICK_FILLING);
memcpy (p, &rnd, sizeof (uint32_t));
rnd = neug_get (NEUG_KICK_FILLING);
memcpy (p + sizeof (uint32_t), &rnd, sizeof (uint32_t));
}
/*
* Random byte iterator
*/
int
random_gen (void *arg, unsigned char *out, size_t out_len)
{
uint8_t *index_p = (uint8_t *)arg;
uint8_t index = *index_p;
size_t n;
while (out_len)
{
neug_wait_full ();
n = RANDOM_BYTES_LENGTH - index;
if (n > out_len)
n = out_len;
memcpy (out, ((unsigned char *)random_word) + index, n);
out += n;
out_len -= n;
index += n;
if (index >= RANDOM_BYTES_LENGTH)
{
index = 0;
neug_flush ();
}
}
*index_p = index;
return 0;
}

12
random.h Normal file
View File

@ -0,0 +1,12 @@
void random_init (void);
void random_fini (void);
/* 32-byte random bytes */
const uint8_t *random_bytes_get (void);
void random_bytes_free (const uint8_t *p);
/* 8-byte salt */
void random_get_salt (uint8_t *p);
/* iterator returning a byta at a time */
int random_gen (void *arg, unsigned char *output, size_t output_len);

1521
rsa.c Normal file

File diff suppressed because it is too large Load Diff

225
sha256.c Normal file
View File

@ -0,0 +1,225 @@
/*
* sha256.c -- Compute SHA-256 hash
*
* Just for little endian architecture.
*
* Code taken from:
* http://gladman.plushost.co.uk/oldsite/cryptography_technology/sha/index.php
*
* File names are sha2.c, sha2.h, brg_types.h, brg_endian.h
* in the archive sha2-07-01-07.zip.
*
* Code is modified in the style of PolarSSL API.
*
* See original copyright notice below.
*/
/*
---------------------------------------------------------------------------
Copyright (c) 2002, Dr Brian Gladman, Worcester, UK. All rights reserved.
LICENSE TERMS
The free distribution and use of this software in both source and binary
form is allowed (with or without changes) provided that:
1. distributions of this source code include the above copyright
notice, this list of conditions and the following disclaimer;
2. distributions in binary form include the above copyright
notice, this list of conditions and the following disclaimer
in the documentation and/or other associated materials;
3. the copyright holder's name is not used to endorse products
built using this software without specific written permission.
ALTERNATIVELY, provided that this notice is retained in full, this product
may be distributed under the terms of the GNU General Public License (GPL),
in which case the provisions of the GPL apply INSTEAD OF those given above.
DISCLAIMER
This software is provided 'as is' with no explicit or implied warranties
in respect of its properties, including, but not limited to, correctness
and/or fitness for purpose.
---------------------------------------------------------------------------
Issue Date: 01/08/2005
*/
#include <string.h>
#include <stdint.h>
#include "sha256.h"
#define SHA256_MASK (SHA256_BLOCK_SIZE - 1)
static void memcpy_output_bswap32 (unsigned char *dst, const uint32_t *p)
{
int i;
uint32_t q = 0;
for (i = 0; i < 32; i++)
{
if ((i & 3) == 0)
q = __builtin_bswap32 (p[i >> 2]); /* bswap32 is GCC extention */
dst[i] = q >> ((i & 3) * 8);
}
}
#define rotr32(x,n) (((x) >> n) | ((x) << (32 - n)))
#define ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z))))
#define maj(x,y,z) (((x) & (y)) | ((z) & ((x) ^ (y))))
/* round transforms for SHA256 compression functions */
#define vf(n,i) v[(n - i) & 7]
#define hf(i) (p[i & 15] += \
g_1(p[(i + 14) & 15]) + p[(i + 9) & 15] + g_0(p[(i + 1) & 15]))
#define v_cycle0(i) \
p[i] = __builtin_bswap32 (p[i]); \
vf(7,i) += p[i] + k_0[i] \
+ s_1(vf(4,i)) + ch(vf(4,i),vf(5,i),vf(6,i)); \
vf(3,i) += vf(7,i); \
vf(7,i) += s_0(vf(0,i))+ maj(vf(0,i),vf(1,i),vf(2,i))
#define v_cycle(i, j) \
vf(7,i) += hf(i) + k_0[i+j] \
+ s_1(vf(4,i)) + ch(vf(4,i),vf(5,i),vf(6,i)); \
vf(3,i) += vf(7,i); \
vf(7,i) += s_0(vf(0,i))+ maj(vf(0,i),vf(1,i),vf(2,i))
#define s_0(x) (rotr32((x), 2) ^ rotr32((x), 13) ^ rotr32((x), 22))
#define s_1(x) (rotr32((x), 6) ^ rotr32((x), 11) ^ rotr32((x), 25))
#define g_0(x) (rotr32((x), 7) ^ rotr32((x), 18) ^ ((x) >> 3))
#define g_1(x) (rotr32((x), 17) ^ rotr32((x), 19) ^ ((x) >> 10))
#define k_0 k256
static const uint32_t k256[64] = {
0X428A2F98, 0X71374491, 0XB5C0FBCF, 0XE9B5DBA5,
0X3956C25B, 0X59F111F1, 0X923F82A4, 0XAB1C5ED5,
0XD807AA98, 0X12835B01, 0X243185BE, 0X550C7DC3,
0X72BE5D74, 0X80DEB1FE, 0X9BDC06A7, 0XC19BF174,
0XE49B69C1, 0XEFBE4786, 0X0FC19DC6, 0X240CA1CC,
0X2DE92C6F, 0X4A7484AA, 0X5CB0A9DC, 0X76F988DA,
0X983E5152, 0XA831C66D, 0XB00327C8, 0XBF597FC7,
0XC6E00BF3, 0XD5A79147, 0X06CA6351, 0X14292967,
0X27B70A85, 0X2E1B2138, 0X4D2C6DFC, 0X53380D13,
0X650A7354, 0X766A0ABB, 0X81C2C92E, 0X92722C85,
0XA2BFE8A1, 0XA81A664B, 0XC24B8B70, 0XC76C51A3,
0XD192E819, 0XD6990624, 0XF40E3585, 0X106AA070,
0X19A4C116, 0X1E376C08, 0X2748774C, 0X34B0BCB5,
0X391C0CB3, 0X4ED8AA4A, 0X5B9CCA4F, 0X682E6FF3,
0X748F82EE, 0X78A5636F, 0X84C87814, 0X8CC70208,
0X90BEFFFA, 0XA4506CEB, 0XBEF9A3F7, 0XC67178F2,
};
void
sha256_process (sha256_context *ctx)
{
uint32_t i;
uint32_t *p = ctx->wbuf;
uint32_t v[8];
memcpy (v, ctx->state, 8 * sizeof (uint32_t));
v_cycle0 ( 0); v_cycle0 ( 1); v_cycle0 ( 2); v_cycle0 ( 3);
v_cycle0 ( 4); v_cycle0 ( 5); v_cycle0 ( 6); v_cycle0 ( 7);
v_cycle0 ( 8); v_cycle0 ( 9); v_cycle0 (10); v_cycle0 (11);
v_cycle0 (12); v_cycle0 (13); v_cycle0 (14); v_cycle0 (15);
for (i = 16; i < 64; i += 16)
{
v_cycle ( 0, i); v_cycle ( 1, i); v_cycle ( 2, i); v_cycle ( 3, i);
v_cycle ( 4, i); v_cycle ( 5, i); v_cycle ( 6, i); v_cycle ( 7, i);
v_cycle ( 8, i); v_cycle ( 9, i); v_cycle (10, i); v_cycle (11, i);
v_cycle (12, i); v_cycle (13, i); v_cycle (14, i); v_cycle (15, i);
}
ctx->state[0] += v[0];
ctx->state[1] += v[1];
ctx->state[2] += v[2];
ctx->state[3] += v[3];
ctx->state[4] += v[4];
ctx->state[5] += v[5];
ctx->state[6] += v[6];
ctx->state[7] += v[7];
}
void
sha256_update (sha256_context *ctx, const unsigned char *input,
unsigned int ilen)
{
uint32_t left = (ctx->total[0] & SHA256_MASK);
uint32_t fill = SHA256_BLOCK_SIZE - left;
ctx->total[0] += ilen;
if (ctx->total[0] < ilen)
ctx->total[1]++;
while (ilen >= fill)
{
memcpy (((unsigned char*)ctx->wbuf) + left, input, fill);
sha256_process (ctx);
input += fill;
ilen -= fill;
left = 0;
fill = SHA256_BLOCK_SIZE;
}
memcpy (((unsigned char*)ctx->wbuf) + left, input, ilen);
}
void
sha256_finish (sha256_context *ctx, unsigned char output[32])
{
uint32_t last = (ctx->total[0] & SHA256_MASK);
ctx->wbuf[last >> 2] = __builtin_bswap32 (ctx->wbuf[last >> 2]);
ctx->wbuf[last >> 2] &= 0xffffff80 << (8 * (~last & 3));
ctx->wbuf[last >> 2] |= 0x00000080 << (8 * (~last & 3));
ctx->wbuf[last >> 2] = __builtin_bswap32 (ctx->wbuf[last >> 2]);
if (last > SHA256_BLOCK_SIZE - 9)
{
if (last < 60)
ctx->wbuf[15] = 0;
sha256_process (ctx);
last = 0;
}
else
last = (last >> 2) + 1;
while (last < 14)
ctx->wbuf[last++] = 0;
ctx->wbuf[14] = __builtin_bswap32 ((ctx->total[0] >> 29) | (ctx->total[1] << 3));
ctx->wbuf[15] = __builtin_bswap32 (ctx->total[0] << 3);
sha256_process (ctx);
memcpy_output_bswap32 (output, ctx->state);
memset (ctx, 0, sizeof (sha256_context));
}
static const uint32_t initial_state[8] =
{
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
};
void
sha256_start (sha256_context *ctx)
{
ctx->total[0] = ctx->total[1] = 0;
memcpy (ctx->state, initial_state, 8 * sizeof(uint32_t));
}
void
sha256 (const unsigned char *input, unsigned int ilen,
unsigned char output[32])
{
sha256_context ctx;
sha256_start (&ctx);
sha256_update (&ctx, input, ilen);
sha256_finish (&ctx, output);
}

17
sha256.h Normal file
View File

@ -0,0 +1,17 @@
#define SHA256_DIGEST_SIZE 32
#define SHA256_BLOCK_SIZE 64
typedef struct
{
uint32_t total[2];
uint32_t state[8];
uint32_t wbuf[16];
} sha256_context;
void sha256 (const unsigned char *input, unsigned int ilen,
unsigned char output[32]);
void sha256_start (sha256_context *ctx);
void sha256_finish (sha256_context *ctx, unsigned char output[32]);
void sha256_update (sha256_context *ctx, const unsigned char *input,
unsigned int ilen);
void sha256_process (sha256_context *ctx);

215
sha512.c Normal file
View File

@ -0,0 +1,215 @@
/*
* sha512.c -- Compute SHA-512 hash (for little endian architecture).
*
* This module is written by gniibe, following the API of sha256.c.
*
* Copyright (C) 2014 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Reference:
*
* [1] FIPS PUB 180-4: Secure hash Standard (SHS), March, 2012.
*
*/
#include <string.h>
#include <stdint.h>
#include "sha512.h"
#define SHA512_MASK (SHA512_BLOCK_SIZE - 1)
static void memcpy_output_bswap64 (unsigned char dst[64], const uint64_t *p)
{
int i;
uint64_t q = 0;
for (i = 0; i < 64; i++)
{
if ((i & 7) == 0)
q = __builtin_bswap64 (p[i >> 3]); /* bswap64 is GCC extention */
dst[i] = q >> ((i & 7) * 8);
}
}
#define rotr64(x,n) (((x) >> n) | ((x) << (64 - n)))
#define ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z))))
#define maj(x,y,z) (((x) & (y)) | ((z) & ((x) ^ (y))))
/* round transforms for SHA512 compression functions */
#define vf(n,i) v[(n - i) & 7]
#define hf(i) (p[i & 15] += \
g_1(p[(i + 14) & 15]) + p[(i + 9) & 15] + g_0(p[(i + 1) & 15]))
#define v_cycle0(i) \
p[i] = __builtin_bswap64 (p[i]); \
vf(7,i) += p[i] + k_0[i] \
+ s_1(vf(4,i)) + ch(vf(4,i),vf(5,i),vf(6,i)); \
vf(3,i) += vf(7,i); \
vf(7,i) += s_0(vf(0,i))+ maj(vf(0,i),vf(1,i),vf(2,i))
#define v_cycle(i, j) \
vf(7,i) += hf(i) + k_0[i+j] \
+ s_1(vf(4,i)) + ch(vf(4,i),vf(5,i),vf(6,i)); \
vf(3,i) += vf(7,i); \
vf(7,i) += s_0(vf(0,i))+ maj(vf(0,i),vf(1,i),vf(2,i))
#define s_0(x) (rotr64((x), 28) ^ rotr64((x), 34) ^ rotr64((x), 39))
#define s_1(x) (rotr64((x), 14) ^ rotr64((x), 18) ^ rotr64((x), 41))
#define g_0(x) (rotr64((x), 1) ^ rotr64((x), 8) ^ ((x) >> 7))
#define g_1(x) (rotr64((x), 19) ^ rotr64((x), 61) ^ ((x) >> 6))
#define k_0 k512
/* Taken from section 4.2.3 of [1]. */
static const uint64_t k512[80] = {
0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc,
0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118,
0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694,
0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4,
0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70,
0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30,
0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8,
0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8,
0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3,
0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b,
0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178,
0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c,
0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817
};
void
sha512_process (sha512_context *ctx)
{
uint32_t i;
uint64_t *p = ctx->wbuf;
uint64_t v[8];
memcpy (v, ctx->state, 8 * sizeof (uint64_t));
v_cycle0 ( 0); v_cycle0 ( 1); v_cycle0 ( 2); v_cycle0 ( 3);
v_cycle0 ( 4); v_cycle0 ( 5); v_cycle0 ( 6); v_cycle0 ( 7);
v_cycle0 ( 8); v_cycle0 ( 9); v_cycle0 (10); v_cycle0 (11);
v_cycle0 (12); v_cycle0 (13); v_cycle0 (14); v_cycle0 (15);
for (i = 16; i < 80; i += 16)
{
v_cycle ( 0, i); v_cycle ( 1, i); v_cycle ( 2, i); v_cycle ( 3, i);
v_cycle ( 4, i); v_cycle ( 5, i); v_cycle ( 6, i); v_cycle ( 7, i);
v_cycle ( 8, i); v_cycle ( 9, i); v_cycle (10, i); v_cycle (11, i);
v_cycle (12, i); v_cycle (13, i); v_cycle (14, i); v_cycle (15, i);
}
ctx->state[0] += v[0];
ctx->state[1] += v[1];
ctx->state[2] += v[2];
ctx->state[3] += v[3];
ctx->state[4] += v[4];
ctx->state[5] += v[5];
ctx->state[6] += v[6];
ctx->state[7] += v[7];
}
void
sha512_update (sha512_context *ctx, const unsigned char *input,
unsigned int ilen)
{
uint32_t left = (ctx->total[0] & SHA512_MASK);
uint32_t fill = SHA512_BLOCK_SIZE - left;
ctx->total[0] += ilen;
if (ctx->total[0] < ilen)
ctx->total[1]++;
while (ilen >= fill)
{
memcpy (((unsigned char*)ctx->wbuf) + left, input, fill);
sha512_process (ctx);
input += fill;
ilen -= fill;
left = 0;
fill = SHA512_BLOCK_SIZE;
}
memcpy (((unsigned char*)ctx->wbuf) + left, input, ilen);
}
void
sha512_finish (sha512_context *ctx, unsigned char output[64])
{
uint32_t last = (ctx->total[0] & SHA512_MASK);
ctx->wbuf[last >> 3] = __builtin_bswap64 (ctx->wbuf[last >> 3]);
ctx->wbuf[last >> 3] &= 0xffffffffffffff80LL << (8 * (~last & 7));
ctx->wbuf[last >> 3] |= 0x0000000000000080LL << (8 * (~last & 7));
ctx->wbuf[last >> 3] = __builtin_bswap64 (ctx->wbuf[last >> 3]);
if (last > SHA512_BLOCK_SIZE - 17)
{
if (last < 120)
ctx->wbuf[15] = 0;
sha512_process (ctx);
last = 0;
}
else
last = (last >> 3) + 1;
while (last < 14)
ctx->wbuf[last++] = 0;
ctx->wbuf[14] = __builtin_bswap64 ((ctx->total[0] >> 61) | (ctx->total[1] << 3));
ctx->wbuf[15] = __builtin_bswap64 (ctx->total[0] << 3);
sha512_process (ctx);
memcpy_output_bswap64 (output, ctx->state);
memset (ctx, 0, sizeof (sha512_context));
}
/* Taken from section 5.3.5 of [1]. */
static const uint64_t initial_state[8] = {
0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179
};
void
sha512_start (sha512_context *ctx)
{
ctx->total[0] = ctx->total[1] = 0;
memcpy (ctx->state, initial_state, 8 * sizeof(uint64_t));
}
void
sha512 (const unsigned char *input, unsigned int ilen,
unsigned char output[64])
{
sha512_context ctx;
sha512_start (&ctx);
sha512_update (&ctx, input, ilen);
sha512_finish (&ctx, output);
}

17
sha512.h Normal file
View File

@ -0,0 +1,17 @@
#define SHA512_DIGEST_SIZE 64
#define SHA512_BLOCK_SIZE 128
typedef struct
{
uint64_t total[2];
uint64_t state[8];
uint64_t wbuf[16];
} sha512_context;
void sha512 (const unsigned char *input, unsigned int ilen,
unsigned char output[64]);
void sha512_start (sha512_context *ctx);
void sha512_finish (sha512_context *ctx, unsigned char output[64]);
void sha512_update (sha512_context *ctx, const unsigned char *input,
unsigned int ilen);
void sha512_process (sha512_context *ctx);

202
shake256.c Normal file
View File

@ -0,0 +1,202 @@
/*
* shake256.c -- Compute SHAKE hash.
*
* Copyright (C) 2021 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
*
* Gnuk is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Gnuk is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Reference:
*
* [1] FIPS PUB 202: SHA-3 Standard:
* Permutation-Based Hash and Extendable-Output Functions,
* August 2015.
*/
#define SHAKE_BITS 256
#define SHAKE_INDEX_MAX (200 - (SHAKE_BITS >> 2))
/*
* b=1600
* nr = 24 iterations
* l = 6
*
* state: 25x64-bit == 5 x 5 x 64
* row column bit
*/
#include <stdint.h>
#include <string.h>
#include "shake256.h"
/* Round constants in iota step. */
static const uint64_t rc[24] = {
UINT64_C (0x0000000000000001), UINT64_C (0x0000000000008082),
UINT64_C (0x800000000000808a), UINT64_C (0x8000000080008000),
UINT64_C (0x000000000000808b), UINT64_C (0x0000000080000001),
UINT64_C (0x8000000080008081), UINT64_C (0x8000000000008009),
UINT64_C (0x000000000000008a), UINT64_C (0x0000000000000088),
UINT64_C (0x0000000080008009), UINT64_C (0x000000008000000a),
UINT64_C (0x000000008000808b), UINT64_C (0x800000000000008b),
UINT64_C (0x8000000000008089), UINT64_C (0x8000000000008003),
UINT64_C (0x8000000000008002), UINT64_C (0x8000000000000080),
UINT64_C (0x000000000000800a), UINT64_C (0x800000008000000a),
UINT64_C (0x8000000080008081), UINT64_C (0x8000000000008080),
UINT64_C (0x0000000080000001), UINT64_C (0x8000000080008008),
};
static const uint8_t rho[25-1] = {
1, 62, 28, 27,
36, 44, 6, 55, 20,
3, 10, 43, 25, 39,
41, 45, 15, 21, 8,
18, 2, 61, 56, 14
};
static const uint8_t pi[24] = {
10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4,
15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1,
};
static uint64_t
rotl64 (uint64_t x, uint64_t y)
{
return (x << y) | (x >> (64U - y));
}
static void
absorb (uint64_t *dst, uint8_t index, uint8_t v)
{
dst[index >> 3] ^= ((uint64_t)v) << ((index & 7) << 3);
}
static uint8_t
squeeze (const uint64_t *src, uint8_t index)
{
return src[index >> 3] >> ((index & 7) << 3);
}
/* The permutation function. */
static void
keccak_f1600 (uint64_t s[25])
{
uint64_t lane[5];
int i, j, round;
for (round = 0; round < 24; round++)
{
uint64_t t;
/* STEP: theta */
for (i = 0; i < 5; i++)
lane[i] = s[i] ^ s[i + 5] ^ s[i + 10] ^ s[i + 15] ^ s[i + 20];
for (i = 0; i < 5; i++)
{
t = lane[(i + 4) % 5] ^ rotl64 (lane[(i + 1) % 5], 1);
for (j = 0; j < 25; j += 5)
s[j + i] ^= t;
}
/* STEP: rho */
for (i = 1; i < 25; i++)
s[i] = rotl64(s[i], rho[i-1]);
/* STEP: pi */
t = s[1];
for (i = 0; i < 25-1; i++)
{
uint64_t tmp;
j = pi[i];
tmp = s[j];
s[j] = t;
t = tmp;
}
/* STEP: chi */
for (i = 0; i < 25; i += 5)
{
for (j = 0; j < 5; j++)
lane[j] = s[i + j];
for (j = 0; j < 5; j++)
s[i + j] ^= (~lane[(j + 1) % 5]) & lane[(j + 2) % 5];
}
/* STEP: iota */
s[0] ^= rc[round];
}
}
void
shake256_start (struct shake_context *shake)
{
memset (shake, 0, sizeof (shake_context));
}
void
shake256_update (struct shake_context *shake,
const unsigned char *src, unsigned int size)
{
if (size == 0)
return;
while (1)
{
absorb (shake->state, shake->index, *src++);
if (++shake->index == SHAKE_INDEX_MAX)
{
keccak_f1600 (shake->state);
shake->index = 0;
}
if (--size == 0)
break;
}
}
void
shake256_finish (struct shake_context *shake,
unsigned char *dst, unsigned int size)
{
if (size == 0)
return;
/*
* SHAKE is defined appending 11 at the end to RawSHAKE,
* RawSHAKE is defined adding 11 at the end to KECCAK,
* and KECCACK uses pad10*1 at the end.
* This means adding 111110*1 at the end.
*/
absorb (shake->state, shake->index, 0x1F);
absorb (shake->state, SHAKE_INDEX_MAX - 1, 0x80);
keccak_f1600 (shake->state);
shake->index = 0;
while (1)
{
*dst++ = squeeze (shake->state, shake->index);
if (--size == 0)
break;
if (++shake->index == SHAKE_INDEX_MAX)
{
keccak_f1600 (shake->state);
shake->index = 0;
}
}
}

13
shake256.h Normal file
View File

@ -0,0 +1,13 @@
#include <stdint.h>
struct shake_context {
uint64_t state[25];
uint32_t index;
};
typedef struct shake_context shake_context;
void shake256_start (struct shake_context *shake);
void shake256_update (struct shake_context *shake,
const unsigned char *src, unsigned int size);
void shake256_finish (struct shake_context *shake,
unsigned char *dst, unsigned int size);

14
status-code.h Normal file
View File

@ -0,0 +1,14 @@
#define GPG_APPLICATION_TERMINATED() set_res_sw (0x62, 0x85)
#define GPG_MEMORY_FAILURE() set_res_sw (0x65, 0x81)
#define GPG_WRONG_LENGTH() set_res_sw (0x67, 0x00)
#define GPG_SECURITY_FAILURE() set_res_sw (0x69, 0x82)
#define GPG_SECURITY_AUTH_BLOCKED() set_res_sw (0x69, 0x83)
#define GPG_CONDITION_NOT_SATISFIED() set_res_sw (0x69, 0x85)
#define GPG_COMMAND_NOT_ALLOWED() set_res_sw (0x69, 0x86)
#define GPG_FUNCTION_NOT_SUPPORTED() set_res_sw (0x6a, 0x81)
#define GPG_NO_FILE() set_res_sw (0x6a, 0x82)
#define GPG_NO_RECORD() set_res_sw (0x6a, 0x88)
#define GPG_BAD_P1_P2() set_res_sw (0x6b, 0x00)
#define GPG_NO_INS() set_res_sw (0x6d, 0x00)
#define GPG_ERROR() set_res_sw (0x6f, 0x00)
#define GPG_SUCCESS() set_res_sw (0x90, 0x00)

0
sys.h Normal file
View File