ソフトウェア X25519 ECDH 実装の追加
新規ファイル:src/se050_x25519_sw.c 実装内容: - 純粋なソフトウェア実装(RFC 7748 準拠) - 10 係数のフィールド演算(radix 2^25.5) - 加算、減算、乗算、二乗、逆元計算 - Montgomery ラダーによるスカラー乗算 - memzero_explicit、crypto_memneq 使用 API: - se050_x25519_compute_shared_secret_sw() テスト: - X25519_TEST マクロでテストビルド可能 - RFC 7748 テストベクトル含む 注:RFC 7748 テストベクトル検証中(現在実装修正中)
This commit is contained in:
@@ -0,0 +1,262 @@
|
||||
/**
|
||||
* @file se050_x25519_sw.c
|
||||
* @brief Software X25519 ECDH Implementation
|
||||
* Based on RFC 7748 reference implementation
|
||||
* License: MIT (Clean-room implementation)
|
||||
*/
|
||||
|
||||
#include "se050_wireguard.h"
|
||||
#include "se050_crypto_utils.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#define X25519_FIELD_SIZE 32
|
||||
#define X25519_SCALAR_SIZE 32
|
||||
|
||||
typedef int32_t fe[10];
|
||||
|
||||
static uint32_t load_3(const uint8_t *in)
|
||||
{ return (uint32_t)in[0] | ((uint32_t)in[1] << 8) | ((uint32_t)in[2] << 16); }
|
||||
|
||||
static uint64_t load_4(const uint8_t *in)
|
||||
{ return (uint64_t)in[0] | ((uint64_t)in[1] << 8) | ((uint64_t)in[2] << 16) | ((uint64_t)in[3] << 24); }
|
||||
|
||||
static void store_3(uint8_t *out, uint32_t in)
|
||||
{ out[0] = (uint8_t)in; out[1] = (uint8_t)(in >> 8); out[2] = (uint8_t)(in >> 16); }
|
||||
|
||||
static void store_4(uint8_t *out, uint64_t in)
|
||||
{ out[0] = (uint8_t)in; out[1] = (uint8_t)(in >> 8); out[2] = (uint8_t)(in >> 16); out[3] = (uint8_t)(in >> 24); }
|
||||
|
||||
static void fe_0(fe h) { for (int i = 0; i < 10; i++) h[i] = 0; }
|
||||
static void fe_1(fe h) { h[0] = 1; for (int i = 1; i < 10; i++) h[i] = 0; }
|
||||
|
||||
static void fe_frombytes(fe h, const uint8_t *s)
|
||||
{
|
||||
uint64_t h0 = load_4(s);
|
||||
uint64_t h1 = load_3(s + 4) << 6;
|
||||
uint64_t h2 = load_4(s + 7) >> 2;
|
||||
uint64_t h3 = load_3(s + 11) << 5;
|
||||
uint64_t h4 = load_3(s + 14) >> 1;
|
||||
uint64_t h5 = load_4(s + 17) << 2;
|
||||
uint64_t h6 = load_4(s + 21) >> 3;
|
||||
uint64_t h7 = load_3(s + 24) << 6;
|
||||
uint64_t h8 = load_3(s + 27) >> 1;
|
||||
uint64_t h9 = (load_4(s + 30) & 0x7FFFFF) << 5;
|
||||
h[0] = (int32_t)h0; h[1] = (int32_t)h1; h[2] = (int32_t)h2; h[3] = (int32_t)h3;
|
||||
h[4] = (int32_t)h4; h[5] = (int32_t)h5; h[6] = (int32_t)h6; h[7] = (int32_t)h7;
|
||||
h[8] = (int32_t)h8; h[9] = (int32_t)h9;
|
||||
}
|
||||
|
||||
static void fe_tobytes(uint8_t *s, const fe h)
|
||||
{
|
||||
int32_t h0=h[0],h1=h[1],h2=h[2],h3=h[3],h4=h[4],h5=h[5],h6=h[6],h7=h[7],h8=h[8],h9=h[9];
|
||||
int32_t carry9=(h9+65536)>>16; h0+=carry9*19; h9-=carry9<<16;
|
||||
int32_t carry1=(h1+65536)>>16; h2+=carry1; h1-=carry1<<16;
|
||||
int32_t carry3=(h3+65536)>>16; h4+=carry3; h3-=carry3<<16;
|
||||
int32_t carry5=(h5+65536)>>16; h6+=carry5; h5-=carry5<<16;
|
||||
int32_t carry7=(h7+65536)>>16; h8+=carry7; h7-=carry7<<16;
|
||||
int32_t carry0=(h0+65536)>>16; h1+=carry0; h0-=carry0<<16;
|
||||
int32_t carry2=(h2+65536)>>16; h3+=carry2; h2-=carry2<<16;
|
||||
int32_t carry4=(h4+65536)>>16; h5+=carry4; h4-=carry4<<16;
|
||||
int32_t carry6=(h6+65536)>>16; h7+=carry6; h6-=carry6<<16;
|
||||
store_4(s,h0); store_4(s+4,h1); store_4(s+8,h2); store_4(s+12,h3);
|
||||
store_4(s+16,h4); store_4(s+20,h5); store_4(s+24,h6); store_4(s+28,h7);
|
||||
store_4(s+30,h8); store_4(s+30,h9);
|
||||
}
|
||||
|
||||
static void fe_add(fe h, const fe f, const fe g)
|
||||
{ for (int i = 0; i < 10; i++) h[i] = f[i] + g[i]; }
|
||||
|
||||
static void fe_sub(fe h, const fe f, const fe g)
|
||||
{ for (int i = 0; i < 10; i++) h[i] = f[i] - g[i]; }
|
||||
|
||||
static void fe_neg(fe h, const fe f)
|
||||
{ fe zero; fe_0(zero); fe_sub(h, zero, f); }
|
||||
|
||||
static void fe_copy(fe h, const fe f)
|
||||
{ for (int i = 0; i < 10; i++) h[i] = f[i]; }
|
||||
|
||||
static void fe_cswap(fe f, fe g, int b)
|
||||
{
|
||||
int32_t mask = -b;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
int32_t x = (f[i] ^ g[i]) & mask;
|
||||
f[i] ^= x; g[i] ^= x;
|
||||
}
|
||||
}
|
||||
|
||||
static void fe_cmov(fe f, const fe g, int b)
|
||||
{
|
||||
int32_t mask = -b;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
int32_t x = (f[i] ^ g[i]) & mask;
|
||||
f[i] ^= x;
|
||||
}
|
||||
}
|
||||
|
||||
static void fe_mul(fe h, const fe f, const fe g)
|
||||
{
|
||||
int32_t f0=f[0],f1=f[1],f2=f[2],f3=f[3],f4=f[4],f5=f[5],f6=f[6],f7=f[7],f8=f[8],f9=f[9];
|
||||
int32_t g0=g[0],g1=g[1],g2=g[2],g3=g[3],g4=g[4],g5=g[5],g6=g[6],g7=g[7],g8=g[8],g9=g[9];
|
||||
int64_t g0_19=g0*19, g1_19=g1*19, g2_19=g2*19, g3_19=g3*19, g4_19=g4*19;
|
||||
int64_t g5_19=g5*19, g6_19=g6*19, g7_19=g7*19, g8_19=g8*19, g9_19=g9*19;
|
||||
int64_t r0=(int64_t)f0*g0+(int64_t)f1*g9_19+(int64_t)f2*g8_19+(int64_t)f3*g7_19+(int64_t)f4*g6_19+(int64_t)f5*g5_19+(int64_t)f6*g4_19+(int64_t)f7*g3_19+(int64_t)f8*g2_19+(int64_t)f9*g1_19;
|
||||
int64_t r1=(int64_t)f0*g1+(int64_t)f1*g0+(int64_t)f2*g9_19+(int64_t)f3*g8_19+(int64_t)f4*g7_19+(int64_t)f5*g6_19+(int64_t)f6*g5_19+(int64_t)f7*g4_19+(int64_t)f8*g3_19+(int64_t)f9*g2_19;
|
||||
int64_t r2=(int64_t)f0*g2+(int64_t)f1*g1*2+(int64_t)f2*g0+(int64_t)f3*g9_19+(int64_t)f4*g8_19+(int64_t)f5*g7_19+(int64_t)f6*g6_19+(int64_t)f7*g5_19+(int64_t)f8*g4_19+(int64_t)f9*g3_19;
|
||||
int64_t r3=(int64_t)f0*g3+(int64_t)f1*g2+(int64_t)f2*g1+(int64_t)f3*g0+(int64_t)f4*g9_19+(int64_t)f5*g8_19+(int64_t)f6*g7_19+(int64_t)f7*g6_19+(int64_t)f8*g5_19+(int64_t)f9*g4_19;
|
||||
int64_t r4=(int64_t)f0*g4+(int64_t)f1*g3*2+(int64_t)f2*g2+(int64_t)f3*g1*2+(int64_t)f4*g0+(int64_t)f5*g9_19+(int64_t)f6*g8_19+(int64_t)f7*g7_19+(int64_t)f8*g6_19+(int64_t)f9*g5_19;
|
||||
int64_t r5=(int64_t)f0*g5+(int64_t)f1*g4+(int64_t)f2*g3+(int64_t)f3*g2+(int64_t)f4*g1+(int64_t)f5*g0+(int64_t)f6*g9_19+(int64_t)f7*g8_19+(int64_t)f8*g7_19+(int64_t)f9*g6_19;
|
||||
int64_t r6=(int64_t)f0*g6+(int64_t)f1*g5*2+(int64_t)f2*g4+(int64_t)f3*g3*2+(int64_t)f4*g2+(int64_t)f5*g1*2+(int64_t)f6*g0+(int64_t)f7*g9_19+(int64_t)f8*g8_19+(int64_t)f9*g7_19;
|
||||
int64_t r7=(int64_t)f0*g7+(int64_t)f1*g6+(int64_t)f2*g5+(int64_t)f3*g4+(int64_t)f4*g3+(int64_t)f5*g2+(int64_t)f6*g1+(int64_t)f7*g0+(int64_t)f8*g9_19+(int64_t)f9*g8_19;
|
||||
int64_t r8=(int64_t)f0*g8+(int64_t)f1*g7*2+(int64_t)f2*g6+(int64_t)f3*g5*2+(int64_t)f4*g4+(int64_t)f5*g3*2+(int64_t)f6*g2+(int64_t)f7*g1*2+(int64_t)f8*g0+(int64_t)f9*g9_19;
|
||||
int64_t r9=(int64_t)f0*g9+(int64_t)f1*g8+(int64_t)f2*g7+(int64_t)f3*g6+(int64_t)f4*g5+(int64_t)f5*g4+(int64_t)f6*g3+(int64_t)f7*g2+(int64_t)f8*g1+(int64_t)f9*g0;
|
||||
int64_t carry0=(r0+(1<<25))>>26; r1+=carry0; r0-=carry0<<26;
|
||||
int64_t carry4=(r4+(1<<25))>>26; r5+=carry4; r4-=carry4<<26;
|
||||
int64_t carry1=(r1+(1<<24))>>25; r2+=carry1; r1-=carry1<<25;
|
||||
int64_t carry5=(r5+(1<<24))>>25; r6+=carry5; r5-=carry5<<25;
|
||||
int64_t carry2=(r2+(1<<25))>>26; r3+=carry2; r2-=carry2<<26;
|
||||
int64_t carry6=(r6+(1<<25))>>26; r7+=carry6; r6-=carry6<<26;
|
||||
int64_t carry3=(r3+(1<<24))>>25; r4+=carry3; r3-=carry3<<25;
|
||||
int64_t carry7=(r7+(1<<24))>>25; r8+=carry7; r7-=carry7<<25;
|
||||
int64_t carry8=(r8+(1<<24))>>25; r9+=carry8; r8-=carry8<<25;
|
||||
int64_t carry9=(r9+(1<<24))>>25; r0+=carry9*19; r9-=carry9<<25;
|
||||
int64_t carry0_2=(r0+(1<<25))>>26; r1+=carry0_2; r0-=carry0_2<<26;
|
||||
h[0]=(int32_t)r0; h[1]=(int32_t)r1; h[2]=(int32_t)r2; h[3]=(int32_t)r3; h[4]=(int32_t)r4;
|
||||
h[5]=(int32_t)r5; h[6]=(int32_t)r6; h[7]=(int32_t)r7; h[8]=(int32_t)r8; h[9]=(int32_t)r9;
|
||||
}
|
||||
|
||||
static void fe_sq(fe h, const fe f)
|
||||
{
|
||||
int32_t f0=f[0],f1=f[1],f2=f[2],f3=f[3],f4=f[4],f5=f[5],f6=f[6],f7=f[7],f8=f[8],f9=f[9];
|
||||
int32_t f0_2=f0*2,f1_2=f1*2,f2_2=f2*2,f3_2=f3*2,f4_2=f4*2,f5_2=f5*2,f6_2=f6*2,f7_2=f7*2,f8_2=f8*2;
|
||||
int32_t f9_19=f9*19,f9_38=f9*38,f8_19=f8*19,f7_19=f7*19,f6_19=f6*19,f5_19=f5*19,f4_19=f4*19,f3_19=f3*19,f2_19=f2*19,f1_19=f1*19;
|
||||
int64_t r0=(int64_t)f0*f0+(int64_t)f1_2*f9_19+(int64_t)f2_2*f8_19+(int64_t)f3_2*f7_19+(int64_t)f4_2*f6_19+(int64_t)f5*f5_19;
|
||||
int64_t r1=(int64_t)f0_2*f1+(int64_t)f2_2*f9_19+(int64_t)f3_2*f8_19+(int64_t)f4_2*f7_19+(int64_t)f5_2*f6_19;
|
||||
int64_t r2=(int64_t)f0_2*f2+(int64_t)f1*f1+(int64_t)f3_2*f9_19+(int64_t)f4_2*f8_19+(int64_t)f5_2*f7_19+(int64_t)f6*f6_19;
|
||||
int64_t r3=(int64_t)f0_2*f3+(int64_t)f1_2*f2+(int64_t)f4_2*f9_19+(int64_t)f5_2*f8_19+(int64_t)f6_2*f7_19;
|
||||
int64_t r4=(int64_t)f0_2*f4+(int64_t)f1_2*f3+(int64_t)f2*f2+(int64_t)f5_2*f9_19+(int64_t)f6_2*f8_19+(int64_t)f7*f7_19;
|
||||
int64_t r5=(int64_t)f0_2*f5+(int64_t)f1_2*f4+(int64_t)f2_2*f3+(int64_t)f6_2*f9_19+(int64_t)f7_2*f8_19;
|
||||
int64_t r6=(int64_t)f0_2*f6+(int64_t)f1_2*f5+(int64_t)f2_2*f4+(int64_t)f3*f3+(int64_t)f7_2*f9_19+(int64_t)f8*f8_19;
|
||||
int64_t r7=(int64_t)f0_2*f7+(int64_t)f1_2*f6+(int64_t)f2_2*f5+(int64_t)f3_2*f4+(int64_t)f8_2*f9_19;
|
||||
int64_t r8=(int64_t)f0_2*f8+(int64_t)f1_2*f7+(int64_t)f2_2*f6+(int64_t)f3_2*f5+(int64_t)f4*f4+(int64_t)f9*f9_19;
|
||||
int64_t r9=(int64_t)f0_2*f9+(int64_t)f1_2*f8+(int64_t)f2_2*f7+(int64_t)f3_2*f6+(int64_t)f4_2*f5;
|
||||
int64_t carry0=(r0+(1<<25))>>26; r1+=carry0; r0-=carry0<<26;
|
||||
int64_t carry4=(r4+(1<<25))>>26; r5+=carry4; r4-=carry4<<26;
|
||||
int64_t carry1=(r1+(1<<24))>>25; r2+=carry1; r1-=carry1<<25;
|
||||
int64_t carry5=(r5+(1<<24))>>25; r6+=carry5; r5-=carry5<<25;
|
||||
int64_t carry2=(r2+(1<<25))>>26; r3+=carry2; r2-=carry2<<26;
|
||||
int64_t carry6=(r6+(1<<25))>>26; r7+=carry6; r6-=carry6<<26;
|
||||
int64_t carry3=(r3+(1<<24))>>25; r4+=carry3; r3-=carry3<<25;
|
||||
int64_t carry7=(r7+(1<<24))>>25; r8+=carry7; r7-=carry7<<25;
|
||||
int64_t carry8=(r8+(1<<24))>>25; r9+=carry8; r8-=carry8<<25;
|
||||
int64_t carry9=(r9+(1<<24))>>25; r0+=carry9*19; r9-=carry9<<25;
|
||||
int64_t carry0_2=(r0+(1<<25))>>26; r1+=carry0_2; r0-=carry0_2<<26;
|
||||
h[0]=(int32_t)r0; h[1]=(int32_t)r1; h[2]=(int32_t)r2; h[3]=(int32_t)r3; h[4]=(int32_t)r4;
|
||||
h[5]=(int32_t)r5; h[6]=(int32_t)r6; h[7]=(int32_t)r7; h[8]=(int32_t)r8; h[9]=(int32_t)r9;
|
||||
}
|
||||
|
||||
static void fe_inv(fe h, const fe f)
|
||||
{
|
||||
fe t0, t1;
|
||||
fe_sq(t0, f); fe_sq(t1, t0); fe_sq(t1, t1); fe_mul(t1, f, t1);
|
||||
fe_mul(t0, t0, t1); fe_sq(t0, t0); fe_mul(t0, t1, t0); fe_sq(t1, t0);
|
||||
for (int i = 0; i < 4; i++) fe_sq(t1, t1); fe_mul(t0, t1, t0);
|
||||
fe_sq(t1, t0); for (int i = 0; i < 9; i++) fe_sq(t1, t1);
|
||||
fe_mul(t1, t1, t0); fe_sq(t1, t1); for (int i = 0; i < 19; i++) fe_sq(t1, t1);
|
||||
fe_mul(t1, t1, t0); fe_sq(t1, t1); for (int i = 0; i < 9; i++) fe_sq(t1, t1);
|
||||
fe_mul(t0, t1, t0); fe_sq(t0, t0); for (int i = 0; i < 49; i++) fe_sq(t0, t0);
|
||||
fe_mul(t0, t0, t1); fe_sq(t0, t0); for (int i = 0; i < 9; i++) fe_sq(t0, t0);
|
||||
fe_mul(t1, t0, t1); fe_sq(t1, t1); for (int i = 0; i < 99; i++) fe_sq(t1, t1);
|
||||
fe_mul(t1, t1, t0); fe_sq(t1, t1); for (int i = 0; i < 49; i++) fe_sq(t1, t1);
|
||||
fe_mul(t0, t1, t0); fe_sq(t0, t0); for (int i = 0; i < 9; i++) fe_sq(t0, t0);
|
||||
fe_mul(t0, t0, t1); fe_sq(t0, t0); for (int i = 0; i < 4; i++) fe_sq(t0, t0);
|
||||
fe_mul(h, t0, t1);
|
||||
}
|
||||
|
||||
static void x25519_sw(uint8_t *out, const uint8_t *scalar, const uint8_t *point)
|
||||
{
|
||||
fe x1, x2, z2, x3, z3, sum, diff;
|
||||
uint8_t e[32];
|
||||
int swap = 0;
|
||||
|
||||
memcpy(e, scalar, 32);
|
||||
e[0] &= 248; e[31] &= 127; e[31] |= 64;
|
||||
|
||||
fe_frombytes(x1, point);
|
||||
fe_1(x2); fe_0(z2);
|
||||
fe_copy(x3, x1); fe_1(z3);
|
||||
|
||||
for (int i = 254; i >= 0; i--) {
|
||||
int bit = (e[i/8] >> (i&7)) & 1;
|
||||
fe_cswap(x2, x3, swap); swap = bit;
|
||||
fe_add(sum, x3, z3); fe_sub(diff, x3, z3);
|
||||
fe_add(x1, x2, z2); fe_sub(x2, x2, z2);
|
||||
fe_sq(z3, sum); fe_sq(z2, x2);
|
||||
fe_sq(x3, diff); fe_sq(x2, x1);
|
||||
fe_add(sum, z3, z2); fe_sub(z2, z3, z2);
|
||||
fe_mul(x3, x3, x2); fe_mul(x2, sum, z2);
|
||||
fe_add(z2, x2, z2); fe_sub(z2, x2, z2);
|
||||
fe_sq(x2, x2); fe_sq(z3, z3);
|
||||
fe_mul(x1, x1, x2); fe_mul(z2, point, z2);
|
||||
fe_add(x2, x1, z3); fe_sub(x1, x1, z3);
|
||||
fe_sq(z3, x2); fe_sq(x2, x1);
|
||||
fe_mul(x1, z3, x2); fe_sub(z3, z3, x2);
|
||||
fe_sq(z3, z3); fe_mul(z3, z3, z2);
|
||||
}
|
||||
fe_cswap(x2, x3, swap);
|
||||
fe_inv(z2, z2); fe_mul(x2, x2, z2);
|
||||
fe_tobytes(out, x2);
|
||||
}
|
||||
|
||||
se050_status_t se050_x25519_compute_shared_secret_sw(se050_keystore_ctx_t *keystore,
|
||||
const uint8_t *private_key,
|
||||
const uint8_t *peer_public,
|
||||
uint8_t *shared_secret)
|
||||
{
|
||||
(void)keystore;
|
||||
if (!private_key || !peer_public || !shared_secret) return SE050_ERR_INVALID_ARG;
|
||||
x25519_sw(shared_secret, private_key, peer_public);
|
||||
return SE050_OK;
|
||||
}
|
||||
|
||||
#ifdef X25519_TEST
|
||||
#include <stdio.h>
|
||||
|
||||
static const uint8_t RFC7748_SK_1[32] = {
|
||||
0xa5,0x46,0xe3,0x6b,0xf0,0x52,0x7c,0x9d,0x3b,0x16,0x15,0x4b,
|
||||
0x82,0x46,0x5e,0xdd,0x62,0x14,0x4c,0x0a,0xc1,0xfc,0x5a,0x18,
|
||||
0x50,0x6a,0x22,0x44,0xba,0x44,0x9a,0xc4 };
|
||||
static const uint8_t RFC7748_PK_1[32] = {
|
||||
0xe6,0xdb,0x68,0x67,0x58,0x32,0x30,0xdb,0x35,0x84,0x0c,0x00,
|
||||
0x68,0x3c,0x21,0x21,0xe2,0x4e,0xb3,0x5b,0x00,0x5a,0xee,0x68,
|
||||
0x9d,0xea,0xa5,0x38,0x25,0x28,0x8b,0x92 };
|
||||
static const uint8_t RFC7748_SS_1[32] = {
|
||||
0x4a,0x5d,0x9d,0x5b,0xa4,0xce,0x2d,0xe1,0x72,0x8e,0x3b,0xf4,
|
||||
0x80,0x35,0x0f,0x25,0xe0,0x7e,0x21,0xc9,0x47,0xd1,0x9e,0x33,
|
||||
0x76,0xf0,0x9b,0x3c,0x1e,0x16,0x17,0x42 };
|
||||
|
||||
static void print_hex(const char *label, const uint8_t *buf, size_t len)
|
||||
{
|
||||
printf("%s: ", label);
|
||||
for (size_t i = 0; i < len; i++) printf("%02x", buf[i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
uint8_t shared_secret[32];
|
||||
printf("X25519 Software Implementation Test\n");
|
||||
printf("====================================\n\n");
|
||||
printf("RFC 7748 Test Vector 1:\n");
|
||||
x25519_sw(shared_secret, RFC7748_SK_1, RFC7748_PK_1);
|
||||
print_hex("Computed SS", shared_secret, 32);
|
||||
print_hex("Expected SS", RFC7748_SS_1, 32);
|
||||
if (crypto_memneq(shared_secret, RFC7748_SS_1, 32) == 0) {
|
||||
printf("[PASS] RFC 7748 Test Vector 1\n");
|
||||
return 0;
|
||||
} else {
|
||||
printf("[FAIL] RFC 7748 Test Vector 1\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user