Skip to content

Commit

Permalink
Add secp256r1 support (#7)
Browse files Browse the repository at this point in the history
* Add support for secp256r1
* More details in docs/secp256r1.md
  • Loading branch information
contrun authored Aug 29, 2023
1 parent b86d932 commit 8cfecf8
Show file tree
Hide file tree
Showing 12 changed files with 825 additions and 182 deletions.
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,7 @@
[submodule "deps/ed25519"]
path = deps/ed25519
url = https://github.com/nervosnetwork/ed25519.git
[submodule "deps/libecc"]
path = deps/libecc
url = https://github.com/cryptape/libecc.git
branch = riscv-optimized
26 changes: 22 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,20 @@ PASSED_MBEDTLS_CFLAGS := $(CFLAGS) -DCKB_DECLARATION_ONLY -I ../../ckb-c-stdlib-

SECP256K1_SRC_20210801 := deps/secp256k1-20210801/src/ecmult_static_pre_context.h

CFLAGS_LIBECC := -fno-builtin -DUSER_NN_BIT_LEN=256 -DWORDSIZE=64 -DWITH_STDLIB -DWITH_CKB -DCKB_DECLARATION_ONLY -fPIC -g -O3
LIBECC_OPTIMIZED_PATH := deps/libecc
LIBECC_OPTIMIZED_FILES := ${LIBECC_OPTIMIZED_PATH}/build/libarith.a ${LIBECC_OPTIMIZED_PATH}/build/libec.a ${LIBECC_OPTIMIZED_PATH}/build/libsign.a
CFLAGS_LIBECC_OPTIMIZED = -I ../ckb-c-stdlib-2023 -I ../ckb-c-stdlib-2023/libc -I ../ckb-c-stdlib-2023/molecule $(CFLAGS_LIBECC) -DWITH_LL_U256_MONT
CFLAGS_LINK_TO_LIBECC_OPTIMIZED := -fno-builtin -fno-builtin-printf -DWORDSIZE=64 -DWITH_STDLIB -DWITH_CKB -I ${LIBECC_OPTIMIZED_PATH}/src -I ${LIBECC_OPTIMIZED_PATH}/src/external_deps

# docker pull nervos/ckb-riscv-gnu-toolchain:gnu-jammy-20230214
BUILDER_DOCKER := nervos/ckb-riscv-gnu-toolchain@sha256:d3f649ef8079395eb25a21ceaeb15674f47eaa2d8cc23adc8bcdae3d5abce6ec

all: build/secp256k1_data_info_20210801.h $(SECP256K1_SRC_20210801) deps/mbedtls/library/libmbedcrypto.a build/auth build/always_success
all: build/secp256k1_data_info_20210801.h $(SECP256K1_SRC_20210801) deps/mbedtls/library/libmbedcrypto.a build/auth_libecc build/auth build/always_success

all-via-docker: ${PROTOCOL_HEADER}
mkdir -p build
docker run --rm -v `pwd`:/code ${BUILDER_DOCKER} bash -c "cd /code && make"
docker run --rm -v `pwd`:/code ${BUILDER_DOCKER} bash -c "cd /code && make all"

build/always_success: c/always_success.c
$(CC) $(AUTH_CFLAGS) $(LDFLAGS) -o $@ $<
Expand All @@ -48,6 +54,11 @@ $(SECP256K1_SRC_20210801):
CC=$(CC) LD=$(LD) ./configure --with-bignum=no --enable-ecmult-static-precomputation --enable-endomorphism --enable-module-recovery --host=$(TARGET) && \
make src/ecmult_static_pre_context.h src/ecmult_static_context.h

$(LIBECC_OPTIMIZED_FILES): libecc

libecc:
make -C ${LIBECC_OPTIMIZED_PATH} LIBECC_WITH_LL_U256_MONT=1 CC=${CC} LD=${LD} CFLAGS="$(CFLAGS_LIBECC_OPTIMIZED)"

deps/mbedtls/library/libmbedcrypto.a:
cp deps/mbedtls-config-template.h deps/mbedtls/include/mbedtls/config.h
make -C deps/mbedtls/library APPLE_BUILD=0 AR=$(AR) CC=${CC} LD=${LD} CFLAGS="${PASSED_MBEDTLS_CFLAGS}" LDFLAGS="${LDFLAGS}" libmbedcrypto.a
Expand All @@ -68,18 +79,25 @@ build/auth: c/auth.c c/cardano/cardano_lock_inc.h c/ripple.h deps/mbedtls/librar
$(CC) $(AUTH_CFLAGS) $(LDFLAGS) -fPIE -pie -Wl,--dynamic-list c/auth.syms -o $@ $^
cp $@ $@.debug
$(OBJCOPY) --strip-debug --strip-all $@
ls -l build/auth
ls -l $@

build/auth_libecc: c/auth_libecc.c $(LIBECC_OPTIMIZED_FILES)
$(CC) $(AUTH_CFLAGS) $(CFLAGS_LINK_TO_LIBECC_OPTIMIZED) $(LDFLAGS) -fPIE -pie -Wl,--dynamic-list c/auth.syms -o $@ $^
cp $@ $@.debug
$(OBJCOPY) --strip-debug --strip-all $@
ls -l $@

fmt:
clang-format -i -style="{BasedOnStyle: Google, IndentWidth: 4}" c/*.c c/*.h

clean:
rm -rf build/*.debug
rm -f build/auth build/auth_demo
rm -f build/auth build/auth_libecc build/auth_demo
rm -rf build/secp256k1_data_info_20210801.h build/dump_secp256k1_data_20210801
rm -rf build/ed25519 build/libed25519.a build/nanocbor build/libnanocbor.a
cd deps/secp256k1-20210801 && [ -f "Makefile" ] && make clean
make -C deps/mbedtls/library clean
make -C deps/libecc clean

.PHONY: all all-via-docker

169 changes: 8 additions & 161 deletions c/auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,33 +30,14 @@
#undef CKB_SUCCESS
#include "ckb_hex.h"
#include "blake2b.h"

// Must be the last to include, as secp256k1 and this header file both define
// the macros CHECK and CHECK2.
// clang-format on

#include "cardano/cardano_lock_inc.h"
#include "ripple.h"

// secp256k1 also defines this macros
#undef CHECK2
#undef CHECK
#define CHECK2(cond, code) \
do { \
if (!(cond)) { \
err = code; \
goto exit; \
} \
} while (0)

#define CHECK(code) \
do { \
if (code != 0) { \
err = code; \
goto exit; \
} \
} while (0)

#define CKB_AUTH_LEN 21
#define BLAKE160_SIZE 20
#define BLAKE2B_BLOCK_SIZE 32
#define SECP256K1_PUBKEY_SIZE 33
#define UNCOMPRESSED_SECP256K1_PUBKEY_SIZE 65
#define SECP256K1_SIGNATURE_SIZE 65
Expand All @@ -77,30 +58,6 @@
#define SOLANA_BLOCKHASH_SIZE 32
#define SOLANA_MESSAGE_HEADER_SIZE 3

enum AuthErrorCodeType {
ERROR_NOT_IMPLEMENTED = 100,
ERROR_MISMATCHED,
ERROR_INVALID_ARG,
ERROR_WRONG_STATE,
// spawn
ERROR_SPAWN_INVALID_LENGTH,
ERROR_SPAWN_SIGN_TOO_LONG,
ERROR_SPAWN_INVALID_ALGORITHM_ID,
ERROR_SPAWN_INVALID_SIG,
ERROR_SPAWN_INVALID_MSG,
ERROR_SPAWN_INVALID_PUBKEY,
// schnorr
ERROR_SCHNORR,
};

typedef int (*validate_signature_t)(void *prefilled_data, const uint8_t *sig,
size_t sig_len, const uint8_t *msg,
size_t msg_len, uint8_t *output,
size_t *output_len);

typedef int (*convert_msg_t)(const uint8_t *msg, size_t msg_len,
uint8_t *new_msg, size_t new_msg_len);

int md_string(const mbedtls_md_info_t *md_info, const uint8_t *buf, size_t n,
unsigned char *output) {
int err = 0;
Expand Down Expand Up @@ -1062,128 +1019,18 @@ __attribute__((visibility("default"))) int ckb_auth_validate(
return err;
}

#define OFFSETOF(TYPE, ELEMENT) ((size_t) & (((TYPE *)0)->ELEMENT))
#define PT_DYNAMIC 2

typedef struct {
uint64_t type;
uint64_t value;
} Elf64_Dynamic;

#ifdef CKB_USE_SIM
int simulator_main(int argc, char *argv[]) {
#else
// spawn entry
int main(int argc, char *argv[]) {
// fix error:
// c/auth.c:810:50: error: array subscript 0 is outside array bounds of
// 'uint64_t[0]' {aka 'long unsigned int[]'} [-Werror=array-bounds]
// 810 | Elf64_Phdr *program_headers = (Elf64_Phdr *)(*phoff);
// | ~^~~~~~~
#if defined(__GNUC__) && (__GNUC__ >= 12)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Warray-bounds"
#endif
uint64_t *phoff = (uint64_t *)OFFSETOF(Elf64_Ehdr, e_phoff);
uint16_t *phnum = (uint16_t *)OFFSETOF(Elf64_Ehdr, e_phnum);
Elf64_Phdr *program_headers = (Elf64_Phdr *)(*phoff);
for (int i = 0; i < *phnum; i++) {
Elf64_Phdr *program_header = &program_headers[i];
if (program_header->p_type == PT_DYNAMIC) {
Elf64_Dynamic *d = (Elf64_Dynamic *)program_header->p_vaddr;
uint64_t rela_address = 0;
uint64_t rela_count = 0;
while (d->type != 0) {
if (d->type == 0x7) {
rela_address = d->value;
} else if (d->type == 0x6ffffff9) {
rela_count = d->value;
}
d++;
}
if (rela_address > 0 && rela_count > 0) {
Elf64_Rela *relocations = (Elf64_Rela *)rela_address;
for (int j = 0; j < rela_count; j++) {
Elf64_Rela *relocation = &relocations[j];
if (relocation->r_info != R_RISCV_RELATIVE) {
return ERROR_INVALID_ELF;
}
*((uint64_t *)(relocation->r_offset)) =
(uint64_t)(relocation->r_addend);
}
}
}
int res = setup_elf();
if (res != 0) {
return res;
}

#if defined(__GNUC__) && (__GNUC__ >= 12)
#pragma GCC diagnostic pop
#endif

#endif

int err = 0;

if (argc != 4) {
return -1;
}

#define ARGV_ALGORITHM_ID argv[0]
#define ARGV_SIGNATURE argv[1]
#define ARGV_MESSAGE argv[2]
#define ARGV_PUBKEY_HASH argv[3]

uint32_t algorithm_id_len = strlen(ARGV_ALGORITHM_ID);
uint32_t signature_len = strlen(ARGV_SIGNATURE);
uint32_t message_len = strlen(ARGV_MESSAGE);
uint32_t pubkey_hash_len = strlen(ARGV_PUBKEY_HASH);

if (algorithm_id_len != 2 || signature_len % 2 != 0 ||
message_len != BLAKE2B_BLOCK_SIZE * 2 ||
pubkey_hash_len != BLAKE160_SIZE * 2) {
return ERROR_SPAWN_INVALID_LENGTH;
}

// Limit the maximum size of signature
if (signature_len > 1024 * 64 * 2) {
return ERROR_SPAWN_SIGN_TOO_LONG;
}

uint8_t algorithm_id = 0;
uint8_t signature[signature_len / 2];
uint8_t message[BLAKE2B_BLOCK_SIZE];
uint8_t pubkey_hash[BLAKE160_SIZE];

// auth algorithm id
CHECK2(
!ckb_hex2bin(ARGV_ALGORITHM_ID, &algorithm_id, 1, &algorithm_id_len) &&
algorithm_id_len == 1,
ERROR_SPAWN_INVALID_ALGORITHM_ID);

// signature
CHECK2(
!ckb_hex2bin(ARGV_SIGNATURE, signature, signature_len, &signature_len),
ERROR_SPAWN_INVALID_SIG);

// message
CHECK2(!ckb_hex2bin(ARGV_MESSAGE, message, message_len, &message_len) &&
message_len == BLAKE2B_BLOCK_SIZE,
ERROR_SPAWN_INVALID_MSG);

// public key hash
CHECK2(!ckb_hex2bin(ARGV_PUBKEY_HASH, pubkey_hash, pubkey_hash_len,
&pubkey_hash_len) &&
pubkey_hash_len == BLAKE160_SIZE,
ERROR_SPAWN_INVALID_PUBKEY);

err = ckb_auth_validate(algorithm_id, signature, signature_len, message,
message_len, pubkey_hash, pubkey_hash_len);
CHECK(err);
return ckb_auth_validate_with_func(argc, argv, *ckb_auth_validate);
}

exit:
return err;

#undef ARGV_ALGORITHM_ID
#undef ARGV_SIGNATURE
#undef ARGV_MESSAGE
#undef ARGV_PUBKEY_HASH
}
113 changes: 113 additions & 0 deletions c/auth_libecc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
#include "ckb_auth.h"

// clang-format off
#include "secp256r1.h"

#include "ckb_consts.h"
#if defined(CKB_USE_SIM)
// exclude ckb_dlfcn.h
#define CKB_C_STDLIB_CKB_DLFCN_H_
#include "ckb_syscall_auth_sim.h"
#else
#include "ckb_syscalls.h"
#endif

#include "blake2b.h"
#undef CKB_SUCCESS
// clang-format on


int validate_signature_secp256r1(void *prefilled_data, const uint8_t *sig,
size_t sig_len, const uint8_t *msg,
size_t msg_len, uint8_t *output,
size_t *output_len) {
int err = 0;

if (*output_len < BLAKE160_SIZE) {
return ERROR_INVALID_ARG;
}
CHECK2(msg_len == BLAKE2B_BLOCK_SIZE, ERROR_INVALID_ARG);
CHECK2(sig_len == SECP256R1_DATA_SIZE, ERROR_INVALID_ARG);
const uint8_t *pub_key_ptr = sig;
const uint8_t *signature_ptr = pub_key_ptr + SECP256R1_PUBKEY_SIZE;

CHECK(secp256r1_verify_signature(signature_ptr, SECP256R1_SIGNATURE_SIZE, pub_key_ptr, SECP256R1_PUBKEY_SIZE, msg, msg_len ));

blake2b_state ctx;
uint8_t pubkey_hash[BLAKE2B_BLOCK_SIZE] = {0};
blake2b_init(&ctx, BLAKE2B_BLOCK_SIZE);
blake2b_update(&ctx, pub_key_ptr, SECP256R1_PUBKEY_SIZE);
blake2b_final(&ctx, pubkey_hash, sizeof(pubkey_hash));

memcpy(output, pubkey_hash, BLAKE160_SIZE);
*output_len = BLAKE160_SIZE;
exit:
return err;
}

int convert_copy(const uint8_t *msg, size_t msg_len, uint8_t *new_msg,
size_t new_msg_len) {
if (msg_len != new_msg_len || msg_len != BLAKE2B_BLOCK_SIZE)
return ERROR_INVALID_ARG;
memcpy(new_msg, msg, msg_len);
return 0;
}

static int verify(uint8_t *pubkey_hash, const uint8_t *sig, uint32_t sig_len,
const uint8_t *msg, uint32_t msg_len,
validate_signature_t func, convert_msg_t convert) {
int err = 0;
uint8_t new_msg[BLAKE2B_BLOCK_SIZE];

err = convert(msg, msg_len, new_msg, sizeof(new_msg));
CHECK(err);

uint8_t output_pubkey_hash[BLAKE160_SIZE];
size_t output_len = BLAKE160_SIZE;
err = func(NULL, sig, sig_len, new_msg, sizeof(new_msg), output_pubkey_hash,
&output_len);
CHECK(err);

int same = memcmp(pubkey_hash, output_pubkey_hash, BLAKE160_SIZE);
CHECK2(same == 0, ERROR_MISMATCHED);

exit:
return err;
}


// dynamic linking entry
__attribute__((visibility("default"))) int ckb_auth_validate(
uint8_t auth_algorithm_id, const uint8_t *signature,
uint32_t signature_size, const uint8_t *message, uint32_t message_size,
uint8_t *pubkey_hash, uint32_t pubkey_hash_size) {
int err = 0;
CHECK2(signature != NULL, ERROR_INVALID_ARG);
CHECK2(message != NULL, ERROR_INVALID_ARG);
CHECK2(message_size > 0, ERROR_INVALID_ARG);
CHECK2(pubkey_hash_size == BLAKE160_SIZE, ERROR_INVALID_ARG);

if (auth_algorithm_id == AuthAlgorithmIdSecp256R1) {
err = verify(pubkey_hash, signature, signature_size, message,
message_size, validate_signature_secp256r1, convert_copy);
CHECK(err);
} else {
CHECK2(false, ERROR_NOT_IMPLEMENTED);
}
exit:
return err;
}

#ifdef CKB_USE_SIM
int simulator_main(int argc, char *argv[]) {
#else
// spawn entry
int main(int argc, char *argv[]) {
int res = setup_elf();
if (res != 0) {
return res;
}
#endif

return ckb_auth_validate_with_func(argc, argv, *ckb_auth_validate);
}
Loading

0 comments on commit 8cfecf8

Please sign in to comment.