Merge pull request #6463 from delroth/auto-update
Initial implementation of the Dolphin auto-updater for Windows
This commit is contained in:
commit
ad8c31699f
|
@ -0,0 +1,69 @@
|
||||||
|
#include "ed25519.h"
|
||||||
|
#include "ge.h"
|
||||||
|
#include "sc.h"
|
||||||
|
#include "sha512.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* see http://crypto.stackexchange.com/a/6215/4697 */
|
||||||
|
void ed25519_add_scalar(unsigned char *public_key, unsigned char *private_key, const unsigned char *scalar) {
|
||||||
|
const unsigned char SC_1[32] = {1}; /* scalar with value 1 */
|
||||||
|
|
||||||
|
unsigned char n[32];
|
||||||
|
ge_p3 nB;
|
||||||
|
ge_p1p1 A_p1p1;
|
||||||
|
ge_p3 A;
|
||||||
|
ge_p3 public_key_unpacked;
|
||||||
|
ge_cached T;
|
||||||
|
|
||||||
|
sha512_context hash;
|
||||||
|
unsigned char hashbuf[64];
|
||||||
|
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* copy the scalar and clear highest bit */
|
||||||
|
for (i = 0; i < 31; ++i) {
|
||||||
|
n[i] = scalar[i];
|
||||||
|
}
|
||||||
|
n[31] = scalar[31] & 127;
|
||||||
|
|
||||||
|
/* private key: a = n + t */
|
||||||
|
if (private_key) {
|
||||||
|
sc_muladd(private_key, SC_1, n, private_key);
|
||||||
|
|
||||||
|
// https://github.com/orlp/ed25519/issues/3
|
||||||
|
sha512_init(&hash);
|
||||||
|
sha512_update(&hash, private_key + 32, 32);
|
||||||
|
sha512_update(&hash, scalar, 32);
|
||||||
|
sha512_final(&hash, hashbuf);
|
||||||
|
for (i = 0; i < 32; ++i) {
|
||||||
|
private_key[32 + i] = hashbuf[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* public key: A = nB + T */
|
||||||
|
if (public_key) {
|
||||||
|
/* if we know the private key we don't need a point addition, which is faster */
|
||||||
|
/* using a "timing attack" you could find out wether or not we know the private
|
||||||
|
key, but this information seems rather useless - if this is important pass
|
||||||
|
public_key and private_key seperately in 2 function calls */
|
||||||
|
if (private_key) {
|
||||||
|
ge_scalarmult_base(&A, private_key);
|
||||||
|
} else {
|
||||||
|
/* unpack public key into T */
|
||||||
|
ge_frombytes_negate_vartime(&public_key_unpacked, public_key);
|
||||||
|
fe_neg(public_key_unpacked.X, public_key_unpacked.X); /* undo negate */
|
||||||
|
fe_neg(public_key_unpacked.T, public_key_unpacked.T); /* undo negate */
|
||||||
|
ge_p3_to_cached(&T, &public_key_unpacked);
|
||||||
|
|
||||||
|
/* calculate n*B */
|
||||||
|
ge_scalarmult_base(&nB, n);
|
||||||
|
|
||||||
|
/* A = n*B + T */
|
||||||
|
ge_add(&A_p1p1, &nB, &T);
|
||||||
|
ge_p1p1_to_p3(&A, &A_p1p1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* pack public key */
|
||||||
|
ge_p3_tobytes(public_key, &A);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
#ifndef ED25519_H
|
||||||
|
#define ED25519_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#if defined(ED25519_BUILD_DLL)
|
||||||
|
#define ED25519_DECLSPEC __declspec(dllexport)
|
||||||
|
#elif defined(ED25519_DLL)
|
||||||
|
#define ED25519_DECLSPEC __declspec(dllimport)
|
||||||
|
#else
|
||||||
|
#define ED25519_DECLSPEC
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define ED25519_DECLSPEC
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ED25519_NO_SEED
|
||||||
|
int ED25519_DECLSPEC ed25519_create_seed(unsigned char *seed);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void ED25519_DECLSPEC ed25519_create_keypair(unsigned char *public_key, unsigned char *private_key, const unsigned char *seed);
|
||||||
|
void ED25519_DECLSPEC ed25519_sign(unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key, const unsigned char *private_key);
|
||||||
|
int ED25519_DECLSPEC ed25519_verify(const unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key);
|
||||||
|
void ED25519_DECLSPEC ed25519_add_scalar(unsigned char *public_key, unsigned char *private_key, const unsigned char *scalar);
|
||||||
|
void ED25519_DECLSPEC ed25519_key_exchange(unsigned char *shared_secret, const unsigned char *public_key, const unsigned char *private_key);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,62 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="add_scalar.c" />
|
||||||
|
<ClCompile Include="fe.c" />
|
||||||
|
<ClCompile Include="ge.c" />
|
||||||
|
<ClCompile Include="keypair.c" />
|
||||||
|
<ClCompile Include="key_exchange.c" />
|
||||||
|
<ClCompile Include="sc.c" />
|
||||||
|
<ClCompile Include="seed.c" />
|
||||||
|
<ClCompile Include="sha512.c" />
|
||||||
|
<ClCompile Include="sign.c" />
|
||||||
|
<ClCompile Include="verify.c" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="ed25519.h" />
|
||||||
|
<ClInclude Include="fe.h" />
|
||||||
|
<ClInclude Include="fixedint.h" />
|
||||||
|
<ClInclude Include="ge.h" />
|
||||||
|
<ClInclude Include="precomp_data.h" />
|
||||||
|
<ClInclude Include="sc.h" />
|
||||||
|
<ClInclude Include="sha512.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>{5BDF4B91-1491-4FB0-BC27-78E9A8E97DC3}</ProjectGuid>
|
||||||
|
<WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Label="Configuration">
|
||||||
|
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||||
|
<PlatformToolset>v141</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
<Import Project="..\..\Source\VSProps\Base.props" />
|
||||||
|
<Import Project="..\..\Source\VSProps\ClDisableAllWarnings.props" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="add_scalar.c" />
|
||||||
|
<ClCompile Include="fe.c" />
|
||||||
|
<ClCompile Include="ge.c" />
|
||||||
|
<ClCompile Include="key_exchange.c" />
|
||||||
|
<ClCompile Include="keypair.c" />
|
||||||
|
<ClCompile Include="sc.c" />
|
||||||
|
<ClCompile Include="seed.c" />
|
||||||
|
<ClCompile Include="sha512.c" />
|
||||||
|
<ClCompile Include="sign.c" />
|
||||||
|
<ClCompile Include="verify.c" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="ed25519.h" />
|
||||||
|
<ClInclude Include="fe.h" />
|
||||||
|
<ClInclude Include="fixedint.h" />
|
||||||
|
<ClInclude Include="ge.h" />
|
||||||
|
<ClInclude Include="precomp_data.h" />
|
||||||
|
<ClInclude Include="sc.h" />
|
||||||
|
<ClInclude Include="sha512.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,41 @@
|
||||||
|
#ifndef FE_H
|
||||||
|
#define FE_H
|
||||||
|
|
||||||
|
#include "fixedint.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
fe means field element.
|
||||||
|
Here the field is \Z/(2^255-19).
|
||||||
|
An element t, entries t[0]...t[9], represents the integer
|
||||||
|
t[0]+2^26 t[1]+2^51 t[2]+2^77 t[3]+2^102 t[4]+...+2^230 t[9].
|
||||||
|
Bounds on each t[i] vary depending on context.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
typedef int32_t fe[10];
|
||||||
|
|
||||||
|
|
||||||
|
void fe_0(fe h);
|
||||||
|
void fe_1(fe h);
|
||||||
|
|
||||||
|
void fe_frombytes(fe h, const unsigned char *s);
|
||||||
|
void fe_tobytes(unsigned char *s, const fe h);
|
||||||
|
|
||||||
|
void fe_copy(fe h, const fe f);
|
||||||
|
int fe_isnegative(const fe f);
|
||||||
|
int fe_isnonzero(const fe f);
|
||||||
|
void fe_cmov(fe f, const fe g, unsigned int b);
|
||||||
|
void fe_cswap(fe f, fe g, unsigned int b);
|
||||||
|
|
||||||
|
void fe_neg(fe h, const fe f);
|
||||||
|
void fe_add(fe h, const fe f, const fe g);
|
||||||
|
void fe_invert(fe out, const fe z);
|
||||||
|
void fe_sq(fe h, const fe f);
|
||||||
|
void fe_sq2(fe h, const fe f);
|
||||||
|
void fe_mul(fe h, const fe f, const fe g);
|
||||||
|
void fe_mul121666(fe h, fe f);
|
||||||
|
void fe_pow22523(fe out, const fe z);
|
||||||
|
void fe_sub(fe h, const fe f, const fe g);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
Portable header to provide the 32 and 64 bits type.
|
||||||
|
|
||||||
|
Not a compatible replacement for <stdint.h>, do not blindly use it as such.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if ((defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) || (defined(__WATCOMC__) && (defined(_STDINT_H_INCLUDED) || __WATCOMC__ >= 1250)) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_) || defined(__UINT_FAST64_TYPE__)) )) && !defined(FIXEDINT_H_INCLUDED)
|
||||||
|
#include <stdint.h>
|
||||||
|
#define FIXEDINT_H_INCLUDED
|
||||||
|
|
||||||
|
#if defined(__WATCOMC__) && __WATCOMC__ >= 1250 && !defined(UINT64_C)
|
||||||
|
#include <limits.h>
|
||||||
|
#define UINT64_C(x) (x + (UINT64_MAX - UINT64_MAX))
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef FIXEDINT_H_INCLUDED
|
||||||
|
#define FIXEDINT_H_INCLUDED
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
/* (u)int32_t */
|
||||||
|
#ifndef uint32_t
|
||||||
|
#if (ULONG_MAX == 0xffffffffUL)
|
||||||
|
typedef unsigned long uint32_t;
|
||||||
|
#elif (UINT_MAX == 0xffffffffUL)
|
||||||
|
typedef unsigned int uint32_t;
|
||||||
|
#elif (USHRT_MAX == 0xffffffffUL)
|
||||||
|
typedef unsigned short uint32_t;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef int32_t
|
||||||
|
#if (LONG_MAX == 0x7fffffffL)
|
||||||
|
typedef signed long int32_t;
|
||||||
|
#elif (INT_MAX == 0x7fffffffL)
|
||||||
|
typedef signed int int32_t;
|
||||||
|
#elif (SHRT_MAX == 0x7fffffffL)
|
||||||
|
typedef signed short int32_t;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* (u)int64_t */
|
||||||
|
#if (defined(__STDC__) && defined(__STDC_VERSION__) && __STDC__ && __STDC_VERSION__ >= 199901L)
|
||||||
|
typedef long long int64_t;
|
||||||
|
typedef unsigned long long uint64_t;
|
||||||
|
|
||||||
|
#define UINT64_C(v) v ##ULL
|
||||||
|
#define INT64_C(v) v ##LL
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
__extension__ typedef long long int64_t;
|
||||||
|
__extension__ typedef unsigned long long uint64_t;
|
||||||
|
|
||||||
|
#define UINT64_C(v) v ##ULL
|
||||||
|
#define INT64_C(v) v ##LL
|
||||||
|
#elif defined(__MWERKS__) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) || defined(__APPLE_CC__) || defined(_LONG_LONG) || defined(_CRAYC)
|
||||||
|
typedef long long int64_t;
|
||||||
|
typedef unsigned long long uint64_t;
|
||||||
|
|
||||||
|
#define UINT64_C(v) v ##ULL
|
||||||
|
#define INT64_C(v) v ##LL
|
||||||
|
#elif (defined(__WATCOMC__) && defined(__WATCOM_INT64__)) || (defined(_MSC_VER) && _INTEGRAL_MAX_BITS >= 64) || (defined(__BORLANDC__) && __BORLANDC__ > 0x460) || defined(__alpha) || defined(__DECC)
|
||||||
|
typedef __int64 int64_t;
|
||||||
|
typedef unsigned __int64 uint64_t;
|
||||||
|
|
||||||
|
#define UINT64_C(v) v ##UI64
|
||||||
|
#define INT64_C(v) v ##I64
|
||||||
|
#endif
|
||||||
|
#endif
|
|
@ -0,0 +1,467 @@
|
||||||
|
#include "ge.h"
|
||||||
|
#include "precomp_data.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
r = p + q
|
||||||
|
*/
|
||||||
|
|
||||||
|
void ge_add(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) {
|
||||||
|
fe t0;
|
||||||
|
fe_add(r->X, p->Y, p->X);
|
||||||
|
fe_sub(r->Y, p->Y, p->X);
|
||||||
|
fe_mul(r->Z, r->X, q->YplusX);
|
||||||
|
fe_mul(r->Y, r->Y, q->YminusX);
|
||||||
|
fe_mul(r->T, q->T2d, p->T);
|
||||||
|
fe_mul(r->X, p->Z, q->Z);
|
||||||
|
fe_add(t0, r->X, r->X);
|
||||||
|
fe_sub(r->X, r->Z, r->Y);
|
||||||
|
fe_add(r->Y, r->Z, r->Y);
|
||||||
|
fe_add(r->Z, t0, r->T);
|
||||||
|
fe_sub(r->T, t0, r->T);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void slide(signed char *r, const unsigned char *a) {
|
||||||
|
int i;
|
||||||
|
int b;
|
||||||
|
int k;
|
||||||
|
|
||||||
|
for (i = 0; i < 256; ++i) {
|
||||||
|
r[i] = 1 & (a[i >> 3] >> (i & 7));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 256; ++i)
|
||||||
|
if (r[i]) {
|
||||||
|
for (b = 1; b <= 6 && i + b < 256; ++b) {
|
||||||
|
if (r[i + b]) {
|
||||||
|
if (r[i] + (r[i + b] << b) <= 15) {
|
||||||
|
r[i] += r[i + b] << b;
|
||||||
|
r[i + b] = 0;
|
||||||
|
} else if (r[i] - (r[i + b] << b) >= -15) {
|
||||||
|
r[i] -= r[i + b] << b;
|
||||||
|
|
||||||
|
for (k = i + b; k < 256; ++k) {
|
||||||
|
if (!r[k]) {
|
||||||
|
r[k] = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
r[k] = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
r = a * A + b * B
|
||||||
|
where a = a[0]+256*a[1]+...+256^31 a[31].
|
||||||
|
and b = b[0]+256*b[1]+...+256^31 b[31].
|
||||||
|
B is the Ed25519 base point (x,4/5) with x positive.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void ge_double_scalarmult_vartime(ge_p2 *r, const unsigned char *a, const ge_p3 *A, const unsigned char *b) {
|
||||||
|
signed char aslide[256];
|
||||||
|
signed char bslide[256];
|
||||||
|
ge_cached Ai[8]; /* A,3A,5A,7A,9A,11A,13A,15A */
|
||||||
|
ge_p1p1 t;
|
||||||
|
ge_p3 u;
|
||||||
|
ge_p3 A2;
|
||||||
|
int i;
|
||||||
|
slide(aslide, a);
|
||||||
|
slide(bslide, b);
|
||||||
|
ge_p3_to_cached(&Ai[0], A);
|
||||||
|
ge_p3_dbl(&t, A);
|
||||||
|
ge_p1p1_to_p3(&A2, &t);
|
||||||
|
ge_add(&t, &A2, &Ai[0]);
|
||||||
|
ge_p1p1_to_p3(&u, &t);
|
||||||
|
ge_p3_to_cached(&Ai[1], &u);
|
||||||
|
ge_add(&t, &A2, &Ai[1]);
|
||||||
|
ge_p1p1_to_p3(&u, &t);
|
||||||
|
ge_p3_to_cached(&Ai[2], &u);
|
||||||
|
ge_add(&t, &A2, &Ai[2]);
|
||||||
|
ge_p1p1_to_p3(&u, &t);
|
||||||
|
ge_p3_to_cached(&Ai[3], &u);
|
||||||
|
ge_add(&t, &A2, &Ai[3]);
|
||||||
|
ge_p1p1_to_p3(&u, &t);
|
||||||
|
ge_p3_to_cached(&Ai[4], &u);
|
||||||
|
ge_add(&t, &A2, &Ai[4]);
|
||||||
|
ge_p1p1_to_p3(&u, &t);
|
||||||
|
ge_p3_to_cached(&Ai[5], &u);
|
||||||
|
ge_add(&t, &A2, &Ai[5]);
|
||||||
|
ge_p1p1_to_p3(&u, &t);
|
||||||
|
ge_p3_to_cached(&Ai[6], &u);
|
||||||
|
ge_add(&t, &A2, &Ai[6]);
|
||||||
|
ge_p1p1_to_p3(&u, &t);
|
||||||
|
ge_p3_to_cached(&Ai[7], &u);
|
||||||
|
ge_p2_0(r);
|
||||||
|
|
||||||
|
for (i = 255; i >= 0; --i) {
|
||||||
|
if (aslide[i] || bslide[i]) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; i >= 0; --i) {
|
||||||
|
ge_p2_dbl(&t, r);
|
||||||
|
|
||||||
|
if (aslide[i] > 0) {
|
||||||
|
ge_p1p1_to_p3(&u, &t);
|
||||||
|
ge_add(&t, &u, &Ai[aslide[i] / 2]);
|
||||||
|
} else if (aslide[i] < 0) {
|
||||||
|
ge_p1p1_to_p3(&u, &t);
|
||||||
|
ge_sub(&t, &u, &Ai[(-aslide[i]) / 2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bslide[i] > 0) {
|
||||||
|
ge_p1p1_to_p3(&u, &t);
|
||||||
|
ge_madd(&t, &u, &Bi[bslide[i] / 2]);
|
||||||
|
} else if (bslide[i] < 0) {
|
||||||
|
ge_p1p1_to_p3(&u, &t);
|
||||||
|
ge_msub(&t, &u, &Bi[(-bslide[i]) / 2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
ge_p1p1_to_p2(r, &t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const fe d = {
|
||||||
|
-10913610, 13857413, -15372611, 6949391, 114729, -8787816, -6275908, -3247719, -18696448, -12055116
|
||||||
|
};
|
||||||
|
|
||||||
|
static const fe sqrtm1 = {
|
||||||
|
-32595792, -7943725, 9377950, 3500415, 12389472, -272473, -25146209, -2005654, 326686, 11406482
|
||||||
|
};
|
||||||
|
|
||||||
|
int ge_frombytes_negate_vartime(ge_p3 *h, const unsigned char *s) {
|
||||||
|
fe u;
|
||||||
|
fe v;
|
||||||
|
fe v3;
|
||||||
|
fe vxx;
|
||||||
|
fe check;
|
||||||
|
fe_frombytes(h->Y, s);
|
||||||
|
fe_1(h->Z);
|
||||||
|
fe_sq(u, h->Y);
|
||||||
|
fe_mul(v, u, d);
|
||||||
|
fe_sub(u, u, h->Z); /* u = y^2-1 */
|
||||||
|
fe_add(v, v, h->Z); /* v = dy^2+1 */
|
||||||
|
fe_sq(v3, v);
|
||||||
|
fe_mul(v3, v3, v); /* v3 = v^3 */
|
||||||
|
fe_sq(h->X, v3);
|
||||||
|
fe_mul(h->X, h->X, v);
|
||||||
|
fe_mul(h->X, h->X, u); /* x = uv^7 */
|
||||||
|
fe_pow22523(h->X, h->X); /* x = (uv^7)^((q-5)/8) */
|
||||||
|
fe_mul(h->X, h->X, v3);
|
||||||
|
fe_mul(h->X, h->X, u); /* x = uv^3(uv^7)^((q-5)/8) */
|
||||||
|
fe_sq(vxx, h->X);
|
||||||
|
fe_mul(vxx, vxx, v);
|
||||||
|
fe_sub(check, vxx, u); /* vx^2-u */
|
||||||
|
|
||||||
|
if (fe_isnonzero(check)) {
|
||||||
|
fe_add(check, vxx, u); /* vx^2+u */
|
||||||
|
|
||||||
|
if (fe_isnonzero(check)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fe_mul(h->X, h->X, sqrtm1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fe_isnegative(h->X) == (s[31] >> 7)) {
|
||||||
|
fe_neg(h->X, h->X);
|
||||||
|
}
|
||||||
|
|
||||||
|
fe_mul(h->T, h->X, h->Y);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
r = p + q
|
||||||
|
*/
|
||||||
|
|
||||||
|
void ge_madd(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q) {
|
||||||
|
fe t0;
|
||||||
|
fe_add(r->X, p->Y, p->X);
|
||||||
|
fe_sub(r->Y, p->Y, p->X);
|
||||||
|
fe_mul(r->Z, r->X, q->yplusx);
|
||||||
|
fe_mul(r->Y, r->Y, q->yminusx);
|
||||||
|
fe_mul(r->T, q->xy2d, p->T);
|
||||||
|
fe_add(t0, p->Z, p->Z);
|
||||||
|
fe_sub(r->X, r->Z, r->Y);
|
||||||
|
fe_add(r->Y, r->Z, r->Y);
|
||||||
|
fe_add(r->Z, t0, r->T);
|
||||||
|
fe_sub(r->T, t0, r->T);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
r = p - q
|
||||||
|
*/
|
||||||
|
|
||||||
|
void ge_msub(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q) {
|
||||||
|
fe t0;
|
||||||
|
|
||||||
|
fe_add(r->X, p->Y, p->X);
|
||||||
|
fe_sub(r->Y, p->Y, p->X);
|
||||||
|
fe_mul(r->Z, r->X, q->yminusx);
|
||||||
|
fe_mul(r->Y, r->Y, q->yplusx);
|
||||||
|
fe_mul(r->T, q->xy2d, p->T);
|
||||||
|
fe_add(t0, p->Z, p->Z);
|
||||||
|
fe_sub(r->X, r->Z, r->Y);
|
||||||
|
fe_add(r->Y, r->Z, r->Y);
|
||||||
|
fe_sub(r->Z, t0, r->T);
|
||||||
|
fe_add(r->T, t0, r->T);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
r = p
|
||||||
|
*/
|
||||||
|
|
||||||
|
void ge_p1p1_to_p2(ge_p2 *r, const ge_p1p1 *p) {
|
||||||
|
fe_mul(r->X, p->X, p->T);
|
||||||
|
fe_mul(r->Y, p->Y, p->Z);
|
||||||
|
fe_mul(r->Z, p->Z, p->T);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
r = p
|
||||||
|
*/
|
||||||
|
|
||||||
|
void ge_p1p1_to_p3(ge_p3 *r, const ge_p1p1 *p) {
|
||||||
|
fe_mul(r->X, p->X, p->T);
|
||||||
|
fe_mul(r->Y, p->Y, p->Z);
|
||||||
|
fe_mul(r->Z, p->Z, p->T);
|
||||||
|
fe_mul(r->T, p->X, p->Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ge_p2_0(ge_p2 *h) {
|
||||||
|
fe_0(h->X);
|
||||||
|
fe_1(h->Y);
|
||||||
|
fe_1(h->Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
r = 2 * p
|
||||||
|
*/
|
||||||
|
|
||||||
|
void ge_p2_dbl(ge_p1p1 *r, const ge_p2 *p) {
|
||||||
|
fe t0;
|
||||||
|
|
||||||
|
fe_sq(r->X, p->X);
|
||||||
|
fe_sq(r->Z, p->Y);
|
||||||
|
fe_sq2(r->T, p->Z);
|
||||||
|
fe_add(r->Y, p->X, p->Y);
|
||||||
|
fe_sq(t0, r->Y);
|
||||||
|
fe_add(r->Y, r->Z, r->X);
|
||||||
|
fe_sub(r->Z, r->Z, r->X);
|
||||||
|
fe_sub(r->X, t0, r->Y);
|
||||||
|
fe_sub(r->T, r->T, r->Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ge_p3_0(ge_p3 *h) {
|
||||||
|
fe_0(h->X);
|
||||||
|
fe_1(h->Y);
|
||||||
|
fe_1(h->Z);
|
||||||
|
fe_0(h->T);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
r = 2 * p
|
||||||
|
*/
|
||||||
|
|
||||||
|
void ge_p3_dbl(ge_p1p1 *r, const ge_p3 *p) {
|
||||||
|
ge_p2 q;
|
||||||
|
ge_p3_to_p2(&q, p);
|
||||||
|
ge_p2_dbl(r, &q);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
r = p
|
||||||
|
*/
|
||||||
|
|
||||||
|
static const fe d2 = {
|
||||||
|
-21827239, -5839606, -30745221, 13898782, 229458, 15978800, -12551817, -6495438, 29715968, 9444199
|
||||||
|
};
|
||||||
|
|
||||||
|
void ge_p3_to_cached(ge_cached *r, const ge_p3 *p) {
|
||||||
|
fe_add(r->YplusX, p->Y, p->X);
|
||||||
|
fe_sub(r->YminusX, p->Y, p->X);
|
||||||
|
fe_copy(r->Z, p->Z);
|
||||||
|
fe_mul(r->T2d, p->T, d2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
r = p
|
||||||
|
*/
|
||||||
|
|
||||||
|
void ge_p3_to_p2(ge_p2 *r, const ge_p3 *p) {
|
||||||
|
fe_copy(r->X, p->X);
|
||||||
|
fe_copy(r->Y, p->Y);
|
||||||
|
fe_copy(r->Z, p->Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ge_p3_tobytes(unsigned char *s, const ge_p3 *h) {
|
||||||
|
fe recip;
|
||||||
|
fe x;
|
||||||
|
fe y;
|
||||||
|
fe_invert(recip, h->Z);
|
||||||
|
fe_mul(x, h->X, recip);
|
||||||
|
fe_mul(y, h->Y, recip);
|
||||||
|
fe_tobytes(s, y);
|
||||||
|
s[31] ^= fe_isnegative(x) << 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static unsigned char equal(signed char b, signed char c) {
|
||||||
|
unsigned char ub = b;
|
||||||
|
unsigned char uc = c;
|
||||||
|
unsigned char x = ub ^ uc; /* 0: yes; 1..255: no */
|
||||||
|
uint64_t y = x; /* 0: yes; 1..255: no */
|
||||||
|
y -= 1; /* large: yes; 0..254: no */
|
||||||
|
y >>= 63; /* 1: yes; 0: no */
|
||||||
|
return (unsigned char) y;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned char negative(signed char b) {
|
||||||
|
uint64_t x = b; /* 18446744073709551361..18446744073709551615: yes; 0..255: no */
|
||||||
|
x >>= 63; /* 1: yes; 0: no */
|
||||||
|
return (unsigned char) x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cmov(ge_precomp *t, const ge_precomp *u, unsigned char b) {
|
||||||
|
fe_cmov(t->yplusx, u->yplusx, b);
|
||||||
|
fe_cmov(t->yminusx, u->yminusx, b);
|
||||||
|
fe_cmov(t->xy2d, u->xy2d, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void select(ge_precomp *t, int pos, signed char b) {
|
||||||
|
ge_precomp minust;
|
||||||
|
unsigned char bnegative = negative(b);
|
||||||
|
unsigned char babs = b - (((-bnegative) & b) << 1);
|
||||||
|
fe_1(t->yplusx);
|
||||||
|
fe_1(t->yminusx);
|
||||||
|
fe_0(t->xy2d);
|
||||||
|
cmov(t, &base[pos][0], equal(babs, 1));
|
||||||
|
cmov(t, &base[pos][1], equal(babs, 2));
|
||||||
|
cmov(t, &base[pos][2], equal(babs, 3));
|
||||||
|
cmov(t, &base[pos][3], equal(babs, 4));
|
||||||
|
cmov(t, &base[pos][4], equal(babs, 5));
|
||||||
|
cmov(t, &base[pos][5], equal(babs, 6));
|
||||||
|
cmov(t, &base[pos][6], equal(babs, 7));
|
||||||
|
cmov(t, &base[pos][7], equal(babs, 8));
|
||||||
|
fe_copy(minust.yplusx, t->yminusx);
|
||||||
|
fe_copy(minust.yminusx, t->yplusx);
|
||||||
|
fe_neg(minust.xy2d, t->xy2d);
|
||||||
|
cmov(t, &minust, bnegative);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
h = a * B
|
||||||
|
where a = a[0]+256*a[1]+...+256^31 a[31]
|
||||||
|
B is the Ed25519 base point (x,4/5) with x positive.
|
||||||
|
|
||||||
|
Preconditions:
|
||||||
|
a[31] <= 127
|
||||||
|
*/
|
||||||
|
|
||||||
|
void ge_scalarmult_base(ge_p3 *h, const unsigned char *a) {
|
||||||
|
signed char e[64];
|
||||||
|
signed char carry;
|
||||||
|
ge_p1p1 r;
|
||||||
|
ge_p2 s;
|
||||||
|
ge_precomp t;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < 32; ++i) {
|
||||||
|
e[2 * i + 0] = (a[i] >> 0) & 15;
|
||||||
|
e[2 * i + 1] = (a[i] >> 4) & 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* each e[i] is between 0 and 15 */
|
||||||
|
/* e[63] is between 0 and 7 */
|
||||||
|
carry = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < 63; ++i) {
|
||||||
|
e[i] += carry;
|
||||||
|
carry = e[i] + 8;
|
||||||
|
carry >>= 4;
|
||||||
|
e[i] -= carry << 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
e[63] += carry;
|
||||||
|
/* each e[i] is between -8 and 8 */
|
||||||
|
ge_p3_0(h);
|
||||||
|
|
||||||
|
for (i = 1; i < 64; i += 2) {
|
||||||
|
select(&t, i / 2, e[i]);
|
||||||
|
ge_madd(&r, h, &t);
|
||||||
|
ge_p1p1_to_p3(h, &r);
|
||||||
|
}
|
||||||
|
|
||||||
|
ge_p3_dbl(&r, h);
|
||||||
|
ge_p1p1_to_p2(&s, &r);
|
||||||
|
ge_p2_dbl(&r, &s);
|
||||||
|
ge_p1p1_to_p2(&s, &r);
|
||||||
|
ge_p2_dbl(&r, &s);
|
||||||
|
ge_p1p1_to_p2(&s, &r);
|
||||||
|
ge_p2_dbl(&r, &s);
|
||||||
|
ge_p1p1_to_p3(h, &r);
|
||||||
|
|
||||||
|
for (i = 0; i < 64; i += 2) {
|
||||||
|
select(&t, i / 2, e[i]);
|
||||||
|
ge_madd(&r, h, &t);
|
||||||
|
ge_p1p1_to_p3(h, &r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
r = p - q
|
||||||
|
*/
|
||||||
|
|
||||||
|
void ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) {
|
||||||
|
fe t0;
|
||||||
|
|
||||||
|
fe_add(r->X, p->Y, p->X);
|
||||||
|
fe_sub(r->Y, p->Y, p->X);
|
||||||
|
fe_mul(r->Z, r->X, q->YminusX);
|
||||||
|
fe_mul(r->Y, r->Y, q->YplusX);
|
||||||
|
fe_mul(r->T, q->T2d, p->T);
|
||||||
|
fe_mul(r->X, p->Z, q->Z);
|
||||||
|
fe_add(t0, r->X, r->X);
|
||||||
|
fe_sub(r->X, r->Z, r->Y);
|
||||||
|
fe_add(r->Y, r->Z, r->Y);
|
||||||
|
fe_sub(r->Z, t0, r->T);
|
||||||
|
fe_add(r->T, t0, r->T);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ge_tobytes(unsigned char *s, const ge_p2 *h) {
|
||||||
|
fe recip;
|
||||||
|
fe x;
|
||||||
|
fe y;
|
||||||
|
fe_invert(recip, h->Z);
|
||||||
|
fe_mul(x, h->X, recip);
|
||||||
|
fe_mul(y, h->Y, recip);
|
||||||
|
fe_tobytes(s, y);
|
||||||
|
s[31] ^= fe_isnegative(x) << 7;
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
#ifndef GE_H
|
||||||
|
#define GE_H
|
||||||
|
|
||||||
|
#include "fe.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
ge means group element.
|
||||||
|
|
||||||
|
Here the group is the set of pairs (x,y) of field elements (see fe.h)
|
||||||
|
satisfying -x^2 + y^2 = 1 + d x^2y^2
|
||||||
|
where d = -121665/121666.
|
||||||
|
|
||||||
|
Representations:
|
||||||
|
ge_p2 (projective): (X:Y:Z) satisfying x=X/Z, y=Y/Z
|
||||||
|
ge_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT
|
||||||
|
ge_p1p1 (completed): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T
|
||||||
|
ge_precomp (Duif): (y+x,y-x,2dxy)
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
fe X;
|
||||||
|
fe Y;
|
||||||
|
fe Z;
|
||||||
|
} ge_p2;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
fe X;
|
||||||
|
fe Y;
|
||||||
|
fe Z;
|
||||||
|
fe T;
|
||||||
|
} ge_p3;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
fe X;
|
||||||
|
fe Y;
|
||||||
|
fe Z;
|
||||||
|
fe T;
|
||||||
|
} ge_p1p1;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
fe yplusx;
|
||||||
|
fe yminusx;
|
||||||
|
fe xy2d;
|
||||||
|
} ge_precomp;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
fe YplusX;
|
||||||
|
fe YminusX;
|
||||||
|
fe Z;
|
||||||
|
fe T2d;
|
||||||
|
} ge_cached;
|
||||||
|
|
||||||
|
void ge_p3_tobytes(unsigned char *s, const ge_p3 *h);
|
||||||
|
void ge_tobytes(unsigned char *s, const ge_p2 *h);
|
||||||
|
int ge_frombytes_negate_vartime(ge_p3 *h, const unsigned char *s);
|
||||||
|
|
||||||
|
void ge_add(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q);
|
||||||
|
void ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q);
|
||||||
|
void ge_double_scalarmult_vartime(ge_p2 *r, const unsigned char *a, const ge_p3 *A, const unsigned char *b);
|
||||||
|
void ge_madd(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q);
|
||||||
|
void ge_msub(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q);
|
||||||
|
void ge_scalarmult_base(ge_p3 *h, const unsigned char *a);
|
||||||
|
|
||||||
|
void ge_p1p1_to_p2(ge_p2 *r, const ge_p1p1 *p);
|
||||||
|
void ge_p1p1_to_p3(ge_p3 *r, const ge_p1p1 *p);
|
||||||
|
void ge_p2_0(ge_p2 *h);
|
||||||
|
void ge_p2_dbl(ge_p1p1 *r, const ge_p2 *p);
|
||||||
|
void ge_p3_0(ge_p3 *h);
|
||||||
|
void ge_p3_dbl(ge_p1p1 *r, const ge_p3 *p);
|
||||||
|
void ge_p3_to_cached(ge_cached *r, const ge_p3 *p);
|
||||||
|
void ge_p3_to_p2(ge_p2 *r, const ge_p3 *p);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,79 @@
|
||||||
|
#include "ed25519.h"
|
||||||
|
#include "fe.h"
|
||||||
|
|
||||||
|
void ed25519_key_exchange(unsigned char *shared_secret, const unsigned char *public_key, const unsigned char *private_key) {
|
||||||
|
unsigned char e[32];
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
fe x1;
|
||||||
|
fe x2;
|
||||||
|
fe z2;
|
||||||
|
fe x3;
|
||||||
|
fe z3;
|
||||||
|
fe tmp0;
|
||||||
|
fe tmp1;
|
||||||
|
|
||||||
|
int pos;
|
||||||
|
unsigned int swap;
|
||||||
|
unsigned int b;
|
||||||
|
|
||||||
|
/* copy the private key and make sure it's valid */
|
||||||
|
for (i = 0; i < 32; ++i) {
|
||||||
|
e[i] = private_key[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
e[0] &= 248;
|
||||||
|
e[31] &= 63;
|
||||||
|
e[31] |= 64;
|
||||||
|
|
||||||
|
/* unpack the public key and convert edwards to montgomery */
|
||||||
|
/* due to CodesInChaos: montgomeryX = (edwardsY + 1)*inverse(1 - edwardsY) mod p */
|
||||||
|
fe_frombytes(x1, public_key);
|
||||||
|
fe_1(tmp1);
|
||||||
|
fe_add(tmp0, x1, tmp1);
|
||||||
|
fe_sub(tmp1, tmp1, x1);
|
||||||
|
fe_invert(tmp1, tmp1);
|
||||||
|
fe_mul(x1, tmp0, tmp1);
|
||||||
|
|
||||||
|
fe_1(x2);
|
||||||
|
fe_0(z2);
|
||||||
|
fe_copy(x3, x1);
|
||||||
|
fe_1(z3);
|
||||||
|
|
||||||
|
swap = 0;
|
||||||
|
for (pos = 254; pos >= 0; --pos) {
|
||||||
|
b = e[pos / 8] >> (pos & 7);
|
||||||
|
b &= 1;
|
||||||
|
swap ^= b;
|
||||||
|
fe_cswap(x2, x3, swap);
|
||||||
|
fe_cswap(z2, z3, swap);
|
||||||
|
swap = b;
|
||||||
|
|
||||||
|
/* from montgomery.h */
|
||||||
|
fe_sub(tmp0, x3, z3);
|
||||||
|
fe_sub(tmp1, x2, z2);
|
||||||
|
fe_add(x2, x2, z2);
|
||||||
|
fe_add(z2, x3, z3);
|
||||||
|
fe_mul(z3, tmp0, x2);
|
||||||
|
fe_mul(z2, z2, tmp1);
|
||||||
|
fe_sq(tmp0, tmp1);
|
||||||
|
fe_sq(tmp1, x2);
|
||||||
|
fe_add(x3, z3, z2);
|
||||||
|
fe_sub(z2, z3, z2);
|
||||||
|
fe_mul(x2, tmp1, tmp0);
|
||||||
|
fe_sub(tmp1, tmp1, tmp0);
|
||||||
|
fe_sq(z2, z2);
|
||||||
|
fe_mul121666(z3, tmp1);
|
||||||
|
fe_sq(x3, x3);
|
||||||
|
fe_add(tmp0, tmp0, z3);
|
||||||
|
fe_mul(z3, x1, z2);
|
||||||
|
fe_mul(z2, tmp1, tmp0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fe_cswap(x2, x3, swap);
|
||||||
|
fe_cswap(z2, z3, swap);
|
||||||
|
|
||||||
|
fe_invert(z2, z2);
|
||||||
|
fe_mul(x2, x2, z2);
|
||||||
|
fe_tobytes(shared_secret, x2);
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
#include "ed25519.h"
|
||||||
|
#include "sha512.h"
|
||||||
|
#include "ge.h"
|
||||||
|
|
||||||
|
|
||||||
|
void ed25519_create_keypair(unsigned char *public_key, unsigned char *private_key, const unsigned char *seed) {
|
||||||
|
ge_p3 A;
|
||||||
|
|
||||||
|
sha512(seed, 32, private_key);
|
||||||
|
private_key[0] &= 248;
|
||||||
|
private_key[31] &= 63;
|
||||||
|
private_key[31] |= 64;
|
||||||
|
|
||||||
|
ge_scalarmult_base(&A, private_key);
|
||||||
|
ge_p3_tobytes(public_key, &A);
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
Copyright (c) 2015 Orson Peters <orsonpeters@gmail.com>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied warranty. In no event will the
|
||||||
|
authors be held liable for any damages arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose, including commercial
|
||||||
|
applications, and to alter it and redistribute it freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not claim that you wrote the
|
||||||
|
original software. If you use this software in a product, an acknowledgment in the product
|
||||||
|
documentation would be appreciated but is not required.
|
||||||
|
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be misrepresented as
|
||||||
|
being the original software.
|
||||||
|
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,809 @@
|
||||||
|
#include "fixedint.h"
|
||||||
|
#include "sc.h"
|
||||||
|
|
||||||
|
static uint64_t load_3(const unsigned char *in) {
|
||||||
|
uint64_t result;
|
||||||
|
|
||||||
|
result = (uint64_t) in[0];
|
||||||
|
result |= ((uint64_t) in[1]) << 8;
|
||||||
|
result |= ((uint64_t) in[2]) << 16;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t load_4(const unsigned char *in) {
|
||||||
|
uint64_t result;
|
||||||
|
|
||||||
|
result = (uint64_t) in[0];
|
||||||
|
result |= ((uint64_t) in[1]) << 8;
|
||||||
|
result |= ((uint64_t) in[2]) << 16;
|
||||||
|
result |= ((uint64_t) in[3]) << 24;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Input:
|
||||||
|
s[0]+256*s[1]+...+256^63*s[63] = s
|
||||||
|
|
||||||
|
Output:
|
||||||
|
s[0]+256*s[1]+...+256^31*s[31] = s mod l
|
||||||
|
where l = 2^252 + 27742317777372353535851937790883648493.
|
||||||
|
Overwrites s in place.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void sc_reduce(unsigned char *s) {
|
||||||
|
int64_t s0 = 2097151 & load_3(s);
|
||||||
|
int64_t s1 = 2097151 & (load_4(s + 2) >> 5);
|
||||||
|
int64_t s2 = 2097151 & (load_3(s + 5) >> 2);
|
||||||
|
int64_t s3 = 2097151 & (load_4(s + 7) >> 7);
|
||||||
|
int64_t s4 = 2097151 & (load_4(s + 10) >> 4);
|
||||||
|
int64_t s5 = 2097151 & (load_3(s + 13) >> 1);
|
||||||
|
int64_t s6 = 2097151 & (load_4(s + 15) >> 6);
|
||||||
|
int64_t s7 = 2097151 & (load_3(s + 18) >> 3);
|
||||||
|
int64_t s8 = 2097151 & load_3(s + 21);
|
||||||
|
int64_t s9 = 2097151 & (load_4(s + 23) >> 5);
|
||||||
|
int64_t s10 = 2097151 & (load_3(s + 26) >> 2);
|
||||||
|
int64_t s11 = 2097151 & (load_4(s + 28) >> 7);
|
||||||
|
int64_t s12 = 2097151 & (load_4(s + 31) >> 4);
|
||||||
|
int64_t s13 = 2097151 & (load_3(s + 34) >> 1);
|
||||||
|
int64_t s14 = 2097151 & (load_4(s + 36) >> 6);
|
||||||
|
int64_t s15 = 2097151 & (load_3(s + 39) >> 3);
|
||||||
|
int64_t s16 = 2097151 & load_3(s + 42);
|
||||||
|
int64_t s17 = 2097151 & (load_4(s + 44) >> 5);
|
||||||
|
int64_t s18 = 2097151 & (load_3(s + 47) >> 2);
|
||||||
|
int64_t s19 = 2097151 & (load_4(s + 49) >> 7);
|
||||||
|
int64_t s20 = 2097151 & (load_4(s + 52) >> 4);
|
||||||
|
int64_t s21 = 2097151 & (load_3(s + 55) >> 1);
|
||||||
|
int64_t s22 = 2097151 & (load_4(s + 57) >> 6);
|
||||||
|
int64_t s23 = (load_4(s + 60) >> 3);
|
||||||
|
int64_t carry0;
|
||||||
|
int64_t carry1;
|
||||||
|
int64_t carry2;
|
||||||
|
int64_t carry3;
|
||||||
|
int64_t carry4;
|
||||||
|
int64_t carry5;
|
||||||
|
int64_t carry6;
|
||||||
|
int64_t carry7;
|
||||||
|
int64_t carry8;
|
||||||
|
int64_t carry9;
|
||||||
|
int64_t carry10;
|
||||||
|
int64_t carry11;
|
||||||
|
int64_t carry12;
|
||||||
|
int64_t carry13;
|
||||||
|
int64_t carry14;
|
||||||
|
int64_t carry15;
|
||||||
|
int64_t carry16;
|
||||||
|
|
||||||
|
s11 += s23 * 666643;
|
||||||
|
s12 += s23 * 470296;
|
||||||
|
s13 += s23 * 654183;
|
||||||
|
s14 -= s23 * 997805;
|
||||||
|
s15 += s23 * 136657;
|
||||||
|
s16 -= s23 * 683901;
|
||||||
|
s23 = 0;
|
||||||
|
s10 += s22 * 666643;
|
||||||
|
s11 += s22 * 470296;
|
||||||
|
s12 += s22 * 654183;
|
||||||
|
s13 -= s22 * 997805;
|
||||||
|
s14 += s22 * 136657;
|
||||||
|
s15 -= s22 * 683901;
|
||||||
|
s22 = 0;
|
||||||
|
s9 += s21 * 666643;
|
||||||
|
s10 += s21 * 470296;
|
||||||
|
s11 += s21 * 654183;
|
||||||
|
s12 -= s21 * 997805;
|
||||||
|
s13 += s21 * 136657;
|
||||||
|
s14 -= s21 * 683901;
|
||||||
|
s21 = 0;
|
||||||
|
s8 += s20 * 666643;
|
||||||
|
s9 += s20 * 470296;
|
||||||
|
s10 += s20 * 654183;
|
||||||
|
s11 -= s20 * 997805;
|
||||||
|
s12 += s20 * 136657;
|
||||||
|
s13 -= s20 * 683901;
|
||||||
|
s20 = 0;
|
||||||
|
s7 += s19 * 666643;
|
||||||
|
s8 += s19 * 470296;
|
||||||
|
s9 += s19 * 654183;
|
||||||
|
s10 -= s19 * 997805;
|
||||||
|
s11 += s19 * 136657;
|
||||||
|
s12 -= s19 * 683901;
|
||||||
|
s19 = 0;
|
||||||
|
s6 += s18 * 666643;
|
||||||
|
s7 += s18 * 470296;
|
||||||
|
s8 += s18 * 654183;
|
||||||
|
s9 -= s18 * 997805;
|
||||||
|
s10 += s18 * 136657;
|
||||||
|
s11 -= s18 * 683901;
|
||||||
|
s18 = 0;
|
||||||
|
carry6 = (s6 + (1 << 20)) >> 21;
|
||||||
|
s7 += carry6;
|
||||||
|
s6 -= carry6 << 21;
|
||||||
|
carry8 = (s8 + (1 << 20)) >> 21;
|
||||||
|
s9 += carry8;
|
||||||
|
s8 -= carry8 << 21;
|
||||||
|
carry10 = (s10 + (1 << 20)) >> 21;
|
||||||
|
s11 += carry10;
|
||||||
|
s10 -= carry10 << 21;
|
||||||
|
carry12 = (s12 + (1 << 20)) >> 21;
|
||||||
|
s13 += carry12;
|
||||||
|
s12 -= carry12 << 21;
|
||||||
|
carry14 = (s14 + (1 << 20)) >> 21;
|
||||||
|
s15 += carry14;
|
||||||
|
s14 -= carry14 << 21;
|
||||||
|
carry16 = (s16 + (1 << 20)) >> 21;
|
||||||
|
s17 += carry16;
|
||||||
|
s16 -= carry16 << 21;
|
||||||
|
carry7 = (s7 + (1 << 20)) >> 21;
|
||||||
|
s8 += carry7;
|
||||||
|
s7 -= carry7 << 21;
|
||||||
|
carry9 = (s9 + (1 << 20)) >> 21;
|
||||||
|
s10 += carry9;
|
||||||
|
s9 -= carry9 << 21;
|
||||||
|
carry11 = (s11 + (1 << 20)) >> 21;
|
||||||
|
s12 += carry11;
|
||||||
|
s11 -= carry11 << 21;
|
||||||
|
carry13 = (s13 + (1 << 20)) >> 21;
|
||||||
|
s14 += carry13;
|
||||||
|
s13 -= carry13 << 21;
|
||||||
|
carry15 = (s15 + (1 << 20)) >> 21;
|
||||||
|
s16 += carry15;
|
||||||
|
s15 -= carry15 << 21;
|
||||||
|
s5 += s17 * 666643;
|
||||||
|
s6 += s17 * 470296;
|
||||||
|
s7 += s17 * 654183;
|
||||||
|
s8 -= s17 * 997805;
|
||||||
|
s9 += s17 * 136657;
|
||||||
|
s10 -= s17 * 683901;
|
||||||
|
s17 = 0;
|
||||||
|
s4 += s16 * 666643;
|
||||||
|
s5 += s16 * 470296;
|
||||||
|
s6 += s16 * 654183;
|
||||||
|
s7 -= s16 * 997805;
|
||||||
|
s8 += s16 * 136657;
|
||||||
|
s9 -= s16 * 683901;
|
||||||
|
s16 = 0;
|
||||||
|
s3 += s15 * 666643;
|
||||||
|
s4 += s15 * 470296;
|
||||||
|
s5 += s15 * 654183;
|
||||||
|
s6 -= s15 * 997805;
|
||||||
|
s7 += s15 * 136657;
|
||||||
|
s8 -= s15 * 683901;
|
||||||
|
s15 = 0;
|
||||||
|
s2 += s14 * 666643;
|
||||||
|
s3 += s14 * 470296;
|
||||||
|
s4 += s14 * 654183;
|
||||||
|
s5 -= s14 * 997805;
|
||||||
|
s6 += s14 * 136657;
|
||||||
|
s7 -= s14 * 683901;
|
||||||
|
s14 = 0;
|
||||||
|
s1 += s13 * 666643;
|
||||||
|
s2 += s13 * 470296;
|
||||||
|
s3 += s13 * 654183;
|
||||||
|
s4 -= s13 * 997805;
|
||||||
|
s5 += s13 * 136657;
|
||||||
|
s6 -= s13 * 683901;
|
||||||
|
s13 = 0;
|
||||||
|
s0 += s12 * 666643;
|
||||||
|
s1 += s12 * 470296;
|
||||||
|
s2 += s12 * 654183;
|
||||||
|
s3 -= s12 * 997805;
|
||||||
|
s4 += s12 * 136657;
|
||||||
|
s5 -= s12 * 683901;
|
||||||
|
s12 = 0;
|
||||||
|
carry0 = (s0 + (1 << 20)) >> 21;
|
||||||
|
s1 += carry0;
|
||||||
|
s0 -= carry0 << 21;
|
||||||
|
carry2 = (s2 + (1 << 20)) >> 21;
|
||||||
|
s3 += carry2;
|
||||||
|
s2 -= carry2 << 21;
|
||||||
|
carry4 = (s4 + (1 << 20)) >> 21;
|
||||||
|
s5 += carry4;
|
||||||
|
s4 -= carry4 << 21;
|
||||||
|
carry6 = (s6 + (1 << 20)) >> 21;
|
||||||
|
s7 += carry6;
|
||||||
|
s6 -= carry6 << 21;
|
||||||
|
carry8 = (s8 + (1 << 20)) >> 21;
|
||||||
|
s9 += carry8;
|
||||||
|
s8 -= carry8 << 21;
|
||||||
|
carry10 = (s10 + (1 << 20)) >> 21;
|
||||||
|
s11 += carry10;
|
||||||
|
s10 -= carry10 << 21;
|
||||||
|
carry1 = (s1 + (1 << 20)) >> 21;
|
||||||
|
s2 += carry1;
|
||||||
|
s1 -= carry1 << 21;
|
||||||
|
carry3 = (s3 + (1 << 20)) >> 21;
|
||||||
|
s4 += carry3;
|
||||||
|
s3 -= carry3 << 21;
|
||||||
|
carry5 = (s5 + (1 << 20)) >> 21;
|
||||||
|
s6 += carry5;
|
||||||
|
s5 -= carry5 << 21;
|
||||||
|
carry7 = (s7 + (1 << 20)) >> 21;
|
||||||
|
s8 += carry7;
|
||||||
|
s7 -= carry7 << 21;
|
||||||
|
carry9 = (s9 + (1 << 20)) >> 21;
|
||||||
|
s10 += carry9;
|
||||||
|
s9 -= carry9 << 21;
|
||||||
|
carry11 = (s11 + (1 << 20)) >> 21;
|
||||||
|
s12 += carry11;
|
||||||
|
s11 -= carry11 << 21;
|
||||||
|
s0 += s12 * 666643;
|
||||||
|
s1 += s12 * 470296;
|
||||||
|
s2 += s12 * 654183;
|
||||||
|
s3 -= s12 * 997805;
|
||||||
|
s4 += s12 * 136657;
|
||||||
|
s5 -= s12 * 683901;
|
||||||
|
s12 = 0;
|
||||||
|
carry0 = s0 >> 21;
|
||||||
|
s1 += carry0;
|
||||||
|
s0 -= carry0 << 21;
|
||||||
|
carry1 = s1 >> 21;
|
||||||
|
s2 += carry1;
|
||||||
|
s1 -= carry1 << 21;
|
||||||
|
carry2 = s2 >> 21;
|
||||||
|
s3 += carry2;
|
||||||
|
s2 -= carry2 << 21;
|
||||||
|
carry3 = s3 >> 21;
|
||||||
|
s4 += carry3;
|
||||||
|
s3 -= carry3 << 21;
|
||||||
|
carry4 = s4 >> 21;
|
||||||
|
s5 += carry4;
|
||||||
|
s4 -= carry4 << 21;
|
||||||
|
carry5 = s5 >> 21;
|
||||||
|
s6 += carry5;
|
||||||
|
s5 -= carry5 << 21;
|
||||||
|
carry6 = s6 >> 21;
|
||||||
|
s7 += carry6;
|
||||||
|
s6 -= carry6 << 21;
|
||||||
|
carry7 = s7 >> 21;
|
||||||
|
s8 += carry7;
|
||||||
|
s7 -= carry7 << 21;
|
||||||
|
carry8 = s8 >> 21;
|
||||||
|
s9 += carry8;
|
||||||
|
s8 -= carry8 << 21;
|
||||||
|
carry9 = s9 >> 21;
|
||||||
|
s10 += carry9;
|
||||||
|
s9 -= carry9 << 21;
|
||||||
|
carry10 = s10 >> 21;
|
||||||
|
s11 += carry10;
|
||||||
|
s10 -= carry10 << 21;
|
||||||
|
carry11 = s11 >> 21;
|
||||||
|
s12 += carry11;
|
||||||
|
s11 -= carry11 << 21;
|
||||||
|
s0 += s12 * 666643;
|
||||||
|
s1 += s12 * 470296;
|
||||||
|
s2 += s12 * 654183;
|
||||||
|
s3 -= s12 * 997805;
|
||||||
|
s4 += s12 * 136657;
|
||||||
|
s5 -= s12 * 683901;
|
||||||
|
s12 = 0;
|
||||||
|
carry0 = s0 >> 21;
|
||||||
|
s1 += carry0;
|
||||||
|
s0 -= carry0 << 21;
|
||||||
|
carry1 = s1 >> 21;
|
||||||
|
s2 += carry1;
|
||||||
|
s1 -= carry1 << 21;
|
||||||
|
carry2 = s2 >> 21;
|
||||||
|
s3 += carry2;
|
||||||
|
s2 -= carry2 << 21;
|
||||||
|
carry3 = s3 >> 21;
|
||||||
|
s4 += carry3;
|
||||||
|
s3 -= carry3 << 21;
|
||||||
|
carry4 = s4 >> 21;
|
||||||
|
s5 += carry4;
|
||||||
|
s4 -= carry4 << 21;
|
||||||
|
carry5 = s5 >> 21;
|
||||||
|
s6 += carry5;
|
||||||
|
s5 -= carry5 << 21;
|
||||||
|
carry6 = s6 >> 21;
|
||||||
|
s7 += carry6;
|
||||||
|
s6 -= carry6 << 21;
|
||||||
|
carry7 = s7 >> 21;
|
||||||
|
s8 += carry7;
|
||||||
|
s7 -= carry7 << 21;
|
||||||
|
carry8 = s8 >> 21;
|
||||||
|
s9 += carry8;
|
||||||
|
s8 -= carry8 << 21;
|
||||||
|
carry9 = s9 >> 21;
|
||||||
|
s10 += carry9;
|
||||||
|
s9 -= carry9 << 21;
|
||||||
|
carry10 = s10 >> 21;
|
||||||
|
s11 += carry10;
|
||||||
|
s10 -= carry10 << 21;
|
||||||
|
|
||||||
|
s[0] = (unsigned char) (s0 >> 0);
|
||||||
|
s[1] = (unsigned char) (s0 >> 8);
|
||||||
|
s[2] = (unsigned char) ((s0 >> 16) | (s1 << 5));
|
||||||
|
s[3] = (unsigned char) (s1 >> 3);
|
||||||
|
s[4] = (unsigned char) (s1 >> 11);
|
||||||
|
s[5] = (unsigned char) ((s1 >> 19) | (s2 << 2));
|
||||||
|
s[6] = (unsigned char) (s2 >> 6);
|
||||||
|
s[7] = (unsigned char) ((s2 >> 14) | (s3 << 7));
|
||||||
|
s[8] = (unsigned char) (s3 >> 1);
|
||||||
|
s[9] = (unsigned char) (s3 >> 9);
|
||||||
|
s[10] = (unsigned char) ((s3 >> 17) | (s4 << 4));
|
||||||
|
s[11] = (unsigned char) (s4 >> 4);
|
||||||
|
s[12] = (unsigned char) (s4 >> 12);
|
||||||
|
s[13] = (unsigned char) ((s4 >> 20) | (s5 << 1));
|
||||||
|
s[14] = (unsigned char) (s5 >> 7);
|
||||||
|
s[15] = (unsigned char) ((s5 >> 15) | (s6 << 6));
|
||||||
|
s[16] = (unsigned char) (s6 >> 2);
|
||||||
|
s[17] = (unsigned char) (s6 >> 10);
|
||||||
|
s[18] = (unsigned char) ((s6 >> 18) | (s7 << 3));
|
||||||
|
s[19] = (unsigned char) (s7 >> 5);
|
||||||
|
s[20] = (unsigned char) (s7 >> 13);
|
||||||
|
s[21] = (unsigned char) (s8 >> 0);
|
||||||
|
s[22] = (unsigned char) (s8 >> 8);
|
||||||
|
s[23] = (unsigned char) ((s8 >> 16) | (s9 << 5));
|
||||||
|
s[24] = (unsigned char) (s9 >> 3);
|
||||||
|
s[25] = (unsigned char) (s9 >> 11);
|
||||||
|
s[26] = (unsigned char) ((s9 >> 19) | (s10 << 2));
|
||||||
|
s[27] = (unsigned char) (s10 >> 6);
|
||||||
|
s[28] = (unsigned char) ((s10 >> 14) | (s11 << 7));
|
||||||
|
s[29] = (unsigned char) (s11 >> 1);
|
||||||
|
s[30] = (unsigned char) (s11 >> 9);
|
||||||
|
s[31] = (unsigned char) (s11 >> 17);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Input:
|
||||||
|
a[0]+256*a[1]+...+256^31*a[31] = a
|
||||||
|
b[0]+256*b[1]+...+256^31*b[31] = b
|
||||||
|
c[0]+256*c[1]+...+256^31*c[31] = c
|
||||||
|
|
||||||
|
Output:
|
||||||
|
s[0]+256*s[1]+...+256^31*s[31] = (ab+c) mod l
|
||||||
|
where l = 2^252 + 27742317777372353535851937790883648493.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b, const unsigned char *c) {
|
||||||
|
int64_t a0 = 2097151 & load_3(a);
|
||||||
|
int64_t a1 = 2097151 & (load_4(a + 2) >> 5);
|
||||||
|
int64_t a2 = 2097151 & (load_3(a + 5) >> 2);
|
||||||
|
int64_t a3 = 2097151 & (load_4(a + 7) >> 7);
|
||||||
|
int64_t a4 = 2097151 & (load_4(a + 10) >> 4);
|
||||||
|
int64_t a5 = 2097151 & (load_3(a + 13) >> 1);
|
||||||
|
int64_t a6 = 2097151 & (load_4(a + 15) >> 6);
|
||||||
|
int64_t a7 = 2097151 & (load_3(a + 18) >> 3);
|
||||||
|
int64_t a8 = 2097151 & load_3(a + 21);
|
||||||
|
int64_t a9 = 2097151 & (load_4(a + 23) >> 5);
|
||||||
|
int64_t a10 = 2097151 & (load_3(a + 26) >> 2);
|
||||||
|
int64_t a11 = (load_4(a + 28) >> 7);
|
||||||
|
int64_t b0 = 2097151 & load_3(b);
|
||||||
|
int64_t b1 = 2097151 & (load_4(b + 2) >> 5);
|
||||||
|
int64_t b2 = 2097151 & (load_3(b + 5) >> 2);
|
||||||
|
int64_t b3 = 2097151 & (load_4(b + 7) >> 7);
|
||||||
|
int64_t b4 = 2097151 & (load_4(b + 10) >> 4);
|
||||||
|
int64_t b5 = 2097151 & (load_3(b + 13) >> 1);
|
||||||
|
int64_t b6 = 2097151 & (load_4(b + 15) >> 6);
|
||||||
|
int64_t b7 = 2097151 & (load_3(b + 18) >> 3);
|
||||||
|
int64_t b8 = 2097151 & load_3(b + 21);
|
||||||
|
int64_t b9 = 2097151 & (load_4(b + 23) >> 5);
|
||||||
|
int64_t b10 = 2097151 & (load_3(b + 26) >> 2);
|
||||||
|
int64_t b11 = (load_4(b + 28) >> 7);
|
||||||
|
int64_t c0 = 2097151 & load_3(c);
|
||||||
|
int64_t c1 = 2097151 & (load_4(c + 2) >> 5);
|
||||||
|
int64_t c2 = 2097151 & (load_3(c + 5) >> 2);
|
||||||
|
int64_t c3 = 2097151 & (load_4(c + 7) >> 7);
|
||||||
|
int64_t c4 = 2097151 & (load_4(c + 10) >> 4);
|
||||||
|
int64_t c5 = 2097151 & (load_3(c + 13) >> 1);
|
||||||
|
int64_t c6 = 2097151 & (load_4(c + 15) >> 6);
|
||||||
|
int64_t c7 = 2097151 & (load_3(c + 18) >> 3);
|
||||||
|
int64_t c8 = 2097151 & load_3(c + 21);
|
||||||
|
int64_t c9 = 2097151 & (load_4(c + 23) >> 5);
|
||||||
|
int64_t c10 = 2097151 & (load_3(c + 26) >> 2);
|
||||||
|
int64_t c11 = (load_4(c + 28) >> 7);
|
||||||
|
int64_t s0;
|
||||||
|
int64_t s1;
|
||||||
|
int64_t s2;
|
||||||
|
int64_t s3;
|
||||||
|
int64_t s4;
|
||||||
|
int64_t s5;
|
||||||
|
int64_t s6;
|
||||||
|
int64_t s7;
|
||||||
|
int64_t s8;
|
||||||
|
int64_t s9;
|
||||||
|
int64_t s10;
|
||||||
|
int64_t s11;
|
||||||
|
int64_t s12;
|
||||||
|
int64_t s13;
|
||||||
|
int64_t s14;
|
||||||
|
int64_t s15;
|
||||||
|
int64_t s16;
|
||||||
|
int64_t s17;
|
||||||
|
int64_t s18;
|
||||||
|
int64_t s19;
|
||||||
|
int64_t s20;
|
||||||
|
int64_t s21;
|
||||||
|
int64_t s22;
|
||||||
|
int64_t s23;
|
||||||
|
int64_t carry0;
|
||||||
|
int64_t carry1;
|
||||||
|
int64_t carry2;
|
||||||
|
int64_t carry3;
|
||||||
|
int64_t carry4;
|
||||||
|
int64_t carry5;
|
||||||
|
int64_t carry6;
|
||||||
|
int64_t carry7;
|
||||||
|
int64_t carry8;
|
||||||
|
int64_t carry9;
|
||||||
|
int64_t carry10;
|
||||||
|
int64_t carry11;
|
||||||
|
int64_t carry12;
|
||||||
|
int64_t carry13;
|
||||||
|
int64_t carry14;
|
||||||
|
int64_t carry15;
|
||||||
|
int64_t carry16;
|
||||||
|
int64_t carry17;
|
||||||
|
int64_t carry18;
|
||||||
|
int64_t carry19;
|
||||||
|
int64_t carry20;
|
||||||
|
int64_t carry21;
|
||||||
|
int64_t carry22;
|
||||||
|
|
||||||
|
s0 = c0 + a0 * b0;
|
||||||
|
s1 = c1 + a0 * b1 + a1 * b0;
|
||||||
|
s2 = c2 + a0 * b2 + a1 * b1 + a2 * b0;
|
||||||
|
s3 = c3 + a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0;
|
||||||
|
s4 = c4 + a0 * b4 + a1 * b3 + a2 * b2 + a3 * b1 + a4 * b0;
|
||||||
|
s5 = c5 + a0 * b5 + a1 * b4 + a2 * b3 + a3 * b2 + a4 * b1 + a5 * b0;
|
||||||
|
s6 = c6 + a0 * b6 + a1 * b5 + a2 * b4 + a3 * b3 + a4 * b2 + a5 * b1 + a6 * b0;
|
||||||
|
s7 = c7 + a0 * b7 + a1 * b6 + a2 * b5 + a3 * b4 + a4 * b3 + a5 * b2 + a6 * b1 + a7 * b0;
|
||||||
|
s8 = c8 + a0 * b8 + a1 * b7 + a2 * b6 + a3 * b5 + a4 * b4 + a5 * b3 + a6 * b2 + a7 * b1 + a8 * b0;
|
||||||
|
s9 = c9 + a0 * b9 + a1 * b8 + a2 * b7 + a3 * b6 + a4 * b5 + a5 * b4 + a6 * b3 + a7 * b2 + a8 * b1 + a9 * b0;
|
||||||
|
s10 = c10 + a0 * b10 + a1 * b9 + a2 * b8 + a3 * b7 + a4 * b6 + a5 * b5 + a6 * b4 + a7 * b3 + a8 * b2 + a9 * b1 + a10 * b0;
|
||||||
|
s11 = c11 + a0 * b11 + a1 * b10 + a2 * b9 + a3 * b8 + a4 * b7 + a5 * b6 + a6 * b5 + a7 * b4 + a8 * b3 + a9 * b2 + a10 * b1 + a11 * b0;
|
||||||
|
s12 = a1 * b11 + a2 * b10 + a3 * b9 + a4 * b8 + a5 * b7 + a6 * b6 + a7 * b5 + a8 * b4 + a9 * b3 + a10 * b2 + a11 * b1;
|
||||||
|
s13 = a2 * b11 + a3 * b10 + a4 * b9 + a5 * b8 + a6 * b7 + a7 * b6 + a8 * b5 + a9 * b4 + a10 * b3 + a11 * b2;
|
||||||
|
s14 = a3 * b11 + a4 * b10 + a5 * b9 + a6 * b8 + a7 * b7 + a8 * b6 + a9 * b5 + a10 * b4 + a11 * b3;
|
||||||
|
s15 = a4 * b11 + a5 * b10 + a6 * b9 + a7 * b8 + a8 * b7 + a9 * b6 + a10 * b5 + a11 * b4;
|
||||||
|
s16 = a5 * b11 + a6 * b10 + a7 * b9 + a8 * b8 + a9 * b7 + a10 * b6 + a11 * b5;
|
||||||
|
s17 = a6 * b11 + a7 * b10 + a8 * b9 + a9 * b8 + a10 * b7 + a11 * b6;
|
||||||
|
s18 = a7 * b11 + a8 * b10 + a9 * b9 + a10 * b8 + a11 * b7;
|
||||||
|
s19 = a8 * b11 + a9 * b10 + a10 * b9 + a11 * b8;
|
||||||
|
s20 = a9 * b11 + a10 * b10 + a11 * b9;
|
||||||
|
s21 = a10 * b11 + a11 * b10;
|
||||||
|
s22 = a11 * b11;
|
||||||
|
s23 = 0;
|
||||||
|
carry0 = (s0 + (1 << 20)) >> 21;
|
||||||
|
s1 += carry0;
|
||||||
|
s0 -= carry0 << 21;
|
||||||
|
carry2 = (s2 + (1 << 20)) >> 21;
|
||||||
|
s3 += carry2;
|
||||||
|
s2 -= carry2 << 21;
|
||||||
|
carry4 = (s4 + (1 << 20)) >> 21;
|
||||||
|
s5 += carry4;
|
||||||
|
s4 -= carry4 << 21;
|
||||||
|
carry6 = (s6 + (1 << 20)) >> 21;
|
||||||
|
s7 += carry6;
|
||||||
|
s6 -= carry6 << 21;
|
||||||
|
carry8 = (s8 + (1 << 20)) >> 21;
|
||||||
|
s9 += carry8;
|
||||||
|
s8 -= carry8 << 21;
|
||||||
|
carry10 = (s10 + (1 << 20)) >> 21;
|
||||||
|
s11 += carry10;
|
||||||
|
s10 -= carry10 << 21;
|
||||||
|
carry12 = (s12 + (1 << 20)) >> 21;
|
||||||
|
s13 += carry12;
|
||||||
|
s12 -= carry12 << 21;
|
||||||
|
carry14 = (s14 + (1 << 20)) >> 21;
|
||||||
|
s15 += carry14;
|
||||||
|
s14 -= carry14 << 21;
|
||||||
|
carry16 = (s16 + (1 << 20)) >> 21;
|
||||||
|
s17 += carry16;
|
||||||
|
s16 -= carry16 << 21;
|
||||||
|
carry18 = (s18 + (1 << 20)) >> 21;
|
||||||
|
s19 += carry18;
|
||||||
|
s18 -= carry18 << 21;
|
||||||
|
carry20 = (s20 + (1 << 20)) >> 21;
|
||||||
|
s21 += carry20;
|
||||||
|
s20 -= carry20 << 21;
|
||||||
|
carry22 = (s22 + (1 << 20)) >> 21;
|
||||||
|
s23 += carry22;
|
||||||
|
s22 -= carry22 << 21;
|
||||||
|
carry1 = (s1 + (1 << 20)) >> 21;
|
||||||
|
s2 += carry1;
|
||||||
|
s1 -= carry1 << 21;
|
||||||
|
carry3 = (s3 + (1 << 20)) >> 21;
|
||||||
|
s4 += carry3;
|
||||||
|
s3 -= carry3 << 21;
|
||||||
|
carry5 = (s5 + (1 << 20)) >> 21;
|
||||||
|
s6 += carry5;
|
||||||
|
s5 -= carry5 << 21;
|
||||||
|
carry7 = (s7 + (1 << 20)) >> 21;
|
||||||
|
s8 += carry7;
|
||||||
|
s7 -= carry7 << 21;
|
||||||
|
carry9 = (s9 + (1 << 20)) >> 21;
|
||||||
|
s10 += carry9;
|
||||||
|
s9 -= carry9 << 21;
|
||||||
|
carry11 = (s11 + (1 << 20)) >> 21;
|
||||||
|
s12 += carry11;
|
||||||
|
s11 -= carry11 << 21;
|
||||||
|
carry13 = (s13 + (1 << 20)) >> 21;
|
||||||
|
s14 += carry13;
|
||||||
|
s13 -= carry13 << 21;
|
||||||
|
carry15 = (s15 + (1 << 20)) >> 21;
|
||||||
|
s16 += carry15;
|
||||||
|
s15 -= carry15 << 21;
|
||||||
|
carry17 = (s17 + (1 << 20)) >> 21;
|
||||||
|
s18 += carry17;
|
||||||
|
s17 -= carry17 << 21;
|
||||||
|
carry19 = (s19 + (1 << 20)) >> 21;
|
||||||
|
s20 += carry19;
|
||||||
|
s19 -= carry19 << 21;
|
||||||
|
carry21 = (s21 + (1 << 20)) >> 21;
|
||||||
|
s22 += carry21;
|
||||||
|
s21 -= carry21 << 21;
|
||||||
|
s11 += s23 * 666643;
|
||||||
|
s12 += s23 * 470296;
|
||||||
|
s13 += s23 * 654183;
|
||||||
|
s14 -= s23 * 997805;
|
||||||
|
s15 += s23 * 136657;
|
||||||
|
s16 -= s23 * 683901;
|
||||||
|
s23 = 0;
|
||||||
|
s10 += s22 * 666643;
|
||||||
|
s11 += s22 * 470296;
|
||||||
|
s12 += s22 * 654183;
|
||||||
|
s13 -= s22 * 997805;
|
||||||
|
s14 += s22 * 136657;
|
||||||
|
s15 -= s22 * 683901;
|
||||||
|
s22 = 0;
|
||||||
|
s9 += s21 * 666643;
|
||||||
|
s10 += s21 * 470296;
|
||||||
|
s11 += s21 * 654183;
|
||||||
|
s12 -= s21 * 997805;
|
||||||
|
s13 += s21 * 136657;
|
||||||
|
s14 -= s21 * 683901;
|
||||||
|
s21 = 0;
|
||||||
|
s8 += s20 * 666643;
|
||||||
|
s9 += s20 * 470296;
|
||||||
|
s10 += s20 * 654183;
|
||||||
|
s11 -= s20 * 997805;
|
||||||
|
s12 += s20 * 136657;
|
||||||
|
s13 -= s20 * 683901;
|
||||||
|
s20 = 0;
|
||||||
|
s7 += s19 * 666643;
|
||||||
|
s8 += s19 * 470296;
|
||||||
|
s9 += s19 * 654183;
|
||||||
|
s10 -= s19 * 997805;
|
||||||
|
s11 += s19 * 136657;
|
||||||
|
s12 -= s19 * 683901;
|
||||||
|
s19 = 0;
|
||||||
|
s6 += s18 * 666643;
|
||||||
|
s7 += s18 * 470296;
|
||||||
|
s8 += s18 * 654183;
|
||||||
|
s9 -= s18 * 997805;
|
||||||
|
s10 += s18 * 136657;
|
||||||
|
s11 -= s18 * 683901;
|
||||||
|
s18 = 0;
|
||||||
|
carry6 = (s6 + (1 << 20)) >> 21;
|
||||||
|
s7 += carry6;
|
||||||
|
s6 -= carry6 << 21;
|
||||||
|
carry8 = (s8 + (1 << 20)) >> 21;
|
||||||
|
s9 += carry8;
|
||||||
|
s8 -= carry8 << 21;
|
||||||
|
carry10 = (s10 + (1 << 20)) >> 21;
|
||||||
|
s11 += carry10;
|
||||||
|
s10 -= carry10 << 21;
|
||||||
|
carry12 = (s12 + (1 << 20)) >> 21;
|
||||||
|
s13 += carry12;
|
||||||
|
s12 -= carry12 << 21;
|
||||||
|
carry14 = (s14 + (1 << 20)) >> 21;
|
||||||
|
s15 += carry14;
|
||||||
|
s14 -= carry14 << 21;
|
||||||
|
carry16 = (s16 + (1 << 20)) >> 21;
|
||||||
|
s17 += carry16;
|
||||||
|
s16 -= carry16 << 21;
|
||||||
|
carry7 = (s7 + (1 << 20)) >> 21;
|
||||||
|
s8 += carry7;
|
||||||
|
s7 -= carry7 << 21;
|
||||||
|
carry9 = (s9 + (1 << 20)) >> 21;
|
||||||
|
s10 += carry9;
|
||||||
|
s9 -= carry9 << 21;
|
||||||
|
carry11 = (s11 + (1 << 20)) >> 21;
|
||||||
|
s12 += carry11;
|
||||||
|
s11 -= carry11 << 21;
|
||||||
|
carry13 = (s13 + (1 << 20)) >> 21;
|
||||||
|
s14 += carry13;
|
||||||
|
s13 -= carry13 << 21;
|
||||||
|
carry15 = (s15 + (1 << 20)) >> 21;
|
||||||
|
s16 += carry15;
|
||||||
|
s15 -= carry15 << 21;
|
||||||
|
s5 += s17 * 666643;
|
||||||
|
s6 += s17 * 470296;
|
||||||
|
s7 += s17 * 654183;
|
||||||
|
s8 -= s17 * 997805;
|
||||||
|
s9 += s17 * 136657;
|
||||||
|
s10 -= s17 * 683901;
|
||||||
|
s17 = 0;
|
||||||
|
s4 += s16 * 666643;
|
||||||
|
s5 += s16 * 470296;
|
||||||
|
s6 += s16 * 654183;
|
||||||
|
s7 -= s16 * 997805;
|
||||||
|
s8 += s16 * 136657;
|
||||||
|
s9 -= s16 * 683901;
|
||||||
|
s16 = 0;
|
||||||
|
s3 += s15 * 666643;
|
||||||
|
s4 += s15 * 470296;
|
||||||
|
s5 += s15 * 654183;
|
||||||
|
s6 -= s15 * 997805;
|
||||||
|
s7 += s15 * 136657;
|
||||||
|
s8 -= s15 * 683901;
|
||||||
|
s15 = 0;
|
||||||
|
s2 += s14 * 666643;
|
||||||
|
s3 += s14 * 470296;
|
||||||
|
s4 += s14 * 654183;
|
||||||
|
s5 -= s14 * 997805;
|
||||||
|
s6 += s14 * 136657;
|
||||||
|
s7 -= s14 * 683901;
|
||||||
|
s14 = 0;
|
||||||
|
s1 += s13 * 666643;
|
||||||
|
s2 += s13 * 470296;
|
||||||
|
s3 += s13 * 654183;
|
||||||
|
s4 -= s13 * 997805;
|
||||||
|
s5 += s13 * 136657;
|
||||||
|
s6 -= s13 * 683901;
|
||||||
|
s13 = 0;
|
||||||
|
s0 += s12 * 666643;
|
||||||
|
s1 += s12 * 470296;
|
||||||
|
s2 += s12 * 654183;
|
||||||
|
s3 -= s12 * 997805;
|
||||||
|
s4 += s12 * 136657;
|
||||||
|
s5 -= s12 * 683901;
|
||||||
|
s12 = 0;
|
||||||
|
carry0 = (s0 + (1 << 20)) >> 21;
|
||||||
|
s1 += carry0;
|
||||||
|
s0 -= carry0 << 21;
|
||||||
|
carry2 = (s2 + (1 << 20)) >> 21;
|
||||||
|
s3 += carry2;
|
||||||
|
s2 -= carry2 << 21;
|
||||||
|
carry4 = (s4 + (1 << 20)) >> 21;
|
||||||
|
s5 += carry4;
|
||||||
|
s4 -= carry4 << 21;
|
||||||
|
carry6 = (s6 + (1 << 20)) >> 21;
|
||||||
|
s7 += carry6;
|
||||||
|
s6 -= carry6 << 21;
|
||||||
|
carry8 = (s8 + (1 << 20)) >> 21;
|
||||||
|
s9 += carry8;
|
||||||
|
s8 -= carry8 << 21;
|
||||||
|
carry10 = (s10 + (1 << 20)) >> 21;
|
||||||
|
s11 += carry10;
|
||||||
|
s10 -= carry10 << 21;
|
||||||
|
carry1 = (s1 + (1 << 20)) >> 21;
|
||||||
|
s2 += carry1;
|
||||||
|
s1 -= carry1 << 21;
|
||||||
|
carry3 = (s3 + (1 << 20)) >> 21;
|
||||||
|
s4 += carry3;
|
||||||
|
s3 -= carry3 << 21;
|
||||||
|
carry5 = (s5 + (1 << 20)) >> 21;
|
||||||
|
s6 += carry5;
|
||||||
|
s5 -= carry5 << 21;
|
||||||
|
carry7 = (s7 + (1 << 20)) >> 21;
|
||||||
|
s8 += carry7;
|
||||||
|
s7 -= carry7 << 21;
|
||||||
|
carry9 = (s9 + (1 << 20)) >> 21;
|
||||||
|
s10 += carry9;
|
||||||
|
s9 -= carry9 << 21;
|
||||||
|
carry11 = (s11 + (1 << 20)) >> 21;
|
||||||
|
s12 += carry11;
|
||||||
|
s11 -= carry11 << 21;
|
||||||
|
s0 += s12 * 666643;
|
||||||
|
s1 += s12 * 470296;
|
||||||
|
s2 += s12 * 654183;
|
||||||
|
s3 -= s12 * 997805;
|
||||||
|
s4 += s12 * 136657;
|
||||||
|
s5 -= s12 * 683901;
|
||||||
|
s12 = 0;
|
||||||
|
carry0 = s0 >> 21;
|
||||||
|
s1 += carry0;
|
||||||
|
s0 -= carry0 << 21;
|
||||||
|
carry1 = s1 >> 21;
|
||||||
|
s2 += carry1;
|
||||||
|
s1 -= carry1 << 21;
|
||||||
|
carry2 = s2 >> 21;
|
||||||
|
s3 += carry2;
|
||||||
|
s2 -= carry2 << 21;
|
||||||
|
carry3 = s3 >> 21;
|
||||||
|
s4 += carry3;
|
||||||
|
s3 -= carry3 << 21;
|
||||||
|
carry4 = s4 >> 21;
|
||||||
|
s5 += carry4;
|
||||||
|
s4 -= carry4 << 21;
|
||||||
|
carry5 = s5 >> 21;
|
||||||
|
s6 += carry5;
|
||||||
|
s5 -= carry5 << 21;
|
||||||
|
carry6 = s6 >> 21;
|
||||||
|
s7 += carry6;
|
||||||
|
s6 -= carry6 << 21;
|
||||||
|
carry7 = s7 >> 21;
|
||||||
|
s8 += carry7;
|
||||||
|
s7 -= carry7 << 21;
|
||||||
|
carry8 = s8 >> 21;
|
||||||
|
s9 += carry8;
|
||||||
|
s8 -= carry8 << 21;
|
||||||
|
carry9 = s9 >> 21;
|
||||||
|
s10 += carry9;
|
||||||
|
s9 -= carry9 << 21;
|
||||||
|
carry10 = s10 >> 21;
|
||||||
|
s11 += carry10;
|
||||||
|
s10 -= carry10 << 21;
|
||||||
|
carry11 = s11 >> 21;
|
||||||
|
s12 += carry11;
|
||||||
|
s11 -= carry11 << 21;
|
||||||
|
s0 += s12 * 666643;
|
||||||
|
s1 += s12 * 470296;
|
||||||
|
s2 += s12 * 654183;
|
||||||
|
s3 -= s12 * 997805;
|
||||||
|
s4 += s12 * 136657;
|
||||||
|
s5 -= s12 * 683901;
|
||||||
|
s12 = 0;
|
||||||
|
carry0 = s0 >> 21;
|
||||||
|
s1 += carry0;
|
||||||
|
s0 -= carry0 << 21;
|
||||||
|
carry1 = s1 >> 21;
|
||||||
|
s2 += carry1;
|
||||||
|
s1 -= carry1 << 21;
|
||||||
|
carry2 = s2 >> 21;
|
||||||
|
s3 += carry2;
|
||||||
|
s2 -= carry2 << 21;
|
||||||
|
carry3 = s3 >> 21;
|
||||||
|
s4 += carry3;
|
||||||
|
s3 -= carry3 << 21;
|
||||||
|
carry4 = s4 >> 21;
|
||||||
|
s5 += carry4;
|
||||||
|
s4 -= carry4 << 21;
|
||||||
|
carry5 = s5 >> 21;
|
||||||
|
s6 += carry5;
|
||||||
|
s5 -= carry5 << 21;
|
||||||
|
carry6 = s6 >> 21;
|
||||||
|
s7 += carry6;
|
||||||
|
s6 -= carry6 << 21;
|
||||||
|
carry7 = s7 >> 21;
|
||||||
|
s8 += carry7;
|
||||||
|
s7 -= carry7 << 21;
|
||||||
|
carry8 = s8 >> 21;
|
||||||
|
s9 += carry8;
|
||||||
|
s8 -= carry8 << 21;
|
||||||
|
carry9 = s9 >> 21;
|
||||||
|
s10 += carry9;
|
||||||
|
s9 -= carry9 << 21;
|
||||||
|
carry10 = s10 >> 21;
|
||||||
|
s11 += carry10;
|
||||||
|
s10 -= carry10 << 21;
|
||||||
|
|
||||||
|
s[0] = (unsigned char) (s0 >> 0);
|
||||||
|
s[1] = (unsigned char) (s0 >> 8);
|
||||||
|
s[2] = (unsigned char) ((s0 >> 16) | (s1 << 5));
|
||||||
|
s[3] = (unsigned char) (s1 >> 3);
|
||||||
|
s[4] = (unsigned char) (s1 >> 11);
|
||||||
|
s[5] = (unsigned char) ((s1 >> 19) | (s2 << 2));
|
||||||
|
s[6] = (unsigned char) (s2 >> 6);
|
||||||
|
s[7] = (unsigned char) ((s2 >> 14) | (s3 << 7));
|
||||||
|
s[8] = (unsigned char) (s3 >> 1);
|
||||||
|
s[9] = (unsigned char) (s3 >> 9);
|
||||||
|
s[10] = (unsigned char) ((s3 >> 17) | (s4 << 4));
|
||||||
|
s[11] = (unsigned char) (s4 >> 4);
|
||||||
|
s[12] = (unsigned char) (s4 >> 12);
|
||||||
|
s[13] = (unsigned char) ((s4 >> 20) | (s5 << 1));
|
||||||
|
s[14] = (unsigned char) (s5 >> 7);
|
||||||
|
s[15] = (unsigned char) ((s5 >> 15) | (s6 << 6));
|
||||||
|
s[16] = (unsigned char) (s6 >> 2);
|
||||||
|
s[17] = (unsigned char) (s6 >> 10);
|
||||||
|
s[18] = (unsigned char) ((s6 >> 18) | (s7 << 3));
|
||||||
|
s[19] = (unsigned char) (s7 >> 5);
|
||||||
|
s[20] = (unsigned char) (s7 >> 13);
|
||||||
|
s[21] = (unsigned char) (s8 >> 0);
|
||||||
|
s[22] = (unsigned char) (s8 >> 8);
|
||||||
|
s[23] = (unsigned char) ((s8 >> 16) | (s9 << 5));
|
||||||
|
s[24] = (unsigned char) (s9 >> 3);
|
||||||
|
s[25] = (unsigned char) (s9 >> 11);
|
||||||
|
s[26] = (unsigned char) ((s9 >> 19) | (s10 << 2));
|
||||||
|
s[27] = (unsigned char) (s10 >> 6);
|
||||||
|
s[28] = (unsigned char) ((s10 >> 14) | (s11 << 7));
|
||||||
|
s[29] = (unsigned char) (s11 >> 1);
|
||||||
|
s[30] = (unsigned char) (s11 >> 9);
|
||||||
|
s[31] = (unsigned char) (s11 >> 17);
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
#ifndef SC_H
|
||||||
|
#define SC_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
The set of scalars is \Z/l
|
||||||
|
where l = 2^252 + 27742317777372353535851937790883648493.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void sc_reduce(unsigned char *s);
|
||||||
|
void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b, const unsigned char *c);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,40 @@
|
||||||
|
#include "ed25519.h"
|
||||||
|
|
||||||
|
#ifndef ED25519_NO_SEED
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#include <wincrypt.h>
|
||||||
|
#else
|
||||||
|
#include <stdio.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int ed25519_create_seed(unsigned char *seed) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
HCRYPTPROV prov;
|
||||||
|
|
||||||
|
if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CryptGenRandom(prov, 32, seed)) {
|
||||||
|
CryptReleaseContext(prov, 0);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
CryptReleaseContext(prov, 0);
|
||||||
|
#else
|
||||||
|
FILE *f = fopen("/dev/urandom", "rb");
|
||||||
|
|
||||||
|
if (f == NULL) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fread(seed, 1, 32, f);
|
||||||
|
fclose(f);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,275 @@
|
||||||
|
/* LibTomCrypt, modular cryptographic library -- Tom St Denis
|
||||||
|
*
|
||||||
|
* LibTomCrypt is a library that provides various cryptographic
|
||||||
|
* algorithms in a highly modular and flexible manner.
|
||||||
|
*
|
||||||
|
* The library is free for all purposes without any express
|
||||||
|
* guarantee it works.
|
||||||
|
*
|
||||||
|
* Tom St Denis, tomstdenis@gmail.com, http://libtom.org
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "fixedint.h"
|
||||||
|
#include "sha512.h"
|
||||||
|
|
||||||
|
/* the K array */
|
||||||
|
static const uint64_t K[80] = {
|
||||||
|
UINT64_C(0x428a2f98d728ae22), UINT64_C(0x7137449123ef65cd),
|
||||||
|
UINT64_C(0xb5c0fbcfec4d3b2f), UINT64_C(0xe9b5dba58189dbbc),
|
||||||
|
UINT64_C(0x3956c25bf348b538), UINT64_C(0x59f111f1b605d019),
|
||||||
|
UINT64_C(0x923f82a4af194f9b), UINT64_C(0xab1c5ed5da6d8118),
|
||||||
|
UINT64_C(0xd807aa98a3030242), UINT64_C(0x12835b0145706fbe),
|
||||||
|
UINT64_C(0x243185be4ee4b28c), UINT64_C(0x550c7dc3d5ffb4e2),
|
||||||
|
UINT64_C(0x72be5d74f27b896f), UINT64_C(0x80deb1fe3b1696b1),
|
||||||
|
UINT64_C(0x9bdc06a725c71235), UINT64_C(0xc19bf174cf692694),
|
||||||
|
UINT64_C(0xe49b69c19ef14ad2), UINT64_C(0xefbe4786384f25e3),
|
||||||
|
UINT64_C(0x0fc19dc68b8cd5b5), UINT64_C(0x240ca1cc77ac9c65),
|
||||||
|
UINT64_C(0x2de92c6f592b0275), UINT64_C(0x4a7484aa6ea6e483),
|
||||||
|
UINT64_C(0x5cb0a9dcbd41fbd4), UINT64_C(0x76f988da831153b5),
|
||||||
|
UINT64_C(0x983e5152ee66dfab), UINT64_C(0xa831c66d2db43210),
|
||||||
|
UINT64_C(0xb00327c898fb213f), UINT64_C(0xbf597fc7beef0ee4),
|
||||||
|
UINT64_C(0xc6e00bf33da88fc2), UINT64_C(0xd5a79147930aa725),
|
||||||
|
UINT64_C(0x06ca6351e003826f), UINT64_C(0x142929670a0e6e70),
|
||||||
|
UINT64_C(0x27b70a8546d22ffc), UINT64_C(0x2e1b21385c26c926),
|
||||||
|
UINT64_C(0x4d2c6dfc5ac42aed), UINT64_C(0x53380d139d95b3df),
|
||||||
|
UINT64_C(0x650a73548baf63de), UINT64_C(0x766a0abb3c77b2a8),
|
||||||
|
UINT64_C(0x81c2c92e47edaee6), UINT64_C(0x92722c851482353b),
|
||||||
|
UINT64_C(0xa2bfe8a14cf10364), UINT64_C(0xa81a664bbc423001),
|
||||||
|
UINT64_C(0xc24b8b70d0f89791), UINT64_C(0xc76c51a30654be30),
|
||||||
|
UINT64_C(0xd192e819d6ef5218), UINT64_C(0xd69906245565a910),
|
||||||
|
UINT64_C(0xf40e35855771202a), UINT64_C(0x106aa07032bbd1b8),
|
||||||
|
UINT64_C(0x19a4c116b8d2d0c8), UINT64_C(0x1e376c085141ab53),
|
||||||
|
UINT64_C(0x2748774cdf8eeb99), UINT64_C(0x34b0bcb5e19b48a8),
|
||||||
|
UINT64_C(0x391c0cb3c5c95a63), UINT64_C(0x4ed8aa4ae3418acb),
|
||||||
|
UINT64_C(0x5b9cca4f7763e373), UINT64_C(0x682e6ff3d6b2b8a3),
|
||||||
|
UINT64_C(0x748f82ee5defb2fc), UINT64_C(0x78a5636f43172f60),
|
||||||
|
UINT64_C(0x84c87814a1f0ab72), UINT64_C(0x8cc702081a6439ec),
|
||||||
|
UINT64_C(0x90befffa23631e28), UINT64_C(0xa4506cebde82bde9),
|
||||||
|
UINT64_C(0xbef9a3f7b2c67915), UINT64_C(0xc67178f2e372532b),
|
||||||
|
UINT64_C(0xca273eceea26619c), UINT64_C(0xd186b8c721c0c207),
|
||||||
|
UINT64_C(0xeada7dd6cde0eb1e), UINT64_C(0xf57d4f7fee6ed178),
|
||||||
|
UINT64_C(0x06f067aa72176fba), UINT64_C(0x0a637dc5a2c898a6),
|
||||||
|
UINT64_C(0x113f9804bef90dae), UINT64_C(0x1b710b35131c471b),
|
||||||
|
UINT64_C(0x28db77f523047d84), UINT64_C(0x32caab7b40c72493),
|
||||||
|
UINT64_C(0x3c9ebe0a15c9bebc), UINT64_C(0x431d67c49c100d4c),
|
||||||
|
UINT64_C(0x4cc5d4becb3e42b6), UINT64_C(0x597f299cfc657e2a),
|
||||||
|
UINT64_C(0x5fcb6fab3ad6faec), UINT64_C(0x6c44198c4a475817)
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Various logical functions */
|
||||||
|
|
||||||
|
#define ROR64c(x, y) \
|
||||||
|
( ((((x)&UINT64_C(0xFFFFFFFFFFFFFFFF))>>((uint64_t)(y)&UINT64_C(63))) | \
|
||||||
|
((x)<<((uint64_t)(64-((y)&UINT64_C(63)))))) & UINT64_C(0xFFFFFFFFFFFFFFFF))
|
||||||
|
|
||||||
|
#define STORE64H(x, y) \
|
||||||
|
{ (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
|
||||||
|
(y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
|
||||||
|
(y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
|
||||||
|
(y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
|
||||||
|
|
||||||
|
#define LOAD64H(x, y) \
|
||||||
|
{ x = (((uint64_t)((y)[0] & 255))<<56)|(((uint64_t)((y)[1] & 255))<<48) | \
|
||||||
|
(((uint64_t)((y)[2] & 255))<<40)|(((uint64_t)((y)[3] & 255))<<32) | \
|
||||||
|
(((uint64_t)((y)[4] & 255))<<24)|(((uint64_t)((y)[5] & 255))<<16) | \
|
||||||
|
(((uint64_t)((y)[6] & 255))<<8)|(((uint64_t)((y)[7] & 255))); }
|
||||||
|
|
||||||
|
|
||||||
|
#define Ch(x,y,z) (z ^ (x & (y ^ z)))
|
||||||
|
#define Maj(x,y,z) (((x | y) & z) | (x & y))
|
||||||
|
#define S(x, n) ROR64c(x, n)
|
||||||
|
#define R(x, n) (((x) &UINT64_C(0xFFFFFFFFFFFFFFFF))>>((uint64_t)n))
|
||||||
|
#define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39))
|
||||||
|
#define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41))
|
||||||
|
#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7))
|
||||||
|
#define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6))
|
||||||
|
#ifndef MIN
|
||||||
|
#define MIN(x, y) ( ((x)<(y))?(x):(y) )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* compress 1024-bits */
|
||||||
|
static int sha512_compress(sha512_context *md, unsigned char *buf)
|
||||||
|
{
|
||||||
|
uint64_t S[8], W[80], t0, t1;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* copy state into S */
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
S[i] = md->state[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* copy the state into 1024-bits into W[0..15] */
|
||||||
|
for (i = 0; i < 16; i++) {
|
||||||
|
LOAD64H(W[i], buf + (8*i));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fill W[16..79] */
|
||||||
|
for (i = 16; i < 80; i++) {
|
||||||
|
W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compress */
|
||||||
|
#define RND(a,b,c,d,e,f,g,h,i) \
|
||||||
|
t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \
|
||||||
|
t1 = Sigma0(a) + Maj(a, b, c);\
|
||||||
|
d += t0; \
|
||||||
|
h = t0 + t1;
|
||||||
|
|
||||||
|
for (i = 0; i < 80; i += 8) {
|
||||||
|
RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i+0);
|
||||||
|
RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],i+1);
|
||||||
|
RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],i+2);
|
||||||
|
RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],i+3);
|
||||||
|
RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],i+4);
|
||||||
|
RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],i+5);
|
||||||
|
RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],i+6);
|
||||||
|
RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],i+7);
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef RND
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* feedback */
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
md->state[i] = md->state[i] + S[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Initialize the hash state
|
||||||
|
@param md The hash state you wish to initialize
|
||||||
|
@return 0 if successful
|
||||||
|
*/
|
||||||
|
int sha512_init(sha512_context * md) {
|
||||||
|
if (md == NULL) return 1;
|
||||||
|
|
||||||
|
md->curlen = 0;
|
||||||
|
md->length = 0;
|
||||||
|
md->state[0] = UINT64_C(0x6a09e667f3bcc908);
|
||||||
|
md->state[1] = UINT64_C(0xbb67ae8584caa73b);
|
||||||
|
md->state[2] = UINT64_C(0x3c6ef372fe94f82b);
|
||||||
|
md->state[3] = UINT64_C(0xa54ff53a5f1d36f1);
|
||||||
|
md->state[4] = UINT64_C(0x510e527fade682d1);
|
||||||
|
md->state[5] = UINT64_C(0x9b05688c2b3e6c1f);
|
||||||
|
md->state[6] = UINT64_C(0x1f83d9abfb41bd6b);
|
||||||
|
md->state[7] = UINT64_C(0x5be0cd19137e2179);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Process a block of memory though the hash
|
||||||
|
@param md The hash state
|
||||||
|
@param in The data to hash
|
||||||
|
@param inlen The length of the data (octets)
|
||||||
|
@return 0 if successful
|
||||||
|
*/
|
||||||
|
int sha512_update (sha512_context * md, const unsigned char *in, size_t inlen)
|
||||||
|
{
|
||||||
|
size_t n;
|
||||||
|
size_t i;
|
||||||
|
int err;
|
||||||
|
if (md == NULL) return 1;
|
||||||
|
if (in == NULL) return 1;
|
||||||
|
if (md->curlen > sizeof(md->buf)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
while (inlen > 0) {
|
||||||
|
if (md->curlen == 0 && inlen >= 128) {
|
||||||
|
if ((err = sha512_compress (md, (unsigned char *)in)) != 0) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
md->length += 128 * 8;
|
||||||
|
in += 128;
|
||||||
|
inlen -= 128;
|
||||||
|
} else {
|
||||||
|
n = MIN(inlen, (128 - md->curlen));
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
md->buf[i + md->curlen] = in[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
md->curlen += n;
|
||||||
|
in += n;
|
||||||
|
inlen -= n;
|
||||||
|
if (md->curlen == 128) {
|
||||||
|
if ((err = sha512_compress (md, md->buf)) != 0) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
md->length += 8*128;
|
||||||
|
md->curlen = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Terminate the hash to get the digest
|
||||||
|
@param md The hash state
|
||||||
|
@param out [out] The destination of the hash (64 bytes)
|
||||||
|
@return 0 if successful
|
||||||
|
*/
|
||||||
|
int sha512_final(sha512_context * md, unsigned char *out)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (md == NULL) return 1;
|
||||||
|
if (out == NULL) return 1;
|
||||||
|
|
||||||
|
if (md->curlen >= sizeof(md->buf)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* increase the length of the message */
|
||||||
|
md->length += md->curlen * UINT64_C(8);
|
||||||
|
|
||||||
|
/* append the '1' bit */
|
||||||
|
md->buf[md->curlen++] = (unsigned char)0x80;
|
||||||
|
|
||||||
|
/* if the length is currently above 112 bytes we append zeros
|
||||||
|
* then compress. Then we can fall back to padding zeros and length
|
||||||
|
* encoding like normal.
|
||||||
|
*/
|
||||||
|
if (md->curlen > 112) {
|
||||||
|
while (md->curlen < 128) {
|
||||||
|
md->buf[md->curlen++] = (unsigned char)0;
|
||||||
|
}
|
||||||
|
sha512_compress(md, md->buf);
|
||||||
|
md->curlen = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* pad upto 120 bytes of zeroes
|
||||||
|
* note: that from 112 to 120 is the 64 MSB of the length. We assume that you won't hash
|
||||||
|
* > 2^64 bits of data... :-)
|
||||||
|
*/
|
||||||
|
while (md->curlen < 120) {
|
||||||
|
md->buf[md->curlen++] = (unsigned char)0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* store length */
|
||||||
|
STORE64H(md->length, md->buf+120);
|
||||||
|
sha512_compress(md, md->buf);
|
||||||
|
|
||||||
|
/* copy output */
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
STORE64H(md->state[i], out+(8*i));
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sha512(const unsigned char *message, size_t message_len, unsigned char *out)
|
||||||
|
{
|
||||||
|
sha512_context ctx;
|
||||||
|
int ret;
|
||||||
|
if ((ret = sha512_init(&ctx))) return ret;
|
||||||
|
if ((ret = sha512_update(&ctx, message, message_len))) return ret;
|
||||||
|
if ((ret = sha512_final(&ctx, out))) return ret;
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
#ifndef SHA512_H
|
||||||
|
#define SHA512_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "fixedint.h"
|
||||||
|
|
||||||
|
/* state */
|
||||||
|
typedef struct sha512_context_ {
|
||||||
|
uint64_t length, state[8];
|
||||||
|
size_t curlen;
|
||||||
|
unsigned char buf[128];
|
||||||
|
} sha512_context;
|
||||||
|
|
||||||
|
|
||||||
|
int sha512_init(sha512_context * md);
|
||||||
|
int sha512_final(sha512_context * md, unsigned char *out);
|
||||||
|
int sha512_update(sha512_context * md, const unsigned char *in, size_t inlen);
|
||||||
|
int sha512(const unsigned char *message, size_t message_len, unsigned char *out);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,31 @@
|
||||||
|
#include "ed25519.h"
|
||||||
|
#include "sha512.h"
|
||||||
|
#include "ge.h"
|
||||||
|
#include "sc.h"
|
||||||
|
|
||||||
|
|
||||||
|
void ed25519_sign(unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key, const unsigned char *private_key) {
|
||||||
|
sha512_context hash;
|
||||||
|
unsigned char hram[64];
|
||||||
|
unsigned char r[64];
|
||||||
|
ge_p3 R;
|
||||||
|
|
||||||
|
|
||||||
|
sha512_init(&hash);
|
||||||
|
sha512_update(&hash, private_key + 32, 32);
|
||||||
|
sha512_update(&hash, message, message_len);
|
||||||
|
sha512_final(&hash, r);
|
||||||
|
|
||||||
|
sc_reduce(r);
|
||||||
|
ge_scalarmult_base(&R, r);
|
||||||
|
ge_p3_tobytes(signature, &R);
|
||||||
|
|
||||||
|
sha512_init(&hash);
|
||||||
|
sha512_update(&hash, signature, 32);
|
||||||
|
sha512_update(&hash, public_key, 32);
|
||||||
|
sha512_update(&hash, message, message_len);
|
||||||
|
sha512_final(&hash, hram);
|
||||||
|
|
||||||
|
sc_reduce(hram);
|
||||||
|
sc_muladd(signature + 32, hram, private_key, r);
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
#include "ed25519.h"
|
||||||
|
#include "sha512.h"
|
||||||
|
#include "ge.h"
|
||||||
|
#include "sc.h"
|
||||||
|
|
||||||
|
static int consttime_equal(const unsigned char *x, const unsigned char *y) {
|
||||||
|
unsigned char r = 0;
|
||||||
|
|
||||||
|
r = x[0] ^ y[0];
|
||||||
|
#define F(i) r |= x[i] ^ y[i]
|
||||||
|
F(1);
|
||||||
|
F(2);
|
||||||
|
F(3);
|
||||||
|
F(4);
|
||||||
|
F(5);
|
||||||
|
F(6);
|
||||||
|
F(7);
|
||||||
|
F(8);
|
||||||
|
F(9);
|
||||||
|
F(10);
|
||||||
|
F(11);
|
||||||
|
F(12);
|
||||||
|
F(13);
|
||||||
|
F(14);
|
||||||
|
F(15);
|
||||||
|
F(16);
|
||||||
|
F(17);
|
||||||
|
F(18);
|
||||||
|
F(19);
|
||||||
|
F(20);
|
||||||
|
F(21);
|
||||||
|
F(22);
|
||||||
|
F(23);
|
||||||
|
F(24);
|
||||||
|
F(25);
|
||||||
|
F(26);
|
||||||
|
F(27);
|
||||||
|
F(28);
|
||||||
|
F(29);
|
||||||
|
F(30);
|
||||||
|
F(31);
|
||||||
|
#undef F
|
||||||
|
|
||||||
|
return !r;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ed25519_verify(const unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key) {
|
||||||
|
unsigned char h[64];
|
||||||
|
unsigned char checker[32];
|
||||||
|
sha512_context hash;
|
||||||
|
ge_p3 A;
|
||||||
|
ge_p2 R;
|
||||||
|
|
||||||
|
if (signature[63] & 224) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ge_frombytes_negate_vartime(&A, public_key) != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
sha512_init(&hash);
|
||||||
|
sha512_update(&hash, signature, 32);
|
||||||
|
sha512_update(&hash, public_key, 32);
|
||||||
|
sha512_update(&hash, message, message_len);
|
||||||
|
sha512_final(&hash, h);
|
||||||
|
|
||||||
|
sc_reduce(h);
|
||||||
|
ge_double_scalarmult_vartime(&R, h, &A, signature + 32);
|
||||||
|
ge_tobytes(checker, &R);
|
||||||
|
|
||||||
|
if (!consttime_equal(checker, signature)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
Copyright 2009-2010 Cybozu Labs, Inc.
|
||||||
|
Copyright 2011-2014 Kazuho Oku
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1 @@
|
||||||
|
// Just an empty compilation unit to make MSVC happy and emit a .lib.
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,47 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="picojson.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="picojson.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>{2C0D058E-DE35-4471-AD99-E68A2CAF9E18}</ProjectGuid>
|
||||||
|
<WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Label="Configuration">
|
||||||
|
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||||
|
<PlatformToolset>v141</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
<Import Project="..\..\Source\VSProps\Base.props" />
|
||||||
|
<Import Project="..\..\Source\VSProps\ClDisableAllWarnings.props" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="picojson.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="picojson.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
|
@ -7,6 +7,7 @@
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
#include "Common/ScopeGuard.h"
|
#include "Common/ScopeGuard.h"
|
||||||
|
@ -30,9 +31,14 @@ public:
|
||||||
size_t size);
|
size_t size);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<CURL, decltype(&curl_easy_cleanup)> m_curl{curl_easy_init(), curl_easy_cleanup};
|
static std::mutex s_curl_was_inited_mutex;
|
||||||
|
static bool s_curl_was_inited;
|
||||||
|
std::unique_ptr<CURL, decltype(&curl_easy_cleanup)> m_curl{nullptr, curl_easy_cleanup};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::mutex HttpRequest::Impl::s_curl_was_inited_mutex;
|
||||||
|
bool HttpRequest::Impl::s_curl_was_inited = false;
|
||||||
|
|
||||||
HttpRequest::HttpRequest(std::chrono::milliseconds timeout_ms)
|
HttpRequest::HttpRequest(std::chrono::milliseconds timeout_ms)
|
||||||
: m_impl(std::make_unique<Impl>(timeout_ms))
|
: m_impl(std::make_unique<Impl>(timeout_ms))
|
||||||
{
|
{
|
||||||
|
@ -65,6 +71,16 @@ HttpRequest::Response HttpRequest::Post(const std::string& url, const std::strin
|
||||||
|
|
||||||
HttpRequest::Impl::Impl(std::chrono::milliseconds timeout_ms)
|
HttpRequest::Impl::Impl(std::chrono::milliseconds timeout_ms)
|
||||||
{
|
{
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lk(s_curl_was_inited_mutex);
|
||||||
|
if (!s_curl_was_inited)
|
||||||
|
{
|
||||||
|
curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||||
|
s_curl_was_inited = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_curl.reset(curl_easy_init());
|
||||||
if (!m_curl)
|
if (!m_curl)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -81,6 +81,8 @@ var isStable = +("master" == branch || "stable" == branch);
|
||||||
// Get environment information.
|
// Get environment information.
|
||||||
var distributor = wshShell.ExpandEnvironmentStrings("%DOLPHIN_DISTRIBUTOR%");
|
var distributor = wshShell.ExpandEnvironmentStrings("%DOLPHIN_DISTRIBUTOR%");
|
||||||
if (distributor == "%DOLPHIN_DISTRIBUTOR%") distributor = "None";
|
if (distributor == "%DOLPHIN_DISTRIBUTOR%") distributor = "None";
|
||||||
|
var default_update_track = wshShell.ExpandEnvironmentStrings("%DOLPHIN_DEFAULT_UPDATE_TRACK%");
|
||||||
|
if (default_update_track == "%DOLPHIN_DEFAULT_UPDATE_TRACK%") default_update_track = "";
|
||||||
|
|
||||||
// remove hash (and trailing "-0" if needed) from description
|
// remove hash (and trailing "-0" if needed) from description
|
||||||
describe = describe.replace(/(-0)?-[^-]+(-dirty)?$/, '$2');
|
describe = describe.replace(/(-0)?-[^-]+(-dirty)?$/, '$2');
|
||||||
|
@ -90,7 +92,8 @@ var out_contents =
|
||||||
"#define SCM_DESC_STR \"" + describe + "\"\n" +
|
"#define SCM_DESC_STR \"" + describe + "\"\n" +
|
||||||
"#define SCM_BRANCH_STR \"" + branch + "\"\n" +
|
"#define SCM_BRANCH_STR \"" + branch + "\"\n" +
|
||||||
"#define SCM_IS_MASTER " + isStable + "\n" +
|
"#define SCM_IS_MASTER " + isStable + "\n" +
|
||||||
"#define SCM_DISTRIBUTOR_STR \"" + distributor + "\"\n";
|
"#define SCM_DISTRIBUTOR_STR \"" + distributor + "\"\n" +
|
||||||
|
"#define SCM_UPDATE_TRACK_STR \"" + default_update_track + "\"\n";
|
||||||
|
|
||||||
// check if file needs updating
|
// check if file needs updating
|
||||||
if (out_contents == GetFileContents(outfile))
|
if (out_contents == GetFileContents(outfile))
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "Common/MsgHandler.h"
|
#include "Common/MsgHandler.h"
|
||||||
#include "Common/NandPaths.h"
|
#include "Common/NandPaths.h"
|
||||||
#include "Common/StringUtil.h"
|
#include "Common/StringUtil.h"
|
||||||
|
#include "Common/scmrev.h"
|
||||||
|
|
||||||
#include "Core/Analytics.h"
|
#include "Core/Analytics.h"
|
||||||
#include "Core/Boot/Boot.h"
|
#include "Core/Boot/Boot.h"
|
||||||
|
@ -90,6 +91,7 @@ void SConfig::SaveSettings()
|
||||||
SaveNetworkSettings(ini);
|
SaveNetworkSettings(ini);
|
||||||
SaveBluetoothPassthroughSettings(ini);
|
SaveBluetoothPassthroughSettings(ini);
|
||||||
SaveUSBPassthroughSettings(ini);
|
SaveUSBPassthroughSettings(ini);
|
||||||
|
SaveAutoUpdateSettings(ini);
|
||||||
|
|
||||||
ini.Save(File::GetUserPath(F_DOLPHINCONFIG_IDX));
|
ini.Save(File::GetUserPath(F_DOLPHINCONFIG_IDX));
|
||||||
|
|
||||||
|
@ -369,6 +371,14 @@ void SConfig::SaveUSBPassthroughSettings(IniFile& ini)
|
||||||
section->Set("Devices", devices_string);
|
section->Set("Devices", devices_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SConfig::SaveAutoUpdateSettings(IniFile& ini)
|
||||||
|
{
|
||||||
|
IniFile::Section* section = ini.GetOrCreateSection("AutoUpdate");
|
||||||
|
|
||||||
|
section->Set("TrackForTesting", m_auto_update_track);
|
||||||
|
section->Set("HashOverride", m_auto_update_hash_override);
|
||||||
|
}
|
||||||
|
|
||||||
void SConfig::LoadSettings()
|
void SConfig::LoadSettings()
|
||||||
{
|
{
|
||||||
Config::Load();
|
Config::Load();
|
||||||
|
@ -390,6 +400,7 @@ void SConfig::LoadSettings()
|
||||||
LoadAnalyticsSettings(ini);
|
LoadAnalyticsSettings(ini);
|
||||||
LoadBluetoothPassthroughSettings(ini);
|
LoadBluetoothPassthroughSettings(ini);
|
||||||
LoadUSBPassthroughSettings(ini);
|
LoadUSBPassthroughSettings(ini);
|
||||||
|
LoadAutoUpdateSettings(ini);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SConfig::LoadGeneralSettings(IniFile& ini)
|
void SConfig::LoadGeneralSettings(IniFile& ini)
|
||||||
|
@ -669,6 +680,15 @@ void SConfig::LoadUSBPassthroughSettings(IniFile& ini)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SConfig::LoadAutoUpdateSettings(IniFile& ini)
|
||||||
|
{
|
||||||
|
IniFile::Section* section = ini.GetOrCreateSection("AutoUpdate");
|
||||||
|
|
||||||
|
// TODO: Rename and default to SCM_UPDATE_TRACK_STR when ready for general consumption.
|
||||||
|
section->Get("TrackForTesting", &m_auto_update_track, "");
|
||||||
|
section->Get("HashOverride", &m_auto_update_hash_override, "");
|
||||||
|
}
|
||||||
|
|
||||||
void SConfig::ResetRunningGameMetadata()
|
void SConfig::ResetRunningGameMetadata()
|
||||||
{
|
{
|
||||||
SetRunningGameMetadata("00000000", 0, 0, Core::TitleDatabase::TitleType::Other);
|
SetRunningGameMetadata("00000000", 0, 0, Core::TitleDatabase::TitleType::Other);
|
||||||
|
|
|
@ -315,6 +315,10 @@ struct SConfig
|
||||||
bool m_SSLDumpRootCA;
|
bool m_SSLDumpRootCA;
|
||||||
bool m_SSLDumpPeerCert;
|
bool m_SSLDumpPeerCert;
|
||||||
|
|
||||||
|
// Auto-update settings
|
||||||
|
std::string m_auto_update_track;
|
||||||
|
std::string m_auto_update_hash_override;
|
||||||
|
|
||||||
SConfig(const SConfig&) = delete;
|
SConfig(const SConfig&) = delete;
|
||||||
SConfig& operator=(const SConfig&) = delete;
|
SConfig& operator=(const SConfig&) = delete;
|
||||||
SConfig(SConfig&&) = delete;
|
SConfig(SConfig&&) = delete;
|
||||||
|
@ -348,6 +352,7 @@ private:
|
||||||
void SaveAnalyticsSettings(IniFile& ini);
|
void SaveAnalyticsSettings(IniFile& ini);
|
||||||
void SaveBluetoothPassthroughSettings(IniFile& ini);
|
void SaveBluetoothPassthroughSettings(IniFile& ini);
|
||||||
void SaveUSBPassthroughSettings(IniFile& ini);
|
void SaveUSBPassthroughSettings(IniFile& ini);
|
||||||
|
void SaveAutoUpdateSettings(IniFile& ini);
|
||||||
|
|
||||||
void LoadGeneralSettings(IniFile& ini);
|
void LoadGeneralSettings(IniFile& ini);
|
||||||
void LoadInterfaceSettings(IniFile& ini);
|
void LoadInterfaceSettings(IniFile& ini);
|
||||||
|
@ -362,6 +367,7 @@ private:
|
||||||
void LoadAnalyticsSettings(IniFile& ini);
|
void LoadAnalyticsSettings(IniFile& ini);
|
||||||
void LoadBluetoothPassthroughSettings(IniFile& ini);
|
void LoadBluetoothPassthroughSettings(IniFile& ini);
|
||||||
void LoadUSBPassthroughSettings(IniFile& ini);
|
void LoadUSBPassthroughSettings(IniFile& ini);
|
||||||
|
void LoadAutoUpdateSettings(IniFile& ini);
|
||||||
|
|
||||||
void SetRunningGameMetadata(const std::string& game_id, u64 title_id, u16 revision,
|
void SetRunningGameMetadata(const std::string& game_id, u64 title_id, u16 revision,
|
||||||
Core::TitleDatabase::TitleType type);
|
Core::TitleDatabase::TitleType type);
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
#include "Common/MsgHandler.h"
|
#include "Common/MsgHandler.h"
|
||||||
#include "Core/Analytics.h"
|
#include "Core/Analytics.h"
|
||||||
|
@ -19,6 +20,7 @@
|
||||||
#include "DolphinQt2/Resources.h"
|
#include "DolphinQt2/Resources.h"
|
||||||
#include "DolphinQt2/Settings.h"
|
#include "DolphinQt2/Settings.h"
|
||||||
#include "DolphinQt2/Translation.h"
|
#include "DolphinQt2/Translation.h"
|
||||||
|
#include "UICommon/AutoUpdate.h"
|
||||||
#include "UICommon/CommandLineParse.h"
|
#include "UICommon/CommandLineParse.h"
|
||||||
#include "UICommon/UICommon.h"
|
#include "UICommon/UICommon.h"
|
||||||
|
|
||||||
|
@ -49,6 +51,35 @@ static bool QtMsgAlertHandler(const char* caption, const char* text, bool yes_no
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: This should be replaced with something in a background thread, it performs a blocking
|
||||||
|
// HTTP query. It also needs a proper UI, and many other things. But right now it needs to be
|
||||||
|
// manually enabled through INI, so all these problems are ignored :)
|
||||||
|
class QtAutoUpdateChecker : public AutoUpdateChecker
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit QtAutoUpdateChecker(QWidget* parent) : m_parent(parent) {}
|
||||||
|
protected:
|
||||||
|
void OnUpdateAvailable(const NewVersionInformation& info) override
|
||||||
|
{
|
||||||
|
QMessageBox prompt(m_parent);
|
||||||
|
|
||||||
|
prompt.setIcon(QMessageBox::Question);
|
||||||
|
prompt.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
|
||||||
|
prompt.setText(QString::fromUtf8("Update Dolphin to version %1?")
|
||||||
|
.arg(QString::fromStdString(info.new_shortrev)));
|
||||||
|
|
||||||
|
const int answer = prompt.exec();
|
||||||
|
if (answer == QMessageBox::Yes)
|
||||||
|
{
|
||||||
|
TriggerUpdate(info);
|
||||||
|
m_parent->close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QWidget* m_parent;
|
||||||
|
};
|
||||||
|
|
||||||
// N.B. On Windows, this should be called from WinMain. Link against qtmain and specify
|
// N.B. On Windows, this should be called from WinMain. Link against qtmain and specify
|
||||||
// /SubSystem:Windows
|
// /SubSystem:Windows
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
|
@ -146,6 +177,9 @@ int main(int argc, char* argv[])
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
QtAutoUpdateChecker updater(&win);
|
||||||
|
updater.CheckForUpdate();
|
||||||
|
|
||||||
retval = app.exec();
|
retval = app.exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -279,6 +279,9 @@
|
||||||
<ProjectReference Include="$(CoreDir)VideoCommon\VideoCommon.vcxproj">
|
<ProjectReference Include="$(CoreDir)VideoCommon\VideoCommon.vcxproj">
|
||||||
<Project>{3de9ee35-3e91-4f27-a014-2866ad8c3fe3}</Project>
|
<Project>{3de9ee35-3e91-4f27-a014-2866ad8c3fe3}</Project>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\Updater\Updater.vcxproj">
|
||||||
|
<Project>{e4becbab-9c6e-41ab-bb56-f9d70ab6be03}</Project>
|
||||||
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
|
|
@ -0,0 +1,139 @@
|
||||||
|
// Copyright 2018 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "UICommon/AutoUpdate.h"
|
||||||
|
|
||||||
|
#include <picojson/picojson.h>
|
||||||
|
|
||||||
|
#include "Common/CommonPaths.h"
|
||||||
|
#include "Common/FileUtil.h"
|
||||||
|
#include "Common/HttpRequest.h"
|
||||||
|
#include "Common/Logging/Log.h"
|
||||||
|
#include "Common/StringUtil.h"
|
||||||
|
#include "Common/scmrev.h"
|
||||||
|
#include "Core/ConfigManager.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <Windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
bool SystemSupportsAutoUpdates()
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
const char UPDATER_FILENAME[] = "Updater.exe";
|
||||||
|
const char UPDATER_RELOC_FILENAME[] = "Updater.2.exe";
|
||||||
|
const char UPDATER_LOG_FILE[] = "Updater.log";
|
||||||
|
|
||||||
|
std::wstring MakeUpdaterCommandLine(const std::map<std::string, std::string>& flags)
|
||||||
|
{
|
||||||
|
std::wstring cmdline = UTF8ToUTF16(UPDATER_FILENAME) + L" "; // Start with a fake argv[0].
|
||||||
|
for (const auto& pair : flags)
|
||||||
|
{
|
||||||
|
std::string value = "--" + pair.first + "=" + pair.second;
|
||||||
|
value = ReplaceAll(value, "\"", "\\\""); // Escape double quotes.
|
||||||
|
value = "\"" + value + "\" ";
|
||||||
|
cmdline += UTF8ToUTF16(value);
|
||||||
|
}
|
||||||
|
return cmdline;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used to remove the relocated updater file once we don't need it anymore.
|
||||||
|
void CleanupFromPreviousUpdate()
|
||||||
|
{
|
||||||
|
std::string reloc_updater_path = File::GetExeDirectory() + DIR_SEP + UPDATER_RELOC_FILENAME;
|
||||||
|
File::Delete(reloc_updater_path);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void AutoUpdateChecker::CheckForUpdate()
|
||||||
|
{
|
||||||
|
// Don't bother checking if updates are not supported or not enabled.
|
||||||
|
if (SConfig::GetInstance().m_auto_update_track.empty() || !SystemSupportsAutoUpdates())
|
||||||
|
return;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
CleanupFromPreviousUpdate();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::string version_hash = SConfig::GetInstance().m_auto_update_hash_override.empty() ?
|
||||||
|
SCM_REV_STR :
|
||||||
|
SConfig::GetInstance().m_auto_update_hash_override;
|
||||||
|
std::string url = "https://dolphin-emu.org/update/check/v0/" +
|
||||||
|
SConfig::GetInstance().m_auto_update_track + "/" + version_hash;
|
||||||
|
|
||||||
|
Common::HttpRequest req{std::chrono::seconds{10}};
|
||||||
|
auto resp = req.Get(url);
|
||||||
|
if (!resp)
|
||||||
|
{
|
||||||
|
ERROR_LOG(COMMON, "Auto-update request failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::string contents(reinterpret_cast<char*>(resp->data()), resp->size());
|
||||||
|
INFO_LOG(COMMON, "Auto-update JSON response: %s", contents.c_str());
|
||||||
|
|
||||||
|
picojson::value json;
|
||||||
|
std::string err = picojson::parse(json, contents);
|
||||||
|
if (!err.empty())
|
||||||
|
{
|
||||||
|
ERROR_LOG(COMMON, "Invalid JSON received from auto-update service: %s", err.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
picojson::object obj = json.get<picojson::object>();
|
||||||
|
|
||||||
|
if (obj["status"].get<std::string>() != "outdated")
|
||||||
|
{
|
||||||
|
INFO_LOG(COMMON, "Auto-update status: we are up to date.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NewVersionInformation nvi;
|
||||||
|
nvi.this_manifest_url = obj["old"].get<picojson::object>()["manifest"].get<std::string>();
|
||||||
|
nvi.next_manifest_url = obj["new"].get<picojson::object>()["manifest"].get<std::string>();
|
||||||
|
nvi.content_store_url = obj["content-store"].get<std::string>();
|
||||||
|
nvi.new_shortrev = obj["new"].get<picojson::object>()["name"].get<std::string>();
|
||||||
|
nvi.new_hash = obj["new"].get<picojson::object>()["hash"].get<std::string>();
|
||||||
|
// TODO: generate the HTML changelog from the JSON information.
|
||||||
|
OnUpdateAvailable(nvi);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AutoUpdateChecker::TriggerUpdate(const AutoUpdateChecker::NewVersionInformation& info)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
std::map<std::string, std::string> updater_flags;
|
||||||
|
updater_flags["this-manifest-url"] = info.this_manifest_url;
|
||||||
|
updater_flags["next-manifest-url"] = info.next_manifest_url;
|
||||||
|
updater_flags["content-store-url"] = info.content_store_url;
|
||||||
|
updater_flags["parent-pid"] = std::to_string(GetCurrentProcessId());
|
||||||
|
updater_flags["install-base-path"] = File::GetExeDirectory();
|
||||||
|
updater_flags["log-file"] = File::GetExeDirectory() + DIR_SEP + UPDATER_LOG_FILE;
|
||||||
|
|
||||||
|
// Copy the updater so it can update itself if needed.
|
||||||
|
std::string updater_path = File::GetExeDirectory() + DIR_SEP + UPDATER_FILENAME;
|
||||||
|
std::string reloc_updater_path = File::GetExeDirectory() + DIR_SEP + UPDATER_RELOC_FILENAME;
|
||||||
|
File::Copy(updater_path, reloc_updater_path);
|
||||||
|
|
||||||
|
// Run the updater!
|
||||||
|
std::wstring command_line = MakeUpdaterCommandLine(updater_flags);
|
||||||
|
STARTUPINFO sinfo = {sizeof(info)};
|
||||||
|
PROCESS_INFORMATION pinfo;
|
||||||
|
INFO_LOG(COMMON, "Updater command line: %s", UTF16ToUTF8(command_line).c_str());
|
||||||
|
if (!CreateProcessW(UTF8ToUTF16(reloc_updater_path).c_str(),
|
||||||
|
const_cast<wchar_t*>(command_line.c_str()), nullptr, nullptr, FALSE, 0,
|
||||||
|
nullptr, nullptr, &sinfo, &pinfo))
|
||||||
|
{
|
||||||
|
ERROR_LOG(COMMON, "Could not start updater process: error=%d", GetLastError());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
// Copyright 2018 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
// This class defines all the logic for Dolphin auto-update checking. UI-specific elements have to
|
||||||
|
// be defined in a backend specific subclass.
|
||||||
|
class AutoUpdateChecker
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Initiates a check for updates in the background. Calls the OnUpdateAvailable callback if an
|
||||||
|
// update is available, does "nothing" otherwise.
|
||||||
|
void CheckForUpdate();
|
||||||
|
|
||||||
|
struct NewVersionInformation
|
||||||
|
{
|
||||||
|
// Name (5.0-1234) and revision hash of the new version.
|
||||||
|
std::string new_shortrev;
|
||||||
|
std::string new_hash;
|
||||||
|
|
||||||
|
// The full changelog in HTML format.
|
||||||
|
std::string changelog_html;
|
||||||
|
|
||||||
|
// Internals, to be passed to the updater binary.
|
||||||
|
std::string this_manifest_url;
|
||||||
|
std::string next_manifest_url;
|
||||||
|
std::string content_store_url;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Starts the updater process, which will wait in the background until the current process exits.
|
||||||
|
void TriggerUpdate(const NewVersionInformation& info);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void OnUpdateAvailable(const NewVersionInformation& info) = 0;
|
||||||
|
};
|
|
@ -1,4 +1,5 @@
|
||||||
set(SRCS
|
set(SRCS
|
||||||
|
AutoUpdate.cpp
|
||||||
CommandLineParse.cpp
|
CommandLineParse.cpp
|
||||||
Disassembler.cpp
|
Disassembler.cpp
|
||||||
GameFile.cpp
|
GameFile.cpp
|
||||||
|
|
|
@ -42,8 +42,12 @@
|
||||||
<ProjectReference Include="$(CoreDir)Core\Core.vcxproj">
|
<ProjectReference Include="$(CoreDir)Core\Core.vcxproj">
|
||||||
<Project>{E54CF649-140E-4255-81A5-30A673C1FB36}</Project>
|
<Project>{E54CF649-140E-4255-81A5-30A673C1FB36}</Project>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\..\..\Externals\picojson\picojson.vcxproj">
|
||||||
|
<Project>{2c0d058e-de35-4471-ad99-e68a2caf9e18}</Project>
|
||||||
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClCompile Include="AutoUpdate.cpp" />
|
||||||
<ClCompile Include="CommandLineParse.cpp" />
|
<ClCompile Include="CommandLineParse.cpp" />
|
||||||
<ClCompile Include="UICommon.cpp" />
|
<ClCompile Include="UICommon.cpp" />
|
||||||
<ClCompile Include="Disassembler.cpp" />
|
<ClCompile Include="Disassembler.cpp" />
|
||||||
|
@ -55,6 +59,7 @@
|
||||||
<ClCompile Include="GameFileCache.cpp" />
|
<ClCompile Include="GameFileCache.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClInclude Include="AutoUpdate.h" />
|
||||||
<ClInclude Include="CommandLineParse.h" />
|
<ClInclude Include="CommandLineParse.h" />
|
||||||
<ClInclude Include="UICommon.h" />
|
<ClInclude Include="UICommon.h" />
|
||||||
<ClInclude Include="Disassembler.h" />
|
<ClInclude Include="Disassembler.h" />
|
||||||
|
|
|
@ -0,0 +1,689 @@
|
||||||
|
// Copyright 2018 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <OptionParser.h>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <ed25519/ed25519.h>
|
||||||
|
#include <mbedtls/base64.h>
|
||||||
|
#include <mbedtls/sha256.h>
|
||||||
|
#include <optional>
|
||||||
|
#include <shellapi.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <zlib.h>
|
||||||
|
|
||||||
|
#include "Common/CommonPaths.h"
|
||||||
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "Common/FileUtil.h"
|
||||||
|
#include "Common/HttpRequest.h"
|
||||||
|
#include "Common/StringUtil.h"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
// Public key used to verify update manifests.
|
||||||
|
const u8 UPDATE_PUB_KEY[] = {0x2a, 0xb3, 0xd1, 0xdc, 0x6e, 0xf5, 0x07, 0xf6, 0xa0, 0x6c, 0x7c,
|
||||||
|
0x54, 0xdf, 0x54, 0xf4, 0x42, 0x80, 0xa6, 0x28, 0x8b, 0x6d, 0x70,
|
||||||
|
0x14, 0xb5, 0x4c, 0x34, 0x95, 0x20, 0x4d, 0xd4, 0xd3, 0x5d};
|
||||||
|
|
||||||
|
const char UPDATE_TEMP_DIR[] = "TempUpdate";
|
||||||
|
|
||||||
|
// Where to log updater output.
|
||||||
|
FILE* log_fp = stderr;
|
||||||
|
|
||||||
|
void FlushLog()
|
||||||
|
{
|
||||||
|
fflush(log_fp);
|
||||||
|
fclose(log_fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal representation of options passed on the command-line.
|
||||||
|
struct Options
|
||||||
|
{
|
||||||
|
std::string this_manifest_url;
|
||||||
|
std::string next_manifest_url;
|
||||||
|
std::string content_store_url;
|
||||||
|
std::string install_base_path;
|
||||||
|
std::optional<DWORD> parent_pid;
|
||||||
|
std::optional<std::string> log_file;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<std::string> CommandLineToUtf8Argv(PCWSTR command_line)
|
||||||
|
{
|
||||||
|
int nargs;
|
||||||
|
LPWSTR* tokenized = CommandLineToArgvW(command_line, &nargs);
|
||||||
|
if (!tokenized)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
std::vector<std::string> argv(nargs);
|
||||||
|
for (int i = 0; i < nargs; ++i)
|
||||||
|
{
|
||||||
|
argv[i] = UTF16ToUTF8(tokenized[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalFree(tokenized);
|
||||||
|
return argv;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<Options> ParseCommandLine(PCWSTR command_line)
|
||||||
|
{
|
||||||
|
using optparse::OptionParser;
|
||||||
|
|
||||||
|
OptionParser parser = OptionParser().prog("updater.exe").description("Dolphin Updater binary");
|
||||||
|
|
||||||
|
parser.add_option("--this-manifest-url")
|
||||||
|
.dest("this-manifest-url")
|
||||||
|
.help("URL to the update manifest for the currently installed version.")
|
||||||
|
.metavar("URL");
|
||||||
|
parser.add_option("--next-manifest-url")
|
||||||
|
.dest("next-manifest-url")
|
||||||
|
.help("URL to the update manifest for the to-be-installed version.")
|
||||||
|
.metavar("URL");
|
||||||
|
parser.add_option("--content-store-url")
|
||||||
|
.dest("content-store-url")
|
||||||
|
.help("Base URL of the content store where files to download are stored.")
|
||||||
|
.metavar("URL");
|
||||||
|
parser.add_option("--install-base-path")
|
||||||
|
.dest("install-base-path")
|
||||||
|
.help("Base path of the Dolphin install to be updated.")
|
||||||
|
.metavar("PATH");
|
||||||
|
parser.add_option("--log-file")
|
||||||
|
.dest("log-file")
|
||||||
|
.help("File where to log updater debug output.")
|
||||||
|
.metavar("PATH");
|
||||||
|
parser.add_option("--parent-pid")
|
||||||
|
.dest("parent-pid")
|
||||||
|
.type("int")
|
||||||
|
.help("(optional) PID of the parent process. The updater will wait for this process to "
|
||||||
|
"complete before proceeding.")
|
||||||
|
.metavar("PID");
|
||||||
|
|
||||||
|
std::vector<std::string> argv = CommandLineToUtf8Argv(command_line);
|
||||||
|
optparse::Values options = parser.parse_args(argv);
|
||||||
|
|
||||||
|
Options opts;
|
||||||
|
|
||||||
|
// Required arguments.
|
||||||
|
std::vector<std::string> required{"this-manifest-url", "next-manifest-url", "content-store-url",
|
||||||
|
"install-base-path"};
|
||||||
|
for (const auto& req : required)
|
||||||
|
{
|
||||||
|
if (!options.is_set(req))
|
||||||
|
{
|
||||||
|
parser.print_help();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
opts.this_manifest_url = options["this-manifest-url"];
|
||||||
|
opts.next_manifest_url = options["next-manifest-url"];
|
||||||
|
opts.content_store_url = options["content-store-url"];
|
||||||
|
opts.install_base_path = options["install-base-path"];
|
||||||
|
|
||||||
|
// Optional arguments.
|
||||||
|
if (options.is_set("parent-pid"))
|
||||||
|
opts.parent_pid = (DWORD)options.get("parent-pid");
|
||||||
|
if (options.is_set("log-file"))
|
||||||
|
opts.log_file = options["log-file"];
|
||||||
|
|
||||||
|
return opts;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::string> GzipInflate(const std::string& data)
|
||||||
|
{
|
||||||
|
z_stream zstrm;
|
||||||
|
zstrm.zalloc = nullptr;
|
||||||
|
zstrm.zfree = nullptr;
|
||||||
|
zstrm.opaque = nullptr;
|
||||||
|
zstrm.avail_in = static_cast<u32>(data.size());
|
||||||
|
zstrm.next_in = reinterpret_cast<u8*>(const_cast<char*>(data.data()));
|
||||||
|
|
||||||
|
// 16 + MAX_WBITS means gzip. Don't ask me.
|
||||||
|
inflateInit2(&zstrm, 16 + MAX_WBITS);
|
||||||
|
|
||||||
|
std::string out;
|
||||||
|
char buffer[4096];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
zstrm.avail_out = sizeof(buffer);
|
||||||
|
zstrm.next_out = reinterpret_cast<u8*>(buffer);
|
||||||
|
|
||||||
|
ret = inflate(&zstrm, 0);
|
||||||
|
out.append(buffer, sizeof(buffer) - zstrm.avail_out);
|
||||||
|
} while (ret == Z_OK);
|
||||||
|
|
||||||
|
inflateEnd(&zstrm);
|
||||||
|
|
||||||
|
if (ret != Z_STREAM_END)
|
||||||
|
{
|
||||||
|
fprintf(log_fp, "Could not read the data as gzip: error %d.\n", ret);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VerifySignature(const std::string& data, const std::string& b64_signature)
|
||||||
|
{
|
||||||
|
u8 signature[64]; // ed25519 sig size.
|
||||||
|
size_t sig_size;
|
||||||
|
|
||||||
|
if (mbedtls_base64_decode(signature, sizeof(signature), &sig_size,
|
||||||
|
reinterpret_cast<const u8*>(b64_signature.data()),
|
||||||
|
b64_signature.size()) ||
|
||||||
|
sig_size != sizeof(signature))
|
||||||
|
{
|
||||||
|
fprintf(log_fp, "Invalid base64: %s\n", b64_signature.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ed25519_verify(signature, reinterpret_cast<const u8*>(data.data()), data.size(),
|
||||||
|
UPDATE_PUB_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Manifest
|
||||||
|
{
|
||||||
|
using Filename = std::string;
|
||||||
|
using Hash = std::array<u8, 16>;
|
||||||
|
std::map<Filename, Hash> entries;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool HexDecode(const std::string& hex, u8* buffer, size_t size)
|
||||||
|
{
|
||||||
|
if (hex.size() != size * 2)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto DecodeNibble = [](char c) -> std::optional<u8> {
|
||||||
|
if (c >= '0' && c <= '9')
|
||||||
|
return static_cast<u8>(c - '0');
|
||||||
|
else if (c >= 'a' && c <= 'f')
|
||||||
|
return static_cast<u8>(c - 'a' + 10);
|
||||||
|
else if (c >= 'A' && c <= 'F')
|
||||||
|
return static_cast<u8>(c - 'A' + 10);
|
||||||
|
else
|
||||||
|
return {};
|
||||||
|
};
|
||||||
|
for (size_t i = 0; i < size; ++i)
|
||||||
|
{
|
||||||
|
std::optional<u8> high = DecodeNibble(hex[2 * i]);
|
||||||
|
std::optional<u8> low = DecodeNibble(hex[2 * i + 1]);
|
||||||
|
|
||||||
|
if (!high || !low)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
buffer[i] = (*high << 4) | *low;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string HexEncode(const u8* buffer, size_t size)
|
||||||
|
{
|
||||||
|
std::string out(size * 2, '\0');
|
||||||
|
|
||||||
|
for (size_t i = 0; i < size; ++i)
|
||||||
|
{
|
||||||
|
out[2 * i] = "0123456789abcdef"[buffer[i] >> 4];
|
||||||
|
out[2 * i + 1] = "0123456789abcdef"[buffer[i] & 0xF];
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<Manifest> ParseManifest(const std::string& manifest)
|
||||||
|
{
|
||||||
|
Manifest parsed;
|
||||||
|
size_t pos = 0;
|
||||||
|
|
||||||
|
while (pos < manifest.size())
|
||||||
|
{
|
||||||
|
size_t filename_end_pos = manifest.find('\t', pos);
|
||||||
|
if (filename_end_pos == std::string::npos)
|
||||||
|
{
|
||||||
|
fprintf(log_fp, "Manifest entry %zu: could not find filename end.\n", parsed.entries.size());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
size_t hash_end_pos = manifest.find('\n', filename_end_pos);
|
||||||
|
if (hash_end_pos == std::string::npos)
|
||||||
|
{
|
||||||
|
fprintf(log_fp, "Manifest entry %zu: could not find hash end.\n", parsed.entries.size());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string filename = manifest.substr(pos, filename_end_pos - pos);
|
||||||
|
std::string hash = manifest.substr(filename_end_pos + 1, hash_end_pos - filename_end_pos - 1);
|
||||||
|
if (hash.size() != 32)
|
||||||
|
{
|
||||||
|
fprintf(log_fp, "Manifest entry %zu: invalid hash: \"%s\".\n", parsed.entries.size(),
|
||||||
|
hash.c_str());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
Manifest::Hash decoded_hash;
|
||||||
|
if (!HexDecode(hash, decoded_hash.data(), decoded_hash.size()))
|
||||||
|
{
|
||||||
|
fprintf(log_fp, "Manifest entry %zu: invalid hash: \"%s\".\n", parsed.entries.size(),
|
||||||
|
hash.c_str());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
parsed.entries[filename] = decoded_hash;
|
||||||
|
pos = hash_end_pos + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<Manifest> FetchAndParseManifest(const std::string& url)
|
||||||
|
{
|
||||||
|
Common::HttpRequest http;
|
||||||
|
|
||||||
|
Common::HttpRequest::Response resp = http.Get(url);
|
||||||
|
if (!resp)
|
||||||
|
{
|
||||||
|
fprintf(log_fp, "Manifest download failed.\n");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string contents(reinterpret_cast<char*>(resp->data()), resp->size());
|
||||||
|
std::optional<std::string> maybe_decompressed = GzipInflate(contents);
|
||||||
|
if (!maybe_decompressed)
|
||||||
|
return {};
|
||||||
|
std::string decompressed = std::move(*maybe_decompressed);
|
||||||
|
|
||||||
|
// Split into manifest and signature.
|
||||||
|
size_t boundary = decompressed.rfind("\n\n");
|
||||||
|
if (boundary == std::string::npos)
|
||||||
|
{
|
||||||
|
fprintf(log_fp, "No signature was found in manifest.\n");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string signature_block = decompressed.substr(boundary + 2); // 2 for "\n\n".
|
||||||
|
decompressed.resize(boundary + 1); // 1 to keep the final "\n".
|
||||||
|
|
||||||
|
std::vector<std::string> signatures = SplitString(signature_block, '\n');
|
||||||
|
bool found_valid_signature = false;
|
||||||
|
for (const auto& signature : signatures)
|
||||||
|
{
|
||||||
|
if (VerifySignature(decompressed, signature))
|
||||||
|
{
|
||||||
|
found_valid_signature = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found_valid_signature)
|
||||||
|
{
|
||||||
|
fprintf(log_fp, "Could not verify signature of the manifest.\n");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return ParseManifest(decompressed);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Represent the operations to be performed by the updater.
|
||||||
|
struct TodoList
|
||||||
|
{
|
||||||
|
std::vector<Manifest::Hash> to_download;
|
||||||
|
|
||||||
|
struct UpdateOp
|
||||||
|
{
|
||||||
|
Manifest::Filename filename;
|
||||||
|
std::optional<Manifest::Hash> old_hash;
|
||||||
|
Manifest::Hash new_hash;
|
||||||
|
};
|
||||||
|
std::vector<UpdateOp> to_update;
|
||||||
|
|
||||||
|
struct DeleteOp
|
||||||
|
{
|
||||||
|
Manifest::Filename filename;
|
||||||
|
Manifest::Hash old_hash;
|
||||||
|
};
|
||||||
|
std::vector<DeleteOp> to_delete;
|
||||||
|
|
||||||
|
void Log() const
|
||||||
|
{
|
||||||
|
if (to_update.size())
|
||||||
|
{
|
||||||
|
fprintf(log_fp, "Updating:\n");
|
||||||
|
for (const auto& op : to_update)
|
||||||
|
{
|
||||||
|
std::string old_desc =
|
||||||
|
op.old_hash ? HexEncode(op.old_hash->data(), op.old_hash->size()) : "(new)";
|
||||||
|
fprintf(log_fp, " - %s: %s -> %s\n", op.filename.c_str(), old_desc.c_str(),
|
||||||
|
HexEncode(op.new_hash.data(), op.new_hash.size()).c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (to_delete.size())
|
||||||
|
{
|
||||||
|
fprintf(log_fp, "Deleting:\n");
|
||||||
|
for (const auto& op : to_delete)
|
||||||
|
{
|
||||||
|
fprintf(log_fp, " - %s (%s)\n", op.filename.c_str(),
|
||||||
|
HexEncode(op.old_hash.data(), op.old_hash.size()).c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TodoList ComputeActionsToDo(Manifest this_manifest, Manifest next_manifest)
|
||||||
|
{
|
||||||
|
TodoList todo;
|
||||||
|
|
||||||
|
// Delete if present in this manifest but not in next manifest.
|
||||||
|
for (const auto& entry : this_manifest.entries)
|
||||||
|
{
|
||||||
|
if (next_manifest.entries.find(entry.first) == next_manifest.entries.end())
|
||||||
|
{
|
||||||
|
TodoList::DeleteOp del;
|
||||||
|
del.filename = entry.first;
|
||||||
|
del.old_hash = entry.second;
|
||||||
|
todo.to_delete.push_back(std::move(del));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Download and update if present in next manifest with different hash from this manifest.
|
||||||
|
for (const auto& entry : next_manifest.entries)
|
||||||
|
{
|
||||||
|
std::optional<Manifest::Hash> old_hash;
|
||||||
|
|
||||||
|
const auto& old_entry = this_manifest.entries.find(entry.first);
|
||||||
|
if (old_entry != this_manifest.entries.end())
|
||||||
|
old_hash = old_entry->second;
|
||||||
|
|
||||||
|
if (!old_hash || *old_hash != entry.second)
|
||||||
|
{
|
||||||
|
todo.to_download.push_back(entry.second);
|
||||||
|
|
||||||
|
TodoList::UpdateOp update;
|
||||||
|
update.filename = entry.first;
|
||||||
|
update.old_hash = old_hash;
|
||||||
|
update.new_hash = entry.second;
|
||||||
|
todo.to_update.push_back(std::move(update));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return todo;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::string> FindOrCreateTempDir(const std::string& base_path)
|
||||||
|
{
|
||||||
|
std::string temp_path = base_path + DIR_SEP + UPDATE_TEMP_DIR;
|
||||||
|
int counter = 0;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (!File::Exists(temp_path))
|
||||||
|
{
|
||||||
|
if (File::CreateDir(temp_path))
|
||||||
|
return temp_path;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf(log_fp, "Couldn't create temp directory.\n");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (File::IsDirectory(temp_path))
|
||||||
|
{
|
||||||
|
return temp_path;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Try again with a counter appended to the path.
|
||||||
|
std::string suffix = UPDATE_TEMP_DIR + std::to_string(counter);
|
||||||
|
temp_path = base_path + DIR_SEP + suffix;
|
||||||
|
}
|
||||||
|
} while (counter++ < 10);
|
||||||
|
|
||||||
|
fprintf(log_fp, "Could not find an appropriate temp directory name. Giving up.\n");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void CleanUpTempDir(const std::string& temp_dir, const TodoList& todo)
|
||||||
|
{
|
||||||
|
// This is best-effort cleanup, we ignore most errors.
|
||||||
|
for (const auto& hash : todo.to_download)
|
||||||
|
File::Delete(temp_dir + DIR_SEP + HexEncode(hash.data(), hash.size()));
|
||||||
|
File::DeleteDir(temp_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
Manifest::Hash ComputeHash(const std::string& contents)
|
||||||
|
{
|
||||||
|
std::array<u8, 32> full;
|
||||||
|
mbedtls_sha256(reinterpret_cast<const u8*>(contents.data()), contents.size(), full.data(), false);
|
||||||
|
|
||||||
|
Manifest::Hash out;
|
||||||
|
std::copy(full.begin(), full.begin() + 16, out.begin());
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DownloadContent(const std::vector<Manifest::Hash>& to_download,
|
||||||
|
const std::string& content_base_url, const std::string& temp_path)
|
||||||
|
{
|
||||||
|
Common::HttpRequest req;
|
||||||
|
for (const auto& h : to_download)
|
||||||
|
{
|
||||||
|
std::string hash_filename = HexEncode(h.data(), h.size());
|
||||||
|
|
||||||
|
// Add slashes where needed.
|
||||||
|
std::string content_store_path = hash_filename;
|
||||||
|
content_store_path.insert(4, "/");
|
||||||
|
content_store_path.insert(2, "/");
|
||||||
|
|
||||||
|
std::string url = content_base_url + content_store_path;
|
||||||
|
fprintf(log_fp, "Downloading %s ...\n", url.c_str());
|
||||||
|
auto resp = req.Get(url);
|
||||||
|
if (!resp)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
std::string contents(reinterpret_cast<char*>(resp->data()), resp->size());
|
||||||
|
std::optional<std::string> maybe_decompressed = GzipInflate(contents);
|
||||||
|
if (!maybe_decompressed)
|
||||||
|
return false;
|
||||||
|
std::string decompressed = std::move(*maybe_decompressed);
|
||||||
|
|
||||||
|
// Check that the downloaded contents have the right hash.
|
||||||
|
Manifest::Hash contents_hash = ComputeHash(decompressed);
|
||||||
|
if (contents_hash != h)
|
||||||
|
{
|
||||||
|
fprintf(log_fp, "Wrong hash on downloaded content %s.\n", url.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string out = temp_path + DIR_SEP + hash_filename;
|
||||||
|
if (!File::WriteStringToFile(decompressed, out))
|
||||||
|
{
|
||||||
|
fprintf(log_fp, "Could not write cache file %s.\n", out.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BackupFile(const std::string& path)
|
||||||
|
{
|
||||||
|
std::string backup_path = path + ".bak";
|
||||||
|
fprintf(log_fp, "Backing up unknown pre-existing %s to .bak.\n", path.c_str());
|
||||||
|
if (!File::Rename(path, backup_path))
|
||||||
|
{
|
||||||
|
fprintf(log_fp, "Cound not rename %s to %s for backup.\n", path.c_str(), backup_path.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UpdateFiles(const std::vector<TodoList::UpdateOp>& to_update,
|
||||||
|
const std::string& install_base_path, const std::string& temp_path)
|
||||||
|
{
|
||||||
|
for (const auto& op : to_update)
|
||||||
|
{
|
||||||
|
std::string path = install_base_path + DIR_SEP + op.filename;
|
||||||
|
if (!File::CreateFullPath(path))
|
||||||
|
{
|
||||||
|
fprintf(log_fp, "Could not create directory structure for %s.\n", op.filename.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (File::Exists(path))
|
||||||
|
{
|
||||||
|
std::string contents;
|
||||||
|
if (!File::ReadFileToString(path, contents))
|
||||||
|
{
|
||||||
|
fprintf(log_fp, "Could not read existing file %s.\n", op.filename.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Manifest::Hash contents_hash = ComputeHash(contents);
|
||||||
|
if (contents_hash == op.new_hash)
|
||||||
|
{
|
||||||
|
fprintf(log_fp, "File %s was already up to date. Partial update?\n", op.filename.c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (!op.old_hash || contents_hash != *op.old_hash)
|
||||||
|
{
|
||||||
|
if (!BackupFile(path))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we can safely move the new contents to the location.
|
||||||
|
std::string content_filename = HexEncode(op.new_hash.data(), op.new_hash.size());
|
||||||
|
fprintf(log_fp, "Updating file %s from content %s...\n", op.filename.c_str(),
|
||||||
|
content_filename.c_str());
|
||||||
|
if (!File::Rename(temp_path + DIR_SEP + content_filename, path))
|
||||||
|
{
|
||||||
|
fprintf(log_fp, "Could not update file %s.\n", op.filename.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeleteObsoleteFiles(const std::vector<TodoList::DeleteOp>& to_delete,
|
||||||
|
const std::string& install_base_path)
|
||||||
|
{
|
||||||
|
for (const auto& op : to_delete)
|
||||||
|
{
|
||||||
|
std::string path = install_base_path + DIR_SEP + op.filename;
|
||||||
|
|
||||||
|
if (!File::Exists(path))
|
||||||
|
{
|
||||||
|
fprintf(log_fp, "File %s is already missing.\n", op.filename.c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::string contents;
|
||||||
|
if (!File::ReadFileToString(path, contents))
|
||||||
|
{
|
||||||
|
fprintf(log_fp, "Could not read file planned for deletion: %s.\n", op.filename.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Manifest::Hash contents_hash = ComputeHash(contents);
|
||||||
|
if (contents_hash != op.old_hash)
|
||||||
|
{
|
||||||
|
if (!BackupFile(path))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
File::Delete(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PerformUpdate(const TodoList& todo, const std::string& install_base_path,
|
||||||
|
const std::string& content_base_url, const std::string& temp_path)
|
||||||
|
{
|
||||||
|
fprintf(log_fp, "Starting download step...\n");
|
||||||
|
if (!DownloadContent(todo.to_download, content_base_url, temp_path))
|
||||||
|
return false;
|
||||||
|
fprintf(log_fp, "Download step completed.\n");
|
||||||
|
|
||||||
|
fprintf(log_fp, "Starting update step...\n");
|
||||||
|
if (!UpdateFiles(todo.to_update, install_base_path, temp_path))
|
||||||
|
return false;
|
||||||
|
fprintf(log_fp, "Update step completed.\n");
|
||||||
|
|
||||||
|
fprintf(log_fp, "Starting deletion step...\n");
|
||||||
|
if (!DeleteObsoleteFiles(todo.to_delete, install_base_path))
|
||||||
|
return false;
|
||||||
|
fprintf(log_fp, "Deletion step completed.\n");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
|
||||||
|
{
|
||||||
|
std::optional<Options> maybe_opts = ParseCommandLine(pCmdLine);
|
||||||
|
if (!maybe_opts)
|
||||||
|
return 1;
|
||||||
|
Options opts = std::move(*maybe_opts);
|
||||||
|
|
||||||
|
if (opts.log_file)
|
||||||
|
{
|
||||||
|
log_fp = _wfopen(UTF8ToUTF16(*opts.log_file).c_str(), L"w");
|
||||||
|
if (!log_fp)
|
||||||
|
log_fp = stderr;
|
||||||
|
else
|
||||||
|
atexit(FlushLog);
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(log_fp, "Updating from: %s\n", opts.this_manifest_url.c_str());
|
||||||
|
fprintf(log_fp, "Updating to: %s\n", opts.next_manifest_url.c_str());
|
||||||
|
fprintf(log_fp, "Install path: %s\n", opts.install_base_path.c_str());
|
||||||
|
|
||||||
|
if (!File::IsDirectory(opts.install_base_path))
|
||||||
|
{
|
||||||
|
fprintf(log_fp, "Cannot find install base path, or not a directory.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.parent_pid)
|
||||||
|
{
|
||||||
|
fprintf(log_fp, "Waiting for parent PID %d to complete...\n", *opts.parent_pid);
|
||||||
|
HANDLE parent_handle = OpenProcess(SYNCHRONIZE, FALSE, *opts.parent_pid);
|
||||||
|
WaitForSingleObject(parent_handle, INFINITE);
|
||||||
|
CloseHandle(parent_handle);
|
||||||
|
fprintf(log_fp, "Completed! Proceeding with update.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
Manifest this_manifest, next_manifest;
|
||||||
|
{
|
||||||
|
std::optional<Manifest> maybe_manifest = FetchAndParseManifest(opts.this_manifest_url);
|
||||||
|
if (!maybe_manifest)
|
||||||
|
{
|
||||||
|
fprintf(log_fp, "Could not fetch current manifest. Aborting.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
this_manifest = std::move(*maybe_manifest);
|
||||||
|
|
||||||
|
maybe_manifest = FetchAndParseManifest(opts.next_manifest_url);
|
||||||
|
if (!maybe_manifest)
|
||||||
|
{
|
||||||
|
fprintf(log_fp, "Could not fetch next manifest. Aborting.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
next_manifest = std::move(*maybe_manifest);
|
||||||
|
}
|
||||||
|
|
||||||
|
TodoList todo = ComputeActionsToDo(this_manifest, next_manifest);
|
||||||
|
todo.Log();
|
||||||
|
|
||||||
|
std::optional<std::string> maybe_temp_dir = FindOrCreateTempDir(opts.install_base_path);
|
||||||
|
if (!maybe_temp_dir)
|
||||||
|
return 1;
|
||||||
|
std::string temp_dir = std::move(*maybe_temp_dir);
|
||||||
|
|
||||||
|
bool ok = PerformUpdate(todo, opts.install_base_path, opts.content_store_url, temp_dir);
|
||||||
|
if (!ok)
|
||||||
|
fprintf(log_fp, "Failed to apply the update.\n");
|
||||||
|
|
||||||
|
CleanUpTempDir(temp_dir, todo);
|
||||||
|
return !ok;
|
||||||
|
}
|
|
@ -0,0 +1,78 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>{E4BECBAB-9C6E-41AB-BB56-F9D70AB6BE03}</ProjectGuid>
|
||||||
|
<WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<PlatformToolset>v141</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
<Import Project="..\..\VSProps\Base.props" />
|
||||||
|
<Import Project="..\..\VSProps\PCHUse.props" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup />
|
||||||
|
<ItemDefinitionGroup>
|
||||||
|
<Link>
|
||||||
|
<AdditionalDependencies>iphlpapi.lib;winmm.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\Externals\cpp-optparse\cpp-optparse.vcxproj">
|
||||||
|
<Project>{c636d9d1-82fe-42b5-9987-63b7d4836341}</Project>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\..\..\Externals\curl\curl.vcxproj">
|
||||||
|
<Project>{bb00605c-125f-4a21-b33b-7bf418322dcb}</Project>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\..\..\externals\ed25519\ed25519.vcxproj">
|
||||||
|
<Project>{5bdf4b91-1491-4fb0-bc27-78e9a8e97dc3}</Project>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\..\..\Externals\mbedtls\mbedTLS.vcxproj">
|
||||||
|
<Project>{bdb6578b-0691-4e80-a46c-df21639fd3b8}</Project>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\..\..\Externals\zlib\zlib.vcxproj">
|
||||||
|
<Project>{ff213b23-2c26-4214-9f88-85271e557e87}</Project>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\Common\Common.vcxproj">
|
||||||
|
<Project>{2e6c348c-c75c-4d94-8d1e-9c1fcbf3efe4}</Project>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="Main.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
<!--Copy the .exe to binary output folder-->
|
||||||
|
<ItemGroup>
|
||||||
|
<SourceFiles Include="$(TargetPath)" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Target Name="AfterBuild" Inputs="@(SourceFiles)" Outputs="@(SourceFiles -> '$(BinaryOutputDir)%(Filename)%(Extension)')">
|
||||||
|
<Message Text="Copy: @(SourceFiles) -> $(BinaryOutputDir)" Importance="High" />
|
||||||
|
<Copy SourceFiles="@(SourceFiles)" DestinationFolder="$(BinaryOutputDir)" />
|
||||||
|
</Target>
|
||||||
|
</Project>
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="Main.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 15
|
# Visual Studio 15
|
||||||
VisualStudioVersion = 15.0.26430.12
|
VisualStudioVersion = 15.0.26430.14
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Dolphin", "Core\DolphinWX\DolphinWX.vcxproj", "{47411FDB-1BF2-48D0-AB4E-C7C41160F898}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Dolphin", "Core\DolphinWX\DolphinWX.vcxproj", "{47411FDB-1BF2-48D0-AB4E-C7C41160F898}"
|
||||||
EndProject
|
EndProject
|
||||||
|
@ -83,6 +83,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cubeb", "..\Externals\cubeb
|
||||||
EndProject
|
EndProject
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pugixml", "..\Externals\pugixml\pugixml.vcxproj", "{38FEE76F-F347-484B-949C-B4649381CFFB}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pugixml", "..\Externals\pugixml\pugixml.vcxproj", "{38FEE76F-F347-484B-949C-B4649381CFFB}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "picojson", "..\Externals\picojson\picojson.vcxproj", "{2C0D058E-DE35-4471-AD99-E68A2CAF9E18}"
|
||||||
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ed25519", "..\externals\ed25519\ed25519.vcxproj", "{5BDF4B91-1491-4FB0-BC27-78E9A8E97DC3}"
|
||||||
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Updater", "Core\Updater\Updater.vcxproj", "{E4BECBAB-9C6E-41AB-BB56-F9D70AB6BE03}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|x64 = Debug|x64
|
Debug|x64 = Debug|x64
|
||||||
|
@ -237,6 +243,18 @@ Global
|
||||||
{38FEE76F-F347-484B-949C-B4649381CFFB}.Debug|x64.Build.0 = Debug|x64
|
{38FEE76F-F347-484B-949C-B4649381CFFB}.Debug|x64.Build.0 = Debug|x64
|
||||||
{38FEE76F-F347-484B-949C-B4649381CFFB}.Release|x64.ActiveCfg = Release|x64
|
{38FEE76F-F347-484B-949C-B4649381CFFB}.Release|x64.ActiveCfg = Release|x64
|
||||||
{38FEE76F-F347-484B-949C-B4649381CFFB}.Release|x64.Build.0 = Release|x64
|
{38FEE76F-F347-484B-949C-B4649381CFFB}.Release|x64.Build.0 = Release|x64
|
||||||
|
{2C0D058E-DE35-4471-AD99-E68A2CAF9E18}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{2C0D058E-DE35-4471-AD99-E68A2CAF9E18}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{2C0D058E-DE35-4471-AD99-E68A2CAF9E18}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{2C0D058E-DE35-4471-AD99-E68A2CAF9E18}.Release|x64.Build.0 = Release|x64
|
||||||
|
{5BDF4B91-1491-4FB0-BC27-78E9A8E97DC3}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{5BDF4B91-1491-4FB0-BC27-78E9A8E97DC3}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{5BDF4B91-1491-4FB0-BC27-78E9A8E97DC3}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{5BDF4B91-1491-4FB0-BC27-78E9A8E97DC3}.Release|x64.Build.0 = Release|x64
|
||||||
|
{E4BECBAB-9C6E-41AB-BB56-F9D70AB6BE03}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{E4BECBAB-9C6E-41AB-BB56-F9D70AB6BE03}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{E4BECBAB-9C6E-41AB-BB56-F9D70AB6BE03}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{E4BECBAB-9C6E-41AB-BB56-F9D70AB6BE03}.Release|x64.Build.0 = Release|x64
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
@ -274,5 +292,7 @@ Global
|
||||||
{C636D9D1-82FE-42B5-9987-63B7D4836341} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}
|
{C636D9D1-82FE-42B5-9987-63B7D4836341} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}
|
||||||
{8EA11166-6512-44FC-B7A5-A4D1ECC81170} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}
|
{8EA11166-6512-44FC-B7A5-A4D1ECC81170} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}
|
||||||
{38FEE76F-F347-484B-949C-B4649381CFFB} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}
|
{38FEE76F-F347-484B-949C-B4649381CFFB} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}
|
||||||
|
{2C0D058E-DE35-4471-AD99-E68A2CAF9E18} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}
|
||||||
|
{5BDF4B91-1491-4FB0-BC27-78E9A8E97DC3} = {87ADDFF9-5768-4DA2-A33B-2477593D6677}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|
Loading…
Reference in New Issue