Initial commit
This commit is contained in:
commit
3a9c1dc4bf
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
build
|
||||||
|
tags
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[submodule "secp256k1"]
|
||||||
|
path = secp256k1
|
||||||
|
url = https://github.com/bitcoin-core/secp256k1
|
24
LICENSE.txt
Normal file
24
LICENSE.txt
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
This is free and unencumbered software released into the public domain.
|
||||||
|
|
||||||
|
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||||
|
distribute this software, either in source code form or as a compiled
|
||||||
|
binary, for any purpose, commercial or non-commercial, and by any
|
||||||
|
means.
|
||||||
|
|
||||||
|
In jurisdictions that recognize copyright laws, the author or authors
|
||||||
|
of this software dedicate any and all copyright interest in the
|
||||||
|
software to the public domain. We make this dedication for the benefit
|
||||||
|
of the public at large and to the detriment of our heirs and
|
||||||
|
successors. We intend this dedication to be an overt act of
|
||||||
|
relinquishment in perpetuity of all present and future rights to this
|
||||||
|
software under copyright law.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||||
|
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||||
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
For more information, please refer to <http://unlicense.org>
|
57
README.md
Normal file
57
README.md
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
# Blockchain Tools - secp256k1 (bt\_secp256k1)
|
||||||
|
|
||||||
|
A code-generated single file header for bitcoin-core/secp256k1, an optimized
|
||||||
|
C library for ECDSA signatures and secret/public key operations on curve
|
||||||
|
secp256k1.
|
||||||
|
|
||||||
|
## Using bt\_secp256k1
|
||||||
|
|
||||||
|
The header files are generated from a metaprogram that is included in this
|
||||||
|
repository. To use the library you only need 1 header file of which, 3 variants
|
||||||
|
are provided,
|
||||||
|
|
||||||
|
- bt\_secp256k1\_i64.h (USE\_FORCE\_WIDEMUL\_INT64 is defined)
|
||||||
|
- bt\_secp256k1\_i128.h (USE\_FORCE\_WIDEMUL\_IN128 is defined)
|
||||||
|
- bt\_secp256k1\_i128\_x86\_64\_asm.h (USE\_FORCE\_WIDEMUL\_IN128 & USE\_ASM\_X86\_64 is defined)
|
||||||
|
|
||||||
|
Given the 3 variants, for optimal performance choose the most featureful variant
|
||||||
|
that your platform supports.
|
||||||
|
|
||||||
|
In exactly one `.c` or `.cpp` file that includes `bt_secp256k1.h` define
|
||||||
|
`BT_SECP256K1_IMPLEMENTATION` as per follows (with additional options to
|
||||||
|
configure the library via macros, see the single file headers for more
|
||||||
|
definitive explanations).
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#define BT_SECP256K1_IMPLEMENTATION
|
||||||
|
// NOTE: The 2 following defines are optional! We provide a default value if
|
||||||
|
// these are not defined before the implementation
|
||||||
|
#define ECMULT_GEN_PREC_BITS 4
|
||||||
|
#define ECMULT_WINDOW_SIZE 15
|
||||||
|
#include "bt_secp256k1_i64.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Details
|
||||||
|
|
||||||
|
The metaprogram provided in `bt_secp256k1_metaprogam.cpp` is responsible for
|
||||||
|
collating code files and patching source files to ensure the project can be
|
||||||
|
combined into a single header file, generating the output files.
|
||||||
|
|
||||||
|
The code generated header files vendored in the repository correspond to the
|
||||||
|
current commit hash checked out from the secp256k1 submodule.
|
||||||
|
|
||||||
|
The single file header code-generator metaprogram is provided under the
|
||||||
|
Unlicense license.
|
||||||
|
|
||||||
|
An example program `bt_secp256k1_example.c` is provided that implements a basic
|
||||||
|
secp256k1 keypair generator for reference and testing the single header file
|
||||||
|
compilation.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This is free and unencumbered software released into the public domain.
|
||||||
|
|
||||||
|
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||||
|
software, either in source code form or as a compiled binary, for any purpose,
|
||||||
|
commercial or non-commercial, and by any means.
|
37
_clang-format
Normal file
37
_clang-format
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
AccessModifierOffset: -4, # 1 tab
|
||||||
|
AlignAfterOpenBracket: true,
|
||||||
|
AlignConsecutiveAssignments: true,
|
||||||
|
AlignConsecutiveDeclarations: true,
|
||||||
|
AlignTrailingComments: true,
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: true,
|
||||||
|
AllowShortBlocksOnASingleLine: false,
|
||||||
|
AllowShortIfStatementsOnASingleLine: true,
|
||||||
|
AllowShortLoopsOnASingleLine: false,
|
||||||
|
AllowShortCaseLabelsOnASingleLine: true,
|
||||||
|
AlwaysBreakAfterDefinitionReturnType: false,
|
||||||
|
AlwaysBreakBeforeMultilineStrings: true,
|
||||||
|
AlwaysBreakTemplateDeclarations: true,
|
||||||
|
BinPackArguments: false,
|
||||||
|
BinPackParameters: false,
|
||||||
|
BreakBeforeBraces: Allman,
|
||||||
|
BreakConstructorInitializersBeforeComma: true,
|
||||||
|
ColumnLimit: 120,
|
||||||
|
ConstructorInitializerIndentWidth: 0,
|
||||||
|
Cpp11BracedListStyle: true,
|
||||||
|
IndentCaseLabels: true,
|
||||||
|
IndentFunctionDeclarationAfterType: false,
|
||||||
|
IndentWidth: 4, # 1 tab
|
||||||
|
MaxEmptyLinesToKeep: 1,
|
||||||
|
NamespaceIndentation: None,
|
||||||
|
PointerBindsToType: false,
|
||||||
|
SpaceBeforeAssignmentOperators: true,
|
||||||
|
SpaceInEmptyParentheses: false,
|
||||||
|
SpacesBeforeTrailingComments: 1,
|
||||||
|
SpacesInAngles: false,
|
||||||
|
SpacesInCStyleCastParentheses: false,
|
||||||
|
SpacesInParentheses: false,
|
||||||
|
SpacesInSquareBrackets: false,
|
||||||
|
Standard: Cpp11,
|
||||||
|
TabWidth: 4,
|
||||||
|
}
|
114
bt_secp256k1_example.c
Normal file
114
bt_secp256k1_example.c
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
// A simple program that generates a secp256k1 cryptographic keypair
|
||||||
|
// and dumps it to standard out.
|
||||||
|
|
||||||
|
#define BT_SECP256K1_IMPLEMENTATION
|
||||||
|
// NOTE: The 2 following defines are optional! We provide a default value if
|
||||||
|
// these are not defined before the implementation
|
||||||
|
#define ECMULT_GEN_PREC_BITS 4
|
||||||
|
#define ECMULT_WINDOW_SIZE 15
|
||||||
|
|
||||||
|
#if defined(EXAMPLE_BUILD_I128)
|
||||||
|
#include "bt_secp256k1_i128.h"
|
||||||
|
#elif defined(EXAMPLE_BUILD_I128_X86_64_ASM)
|
||||||
|
#include "bt_secp256k1_i128_x86_64_asm.h"
|
||||||
|
#else
|
||||||
|
#include "bt_secp256k1_i64.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
#define BCRYPT_RNG_ALGORITHM L"RNG"
|
||||||
|
/*NTSTATUS*/ long __stdcall BCryptOpenAlgorithmProvider(void *phAlgorithm, wchar_t const *pszAlgId, wchar_t const *pszImplementation, unsigned long dwFlags);
|
||||||
|
/*NTSTATUS*/ long __stdcall BCryptGenRandom (void *hAlgorithm, unsigned char *pbBuffer, unsigned long cbBuffer, unsigned long dwFlags);
|
||||||
|
#pragma comment(lib, "bcrypt")
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#include <sys/random.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int Random32Bytes(void *buffer)
|
||||||
|
{
|
||||||
|
#if defined(_WIN32)
|
||||||
|
static void *bcrypt_handle = NULL;
|
||||||
|
if (!bcrypt_handle)
|
||||||
|
{
|
||||||
|
long init_status = BCryptOpenAlgorithmProvider(&bcrypt_handle, BCRYPT_RNG_ALGORITHM, NULL /*implementation*/, 0 /*flags*/);
|
||||||
|
if (!bcrypt_handle || init_status != 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Failed to initialise random number generator [error=%ld]\n", init_status);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
long gen_status = BCryptGenRandom(bcrypt_handle, (unsigned char *)buffer, 32 /*size*/, 0 /*flags*/);
|
||||||
|
if (gen_status != 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Failed to generate random bytes [error=%ld]\n", gen_status);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
int read_bytes = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
read_bytes = getrandom(buffer, 32 /*size*/, 0);
|
||||||
|
} while (read_bytes != size || errno == EAGAIN); // NOTE: EINTR can not be triggered if size <= 32 bytes
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
(void)argc; (void)argv;
|
||||||
|
|
||||||
|
// NOTE: Initialise the library
|
||||||
|
secp256k1_context *lib_context = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
|
||||||
|
|
||||||
|
// NOTE: Generate a public key
|
||||||
|
unsigned char skey[32];
|
||||||
|
if (!Random32Bytes(skey))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Failed to generate secret key\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
secp256k1_pubkey pkey;
|
||||||
|
if (secp256k1_ec_pubkey_create(lib_context, &pkey, skey) == 1)
|
||||||
|
{
|
||||||
|
// NOTE: Serialize the key
|
||||||
|
unsigned char pkey_serialized[33];
|
||||||
|
size_t pkey_serialized_size = sizeof(pkey_serialized);
|
||||||
|
secp256k1_ec_pubkey_serialize(lib_context, pkey_serialized, &pkey_serialized_size, &pkey, SECP256K1_EC_COMPRESSED);
|
||||||
|
|
||||||
|
// NOTE: Dump the secret key to stdout
|
||||||
|
fprintf(stdout, "Secret Key [key=0x");
|
||||||
|
for (size_t index = 0; index < sizeof(skey); index++)
|
||||||
|
{
|
||||||
|
fprintf(stdout, "%x", (skey[index] >> 4) & 0xF);
|
||||||
|
fprintf(stdout, "%x", (skey[index] >> 0) & 0xF);
|
||||||
|
}
|
||||||
|
fprintf(stdout, "]\n");
|
||||||
|
|
||||||
|
// NOTE: Dump the serialized public key to stdout
|
||||||
|
fprintf(stdout, "Public Key [key=0x");
|
||||||
|
for (size_t index = 0; index < pkey_serialized_size; index++)
|
||||||
|
{
|
||||||
|
fprintf(stdout, "%x", (pkey_serialized[index] >> 4) & 0xF);
|
||||||
|
fprintf(stdout, "%x", (pkey_serialized[index] >> 0) & 0xF);
|
||||||
|
}
|
||||||
|
fprintf(stdout, "]\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Failed to generate public key");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
35516
bt_secp256k1_i128.h
Normal file
35516
bt_secp256k1_i128.h
Normal file
File diff suppressed because it is too large
Load Diff
35744
bt_secp256k1_i128_x86_64_asm.h
Normal file
35744
bt_secp256k1_i128_x86_64_asm.h
Normal file
File diff suppressed because it is too large
Load Diff
35136
bt_secp256k1_i64.h
Normal file
35136
bt_secp256k1_i64.h
Normal file
File diff suppressed because it is too large
Load Diff
636
bt_secp256k1_metaprogram.cpp
Normal file
636
bt_secp256k1_metaprogram.cpp
Normal file
@ -0,0 +1,636 @@
|
|||||||
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define FILE_SCOPE static
|
||||||
|
|
||||||
|
FILE_SCOPE char *ReadEntireFile(char const *file_path, int *file_size)
|
||||||
|
{
|
||||||
|
char *result = nullptr;
|
||||||
|
FILE *file_handle = fopen(file_path, "rb");
|
||||||
|
if (file_handle)
|
||||||
|
{
|
||||||
|
fseek(file_handle, 0, SEEK_END);
|
||||||
|
*file_size = ftell(file_handle);
|
||||||
|
rewind(file_handle);
|
||||||
|
|
||||||
|
result = (char *)malloc(*file_size + 1);
|
||||||
|
result[*file_size] = 0;
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
if (fread(result, (size_t)(*file_size), 1, file_handle) != 1)
|
||||||
|
{
|
||||||
|
free(result);
|
||||||
|
result = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(file_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum FileFlag
|
||||||
|
{
|
||||||
|
FileFlag_Normal = 1 << 0,
|
||||||
|
FileFlag_Mul64Support = 1 << 1,
|
||||||
|
FileFlag_Mul128Support = 1 << 2,
|
||||||
|
FileFlag_AsmX86_64 = 1 << 3,
|
||||||
|
FileFlag_AsmInt128 = 1 << 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct String { char *str; int size; };
|
||||||
|
struct StringList { String string; StringList *next; };
|
||||||
|
#define STRING(string) {string, sizeof(string) - 1}
|
||||||
|
|
||||||
|
struct LoadedFile
|
||||||
|
{
|
||||||
|
unsigned flag;
|
||||||
|
char *buffer;
|
||||||
|
int size;
|
||||||
|
String sub_dir;
|
||||||
|
String name;
|
||||||
|
};
|
||||||
|
|
||||||
|
FILE_SCOPE bool LoadFiles(LoadedFile *files, int file_count, char const *root_dir)
|
||||||
|
{
|
||||||
|
bool result = true;
|
||||||
|
for (int file_index = 0; file_index < file_count; file_index++)
|
||||||
|
{
|
||||||
|
LoadedFile *file = files + file_index;
|
||||||
|
char file_path[2048];
|
||||||
|
if (file->sub_dir.size)
|
||||||
|
{
|
||||||
|
snprintf(file_path, sizeof(file_path), "%s/%.*s/%.*s", root_dir, file->sub_dir.size, file->sub_dir.str, file->name.size, file->name.str);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
snprintf(file_path, sizeof(file_path), "%s/%.*s", root_dir, file->name.size, file->name.str);
|
||||||
|
}
|
||||||
|
|
||||||
|
file->buffer = ReadEntireFile(file_path, &file->size);
|
||||||
|
if (!file->buffer || file->size == 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Failed to load file [file=%s]\n", file_path);
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE_SCOPE String StringCopy(String src)
|
||||||
|
{
|
||||||
|
String result = String{(char *)malloc(src.size + 1), src.size};
|
||||||
|
memcpy(result.str, src.str, src.size);
|
||||||
|
result.str[src.size] = 0;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE_SCOPE StringList *StringListAppendRef(StringList *list, String string)
|
||||||
|
{
|
||||||
|
StringList *result = list;
|
||||||
|
if (string.str && string.size)
|
||||||
|
{
|
||||||
|
if (list->string.str)
|
||||||
|
{
|
||||||
|
list->next = (StringList *)malloc(sizeof(StringList));
|
||||||
|
result = list->next;
|
||||||
|
*result = {};
|
||||||
|
}
|
||||||
|
result->string = string;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE_SCOPE String StringListBuild(StringList *list)
|
||||||
|
{
|
||||||
|
int total_size = 0;
|
||||||
|
for (StringList *entry = list; entry; entry = entry->next)
|
||||||
|
total_size += entry->string.size;
|
||||||
|
|
||||||
|
char *string = (char *)malloc(total_size + 1);
|
||||||
|
char *writer = string;
|
||||||
|
for (StringList *entry = list; entry; entry = entry->next)
|
||||||
|
{
|
||||||
|
memcpy(writer, entry->string.str, entry->string.size);
|
||||||
|
writer += entry->string.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
writer[0] = 0;
|
||||||
|
|
||||||
|
String result = {string, total_size};
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE_SCOPE bool StringEquals(String lhs, String rhs)
|
||||||
|
{
|
||||||
|
bool result = lhs.size == rhs.size && (memcmp(lhs.str, rhs.str, lhs.size) == 0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE_SCOPE String StringFindThenInsert(String src, String find, String insert)
|
||||||
|
{
|
||||||
|
// NOTE: We leak the string list memory but don't care because this is
|
||||||
|
// a meta tool that lives for a couple of seconds and kills itself.
|
||||||
|
|
||||||
|
StringList list_head = {};
|
||||||
|
StringList *list_tail = &list_head;
|
||||||
|
|
||||||
|
int src_end = src.size - find.size;
|
||||||
|
int head = 0;
|
||||||
|
for (int tail = head; tail <= src_end; tail++)
|
||||||
|
{
|
||||||
|
String check = String{src.str + tail, find.size};
|
||||||
|
if (!StringEquals(check, find))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
String range = String{src.str + head, (tail - head)};
|
||||||
|
list_tail = StringListAppendRef(list_tail, range);
|
||||||
|
list_tail = StringListAppendRef(list_tail, insert);
|
||||||
|
list_tail = StringListAppendRef(list_tail, check);
|
||||||
|
head = tail + find.size;
|
||||||
|
tail = head - 1; ; // NOTE: -1 because for loop post increment
|
||||||
|
}
|
||||||
|
|
||||||
|
String result = {};
|
||||||
|
if (list_head.string.size == 0)
|
||||||
|
{
|
||||||
|
// NOTE: No insertment possible, so we just do a full-copy
|
||||||
|
result = StringCopy(src);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
String remainder = String{src.str + head, src.size - head};
|
||||||
|
list_tail = StringListAppendRef(list_tail, remainder);
|
||||||
|
result = StringListBuild(&list_head);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE_SCOPE String StringReplace(String src, String find, String replace)
|
||||||
|
{
|
||||||
|
// NOTE: We leak the string list memory but don't care because this is
|
||||||
|
// a meta tool that lives for a couple of seconds and kills itself.
|
||||||
|
|
||||||
|
StringList list_head = {};
|
||||||
|
StringList *list_tail = &list_head;
|
||||||
|
|
||||||
|
int src_end = src.size - find.size;
|
||||||
|
int head = 0;
|
||||||
|
for (int tail = head; tail <= src_end; tail++)
|
||||||
|
{
|
||||||
|
String check = String{src.str + tail, find.size};
|
||||||
|
if (!StringEquals(check, find))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
String range = String{src.str + head, (tail - head)};
|
||||||
|
list_tail = StringListAppendRef(list_tail, range);
|
||||||
|
list_tail = StringListAppendRef(list_tail, replace);
|
||||||
|
head = tail + find.size;
|
||||||
|
tail = head - 1; ; // NOTE: -1 because for loop post increment
|
||||||
|
}
|
||||||
|
|
||||||
|
String result = {};
|
||||||
|
if (list_head.string.size == 0)
|
||||||
|
{
|
||||||
|
// NOTE: No insertment possible, so we just do a full-copy
|
||||||
|
result = StringCopy(src);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
String remainder = String{src.str + head, src.size - head};
|
||||||
|
list_tail = StringListAppendRef(list_tail, remainder);
|
||||||
|
result = StringListBuild(&list_head);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringList *AddSourceFileComment(StringList *tail, LoadedFile const *file)
|
||||||
|
{
|
||||||
|
StringList *result = StringListAppendRef(tail, STRING("\n// File: "));
|
||||||
|
if (file->sub_dir.size)
|
||||||
|
{
|
||||||
|
result = StringListAppendRef(result, file->sub_dir);
|
||||||
|
result = StringListAppendRef(result, STRING("/"));
|
||||||
|
}
|
||||||
|
|
||||||
|
result = StringListAppendRef(result, file->name);
|
||||||
|
result = StringListAppendRef(result, STRING("\n"));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
if (argc != 2)
|
||||||
|
{
|
||||||
|
printf("Usage: bt_secp256k1_metaprogram <path/to/secp256k1/directory>\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadedFile intro_files[] = {
|
||||||
|
{FileFlag_Normal, nullptr, 0, STRING(""), STRING("COPYING")},
|
||||||
|
};
|
||||||
|
|
||||||
|
LoadedFile header_files[] = {
|
||||||
|
{FileFlag_Normal, nullptr, 0, STRING("include"), STRING("secp256k1.h")},
|
||||||
|
{FileFlag_Normal, nullptr, 0, STRING("include"), STRING("secp256k1_preallocated.h")},
|
||||||
|
};
|
||||||
|
|
||||||
|
LoadedFile private_header_files[] = {
|
||||||
|
{FileFlag_Normal, nullptr, 0, STRING("src"), STRING("util.h")},
|
||||||
|
{FileFlag_Mul64Support, nullptr, 0, STRING("src"), STRING("field_10x26.h")},
|
||||||
|
{FileFlag_Mul64Support, nullptr, 0, STRING("src"), STRING("scalar_8x32.h")},
|
||||||
|
{FileFlag_Mul128Support, nullptr, 0, STRING("src"), STRING("field_5x52.h")},
|
||||||
|
{FileFlag_Mul128Support, nullptr, 0, STRING("src"), STRING("scalar_4x64.h")},
|
||||||
|
{FileFlag_Mul128Support, nullptr, 0, STRING("src"), STRING("modinv64.h")},
|
||||||
|
{FileFlag_Normal, nullptr, 0, STRING("src"), STRING("hash.h")},
|
||||||
|
{FileFlag_Normal, nullptr, 0, STRING("src"), STRING("modinv32.h")},
|
||||||
|
{FileFlag_Normal, nullptr, 0, STRING("src"), STRING("assumptions.h")},
|
||||||
|
{FileFlag_Normal, nullptr, 0, STRING("src"), STRING("scalar.h")},
|
||||||
|
{FileFlag_Normal, nullptr, 0, STRING("src"), STRING("field.h")},
|
||||||
|
{FileFlag_Normal, nullptr, 0, STRING("src"), STRING("group.h")},
|
||||||
|
{FileFlag_Normal, nullptr, 0, STRING("src"), STRING("ecmult_const.h")},
|
||||||
|
{FileFlag_Normal, nullptr, 0, STRING("src"), STRING("ecmult_gen.h")},
|
||||||
|
{FileFlag_Normal, nullptr, 0, STRING("src"), STRING("scratch.h")},
|
||||||
|
{FileFlag_Normal, nullptr, 0, STRING("src"), STRING("ecmult.h")},
|
||||||
|
{FileFlag_Normal, nullptr, 0, STRING("src"), STRING("precomputed_ecmult.h")},
|
||||||
|
{FileFlag_Normal, nullptr, 0, STRING("src"), STRING("precomputed_ecmult_gen.h")},
|
||||||
|
{FileFlag_Normal, nullptr, 0, STRING("src"), STRING("ecdsa.h")},
|
||||||
|
{FileFlag_Normal, nullptr, 0, STRING("src"), STRING("eckey.h")},
|
||||||
|
{FileFlag_Normal, nullptr, 0, STRING("src"), STRING("selftest.h")},
|
||||||
|
};
|
||||||
|
|
||||||
|
LoadedFile private_impl_files[] = {
|
||||||
|
{FileFlag_Mul64Support, nullptr, 0, STRING("src"), STRING("field_10x26_impl.h")},
|
||||||
|
{FileFlag_Mul64Support, nullptr, 0, STRING("src"), STRING("scalar_8x32_impl.h")},
|
||||||
|
{FileFlag_AsmInt128, nullptr, 0, STRING("src"), STRING("field_5x52_int128_impl.h")},
|
||||||
|
{FileFlag_AsmX86_64, nullptr, 0, STRING("src"), STRING("field_5x52_asm_impl.h")},
|
||||||
|
{FileFlag_Mul128Support, nullptr, 0, STRING("src"), STRING("field_5x52_impl.h")},
|
||||||
|
{FileFlag_Mul128Support, nullptr, 0, STRING("src"), STRING("scalar_4x64_impl.h")},
|
||||||
|
{FileFlag_Mul128Support, nullptr, 0, STRING("src"), STRING("modinv64_impl.h")},
|
||||||
|
{FileFlag_Normal, nullptr, 0, STRING("src"), STRING("ecdsa_impl.h")},
|
||||||
|
{FileFlag_Normal, nullptr, 0, STRING("src"), STRING("eckey_impl.h")},
|
||||||
|
{FileFlag_Normal, nullptr, 0, STRING("src"), STRING("group_impl.h")},
|
||||||
|
{FileFlag_Normal, nullptr, 0, STRING("src"), STRING("field_impl.h")},
|
||||||
|
{FileFlag_Normal, nullptr, 0, STRING("src"), STRING("scalar_impl.h")},
|
||||||
|
{FileFlag_Normal, nullptr, 0, STRING("src"), STRING("ecmult_impl.h")},
|
||||||
|
{FileFlag_Normal, nullptr, 0, STRING("src"), STRING("ecmult_const_impl.h")},
|
||||||
|
{FileFlag_Normal, nullptr, 0, STRING("src"), STRING("ecmult_gen_impl.h")},
|
||||||
|
{FileFlag_Normal, nullptr, 0, STRING("src"), STRING("precomputed_ecmult.c")},
|
||||||
|
{FileFlag_Normal, nullptr, 0, STRING("src"), STRING("precomputed_ecmult_gen.c")},
|
||||||
|
{FileFlag_Normal, nullptr, 0, STRING("src"), STRING("hash_impl.h")},
|
||||||
|
{FileFlag_Normal, nullptr, 0, STRING("src"), STRING("modinv32_impl.h")},
|
||||||
|
{FileFlag_Normal, nullptr, 0, STRING("src"), STRING("scratch_impl.h")},
|
||||||
|
{FileFlag_Normal, nullptr, 0, STRING("src"), STRING("secp256k1.c")},
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ARRAY_COUNT(array) sizeof(array)/sizeof((array)[0])
|
||||||
|
char const *root_dir = argv[1];
|
||||||
|
bool files_loaded = true;
|
||||||
|
files_loaded &= LoadFiles(intro_files, ARRAY_COUNT(intro_files), root_dir);
|
||||||
|
files_loaded &= LoadFiles(header_files, ARRAY_COUNT(header_files), root_dir);
|
||||||
|
files_loaded &= LoadFiles(private_header_files, ARRAY_COUNT(private_header_files), root_dir);
|
||||||
|
files_loaded &= LoadFiles(private_impl_files, ARRAY_COUNT(private_impl_files), root_dir);
|
||||||
|
|
||||||
|
if (!files_loaded)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
unsigned const BUILD_FLAGS[] = {
|
||||||
|
FileFlag_Normal | FileFlag_Mul64Support,
|
||||||
|
FileFlag_Normal | FileFlag_Mul128Support | FileFlag_AsmInt128,
|
||||||
|
FileFlag_Normal | FileFlag_Mul128Support | FileFlag_AsmX86_64,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int build_index = 0; build_index < ARRAY_COUNT(BUILD_FLAGS); build_index++)
|
||||||
|
{
|
||||||
|
unsigned const build_flags = BUILD_FLAGS[build_index];
|
||||||
|
|
||||||
|
char build_name_buf[1024];
|
||||||
|
String build_name = {};
|
||||||
|
build_name.str = build_name_buf;
|
||||||
|
build_name.size = snprintf(build_name_buf,
|
||||||
|
sizeof(build_name_buf),
|
||||||
|
"bt_secp256k1_i%s%s.h",
|
||||||
|
(build_flags & FileFlag_Mul64Support) ? "64" : "128",
|
||||||
|
(build_flags & FileFlag_AsmX86_64) ? "_x86_64_asm" : "");
|
||||||
|
|
||||||
|
// NOTE: Append all the files into one contiguous buffer
|
||||||
|
String buffer = {};
|
||||||
|
{
|
||||||
|
StringList list_head = {};
|
||||||
|
StringList *list_tail = &list_head;
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------
|
||||||
|
// Intro files
|
||||||
|
// -------------------------------------------------------------------------------------
|
||||||
|
// TODO(doyle): Add no precomputed table macro
|
||||||
|
list_tail = StringListAppendRef(list_tail, STRING(
|
||||||
|
"// -----------------------------------------------------------------------------\n"
|
||||||
|
"// NOTE: Overview\n"
|
||||||
|
"// -----------------------------------------------------------------------------\n"
|
||||||
|
"// A machine generated single-header file of bitcoin-core/libsecp256k1 that is\n"
|
||||||
|
"// compilable in C/C++ with minimal effort.\n"
|
||||||
|
"//\n"
|
||||||
|
"// - By default ECMULT_WINDOW_SIZE is set to 15. This is the default\n"
|
||||||
|
"// recommended value you'd get from building the library with \"auto\" settings.\n"
|
||||||
|
"// You may override this by defining this macro before defining the\n"
|
||||||
|
"// IMPLEMENTATION macro for this file.\n"
|
||||||
|
"//\n"
|
||||||
|
"// - By default ECMULT_GEN_PREC_BITS is set to 4. This is the default\n"
|
||||||
|
"// recommended value you'd get from building the library with \"auto\" settings.\n"
|
||||||
|
"// You may override this by defining this macro before defining the\n"
|
||||||
|
"// IMPLEMENTATION macro for this file.\n"
|
||||||
|
"//\n"
|
||||||
|
"// - Define BT_SECP256K1_DISABLE_WARNING_PRAGMAS to disable the extra pragmas in\n"
|
||||||
|
"// this file that suppress some compiler warnings- since this is not really the\n"
|
||||||
|
"// concern of a machine generated single header file library, fixes should be sent\n"
|
||||||
|
"// upstream.\n"
|
||||||
|
"//\n"
|
||||||
|
"// - Define BT_SECP256K1_NO_PRECOMPUTED_TABLE to disable the precomputed table\n"
|
||||||
|
"// that was generated by building and running gen_context.c\n"
|
||||||
|
"// -----------------------------------------------------------------------------\n"
|
||||||
|
"// NOTE: License\n"
|
||||||
|
"// -----------------------------------------------------------------------------\n"
|
||||||
|
));
|
||||||
|
|
||||||
|
list_tail = StringListAppendRef(list_tail, STRING("/*\n"));
|
||||||
|
for (LoadedFile const &file : intro_files)
|
||||||
|
{
|
||||||
|
if (build_flags & file.flag)
|
||||||
|
list_tail = StringListAppendRef(list_tail, String{file.buffer, file.size});
|
||||||
|
}
|
||||||
|
list_tail = StringListAppendRef(list_tail, STRING("*/\n"));
|
||||||
|
|
||||||
|
list_tail = StringListAppendRef(list_tail, STRING(
|
||||||
|
"// -----------------------------------------------------------------------------\n"
|
||||||
|
"// NOTE: Example\n"
|
||||||
|
"// -----------------------------------------------------------------------------\n"
|
||||||
|
"#if 0\n"
|
||||||
|
"#define BT_SECP256K1_IMPLEMENTATION\n"
|
||||||
|
"// NOTE: The 2 following defines are optional! We provide a default value if\n"
|
||||||
|
"// these are not defined before the implementation\n"
|
||||||
|
"#define ECMULT_GEN_PREC_BITS 4\n"
|
||||||
|
"#define ECMULT_WINDOW_SIZE 15\n"
|
||||||
|
"#include \""
|
||||||
|
));
|
||||||
|
|
||||||
|
list_tail = StringListAppendRef(list_tail, build_name);
|
||||||
|
|
||||||
|
list_tail = StringListAppendRef(list_tail, STRING("\"\n"
|
||||||
|
"#include <stdio.h>\n"
|
||||||
|
"\n"
|
||||||
|
"int main(int argc, char **argv)\n"
|
||||||
|
"{\n"
|
||||||
|
" (void)argc; (void)argv;\n"
|
||||||
|
"\n"
|
||||||
|
" // NOTE: Initialise the library\n"
|
||||||
|
" secp256k1_context *lib_context = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);\n"
|
||||||
|
"\n"
|
||||||
|
" // NOTE: Generate a public key from a hard-coded secret key\n"
|
||||||
|
" unsigned char const skey[32 + 1] = \"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\n"
|
||||||
|
" \"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\n"
|
||||||
|
" \"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\"\n"
|
||||||
|
" \"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x01\";\n"
|
||||||
|
" secp256k1_pubkey pkey;\n"
|
||||||
|
"\n"
|
||||||
|
" if (secp256k1_ec_pubkey_create(lib_context, &pkey, skey) == 1)\n"
|
||||||
|
" {\n"
|
||||||
|
"\n"
|
||||||
|
" // NOTE: Serialize the key\n"
|
||||||
|
" unsigned char pkey_serialized[33];\n"
|
||||||
|
" size_t pkey_serialized_size = sizeof(pkey_serialized);\n"
|
||||||
|
" secp256k1_ec_pubkey_serialize(lib_context, pkey_serialized, &pkey_serialized_size, &pkey, SECP256K1_EC_COMPRESSED);\n"
|
||||||
|
"\n"
|
||||||
|
" // NOTE: Dump the secret key to stdout\n"
|
||||||
|
" fprintf(stdout, \"Secret Key [key=0x\");\n"
|
||||||
|
" for (size_t index = 0; index < sizeof(skey); index++)\n"
|
||||||
|
" {\n"
|
||||||
|
" fprintf(stdout, \"%x\", (skey[index] >> 4) & 0xF);\n"
|
||||||
|
" fprintf(stdout, \"%x\", (skey[index] >> 0) & 0xF);\n"
|
||||||
|
" }\n"
|
||||||
|
" fprintf(stdout, \"]\\n\");\n"
|
||||||
|
"\n"
|
||||||
|
" // NOTE: Dump the serialized public key to stdout\n"
|
||||||
|
" fprintf(stdout, \"Public Key [key=0x\");\n"
|
||||||
|
" for (size_t index = 0; index < pkey_serialized_size; index++)\n"
|
||||||
|
" {\n"
|
||||||
|
" fprintf(stdout, \"%x\", (pkey_serialized[index] >> 4) & 0xF);\n"
|
||||||
|
" fprintf(stdout, \"%x\", (pkey_serialized[index] >> 0) & 0xF);\n"
|
||||||
|
" }\n"
|
||||||
|
" fprintf(stdout, \"]\\n\");\n"
|
||||||
|
" }\n"
|
||||||
|
" else\n"
|
||||||
|
" {\n"
|
||||||
|
" fprintf(stderr, \"Failed to generate public key\");\n"
|
||||||
|
" }\n"
|
||||||
|
"\n"
|
||||||
|
" return 0;\n"
|
||||||
|
"}\n"
|
||||||
|
"#endif\n"
|
||||||
|
"\n"
|
||||||
|
"// -----------------------------------------------------------------------------\n"
|
||||||
|
"// NOTE: Single Header Start\n"
|
||||||
|
"// -----------------------------------------------------------------------------\n"
|
||||||
|
));
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------
|
||||||
|
// Header defines
|
||||||
|
// -------------------------------------------------------------------------------------
|
||||||
|
list_tail = StringListAppendRef(list_tail, STRING("#if !defined(BT_SECP256K1_H)\n"));
|
||||||
|
list_tail = StringListAppendRef(list_tail, STRING("#define BT_SECP256K1_H\n\n"));
|
||||||
|
|
||||||
|
list_tail = StringListAppendRef(list_tail, STRING("#if !defined(SECP256K1_BUILD)\n"));
|
||||||
|
list_tail = StringListAppendRef(list_tail, STRING(" #define SECP256K1_BUILD\n"));
|
||||||
|
list_tail = StringListAppendRef(list_tail, STRING("#endif\n\n"));
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------
|
||||||
|
// Header files
|
||||||
|
// -------------------------------------------------------------------------------------
|
||||||
|
for (LoadedFile const &file : header_files)
|
||||||
|
{
|
||||||
|
if (build_flags & file.flag)
|
||||||
|
{
|
||||||
|
list_tail = AddSourceFileComment(list_tail, &file);
|
||||||
|
list_tail = StringListAppendRef(list_tail, String{file.buffer, file.size});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list_tail = StringListAppendRef(list_tail, STRING("#endif // BT_SECP256K1_H\n"));
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------
|
||||||
|
// Add implementation defines
|
||||||
|
// -------------------------------------------------------------------------------------
|
||||||
|
list_tail = StringListAppendRef(list_tail, STRING("#if defined(BT_SECP256K1_IMPLEMENTATION)\n"));
|
||||||
|
|
||||||
|
{
|
||||||
|
list_tail = StringListAppendRef(list_tail, STRING("#if !defined(ECMULT_GEN_PREC_BITS)\n"));
|
||||||
|
list_tail = StringListAppendRef(list_tail, STRING(" #define ECMULT_GEN_PREC_BITS 4\n"));
|
||||||
|
list_tail = StringListAppendRef(list_tail, STRING("#endif\n\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
list_tail = StringListAppendRef(list_tail, STRING("#if !defined(ECMULT_WINDOW_SIZE)\n"));
|
||||||
|
list_tail = StringListAppendRef(list_tail, STRING(" #define ECMULT_WINDOW_SIZE 15\n"));
|
||||||
|
list_tail = StringListAppendRef(list_tail, STRING("#endif\n\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (build_flags & FileFlag_Mul64Support)
|
||||||
|
{
|
||||||
|
list_tail = StringListAppendRef(list_tail, STRING("#if !defined(USE_FORCE_WIDEMUL_INT64)\n"));
|
||||||
|
list_tail = StringListAppendRef(list_tail, STRING(" #define USE_FORCE_WIDEMUL_INT64\n"));
|
||||||
|
list_tail = StringListAppendRef(list_tail, STRING("#endif\n\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (build_flags & FileFlag_Mul128Support)
|
||||||
|
{
|
||||||
|
list_tail = StringListAppendRef(list_tail, STRING("#if !defined(USE_FORCE_WIDEMUL_INT128)\n"));
|
||||||
|
list_tail = StringListAppendRef(list_tail, STRING(" #define USE_FORCE_WIDEMUL_INT128\n"));
|
||||||
|
list_tail = StringListAppendRef(list_tail, STRING("#endif\n\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (build_flags & FileFlag_AsmX86_64)
|
||||||
|
{
|
||||||
|
list_tail = StringListAppendRef(list_tail, STRING("#if !defined(USE_ASM_X86_64)\n"));
|
||||||
|
list_tail = StringListAppendRef(list_tail, STRING(" #define USE_ASM_X86_64\n"));
|
||||||
|
list_tail = StringListAppendRef(list_tail, STRING("#endif\n\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
list_tail = StringListAppendRef(list_tail, STRING(
|
||||||
|
"#if !defined(BT_SECP256K1_DISABLE_WARNING_PRAGMAS)\n"
|
||||||
|
" #if defined(__clang__)\n"
|
||||||
|
" #pragma clang diagnostic push\n"
|
||||||
|
" #pragma clang diagnostic ignored \"-Wunused-function\"\n"
|
||||||
|
" #pragma clang diagnostic ignored \"-Wmissing-field-initializers\"\n"
|
||||||
|
" #elif defined(_MSC_VER)\n"
|
||||||
|
" #pragma warning(push)\n"
|
||||||
|
" #pragma warning(disable: 4146)\n"
|
||||||
|
" #pragma warning(disable: 4310)\n"
|
||||||
|
" #pragma warning(disable: 4244)\n"
|
||||||
|
" #pragma warning(disable: 4319)\n"
|
||||||
|
" #pragma warning(disable: 4267)\n"
|
||||||
|
" #pragma warning(disable: 4334)\n"
|
||||||
|
" #pragma warning(disable: 4127)\n"
|
||||||
|
" #pragma warning(disable: 4505)\n"
|
||||||
|
" #pragma warning(disable: 4706)\n"
|
||||||
|
" #endif\n"
|
||||||
|
"#endif // !defined(BT_SECP256K1_DISABLE_WARNING_PRAGMAS)\n"
|
||||||
|
"\n"
|
||||||
|
));
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------
|
||||||
|
// Append implementation Files
|
||||||
|
// -------------------------------------------------------------------------------------
|
||||||
|
for (LoadedFile const &file : private_header_files)
|
||||||
|
{
|
||||||
|
if (build_flags & file.flag)
|
||||||
|
{
|
||||||
|
list_tail = AddSourceFileComment(list_tail, &file);
|
||||||
|
list_tail = StringListAppendRef(list_tail, String{file.buffer, file.size});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (LoadedFile const &file : private_impl_files)
|
||||||
|
{
|
||||||
|
if (build_flags & file.flag)
|
||||||
|
{
|
||||||
|
list_tail = AddSourceFileComment(list_tail, &file);
|
||||||
|
list_tail = StringListAppendRef(list_tail, String{file.buffer, file.size});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
list_tail = StringListAppendRef(list_tail, STRING(
|
||||||
|
"\n"
|
||||||
|
"#if !defined(BT_SECP256K1_DISABLE_WARNING_PRAGMAS)\n"
|
||||||
|
" #if defined(__clang__)\n"
|
||||||
|
" #pragma clang diagnostic pop\n"
|
||||||
|
" #elif defined(_MSC_VER)\n"
|
||||||
|
" #pragma warning(pop)\n"
|
||||||
|
" #endif\n"
|
||||||
|
"#endif // !defined(BT_SECP256K1_DISABLE_WARNING_PRAGMAS)\n"
|
||||||
|
"\n"
|
||||||
|
"#endif // BT_SECP256K1_IMPLEMENTATION\n"
|
||||||
|
));
|
||||||
|
|
||||||
|
buffer = StringListBuild(&list_head);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: Do string inserts and comment out header include directives
|
||||||
|
{
|
||||||
|
char old_directive_buf[1024];
|
||||||
|
char new_directive_buf[1024];
|
||||||
|
String old_directive = String{old_directive_buf, 0};
|
||||||
|
String new_directive = String{new_directive_buf, 0};
|
||||||
|
|
||||||
|
struct LoadedFileList
|
||||||
|
{
|
||||||
|
LoadedFile *data;
|
||||||
|
int size;
|
||||||
|
};
|
||||||
|
|
||||||
|
LoadedFileList file_list[] = {
|
||||||
|
{header_files, ARRAY_COUNT(header_files)},
|
||||||
|
{private_header_files, ARRAY_COUNT(private_header_files)},
|
||||||
|
{private_impl_files, ARRAY_COUNT(private_impl_files)},
|
||||||
|
};
|
||||||
|
|
||||||
|
for (LoadedFileList const &list : file_list)
|
||||||
|
{
|
||||||
|
for (int file_index = 0; file_index < list.size; file_index++)
|
||||||
|
{
|
||||||
|
LoadedFile const &file = list.data[file_index];
|
||||||
|
if (build_flags & file.flag)
|
||||||
|
{
|
||||||
|
// NOTE: Comment out the #includes for the file since
|
||||||
|
// we're producing a single header file.
|
||||||
|
old_directive.size = snprintf(old_directive_buf, sizeof(old_directive_buf), "#include \"%.*s\"", file.name.size, file.name.str);
|
||||||
|
buffer = StringFindThenInsert(buffer, old_directive, STRING("// "));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: secp256k1 uses relative headers, so patch them out
|
||||||
|
buffer = StringFindThenInsert(buffer, STRING("#include \"../include/secp256k1"), STRING("// "));
|
||||||
|
|
||||||
|
// NOTE: Allow adding a static context ontop of the single file
|
||||||
|
// header library by commenting the #include directive in the source
|
||||||
|
// code out. This allows the user to #include their own generated
|
||||||
|
// static context before including this library.
|
||||||
|
buffer = StringFindThenInsert(buffer, STRING("#include \"ecmult_static_context.h\""), STRING("// "));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: Misc patches to source code
|
||||||
|
{
|
||||||
|
// NOTE: Patch one problematic line that causes a compile failure in
|
||||||
|
// C++ (but not C, since this a C library).
|
||||||
|
buffer = StringReplace(
|
||||||
|
buffer,
|
||||||
|
STRING("const unsigned char *p1 = s1, *p2 = s2;"),
|
||||||
|
STRING("const unsigned char *p1 = (const unsigned char *)s1, *p2 = (const unsigned char *)s2;"));
|
||||||
|
|
||||||
|
// NOTE: Delete any Windows style new-lines if there were any
|
||||||
|
buffer = StringReplace(buffer, STRING("\r"), STRING(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: Output file
|
||||||
|
{
|
||||||
|
FILE *file_handle = fopen(build_name.str, "w+b");
|
||||||
|
if (!file_handle)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Failed to write to file, unable to run metaprogram [file=%s]\n", build_name.str);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fwrite(buffer.str, buffer.size, 1, file_handle);
|
||||||
|
fclose(file_handle);
|
||||||
|
|
||||||
|
printf("File generated to %s\n", build_name.str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
49
build.bat
Normal file
49
build.bat
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
@echo off
|
||||||
|
setlocal EnableDelayedExpansion
|
||||||
|
|
||||||
|
where /q cl || (
|
||||||
|
echo MSVC's cl is not found - please run this from the MSVC x64 native tools command prompt
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
set code_dir=%~dp0
|
||||||
|
set build_dir=!code_dir!\build
|
||||||
|
if not exist !build_dir! mkdir !build_dir!
|
||||||
|
|
||||||
|
set common_compile_flags=-W4 -O2
|
||||||
|
set common_linker_flags=-link -nologo
|
||||||
|
|
||||||
|
REM Build the metaprogram
|
||||||
|
pushd !build_dir!
|
||||||
|
cl !common_compiler_flags! !code_dir!\bt_secp256k1_metaprogram.cpp !common_linker_flags! || (
|
||||||
|
echo Build script failed because the metaprogram failed to build successfully
|
||||||
|
exit
|
||||||
|
)
|
||||||
|
popd
|
||||||
|
|
||||||
|
REM Code generate the single file header
|
||||||
|
!build_dir!\bt_secp256k1_metaprogram.exe !code_dir!\secp256k1 || (
|
||||||
|
echo Build script failed because the metaprogram did not run successfully
|
||||||
|
exit
|
||||||
|
)
|
||||||
|
|
||||||
|
REM Build the test program to sanity check the single file header
|
||||||
|
pushd !build_dir!
|
||||||
|
set common_source_files=!code_dir!\bt_secp256k1_example.c
|
||||||
|
|
||||||
|
REM Build a C/C++ i64 version
|
||||||
|
cl !common_compile_flags! -Tc !common_source_files! !common_linker_flags! -out:bt_secp256k1_i64_example_c.exe
|
||||||
|
cl !common_compile_flags! -Tp !common_source_files! !common_linker_flags! -out:bt_secp256k1_i64_example_cpp.exe
|
||||||
|
|
||||||
|
where /q clang-cl || (
|
||||||
|
exit
|
||||||
|
)
|
||||||
|
|
||||||
|
REM (Optional) Build a C/C++ {i128, i128 x86_64 ASM} version
|
||||||
|
REM This requires clang-cl because MSVC does not expose a uint128_t type
|
||||||
|
clang-cl !common_compile_flags! -D EXAMPLE_BUILD_I128 -Tc !common_source_files! !common_linker_flags! -out:bt_secp256k1_i128_example_c.exe
|
||||||
|
clang-cl !common_compile_flags! -D EXAMPLE_BUILD_I128_X86_64_ASM -Tc !common_source_files! !common_linker_flags! -out:bt_secp256k1_i128_x86_64_asm_example_c.exe
|
||||||
|
|
||||||
|
clang-cl !common_compile_flags! -D EXAMPLE_BUILD_I128 -Tp !common_source_files! !common_linker_flags! -out:bt_secp256k1_i128_example_cpp.exe
|
||||||
|
clang-cl !common_compile_flags! -D EXAMPLE_BUILD_I128_X86_64_ASM -Tp !common_source_files! !common_linker_flags! -out:bt_secp256k1_i128_x86_64_asm_example_cpp.exe
|
||||||
|
popd
|
1
secp256k1
Submodule
1
secp256k1
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit c8aa516b57ab951e26a1ff5fa283d6f5612ca809
|
Loading…
x
Reference in New Issue
Block a user