├── molecule ├── VERSION ├── molecule_reader.h ├── molecule_builder.h └── molecule2_reader.h ├── simulator ├── blake2b_imp.c ├── blake2b_decl_only.h ├── ckb_syscall_simulator.h ├── ckb_syscall_sim.c ├── README.md ├── ckb_syscall_sim.h ├── rsa_sighash_all_usesim.c ├── cJSON.h └── ckb_syscall_simulator.c ├── libc ├── memory.h ├── stddef.h ├── stdbool.h ├── stdarg.h ├── internal │ ├── types.h │ └── atomic.h ├── stdlib.h ├── string.h ├── stdint.h ├── entry.h ├── stdio.h └── limits.h ├── ckb_syscalls.h ├── .travis.yml ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── README.md ├── tests └── ci.c ├── LICENSE ├── Makefile ├── ckb_streaming.h ├── ckb_swappable_signatures.h ├── ckb_consts.h ├── ckb_utils.h ├── ckb_type_id.h ├── ckb_exec.h ├── ckb_syscall_apis.h ├── ckb_syscall_utils.h ├── ckb_raw_syscalls.h ├── ckb_keccak256.h ├── blake2b.h └── ckb_dlfcn.h /molecule/VERSION: -------------------------------------------------------------------------------- 1 | 0.4.1 2 | -------------------------------------------------------------------------------- /simulator/blake2b_imp.c: -------------------------------------------------------------------------------- 1 | 2 | #include "blake2b.h" 3 | -------------------------------------------------------------------------------- /libc/memory.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | -------------------------------------------------------------------------------- /libc/stddef.h: -------------------------------------------------------------------------------- 1 | #ifndef CKB_C_STDLIB_STDDEF_H_ 2 | #define CKB_C_STDLIB_STDDEF_H_ 3 | 4 | #include "internal/types.h" 5 | #define NULL ((void*)0) 6 | #include 7 | 8 | #endif /* CKB_C_STDLIB_STDDEF_H_ */ 9 | -------------------------------------------------------------------------------- /ckb_syscalls.h: -------------------------------------------------------------------------------- 1 | #ifndef CKB_C_STDLIB_CKB_SYSCALLS_H_ 2 | #define CKB_C_STDLIB_CKB_SYSCALLS_H_ 3 | 4 | #include "ckb_raw_syscalls.h" 5 | #include "ckb_syscall_utils.h" 6 | 7 | #endif /* CKB_C_STDLIB_CKB_SYSCALLS_H_ */ 8 | -------------------------------------------------------------------------------- /libc/stdbool.h: -------------------------------------------------------------------------------- 1 | #ifndef CKB_C_STDLIB_STDBOOL_H_ 2 | #define CKB_C_STDLIB_STDBOOL_H_ 3 | #include 4 | 5 | #define true 1 6 | #define false 0 7 | #define bool _Bool 8 | 9 | #endif /* CKB_C_STDLIB_STDBOOL_H_ */ 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | dist: bionic 3 | sudo: true 4 | 5 | git: 6 | depth: 2 7 | 8 | addons: 9 | apt: 10 | packages: 11 | - clang-format 12 | 13 | matrix: 14 | include: 15 | - name: Format 16 | script: 17 | - make fmt 18 | -------------------------------------------------------------------------------- /libc/stdarg.h: -------------------------------------------------------------------------------- 1 | #ifndef CKB_C_STDLIB_STDARG_H_ 2 | #define CKB_C_STDLIB_STDARG_H_ 3 | 4 | #define va_start(v, l) __builtin_va_start(v, l) 5 | #define va_end(v) __builtin_va_end(v) 6 | #define va_arg(v, l) __builtin_va_arg(v, l) 7 | #define __va_copy(d, s) __builtin_va_copy(d, s) 8 | #define va_list __builtin_va_list 9 | 10 | #endif /* CKB_C_STDLIB_STDARG_H_ */ 11 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v1 12 | - name: Update submodules 13 | run: git submodule update --init 14 | - name: Check format 15 | run: make fmt 16 | - name: Check compilation 17 | run: make all-via-docker 18 | -------------------------------------------------------------------------------- /libc/internal/types.h: -------------------------------------------------------------------------------- 1 | #ifndef CKB_C_STDLIB_INTERNAL_TYPES_H_ 2 | #define CKB_C_STDLIB_INTERNAL_TYPES_H_ 3 | 4 | typedef unsigned long size_t; 5 | typedef signed long ssize_t; 6 | 7 | typedef unsigned long uintptr_t; 8 | typedef signed long intptr_t; 9 | 10 | typedef unsigned char uint8_t; 11 | typedef signed char int8_t; 12 | 13 | typedef unsigned short uint16_t; 14 | typedef signed short int16_t; 15 | 16 | typedef unsigned int uint32_t; 17 | typedef signed int int32_t; 18 | 19 | typedef unsigned long uint64_t; 20 | typedef signed long int64_t; 21 | 22 | #endif /* CKB_C_STDLIB_INTERNAL_TYPES_H_ */ 23 | -------------------------------------------------------------------------------- /libc/stdlib.h: -------------------------------------------------------------------------------- 1 | #ifndef CKB_C_STDLIB_STDLIB_H_ 2 | #define CKB_C_STDLIB_STDLIB_H_ 3 | #include 4 | #include 5 | 6 | void *malloc(size_t size); 7 | void free(void *ptr); 8 | void *calloc(size_t nmemb, size_t size); 9 | void *realloc(void *ptr, size_t size); 10 | typedef int (*cmpfun)(const void *, const void *); 11 | void qsort(void *base, size_t nel, size_t width, cmpfun cmp); 12 | int rand(void); 13 | void *bsearch(const void *key, const void *base, size_t nel, size_t width, 14 | int (*cmp)(const void *, const void *)); 15 | 16 | #endif /* CKB_C_STDLIB_STDLIB_H_ */ 17 | -------------------------------------------------------------------------------- /libc/string.h: -------------------------------------------------------------------------------- 1 | #ifndef CKB_C_STDLIB_STRING_H_ 2 | #define CKB_C_STDLIB_STRING_H_ 3 | 4 | #include 5 | #include 6 | 7 | void *memset(void *dest, int c, size_t n); 8 | void *memcpy(void *restrict dest, const void *restrict src, size_t n); 9 | void *memmove(void *dest, const void *src, size_t n); 10 | int memcmp(const void *vl, const void *vr, size_t n); 11 | char *strcpy(char *restrict d, const char *restrict s); 12 | size_t strlen(const char *s); 13 | int strcmp(const char *l, const char *r); 14 | char *strstr(const char *, const char *); 15 | 16 | #endif /* CKB_C_STDLIB_STRING_H_ */ 17 | -------------------------------------------------------------------------------- /libc/stdint.h: -------------------------------------------------------------------------------- 1 | #ifndef CKB_C_STDLIB_STDINT_H_ 2 | #define CKB_C_STDLIB_STDINT_H_ 3 | 4 | #include 5 | 6 | #include "internal/types.h" 7 | 8 | #define INT8_MIN (-1 - 0x7f) 9 | #define INT16_MIN (-1 - 0x7fff) 10 | #define INT32_MIN (-1 - 0x7fffffff) 11 | #define INT64_MIN (-1 - 0x7fffffffffffffff) 12 | 13 | #define INT8_MAX (0x7f) 14 | #define INT16_MAX (0x7fff) 15 | #define INT32_MAX (0x7fffffff) 16 | #define INT64_MAX (0x7fffffffffffffff) 17 | 18 | #define UINT8_MAX (0xff) 19 | #define UINT16_MAX (0xffff) 20 | #define UINT32_MAX (0xffffffffu) 21 | #define UINT64_MAX (0xffffffffffffffffu) 22 | 23 | #define SIZE_MAX UINT64_MAX 24 | 25 | #endif /* CKB_C_STDLIB_STDINT_H_ */ 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | simulator/build.simulator 54 | 55 | tests/ci 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ckb-c-stdlib 2 | 3 | In the development of CKB scripts, we discovered many use-cases and patterns that could be really useful in writing CKB scripts. This repo serves as a commonplace for all those useful scripts. This could include but aren't limit to: 4 | 5 | * CKB's data structure definitions 6 | * Utilities for interacting with CKB via syscalls 7 | * A shimmed libc, notice the libc here is tailored for CKB's special needs, implementing everything in POSIX's standard is never a goal. If you do have special requirements, using a more complete libc is always a better choice 8 | 9 | Notice while this repo would focus on C code, it is not limited to scripts written in C. A Rust script might use FFI to leverage the C code here, a higher level language can also use certain glues to use the code here. 10 | -------------------------------------------------------------------------------- /tests/ci.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "blake2b.h" 12 | #include "ckb_consts.h" 13 | #include "ckb_dlfcn.h" 14 | #include "ckb_exec.h" 15 | #include "ckb_keccak256.h" 16 | #include "ckb_streaming.h" 17 | #include "ckb_swappable_signatures.h" 18 | #include "ckb_syscall_apis.h" 19 | #include "ckb_syscalls.h" 20 | #include "ckb_type_id.h" 21 | #include "ckb_utils.h" 22 | #define MOL2_EXIT ckb_exit 23 | #include "blockchain.h" 24 | #include "blockchain-api2.h" 25 | #include "molecule_reader.h" 26 | #include "molecule2_reader.h" 27 | #include "molecule_builder.h" 28 | 29 | int main(int argc, const char* argv[]) { return 0; } 30 | -------------------------------------------------------------------------------- /libc/entry.h: -------------------------------------------------------------------------------- 1 | #ifndef CKB_C_STDLIB_ENTRY_H_ 2 | #define CKB_C_STDLIB_ENTRY_H_ 3 | 4 | #ifndef CKB_DECLARATION_ONLY 5 | #include "src/impl.c" 6 | 7 | #ifndef __SHARED_LIBRARY__ 8 | __attribute__((visibility("default"))) __attribute__((naked)) void _start() { 9 | asm volatile( 10 | ".option push\n" 11 | ".option norelax\n" 12 | #ifndef CKB_NO_ENTRY_GP 13 | "1:auipc gp, %pcrel_hi(__global_pointer$)\n" 14 | "addi gp, gp, %pcrel_lo(1b)\n" 15 | ".option pop\n" 16 | #endif 17 | /* 18 | * By default CKB VM initializes all memory to 0, there's no need 19 | * to clear BSS segment again. 20 | */ 21 | "lw a0, 0(sp)\n" 22 | "addi a1, sp, 8\n" 23 | "li a2, 0\n" 24 | "call main\n" 25 | "li a7, 93\n" 26 | "ecall"); 27 | } 28 | #endif /* __SHARED_LIBRARY__ */ 29 | #endif /* CKB_DECLARATION_ONLY*/ 30 | 31 | #endif /* CKB_C_STDLIB_ENTRY_H_ */ 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Nervos Network 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /libc/internal/atomic.h: -------------------------------------------------------------------------------- 1 | #ifndef CKB_C_STDLIB_INTERNAL_ATOMIC_H_ 2 | #define CKB_C_STDLIB_INTERNAL_ATOMIC_H_ 3 | #include 4 | 5 | /* 6 | * Modified from 7 | * https://git.musl-libc.org/cgit/musl/tree/src/internal/atomic.h?id=33338ebc853d37c80f0f236cc7a92cb0acc6aace 8 | */ 9 | static inline int a_ctz_32(uint32_t x) { 10 | static const char debruijn32[32] = { 11 | 0, 1, 23, 2, 29, 24, 19, 3, 30, 27, 25, 11, 20, 8, 4, 13, 12 | 31, 22, 28, 18, 26, 10, 7, 12, 21, 17, 9, 6, 16, 5, 15, 14}; 13 | return debruijn32[(x & -x) * 0x076be629 >> 27]; 14 | } 15 | 16 | static inline int a_ctz_64(uint64_t x) { 17 | static const char debruijn64[64] = { 18 | 0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28, 19 | 62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11, 20 | 63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10, 21 | 51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12}; 22 | if (sizeof(long) < 8) { 23 | uint32_t y = x; 24 | if (!y) { 25 | y = x >> 32; 26 | return 32 + a_ctz_32(y); 27 | } 28 | return a_ctz_32(y); 29 | } 30 | return debruijn64[(x & -x) * 0x022fdd63cc95386dull >> 58]; 31 | } 32 | 33 | static inline int a_ctz_l(unsigned long x) { 34 | return (sizeof(long) < 8) ? a_ctz_32(x) : a_ctz_64(x); 35 | } 36 | 37 | #endif /* CKB_C_STDLIB_INTERNAL_ATOMIC_H_ */ 38 | -------------------------------------------------------------------------------- /simulator/blake2b_decl_only.h: -------------------------------------------------------------------------------- 1 | #ifndef CKB_MISCELLANEOUS_SCRIPTS_SIMULATOR_BLAKE2B_DECL_ONLY_H_ 2 | #define CKB_MISCELLANEOUS_SCRIPTS_SIMULATOR_BLAKE2B_DECL_ONLY_H_ 3 | #include 4 | #include 5 | 6 | enum blake2b_constant { 7 | BLAKE2B_BLOCKBYTES = 128, 8 | BLAKE2B_OUTBYTES = 64, 9 | BLAKE2B_KEYBYTES = 64, 10 | BLAKE2B_SALTBYTES = 16, 11 | BLAKE2B_PERSONALBYTES = 16 12 | }; 13 | 14 | typedef struct blake2b_state__ { 15 | uint64_t h[8]; 16 | uint64_t t[2]; 17 | uint64_t f[2]; 18 | uint8_t buf[BLAKE2B_BLOCKBYTES]; 19 | size_t buflen; 20 | size_t outlen; 21 | uint8_t last_node; 22 | } blake2b_state; 23 | 24 | /* Streaming API */ 25 | int ckb_blake2b_init(blake2b_state *S, size_t outlen); 26 | int blake2b_init(blake2b_state *S, size_t outlen); 27 | int blake2b_init_key(blake2b_state *S, size_t outlen, const void *key, 28 | size_t keylen); 29 | int blake2b_update(blake2b_state *S, const void *in, size_t inlen); 30 | int blake2b_final(blake2b_state *S, void *out, size_t outlen); 31 | /* Simple API */ 32 | int blake2b(void *out, size_t outlen, const void *in, size_t inlen, 33 | const void *key, size_t keylen); 34 | 35 | /* This is simply an alias for blake2b */ 36 | int blake2(void *out, size_t outlen, const void *in, size_t inlen, 37 | const void *key, size_t keylen); 38 | 39 | #endif // CKB_MISCELLANEOUS_SCRIPTS_SIMULATOR_BLAKE2B_DECL_ONLY_H_ 40 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC := riscv64-unknown-elf-gcc 2 | AR := riscv64-unknown-elf-ar 3 | LIB := libdummylibc.a 4 | CFLAGS := -Wall -Werror -Wextra -Wno-unused-parameter -Wno-dangling-pointer -Wno-nonnull -Wno-nonnull-compare -fno-builtin-printf -fno-builtin-memcmp -O3 -g -fdata-sections -ffunction-sections 5 | 6 | LDFLAGS := -nostdlib -nostartfiles -Wl,-static -Wl,--gc-sections 7 | EXTRA := -I . -I libc -I molecule -Wno-unused-function -Wno-array-bounds -Wno-stringop-overflow 8 | 9 | # nervos/ckb-riscv-gnu-toolchain:jammy-20230214 10 | BUILDER_DOCKER := nervos/ckb-riscv-gnu-toolchain@sha256:d175f4a766b4b17a44bd9bbeca8e24ab2427ba615738016dc49e194046e6b28b 11 | CLANG_FORMAT_DOCKER := xujiandong/ckb-riscv-llvm-toolchain@sha256:6409ab0d3e335c74088b54f4f73252f4b3367ae364d5c7ca7acee82135f5af4d 12 | 13 | 14 | default: fmt 15 | 16 | all-via-docker: 17 | docker run -u $(shell id -u):$(shell id -g) --rm -v `pwd`:/code ${BUILDER_DOCKER} bash -c "cd /code && make all" 18 | 19 | all: tests/ci 20 | 21 | tests/ci: tests/ci.c 22 | $(CC) $(CFLAGS) $(EXTRA) $(LDFLAGS) -o $@ $< 23 | 24 | ALL_C_SOURCE := $(wildcard *.h */*.h *.c */*.c libc/*.h libc/src/*.c) 25 | 26 | fmt: 27 | docker run -u $(shell id -u):$(shell id -g) --rm -v `pwd`:/code ${CLANG_FORMAT_DOCKER} bash -c "cd code && clang-format -i -style='{BasedOnStyle: google, SortIncludes: false}' $(ALL_C_SOURCE)" 28 | git diff --exit-code $(ALL_C_SOURCE) 29 | 30 | 31 | $(LIB): impl.o 32 | $(AR) rcs $@ $^ 33 | 34 | impl.o: libc/src/impl.c 35 | $(CC) $(CFLAGS) -c $< -o $@ -I libc -D__SHARED_LIBRARY__ 36 | 37 | clean: 38 | rm -rf $(LIB) impl.o 39 | rm tests/ci 40 | 41 | .PHONY: clean default fmt 42 | -------------------------------------------------------------------------------- /ckb_streaming.h: -------------------------------------------------------------------------------- 1 | #ifndef CKB_C_STDLIB_CKB_STREAMING_H_ 2 | #define CKB_C_STDLIB_CKB_STREAMING_H_ 3 | 4 | #ifndef CKB_ONE_BATCH_SIZE 5 | #define CKB_ONE_BATCH_SIZE 16384 6 | #endif /* CKB_ONE_BATCH_SIZE */ 7 | 8 | #include "blake2b.h" 9 | #include "ckb_syscalls.h" 10 | 11 | typedef int (*load_function)(void *, uint64_t *, size_t, size_t, size_t); 12 | 13 | int ckb_load_and_hash(blake2b_state *ctx, size_t start, size_t index, 14 | size_t source, load_function f) { 15 | uint8_t temp[CKB_ONE_BATCH_SIZE]; 16 | uint64_t len = CKB_ONE_BATCH_SIZE; 17 | int ret = f(temp, &len, start, index, source); 18 | if (ret != CKB_SUCCESS) { 19 | return ret; 20 | } 21 | blake2b_update(ctx, (char *)&len, sizeof(uint64_t)); 22 | uint64_t offset = (len > CKB_ONE_BATCH_SIZE) ? CKB_ONE_BATCH_SIZE : len; 23 | blake2b_update(ctx, temp, offset); 24 | while (offset < len) { 25 | uint64_t current_len = CKB_ONE_BATCH_SIZE; 26 | ret = f(temp, ¤t_len, start + offset, index, source); 27 | if (ret != CKB_SUCCESS) { 28 | return ret; 29 | } 30 | uint64_t current_read = 31 | (current_len > CKB_ONE_BATCH_SIZE) ? CKB_ONE_BATCH_SIZE : current_len; 32 | blake2b_update(ctx, temp, current_read); 33 | offset += current_read; 34 | } 35 | return CKB_SUCCESS; 36 | } 37 | 38 | int ckb_hash_cell(blake2b_state *ctx, size_t index_code, size_t source) { 39 | return ckb_load_and_hash(ctx, 0, index_code, source, ckb_load_cell); 40 | } 41 | 42 | int ckb_hash_input(blake2b_state *ctx, size_t index_code, size_t source) { 43 | return ckb_load_and_hash(ctx, 0, index_code, source, ckb_load_input); 44 | } 45 | 46 | #endif /* CKB_C_STDLIB_CKB_STREAMING_H_ */ 47 | -------------------------------------------------------------------------------- /ckb_swappable_signatures.h: -------------------------------------------------------------------------------- 1 | #ifndef CKB_C_STDLIB_CKB_SWAPPABLE_SIGNATURES_H_ 2 | #define CKB_C_STDLIB_CKB_SWAPPABLE_SIGNATURES_H_ 3 | 4 | #include "ckb_dlfcn.h" 5 | 6 | #ifdef CKB_SWAPPABLE_SIGNATURES_DEBUG 7 | #define DEBUG(s) ckb_debug(s) 8 | #else 9 | #define DEBUG(s) 10 | #endif /* CKB_SWAPPABLE_SIGNATURES_DEBUG */ 11 | 12 | typedef int (*verify_function)(void *, const uint8_t *, size_t, const uint8_t *, 13 | size_t, uint8_t *, size_t *); 14 | 15 | typedef struct { 16 | uint8_t *code_buffer; 17 | uint64_t code_buffer_size; 18 | uint8_t *prefilled_data_buffer; 19 | size_t prefilled_buffer_size; 20 | verify_function verify_func; 21 | } CkbSwappableSignatureInstance; 22 | 23 | int ckb_initialize_swappable_signature( 24 | const uint8_t *code_hash, uint8_t hash_type, 25 | CkbSwappableSignatureInstance *instance) { 26 | void *handle = NULL; 27 | size_t consumed_size = 0; 28 | int ret = ckb_dlopen2(code_hash, hash_type, instance->code_buffer, 29 | instance->code_buffer_size, &handle, &consumed_size); 30 | if (ret != CKB_SUCCESS) { 31 | return ret; 32 | } 33 | instance->code_buffer_size = consumed_size; 34 | int (*load_prefilled_data_func)(void *, size_t *); 35 | *(void **)(&load_prefilled_data_func) = 36 | ckb_dlsym(handle, "load_prefilled_data"); 37 | if (load_prefilled_data_func == NULL) { 38 | DEBUG("Error loading load prefilled data func!"); 39 | return CKB_INVALID_DATA; 40 | } 41 | ret = load_prefilled_data_func(instance->prefilled_data_buffer, 42 | &instance->prefilled_buffer_size); 43 | if (ret != CKB_SUCCESS) { 44 | DEBUG("Error loading prefilled data!"); 45 | return ret; 46 | } 47 | *(void **)(&instance->verify_func) = ckb_dlsym(handle, "validate_signature"); 48 | if (instance->verify_func == NULL) { 49 | DEBUG("Error loading validate signature func!"); 50 | return CKB_INVALID_DATA; 51 | } 52 | return CKB_SUCCESS; 53 | } 54 | 55 | #endif /* CKB_C_STDLIB_CKB_SWAPPABLE_SIGNATURES_H_ */ 56 | -------------------------------------------------------------------------------- /ckb_consts.h: -------------------------------------------------------------------------------- 1 | #ifndef CKB_C_STDLIB_CKB_CONSTS_H_ 2 | #define CKB_C_STDLIB_CKB_CONSTS_H_ 3 | 4 | #define SYS_exit 93 5 | #define SYS_ckb_vm_version 2041 6 | #define SYS_ckb_current_cycles 2042 7 | #define SYS_ckb_exec 2043 8 | #define SYS_ckb_load_transaction 2051 9 | #define SYS_ckb_load_script 2052 10 | #define SYS_ckb_load_tx_hash 2061 11 | #define SYS_ckb_load_script_hash 2062 12 | #define SYS_ckb_load_cell 2071 13 | #define SYS_ckb_load_header 2072 14 | #define SYS_ckb_load_input 2073 15 | #define SYS_ckb_load_witness 2074 16 | #define SYS_ckb_load_cell_by_field 2081 17 | #define SYS_ckb_load_header_by_field 2082 18 | #define SYS_ckb_load_input_by_field 2083 19 | #define SYS_ckb_load_cell_data_as_code 2091 20 | #define SYS_ckb_load_cell_data 2092 21 | #define SYS_ckb_debug 2177 22 | #define SYS_ckb_load_block_extension 2104 23 | #define SYS_ckb_spawn 2601 24 | #define SYS_ckb_wait 2602 25 | #define SYS_ckb_process_id 2603 26 | #define SYS_ckb_pipe 2604 27 | #define SYS_ckb_write 2605 28 | #define SYS_ckb_read 2606 29 | #define SYS_ckb_inherited_fds 2607 30 | #define SYS_ckb_close 2608 31 | 32 | #define CKB_SUCCESS 0 33 | #define CKB_INDEX_OUT_OF_BOUND 1 34 | #define CKB_ITEM_MISSING 2 35 | #define CKB_LENGTH_NOT_ENOUGH 3 36 | #define CKB_INVALID_DATA 4 37 | #define CKB_WAIT_FAILURE 5 38 | #define CKB_INVALID_FD 6 39 | #define CKB_OTHER_END_CLOSED 7 40 | #define CKB_MAX_VMS_SPAWNED 8 41 | #define CKB_MAX_FDS_CREATED 9 42 | 43 | #define CKB_SOURCE_INPUT 1 44 | #define CKB_SOURCE_OUTPUT 2 45 | #define CKB_SOURCE_CELL_DEP 3 46 | #define CKB_SOURCE_HEADER_DEP 4 47 | #define CKB_SOURCE_GROUP_INPUT 0x0100000000000001 48 | #define CKB_SOURCE_GROUP_OUTPUT 0x0100000000000002 49 | 50 | #define CKB_CELL_FIELD_CAPACITY 0 51 | #define CKB_CELL_FIELD_DATA_HASH 1 52 | #define CKB_CELL_FIELD_LOCK 2 53 | #define CKB_CELL_FIELD_LOCK_HASH 3 54 | #define CKB_CELL_FIELD_TYPE 4 55 | #define CKB_CELL_FIELD_TYPE_HASH 5 56 | #define CKB_CELL_FIELD_OCCUPIED_CAPACITY 6 57 | 58 | #define CKB_HEADER_FIELD_EPOCH_NUMBER 0 59 | #define CKB_HEADER_FIELD_EPOCH_START_BLOCK_NUMBER 1 60 | #define CKB_HEADER_FIELD_EPOCH_LENGTH 2 61 | 62 | #define CKB_INPUT_FIELD_OUT_POINT 0 63 | #define CKB_INPUT_FIELD_SINCE 1 64 | 65 | #endif /* CKB_C_STDLIB_CKB_CONSTS_H_ */ 66 | -------------------------------------------------------------------------------- /simulator/ckb_syscall_simulator.h: -------------------------------------------------------------------------------- 1 | // note, this macro must be same as in ckb_syscall.h 2 | #ifndef CKB_C_STDLIB_CKB_SYSCALLS_H_ 3 | #define CKB_C_STDLIB_CKB_SYSCALLS_H_ 4 | #include 5 | #include 6 | 7 | #include "ckb_consts.h" 8 | 9 | int ckb_exit(int8_t code); 10 | 11 | int ckb_load_tx_hash(void* addr, uint64_t* len, size_t offset); 12 | 13 | int ckb_load_script_hash(void* addr, uint64_t* len, size_t offset); 14 | 15 | int ckb_load_cell(void* addr, uint64_t* len, size_t offset, size_t index, 16 | size_t source); 17 | 18 | int ckb_load_input(void* addr, uint64_t* len, size_t offset, size_t index, 19 | size_t source); 20 | 21 | int ckb_load_header(void* addr, uint64_t* len, size_t offset, size_t index, 22 | size_t source); 23 | 24 | int ckb_load_witness(void* addr, uint64_t* len, size_t offset, size_t index, 25 | size_t source); 26 | 27 | int ckb_load_script(void* addr, uint64_t* len, size_t offset); 28 | 29 | int ckb_load_cell_by_field(void* addr, uint64_t* len, size_t offset, 30 | size_t index, size_t source, size_t field); 31 | 32 | int ckb_load_header_by_field(void* addr, uint64_t* len, size_t offset, 33 | size_t index, size_t source, size_t field); 34 | 35 | int ckb_load_input_by_field(void* addr, uint64_t* len, size_t offset, 36 | size_t index, size_t source, size_t field); 37 | 38 | int ckb_load_cell_code(void* addr, size_t memory_size, size_t content_offset, 39 | size_t content_size, size_t index, size_t source); 40 | 41 | int ckb_load_cell_data(void* addr, uint64_t* len, size_t offset, size_t index, 42 | size_t source); 43 | 44 | int ckb_debug(const char* s); 45 | 46 | int load_actual_type_witness(uint8_t* buf, uint64_t* len, size_t index, 47 | size_t* type_source); 48 | 49 | int ckb_look_for_dep_with_hash(const uint8_t* data_hash, size_t* index); 50 | 51 | int ckb_calculate_inputs_len(); 52 | 53 | int ckb_look_for_dep_with_hash2(const uint8_t* code_hash, uint8_t hash_type, 54 | size_t* index); 55 | 56 | int ckb_checked_load_cell_by_field(void* addr, uint64_t* len, size_t offset, 57 | size_t index, size_t source, size_t field); 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /simulator/ckb_syscall_sim.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static inline long __internal_syscall(long n, long _a0, long _a1, long _a2, 5 | long _a3, long _a4, long _a5) { 6 | return 0; 7 | } 8 | 9 | #define syscall(n, a, b, c, d, e, f) \ 10 | __internal_syscall(n, (long)(a), (long)(b), (long)(c), (long)(d), (long)(e), \ 11 | (long)(f)) 12 | 13 | int ckb_exit(int8_t code) { return 0; } 14 | 15 | int ckb_load_tx_hash(void* addr, uint64_t* len, size_t offset) { return 0; } 16 | 17 | int ckb_load_script_hash(void* addr, uint64_t* len, size_t offset) { return 0; } 18 | 19 | int ckb_load_cell(void* addr, uint64_t* len, size_t offset, size_t index, 20 | size_t source) { 21 | return 0; 22 | } 23 | 24 | int ckb_load_input(void* addr, uint64_t* len, size_t offset, size_t index, 25 | size_t source) { 26 | return 0; 27 | } 28 | 29 | int ckb_load_header(void* addr, uint64_t* len, size_t offset, size_t index, 30 | size_t source) { 31 | return 0; 32 | } 33 | 34 | int ckb_load_witness(void* addr, uint64_t* len, size_t offset, size_t index, 35 | size_t source) { 36 | return 0; 37 | } 38 | 39 | int ckb_load_script(void* addr, uint64_t* len, size_t offset) { return 0; } 40 | 41 | int ckb_load_cell_by_field(void* addr, uint64_t* len, size_t offset, 42 | size_t index, size_t source, size_t field) { 43 | return 0; 44 | } 45 | 46 | int ckb_load_header_by_field(void* addr, uint64_t* len, size_t offset, 47 | size_t index, size_t source, size_t field) { 48 | return 0; 49 | } 50 | 51 | int ckb_load_input_by_field(void* addr, uint64_t* len, size_t offset, 52 | size_t index, size_t source, size_t field) { 53 | return 0; 54 | } 55 | 56 | int ckb_load_cell_code(void* addr, size_t memory_size, size_t content_offset, 57 | size_t content_size, size_t index, size_t source) { 58 | return 0; 59 | } 60 | 61 | int ckb_load_cell_data(void* addr, uint64_t* len, size_t offset, size_t index, 62 | size_t source) { 63 | return 0; 64 | } 65 | 66 | int ckb_debug(const char* s) { return 0; } 67 | 68 | /* load the actual witness for the current type verify group. 69 | use this instead of ckb_load_witness if type contract needs args to verify 70 | input/output. 71 | */ 72 | int load_actual_type_witness(uint8_t* buf, uint64_t* len, size_t index, 73 | size_t* type_source) { 74 | return 0; 75 | } 76 | 77 | int ckb_look_for_dep_with_hash(const uint8_t* data_hash, size_t* index) { 78 | return 0; 79 | } 80 | 81 | int ckb_calculate_inputs_len() { return 0; } 82 | -------------------------------------------------------------------------------- /libc/stdio.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // \author (c) Marco Paland (info@paland.com) 3 | // 2014-2019, PALANDesign Hannover, Germany 4 | // 5 | // \license The MIT License (MIT) 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | // \brief Tiny printf, sprintf and (v)snprintf implementation, optimized for 26 | // speed on 27 | // embedded systems with a very limited resources. These routines are 28 | // thread safe and reentrant! Use this instead of the bloated 29 | // standard/newlib printf cause these use malloc for printf (and may not 30 | // be thread safe). 31 | // 32 | /////////////////////////////////////////////////////////////////////////////// 33 | 34 | #ifndef CKB_C_STDLIB_STDIO_H_ 35 | #define CKB_C_STDLIB_STDIO_H_ 36 | #include 37 | 38 | /* 39 | * This function uses `ckb_debug` syscall to output formatted messages. 40 | * 41 | * Pass `-D CKB_C_STDLIB_PRINTF` flag to GCC to enable printf; 42 | * If the flag is undefined the printf will be compiled as an empty function. 43 | * 44 | * Some versions of GCC raise errors on compiling since those versions have a 45 | * built-in printf function; pass `-fno-builtin-printf` flag to GCC to fix the 46 | * compiling. 47 | */ 48 | int printf(const char* format, ...); 49 | /* 50 | * This function uses `ckb_debug` syscall to output formatted messages. 51 | * 52 | * Pass `-D CKB_C_STDLIB_PRINTF` flag to GCC to enable ckb_printf; 53 | * If the flag is undefined the ckb_printf will be compiled as an empty 54 | * function. 55 | */ 56 | int ckb_printf(const char* format, ...); 57 | int ckb_debug(const char* s); 58 | 59 | #endif /* CKB_C_STDLIB_STDIO_H_ */ 60 | -------------------------------------------------------------------------------- /simulator/README.md: -------------------------------------------------------------------------------- 1 | 2 | # Simulator 3 | The target of simulator is to compile, run code (which will be run on CKB-VM) on any OS and PC. 4 | The we can use our favorite IDE and OS. It can only speed up development but don't skip necessary steps like testing on real CKB-VM. 5 | 6 | This is a library: see [ckb-miscellaneous-scripts](https://github.com/nervosnetwork/ckb-miscellaneous-scripts/tree/master/simulator) to get more idea about how to use it. 7 | 8 | ## Changes 9 | There some changes: 10 | - All contents under simulator folder 11 | - All code enabled by CKB_SIMULATOR macro 12 | 13 | If you don't want to use the simulator feature, just ignore the folder. 14 | 15 | ## How to run 16 | See more in run-simulator.sh script in [ckb-miscellaneous-scripts](https://github.com/nervosnetwork/ckb-miscellaneous-scripts/tree/master/simulator). 17 | 18 | ## How to get json file 19 | Dump json using [ckb-transaction-dumper](https://github.com/xxuejie/ckb-transaction-dumper). We need a running mainnet 20 | on local machine to dump json. In the following example, we named the dumped json: "original.json". 21 | 22 | Then write a root json file manually (named it data.json): 23 | ```json 24 | { 25 | "is_lock_script": true, 26 | "script_index": 0, 27 | "main": "0xa98c212cf055cedbbb665d475c0561b56c68ea735c8aa830c493264effaf18bd", 28 | "0xa98c212cf055cedbbb665d475c0561b56c68ea735c8aa830c493264effaf18bd": "original.json" 29 | } 30 | ``` 31 | * is_lock_script, the script to run is "lock" script or "type" script 32 | * script_index, the index of the script in "input" 33 | * main, the tx hash of the dumped json 34 | * "tx_hash": the file name of the dumped json. The key part should be same as the value part of "main". 35 | 36 | It might be possible to extend this json to support more TX data. 37 | 38 | 39 | When run the executables, pass this json file name (data.json, not original.json) as first arguments. 40 | See more in simulator/run-simulator.sh : 41 | 42 | ```bash 43 | ../build.simulator/sighash_all data.json 44 | ../build.simulator/sighash_all data2.json 45 | ../build.simulator/sighash_all data3.json 46 | ../build.simulator/sudt sudt_data.json 47 | ``` 48 | 49 | There are more example data under simulator/data folder. 50 | 51 | 52 | ## Used as a library 53 | The simulator is also compiled into library. After build, we can find 54 | library file "libckb_simulator.a". (location simulator/build.simulator/libckb_simulator.a). 55 | It must be used together with following files and macro: 56 | - simulator/ckb_syscall_simulator.h 57 | - optional simulator/blake2b_imp.c file 58 | - macro: CKB_SIMULATOR, see example in secp256k1_blake2b_sighash_all_dual.c 59 | 60 | 61 | 62 | Explanation of extra blake2b_imp.c file: Some contracts include implementation of blake2b directly 63 | but some don't. So we don't include implementation of blake2b source in library. 64 | For example, simple_udt doesn't include it so we need to add it to project manually. 65 | -------------------------------------------------------------------------------- /libc/limits.h: -------------------------------------------------------------------------------- 1 | #ifndef HEADER__LIBC_LIMITS_H_ 2 | #define HEADER__LIBC_LIMITS_H_ 1 3 | 4 | #ifdef _MB_LEN_MAX 5 | #define MB_LEN_MAX _MB_LEN_MAX 6 | #else 7 | #define MB_LEN_MAX 1 8 | #endif 9 | 10 | /* Maximum number of positional arguments, if _WANT_IO_POS_ARGS. */ 11 | #ifndef NL_ARGMAX 12 | #define NL_ARGMAX 32 13 | #endif 14 | 15 | /* Number of bits in a `char'. */ 16 | #undef CHAR_BIT 17 | #define CHAR_BIT 8 18 | 19 | /* Minimum and maximum values a `signed char' can hold. */ 20 | #undef SCHAR_MIN 21 | #define SCHAR_MIN (-128) 22 | #undef SCHAR_MAX 23 | #define SCHAR_MAX 127 24 | 25 | /* Maximum value an `unsigned char' can hold. (Minimum is 0). */ 26 | #undef UCHAR_MAX 27 | #define UCHAR_MAX 255 28 | 29 | /* Minimum and maximum values a `char' can hold. */ 30 | #ifdef __CHAR_UNSIGNED__ 31 | #undef CHAR_MIN 32 | #define CHAR_MIN 0 33 | #undef CHAR_MAX 34 | #define CHAR_MAX 255 35 | #else 36 | #undef CHAR_MIN 37 | #define CHAR_MIN (-128) 38 | #undef CHAR_MAX 39 | #define CHAR_MAX 127 40 | #endif 41 | 42 | /* Minimum and maximum values a `signed short int' can hold. */ 43 | #undef SHRT_MIN 44 | /* For the sake of 16 bit hosts, we may not use -32768 */ 45 | #define SHRT_MIN (-32767 - 1) 46 | #undef SHRT_MAX 47 | #define SHRT_MAX 32767 48 | 49 | /* Maximum value an `unsigned short int' can hold. (Minimum is 0). */ 50 | #undef USHRT_MAX 51 | #define USHRT_MAX 65535 52 | 53 | /* Minimum and maximum values a `signed int' can hold. */ 54 | #ifndef __INT_MAX__ 55 | #define __INT_MAX__ 2147483647 56 | #endif 57 | #undef INT_MIN 58 | #define INT_MIN (-INT_MAX - 1) 59 | #undef INT_MAX 60 | #define INT_MAX __INT_MAX__ 61 | 62 | /* Maximum value an `unsigned int' can hold. (Minimum is 0). */ 63 | #undef UINT_MAX 64 | #define UINT_MAX (INT_MAX * 2U + 1) 65 | 66 | /* Minimum and maximum values a `signed long int' can hold. 67 | (Same as `int'). */ 68 | #ifndef __LONG_MAX__ 69 | #if defined(__alpha__) || (defined(__sparc__) && defined(__arch64__)) || \ 70 | defined(__sparcv9) 71 | #define __LONG_MAX__ 9223372036854775807L 72 | #else 73 | #define __LONG_MAX__ 2147483647L 74 | #endif /* __alpha__ || sparc64 */ 75 | #endif 76 | #undef LONG_MIN 77 | #define LONG_MIN (-LONG_MAX - 1) 78 | #undef LONG_MAX 79 | #define LONG_MAX __LONG_MAX__ 80 | 81 | /* Maximum value an `unsigned long int' can hold. (Minimum is 0). */ 82 | #undef ULONG_MAX 83 | #define ULONG_MAX (LONG_MAX * 2UL + 1) 84 | 85 | #ifndef __LONG_LONG_MAX__ 86 | #define __LONG_LONG_MAX__ 9223372036854775807LL 87 | #endif 88 | 89 | #if __ISO_C_VISIBLE >= 1999 90 | /* Minimum and maximum values a `signed long long int' can hold. */ 91 | #undef LLONG_MIN 92 | #define LLONG_MIN (-LLONG_MAX - 1) 93 | #undef LLONG_MAX 94 | #define LLONG_MAX __LONG_LONG_MAX__ 95 | 96 | /* Maximum value an `unsigned long long int' can hold. (Minimum is 0). */ 97 | #undef ULLONG_MAX 98 | #define ULLONG_MAX (LLONG_MAX * 2ULL + 1) 99 | #endif 100 | 101 | #if __GNU_VISIBLE 102 | /* Minimum and maximum values a `signed long long int' can hold. */ 103 | #undef LONG_LONG_MIN 104 | #define LONG_LONG_MIN (-LONG_LONG_MAX - 1) 105 | #undef LONG_LONG_MAX 106 | #define LONG_LONG_MAX __LONG_LONG_MAX__ 107 | 108 | /* Maximum value an `unsigned long long int' can hold. (Minimum is 0). */ 109 | #undef ULONG_LONG_MAX 110 | #define ULONG_LONG_MAX (LONG_LONG_MAX * 2ULL + 1) 111 | #endif 112 | 113 | #endif /* _LIBC_LIMITS_H_ */ 114 | 115 | #ifndef _POSIX2_RE_DUP_MAX 116 | /* The maximum number of repeated occurrences of a regular expression 117 | * permitted when using the interval notation `\{M,N\}'. */ 118 | #define _POSIX2_RE_DUP_MAX 255 119 | #endif /* _POSIX2_RE_DUP_MAX */ 120 | 121 | #ifndef ARG_MAX 122 | #define ARG_MAX 4096 123 | #endif 124 | 125 | #ifndef PATH_MAX 126 | #define PATH_MAX 4096 127 | #endif 128 | -------------------------------------------------------------------------------- /ckb_utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | utils.h 3 | 4 | Defines basic utility functions. 5 | */ 6 | 7 | #ifndef CKB_C_STDLIB_CKB_UTILS_H_ 8 | #define CKB_C_STDLIB_CKB_UTILS_H_ 9 | 10 | #include "stddef.h" 11 | 12 | /* a and b are since value, 13 | return 0 if a is equals to b, 14 | return -1 if a is less than b, 15 | return 1 if a is greater than b */ 16 | int ckb_epoch_number_with_fraction_cmp(uint64_t a, uint64_t b) { 17 | static const size_t NUMBER_OFFSET = 0; 18 | static const size_t NUMBER_BITS = 24; 19 | static const uint64_t NUMBER_MAXIMUM_VALUE = (1 << NUMBER_BITS); 20 | static const uint64_t NUMBER_MASK = (NUMBER_MAXIMUM_VALUE - 1); 21 | static const size_t INDEX_OFFSET = NUMBER_BITS; 22 | static const size_t INDEX_BITS = 16; 23 | static const uint64_t INDEX_MAXIMUM_VALUE = (1 << INDEX_BITS); 24 | static const uint64_t INDEX_MASK = (INDEX_MAXIMUM_VALUE - 1); 25 | static const size_t LENGTH_OFFSET = NUMBER_BITS + INDEX_BITS; 26 | static const size_t LENGTH_BITS = 16; 27 | static const uint64_t LENGTH_MAXIMUM_VALUE = (1 << LENGTH_BITS); 28 | static const uint64_t LENGTH_MASK = (LENGTH_MAXIMUM_VALUE - 1); 29 | 30 | /* extract a epoch */ 31 | uint64_t a_epoch = (a >> NUMBER_OFFSET) & NUMBER_MASK; 32 | uint64_t a_index = (a >> INDEX_OFFSET) & INDEX_MASK; 33 | uint64_t a_len = (a >> LENGTH_OFFSET) & LENGTH_MASK; 34 | 35 | /* extract b epoch */ 36 | uint64_t b_epoch = (b >> NUMBER_OFFSET) & NUMBER_MASK; 37 | uint64_t b_index = (b >> INDEX_OFFSET) & INDEX_MASK; 38 | uint64_t b_len = (b >> LENGTH_OFFSET) & LENGTH_MASK; 39 | 40 | if (a_epoch < b_epoch) { 41 | return -1; 42 | } else if (a_epoch > b_epoch) { 43 | return 1; 44 | } else { 45 | /* a and b is in the same epoch, 46 | compare a_index / a_len <=> b_index / b_len 47 | */ 48 | uint64_t a_block = a_index * b_len; 49 | uint64_t b_block = b_index * a_len; 50 | /* compare block */ 51 | if (a_block < b_block) { 52 | return -1; 53 | } else if (a_block > b_block) { 54 | return 1; 55 | } else { 56 | return 0; 57 | } 58 | } 59 | } 60 | 61 | #define CKB_SINCE_VALUE_BITS 56 62 | #define CKB_SINCE_VALUE_MASK 0x00ffffffffffffff 63 | #define CKB_SINCE_FLAG_METRIC_MASK 0b01100000 64 | #define CKB_SINCE_EPOCH_FRACTION_FLAG 0b00100000 65 | 66 | /* 67 | * Compare since, comparable is set to 1 when the 68 | * a and b since values have the same flags, otherwise comparable is set to 0. 69 | * 70 | * Return value only has meaning when the comparable is set to 1: 71 | * return 0 if a is equals to b, 72 | * return -1 if a is less than b, 73 | * return 1 if a is greater than b 74 | */ 75 | int ckb_since_cmp(uint64_t a, uint64_t b, int *comparable) { 76 | uint8_t a_flag = a >> CKB_SINCE_VALUE_BITS; 77 | uint8_t b_flag = b >> CKB_SINCE_VALUE_BITS; 78 | if (a_flag != b_flag) { 79 | *comparable = 0; 80 | return 0; 81 | } 82 | *comparable = 1; 83 | if ((a_flag & CKB_SINCE_FLAG_METRIC_MASK) == CKB_SINCE_EPOCH_FRACTION_FLAG) { 84 | return ckb_epoch_number_with_fraction_cmp(a, b); 85 | } else { 86 | uint64_t a_value = a & CKB_SINCE_VALUE_MASK; 87 | uint64_t b_value = b & CKB_SINCE_VALUE_MASK; 88 | if (a_value < b_value) { 89 | return -1; 90 | } else if (a_value > b_value) { 91 | return 1; 92 | } else { 93 | return 0; 94 | } 95 | } 96 | } 97 | 98 | /* 99 | * A temporal patch to solve https://github.com/nervosnetwork/ckb-vm/issues/97. 100 | * If you use a ckb-vm >= 0.20.x, you can safely ignore it. A common practice 101 | * is that use CKB_SP_ALIGN in the first line of the main(), and then use 102 | * CKB_SP_ALIGN_END before exiting. 103 | * 104 | * Example: 105 | * int main() { 106 | * CKB_SP_ALIGN; 107 | * ... 108 | * if cond { 109 | * CKB_SP_ALIGN_END; 110 | * return 1; 111 | * } 112 | * ... 113 | * CKB_SP_ALIGN_END; 114 | * return 0; 115 | * } 116 | */ 117 | #define CKB_SP_ALIGN \ 118 | __asm__( \ 119 | "addi t0, sp, 0\n" \ 120 | "andi sp, sp, 0xfffffffffffffff8\n" \ 121 | "sd t0, -8(sp)\n" \ 122 | "sd t0, -16(sp)\n" \ 123 | "addi sp, sp, -8\n" \ 124 | "andi sp, sp, 0xfffffffffffffff0" \ 125 | : \ 126 | : \ 127 | : "t0") 128 | #define CKB_SP_ALIGN_END __asm__("ld sp, 0(sp)") 129 | 130 | #endif /* CKB_C_STDLIB_CKB_UTILS_H_ */ 131 | -------------------------------------------------------------------------------- /simulator/ckb_syscall_sim.h: -------------------------------------------------------------------------------- 1 | // note, this macro must be same as in ckb_syscall.h 2 | #ifndef CKB_C_STDLIB_CKB_SYSCALLS_H_ 3 | #define CKB_C_STDLIB_CKB_SYSCALLS_H_ 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | static inline long __internal_syscall(long n, long _a0, long _a1, long _a2, 10 | long _a3, long _a4, long _a5) { 11 | return 0; 12 | } 13 | 14 | #define syscall(n, a, b, c, d, e, f) \ 15 | __internal_syscall(n, (long)(a), (long)(b), (long)(c), (long)(d), (long)(e), \ 16 | (long)(f)) 17 | 18 | int ckb_exit(int8_t code); 19 | 20 | int ckb_load_tx_hash(void* addr, uint64_t* len, size_t offset) { 21 | assert(offset == 0); 22 | uint8_t* p = (uint8_t*)addr; 23 | for (int i = 0; i < 32; i++) { 24 | p[i] = 0; 25 | } 26 | *len = 32; 27 | return 0; 28 | } 29 | 30 | int ckb_load_script_hash(void* addr, uint64_t* len, size_t offset); 31 | 32 | int ckb_load_cell(void* addr, uint64_t* len, size_t offset, size_t index, 33 | size_t source); 34 | 35 | int ckb_load_input(void* addr, uint64_t* len, size_t offset, size_t index, 36 | size_t source); 37 | 38 | int ckb_load_header(void* addr, uint64_t* len, size_t offset, size_t index, 39 | size_t source); 40 | 41 | int ckb_load_witness(void* addr, uint64_t* len, size_t offset, size_t index, 42 | size_t source) { 43 | mol_builder_t b; 44 | mol_seg_res_t res; 45 | RsaInfo info; 46 | info.algorithm_id = CKB_VERIFY_RSA; 47 | info.key_size = 1024; 48 | uint8_t* ptr = (uint8_t*)&info; 49 | 50 | if (index > 1) { 51 | return 1; // CKB_INDEX_OUT_OF_BOUND; 52 | } 53 | 54 | MolBuilder_Bytes_init(&b); 55 | for (int i = 0; i < sizeof(info); i++) { 56 | MolBuilder_Bytes_push(&b, ptr[i]); 57 | } 58 | 59 | res = MolBuilder_Bytes_build(b); 60 | assert(res.errno == 0); 61 | assert(MolReader_Bytes_verify(&res.seg, false) == 0); 62 | assert(*len > res.seg.size); 63 | 64 | mol_builder_t w; 65 | MolBuilder_WitnessArgs_init(&w); 66 | MolBuilder_WitnessArgs_set_lock(&w, res.seg.ptr, res.seg.size); 67 | mol_seg_res_t res2 = MolBuilder_WitnessArgs_build(w); 68 | assert(res2.errno == 0); 69 | 70 | memcpy(addr, res2.seg.ptr, res2.seg.size); 71 | *len = res2.seg.size; 72 | return 0; 73 | } 74 | 75 | mol_seg_t build_args_bytes() { 76 | // public key, size: 4+128 = 132 bytes 77 | const int PUBLIC_KEY_SIZE = 132; 78 | uint8_t public_key[132] = {1, 0, 1, 0, 0x56, 0x78}; 79 | 80 | mol_builder_t b; 81 | mol_seg_res_t res; 82 | MolBuilder_Bytes_init(&b); 83 | for (int i = 0; i < PUBLIC_KEY_SIZE; i++) { 84 | MolBuilder_Bytes_push(&b, public_key[i]); 85 | } 86 | res = MolBuilder_Bytes_build(b); 87 | return res.seg; 88 | } 89 | 90 | int ckb_load_script(void* addr, uint64_t* len, size_t offset) { 91 | mol_builder_t b; 92 | mol_seg_res_t res; 93 | 94 | assert(offset == 0); 95 | 96 | MolBuilder_Script_init(&b); 97 | uint8_t code_hash[32] = {0}; 98 | uint8_t hash_type = 0; 99 | 100 | MolBuilder_Script_set_code_hash(&b, code_hash, 32); 101 | MolBuilder_Script_set_hash_type(&b, hash_type); 102 | mol_seg_t bytes = build_args_bytes(); 103 | MolBuilder_Script_set_args(&b, bytes.ptr, bytes.size); 104 | 105 | res = MolBuilder_Script_build(b); 106 | assert(res.errno == 0); 107 | 108 | if (*len < res.seg.size) { 109 | return -1; 110 | } 111 | memcpy(addr, res.seg.ptr, res.seg.size); 112 | *len = res.seg.size; 113 | return 0; 114 | } 115 | 116 | int ckb_load_cell_by_field(void* addr, uint64_t* len, size_t offset, 117 | size_t index, size_t source, size_t field); 118 | 119 | int ckb_load_header_by_field(void* addr, uint64_t* len, size_t offset, 120 | size_t index, size_t source, size_t field); 121 | 122 | int ckb_load_input_by_field(void* addr, uint64_t* len, size_t offset, 123 | size_t index, size_t source, size_t field); 124 | 125 | int ckb_load_cell_code(void* addr, size_t memory_size, size_t content_offset, 126 | size_t content_size, size_t index, size_t source); 127 | 128 | int ckb_load_cell_data(void* addr, uint64_t* len, size_t offset, size_t index, 129 | size_t source); 130 | 131 | int ckb_debug(const char* s); 132 | 133 | /* load the actual witness for the current type verify group. 134 | use this instead of ckb_load_witness if type contract needs args to verify 135 | input/output. 136 | */ 137 | int load_actual_type_witness(uint8_t* buf, uint64_t* len, size_t index, 138 | size_t* type_source); 139 | 140 | int ckb_look_for_dep_with_hash(const uint8_t* data_hash, size_t* index); 141 | 142 | int ckb_calculate_inputs_len() { return 0; } 143 | 144 | #endif 145 | -------------------------------------------------------------------------------- /ckb_type_id.h: -------------------------------------------------------------------------------- 1 | #ifndef CKB_C_STDLIB_CKB_TYPE_ID_H_ 2 | #define CKB_C_STDLIB_CKB_TYPE_ID_H_ 3 | 4 | #include 5 | 6 | #include "blake2b.h" 7 | #include "blockchain.h" 8 | #include "ckb_syscalls.h" 9 | 10 | // Given a 32-byte type id, this function validates if 11 | // current transaction confronts to the type ID rules. 12 | int ckb_validate_type_id(const uint8_t type_id[32]); 13 | // Loading type ID from current script args, type_id must be at least 32 byte 14 | // long. 15 | int ckb_load_type_id_from_script_args(size_t offset, uint8_t type_id[32]); 16 | 17 | #ifndef CKB_TYPE_ID_DECLARATION_ONLY 18 | 19 | #ifdef CKB_TYPE_ID_DEBUG 20 | #define DEBUG(s) ckb_debug(s) 21 | #else 22 | #define DEBUG(s) 23 | #endif /* CKB_TYPE_ID_DEBUG */ 24 | 25 | int ckb_load_type_id_from_script_args(size_t offset, uint8_t type_id[32]) { 26 | // TODO: it is possible to simply load the script header, then only load the 27 | // 32 byte requested data based on offsets. 28 | uint8_t current_script[32768]; 29 | uint64_t len = 32768; 30 | int ret = ckb_load_script(current_script, &len, 0); 31 | if (ret != CKB_SUCCESS) { 32 | DEBUG("Cannot load current script!"); 33 | return CKB_INVALID_DATA; 34 | } 35 | if (len > 32768) { 36 | DEBUG("Current script is too large!"); 37 | return CKB_INVALID_DATA; 38 | } 39 | 40 | mol_seg_t script_seg; 41 | script_seg.ptr = (uint8_t*)current_script; 42 | script_seg.size = len; 43 | if (MolReader_Script_verify(&script_seg, false) != MOL_OK) { 44 | DEBUG("Corrupted data!"); 45 | return CKB_INVALID_DATA; 46 | } 47 | 48 | mol_seg_t args_seg = MolReader_Script_get_args(&script_seg); 49 | mol_seg_t args_bytes_seg = MolReader_Bytes_raw_bytes(&args_seg); 50 | if (offset + 32 > args_bytes_seg.size) { 51 | DEBUG("Length of type id is incorrect!"); 52 | return CKB_INVALID_DATA; 53 | } 54 | memcpy(type_id, &args_bytes_seg.ptr[offset], 32); 55 | return CKB_SUCCESS; 56 | } 57 | 58 | // 1 for true, 0 for false 59 | int _ckb_has_type_id_cell(size_t index, int is_input) { 60 | uint64_t len = 0; 61 | size_t source = 62 | is_input == 1 ? CKB_SOURCE_GROUP_INPUT : CKB_SOURCE_GROUP_OUTPUT; 63 | int ret = ckb_load_cell(NULL, &len, 0, index, source); 64 | return ret == CKB_SUCCESS ? 1 : 0; 65 | } 66 | 67 | int _ckb_locate_first_type_id_output_index(uint64_t* index) { 68 | uint8_t current_script_hash[32]; 69 | uint64_t len = 32; 70 | int ret = ckb_load_script_hash(current_script_hash, &len, 0); 71 | if (ret != CKB_SUCCESS) { 72 | DEBUG("Error loading current script hash!"); 73 | return ret; 74 | } 75 | if (len != 32) { 76 | DEBUG("Invalid script hash length!"); 77 | return CKB_INVALID_DATA; 78 | } 79 | 80 | uint64_t i = 0; 81 | while (1) { 82 | uint8_t buffer[32]; 83 | len = 32; 84 | ret = ckb_load_cell_by_field(buffer, &len, 0, i, CKB_SOURCE_OUTPUT, 85 | CKB_CELL_FIELD_TYPE_HASH); 86 | 87 | if (ret != CKB_SUCCESS) { 88 | if (ret != CKB_ITEM_MISSING) { 89 | DEBUG("Error fetching output type hash to locate type id index!"); 90 | return ret; 91 | } else { 92 | // type script hash can be missing, it's not error 93 | i += 1; 94 | continue; 95 | } 96 | } 97 | if (len != 32) { 98 | DEBUG("Invalid type hash length!"); 99 | return CKB_INVALID_DATA; 100 | } 101 | if (memcmp(buffer, current_script_hash, 32) == 0) { 102 | break; 103 | } 104 | i += 1; 105 | } 106 | *index = i; 107 | return CKB_SUCCESS; 108 | } 109 | 110 | int ckb_validate_type_id(const uint8_t type_id[32]) { 111 | int has_second_type_id_input = _ckb_has_type_id_cell(1, 1); 112 | int has_second_type_id_output = _ckb_has_type_id_cell(1, 0); 113 | if (has_second_type_id_input || has_second_type_id_output) { 114 | DEBUG( 115 | "There can only be at most one input and at most one output type ID " 116 | "cell!"); 117 | return CKB_INVALID_DATA; 118 | } 119 | 120 | int has_first_type_id_input = _ckb_has_type_id_cell(0, 1); 121 | if (!has_first_type_id_input) { 122 | // We are creating a new type ID cell here. Additional checkings are needed 123 | // to ensure the type ID is legit. 124 | uint64_t index = 0xFFFFFFFFFFFFFFFF; 125 | int ret = _ckb_locate_first_type_id_output_index(&index); 126 | if (ret != CKB_SUCCESS) { 127 | return ret; 128 | } 129 | // The type ID is calculated as the blake2b (with CKB's personalization) of 130 | // the first CellInput in current transaction, and the created output cell 131 | // index(in 64-bit little endian unsigned integer). 132 | uint8_t buffer[128]; 133 | uint64_t len = 128; 134 | ret = ckb_checked_load_input(buffer, &len, 0, 0, CKB_SOURCE_INPUT); 135 | if (ret != CKB_SUCCESS) { 136 | DEBUG("Cannot load the first input of the transaction!"); 137 | return ret; 138 | } 139 | blake2b_state blake2b_ctx; 140 | ckb_blake2b_init(&blake2b_ctx, 32); 141 | blake2b_update(&blake2b_ctx, buffer, len); 142 | blake2b_update(&blake2b_ctx, (uint8_t*)(&index), sizeof(index)); 143 | uint8_t expected_type_id[32]; 144 | blake2b_final(&blake2b_ctx, expected_type_id, 32); 145 | if (memcmp(expected_type_id, type_id, 32) != 0) { 146 | DEBUG("Invalid type ID!"); 147 | return CKB_INVALID_DATA; 148 | } 149 | } 150 | return CKB_SUCCESS; 151 | } 152 | 153 | #endif /* CKB_TYPE_ID_DECLARATION_ONLY */ 154 | 155 | #endif /* CKB_C_STDLIB_CKB_TYPE_ID_H_ */ 156 | -------------------------------------------------------------------------------- /ckb_exec.h: -------------------------------------------------------------------------------- 1 | #ifndef _CBK_C_STDLIB_CKB_EXEC_H_ 2 | #define _CBK_C_STDLIB_CKB_EXEC_H_ 3 | #include 4 | #include 5 | 6 | #ifndef CKB_EXEC_MAX_ARGS_COUNT 7 | #define CKB_EXEC_MAX_ARGS_COUNT 64 8 | #endif 9 | 10 | #ifndef CKB_EXEC_MAX_BUFF_LEN 11 | #define CKB_EXEC_MAX_BUFF_LEN (32 * 1024) 12 | #endif 13 | 14 | #ifndef CKB_EXEC_MAX_PARAM_LEN 15 | #define CKB_EXEC_MAX_PARAM_LEN (32 * 1024) 16 | #endif 17 | 18 | enum CkbExecErrorCodeType { 19 | ERROR_EXEC_OUT_OF_BOUNDS = 30, 20 | ERROR_EXEC_INVALID_HEX, 21 | }; 22 | 23 | typedef struct CkbBinaryArgsType { 24 | uint32_t count; 25 | uint32_t len[CKB_EXEC_MAX_ARGS_COUNT]; 26 | uint8_t* params[CKB_EXEC_MAX_ARGS_COUNT]; 27 | 28 | uint32_t used_buff; 29 | uint8_t buff[CKB_EXEC_MAX_BUFF_LEN]; 30 | } CkbBinaryArgsType; 31 | 32 | typedef struct CkbHexArgsType { 33 | uint32_t used_buff; 34 | char buff[CKB_EXEC_MAX_BUFF_LEN]; 35 | } CkbHexArgsType; 36 | 37 | static int _exec_getbin(uint8_t x, uint8_t* out) { 38 | if (x >= '0' && x <= '9') { 39 | *out = x - '0'; 40 | } else if (x >= 'A' && x <= 'F') { 41 | *out = x - 'A' + 10; 42 | } else if (x >= 'a' && x <= 'f') { 43 | *out = x - 'a' + 10; 44 | } else { 45 | return ERROR_EXEC_INVALID_HEX; 46 | } 47 | return 0; 48 | } 49 | 50 | static void _exec_gethex(uint8_t x, char* out) { 51 | static char s_mapping[] = {'0', '1', '2', '3', '4', '5', '6', '7', 52 | '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; 53 | out[0] = s_mapping[(x >> 4) & 0x0F]; 54 | out[1] = s_mapping[x & 0x0F]; 55 | } 56 | 57 | int _exec_safe_strlen(const char* s, uint32_t limit, uint32_t* length) { 58 | if (s == NULL) return ERROR_EXEC_OUT_OF_BOUNDS; 59 | 60 | uint32_t count = 0; 61 | for (; *s; s++) { 62 | count++; 63 | if (count > limit) return ERROR_EXEC_OUT_OF_BOUNDS; 64 | } 65 | *length = count; 66 | return 0; 67 | } 68 | 69 | // the string length of "hex" should be no more than bin_len*2 70 | // "length" returns the bytes count written in "bin" 71 | static int _exec_hex2bin(const char* hex, uint8_t* bin, uint32_t bin_len, 72 | uint32_t* length) { 73 | uint32_t limit = 2 * bin_len; 74 | uint32_t hex_len; 75 | int err = _exec_safe_strlen(hex, limit, &hex_len); 76 | if (err != 0) return err; 77 | if (hex_len % 2 != 0) return ERROR_EXEC_INVALID_HEX; 78 | *length = hex_len / 2; 79 | if (*length > bin_len) { 80 | return ERROR_EXEC_OUT_OF_BOUNDS; 81 | } 82 | for (uint32_t i = 0; i < *length; i++) { 83 | uint8_t high, low; 84 | err = _exec_getbin(hex[i * 2], &high); 85 | if (err != 0) return err; 86 | err = _exec_getbin(hex[i * 2 + 1], &low); 87 | if (err != 0) return err; 88 | bin[i] = high << 4 | low; 89 | } 90 | return 0; 91 | } 92 | 93 | static int _exec_bin2hex(const uint8_t* bin, uint32_t bin_len, char* hex, 94 | uint32_t hex_len, uint32_t* length, bool last_field) { 95 | if (hex_len < (bin_len * 2 + 1)) { 96 | return ERROR_EXEC_OUT_OF_BOUNDS; 97 | } 98 | for (uint32_t i = 0; i < bin_len; i++) { 99 | _exec_gethex(bin[i], hex + 2 * i); 100 | } 101 | if (last_field) 102 | *(hex + bin_len * 2) = 0; 103 | else 104 | *(hex + bin_len * 2) = ':'; 105 | 106 | *length = 2 * bin_len + 1; 107 | return 0; 108 | } 109 | 110 | // use ckb_exec_reset and ckb_exec_append to generate CkbBinaryArgsType from 111 | // scratch 112 | void ckb_exec_reset(CkbBinaryArgsType* args) { 113 | args->count = 0; 114 | args->used_buff = 0; 115 | } 116 | 117 | int ckb_exec_append(CkbBinaryArgsType* args, uint8_t* data, uint32_t len) { 118 | if (args->count >= CKB_EXEC_MAX_ARGS_COUNT) { 119 | return ERROR_EXEC_INVALID_HEX; 120 | } 121 | uint8_t* p = args->buff + args->used_buff; 122 | args->used_buff += len; 123 | if (args->used_buff > CKB_EXEC_MAX_BUFF_LEN) { 124 | return ERROR_EXEC_OUT_OF_BOUNDS; 125 | } 126 | 127 | memcpy(p, data, len); 128 | args->params[args->count] = p; 129 | args->len[args->count] = len; 130 | 131 | args->count++; 132 | 133 | return 0; 134 | } 135 | 136 | int ckb_exec_encode_params(CkbBinaryArgsType* in, CkbHexArgsType* out) { 137 | int err = 0; 138 | 139 | if (in->count > CKB_EXEC_MAX_ARGS_COUNT || in->count == 0) { 140 | return ERROR_EXEC_OUT_OF_BOUNDS; 141 | } 142 | 143 | out->used_buff = 0; 144 | 145 | for (uint32_t i = 0; i < in->count; i++) { 146 | uint8_t* p = in->params[i]; 147 | uint32_t len = in->len[i]; 148 | uint32_t length; 149 | if (out->used_buff >= CKB_EXEC_MAX_BUFF_LEN) { 150 | return ERROR_EXEC_OUT_OF_BOUNDS; 151 | } 152 | bool last_field = (i == (in->count - 1)); 153 | err = _exec_bin2hex(p, len, out->buff + out->used_buff, 154 | CKB_EXEC_MAX_BUFF_LEN - out->used_buff, &length, 155 | last_field); 156 | if (err != 0) return err; 157 | out->used_buff += length; 158 | } 159 | return 0; 160 | } 161 | 162 | int ckb_exec_decode_params(char* argv, uint8_t** param_ptr, uint32_t* param_len, 163 | char** next_iterator_argv) { 164 | int err = 0; 165 | *param_len = 0; 166 | *param_ptr = NULL; 167 | if (argv == NULL) { 168 | return ERROR_EXEC_INVALID_HEX; 169 | } 170 | uint8_t* cur = (uint8_t*)argv; 171 | uint8_t* write_ptr = cur; 172 | *param_ptr = cur; 173 | *param_len = 0; 174 | 175 | uint32_t count = 0; 176 | 177 | uint8_t high, low; 178 | while (true) { 179 | if (*cur == '\0') { 180 | *next_iterator_argv = NULL; 181 | break; 182 | } 183 | if (*cur == ':') { 184 | *next_iterator_argv = (char*)(cur + 1); 185 | break; 186 | } 187 | err = _exec_getbin(*cur, &high); 188 | if (err != 0) return err; 189 | cur++; 190 | err = _exec_getbin(*cur, &low); 191 | if (err != 0) return err; 192 | cur++; 193 | 194 | (*write_ptr) = high << 4 | low; 195 | write_ptr++; 196 | (*param_len)++; 197 | 198 | // prevent infinite loop when no ":" or "\0" is detected 199 | count++; 200 | if (count > CKB_EXEC_MAX_PARAM_LEN) { 201 | return ERROR_EXEC_OUT_OF_BOUNDS; 202 | } 203 | } 204 | return 0; 205 | } 206 | 207 | #endif // _CBK_C_STDLIB_CKB_EXEC_H_ 208 | -------------------------------------------------------------------------------- /ckb_syscall_apis.h: -------------------------------------------------------------------------------- 1 | #ifndef CKB_C_STDLIB_CKB_SYSCALL_APIS_H_ 2 | #define CKB_C_STDLIB_CKB_SYSCALL_APIS_H_ 3 | 4 | /* 5 | * Syscall related APIs that will be shared and used in all CKB 6 | * smart contract environments 7 | */ 8 | 9 | #include 10 | #include 11 | 12 | /* Raw APIs */ 13 | 14 | /* VM version 0 APIs */ 15 | int ckb_exit(int8_t code); 16 | int ckb_load_tx_hash(void* addr, uint64_t* len, size_t offset); 17 | int ckb_load_transaction(void* addr, uint64_t* len, size_t offset); 18 | int ckb_load_script_hash(void* addr, uint64_t* len, size_t offset); 19 | int ckb_load_script(void* addr, uint64_t* len, size_t offset); 20 | int ckb_debug(const char* s); 21 | 22 | int ckb_load_cell(void* addr, uint64_t* len, size_t offset, size_t index, 23 | size_t source); 24 | int ckb_load_input(void* addr, uint64_t* len, size_t offset, size_t index, 25 | size_t source); 26 | int ckb_load_header(void* addr, uint64_t* len, size_t offset, size_t index, 27 | size_t source); 28 | int ckb_load_witness(void* addr, uint64_t* len, size_t offset, size_t index, 29 | size_t source); 30 | int ckb_load_cell_by_field(void* addr, uint64_t* len, size_t offset, 31 | size_t index, size_t source, size_t field); 32 | int ckb_load_header_by_field(void* addr, uint64_t* len, size_t offset, 33 | size_t index, size_t source, size_t field); 34 | int ckb_load_input_by_field(void* addr, uint64_t* len, size_t offset, 35 | size_t index, size_t source, size_t field); 36 | int ckb_load_cell_data(void* addr, uint64_t* len, size_t offset, size_t index, 37 | size_t source); 38 | int ckb_load_cell_data_as_code(void* addr, size_t memory_size, 39 | size_t content_offset, size_t content_size, 40 | size_t index, size_t source); 41 | 42 | /* VM version 1 APIs */ 43 | int ckb_vm_version(); 44 | uint64_t ckb_current_cycles(); 45 | int ckb_exec(size_t index, size_t source, size_t place, size_t bounds, int argc, 46 | const char* argv[]); 47 | 48 | /* VM version 2 APIs */ 49 | typedef struct spawn_args_t { 50 | size_t argc; 51 | const char** argv; 52 | /* Spawned VM process ID */ 53 | uint64_t* process_id; 54 | /* A list of file descriptor, 0 indicates end of array */ 55 | const uint64_t* inherited_fds; 56 | } spawn_args_t; 57 | 58 | int ckb_spawn(size_t index, size_t source, size_t place, size_t bounds, 59 | spawn_args_t* spawn_args); 60 | 61 | int ckb_wait(uint64_t pid, int8_t* exit_code); 62 | 63 | uint64_t ckb_process_id(); 64 | 65 | int ckb_pipe(uint64_t fds[2]); 66 | 67 | int ckb_read(uint64_t fd, void* buffer, size_t* length); 68 | 69 | int ckb_write(uint64_t fd, const void* buffer, size_t* length); 70 | 71 | int ckb_inherited_fds(uint64_t* fds, size_t* length); 72 | 73 | int ckb_close(uint64_t fd); 74 | 75 | int ckb_load_block_extension(void* addr, uint64_t* len, size_t offset, 76 | size_t index, size_t source); 77 | 78 | /* Handy utilities */ 79 | int ckb_exec_cell(const uint8_t* code_hash, uint8_t hash_type, uint32_t offset, 80 | uint32_t length, int argc, const char* argv[]); 81 | int ckb_spawn_cell(const uint8_t* code_hash, uint8_t hash_type, uint32_t offset, 82 | uint32_t length, spawn_args_t* spawn_args); 83 | int ckb_checked_load_tx_hash(void* addr, uint64_t* len, size_t offset); 84 | int ckb_checked_load_script_hash(void* addr, uint64_t* len, size_t offset); 85 | int ckb_checked_load_cell(void* addr, uint64_t* len, size_t offset, 86 | size_t index, size_t source); 87 | int ckb_checked_load_input(void* addr, uint64_t* len, size_t offset, 88 | size_t index, size_t source); 89 | int ckb_checked_load_header(void* addr, uint64_t* len, size_t offset, 90 | size_t index, size_t source); 91 | int ckb_checked_load_witness(void* addr, uint64_t* len, size_t offset, 92 | size_t index, size_t source); 93 | int ckb_checked_load_script(void* addr, uint64_t* len, size_t offset); 94 | int ckb_checked_load_transaction(void* addr, uint64_t* len, size_t offset); 95 | int ckb_checked_load_cell_by_field(void* addr, uint64_t* len, size_t offset, 96 | size_t index, size_t source, size_t field); 97 | int ckb_checked_load_header_by_field(void* addr, uint64_t* len, size_t offset, 98 | size_t index, size_t source, size_t field); 99 | int ckb_checked_load_input_by_field(void* addr, uint64_t* len, size_t offset, 100 | size_t index, size_t source, size_t field); 101 | int ckb_checked_load_cell_data(void* addr, uint64_t* len, size_t offset, 102 | size_t index, size_t source); 103 | /* load the actual witness for the current type verify group. 104 | use this instead of ckb_load_witness if type contract needs args to verify 105 | input/output. 106 | */ 107 | int ckb_load_actual_type_witness(uint8_t* buf, uint64_t* len, size_t index, 108 | size_t* type_source); 109 | /* calculate inputs length */ 110 | int ckb_calculate_inputs_len(); 111 | /* 112 | * Look for a dep cell with specific code hash, code_hash should be a buffer 113 | * with 32 bytes. 114 | */ 115 | int ckb_look_for_dep_with_hash2(const uint8_t* code_hash, uint8_t hash_type, 116 | size_t* index); 117 | /* 118 | * Deprecated, please use ckb_look_for_dep_with_hash2 instead. 119 | */ 120 | int ckb_look_for_dep_with_hash(const uint8_t* data_hash, size_t* index); 121 | 122 | /* 123 | * Those 2 are in fact implemented by ckb_dlfcn.h, which is not a direct 124 | * CKB syscall(or simple wrapper on a syscall), but rather a whole dynamic 125 | * linking solution. However for compatibility reasons, we are still keeping 126 | * those APIs in this file so as not to break existing code. 127 | */ 128 | int ckb_dlopen2(const uint8_t* dep_cell_hash, uint8_t hash_type, 129 | uint8_t* aligned_addr, size_t aligned_size, void** handle, 130 | size_t* consumed_size); 131 | void* ckb_dlsym(void* handle, const char* symbol); 132 | 133 | #endif /* CKB_C_STDLIB_CKB_SYSCALL_APIS_H_ */ 134 | -------------------------------------------------------------------------------- /ckb_syscall_utils.h: -------------------------------------------------------------------------------- 1 | #ifndef CKB_C_STDLIB_CKB_SYSCALL_UTILS_H_ 2 | #define CKB_C_STDLIB_CKB_SYSCALL_UTILS_H_ 3 | 4 | #include 5 | 6 | #include "ckb_consts.h" 7 | #include "ckb_syscall_apis.h" 8 | 9 | #ifndef CKB_STDLIB_NO_SYSCALL_IMPL 10 | 11 | int ckb_checked_load_tx_hash(void* addr, uint64_t* len, size_t offset) { 12 | uint64_t old_len = *len; 13 | int ret = ckb_load_tx_hash(addr, len, offset); 14 | if (ret == CKB_SUCCESS && (*len) > old_len) { 15 | ret = CKB_LENGTH_NOT_ENOUGH; 16 | } 17 | return ret; 18 | } 19 | 20 | int ckb_checked_load_script_hash(void* addr, uint64_t* len, size_t offset) { 21 | uint64_t old_len = *len; 22 | int ret = ckb_load_script_hash(addr, len, offset); 23 | if (ret == CKB_SUCCESS && (*len) > old_len) { 24 | ret = CKB_LENGTH_NOT_ENOUGH; 25 | } 26 | return ret; 27 | } 28 | 29 | int ckb_checked_load_cell(void* addr, uint64_t* len, size_t offset, 30 | size_t index, size_t source) { 31 | uint64_t old_len = *len; 32 | int ret = ckb_load_cell(addr, len, offset, index, source); 33 | if (ret == CKB_SUCCESS && (*len) > old_len) { 34 | ret = CKB_LENGTH_NOT_ENOUGH; 35 | } 36 | return ret; 37 | } 38 | 39 | int ckb_checked_load_input(void* addr, uint64_t* len, size_t offset, 40 | size_t index, size_t source) { 41 | uint64_t old_len = *len; 42 | int ret = ckb_load_input(addr, len, offset, index, source); 43 | if (ret == CKB_SUCCESS && (*len) > old_len) { 44 | ret = CKB_LENGTH_NOT_ENOUGH; 45 | } 46 | return ret; 47 | } 48 | 49 | int ckb_checked_load_header(void* addr, uint64_t* len, size_t offset, 50 | size_t index, size_t source) { 51 | uint64_t old_len = *len; 52 | int ret = ckb_load_header(addr, len, offset, index, source); 53 | if (ret == CKB_SUCCESS && (*len) > old_len) { 54 | ret = CKB_LENGTH_NOT_ENOUGH; 55 | } 56 | return ret; 57 | } 58 | 59 | int ckb_checked_load_witness(void* addr, uint64_t* len, size_t offset, 60 | size_t index, size_t source) { 61 | uint64_t old_len = *len; 62 | int ret = ckb_load_witness(addr, len, offset, index, source); 63 | if (ret == CKB_SUCCESS && (*len) > old_len) { 64 | ret = CKB_LENGTH_NOT_ENOUGH; 65 | } 66 | return ret; 67 | } 68 | 69 | int ckb_checked_load_script(void* addr, uint64_t* len, size_t offset) { 70 | uint64_t old_len = *len; 71 | int ret = ckb_load_script(addr, len, offset); 72 | if (ret == CKB_SUCCESS && (*len) > old_len) { 73 | ret = CKB_LENGTH_NOT_ENOUGH; 74 | } 75 | return ret; 76 | } 77 | 78 | int ckb_checked_load_transaction(void* addr, uint64_t* len, size_t offset) { 79 | uint64_t old_len = *len; 80 | int ret = ckb_load_transaction(addr, len, offset); 81 | if (ret == CKB_SUCCESS && (*len) > old_len) { 82 | ret = CKB_LENGTH_NOT_ENOUGH; 83 | } 84 | return ret; 85 | } 86 | 87 | int ckb_checked_load_cell_by_field(void* addr, uint64_t* len, size_t offset, 88 | size_t index, size_t source, size_t field) { 89 | uint64_t old_len = *len; 90 | int ret = ckb_load_cell_by_field(addr, len, offset, index, source, field); 91 | if (ret == CKB_SUCCESS && (*len) > old_len) { 92 | ret = CKB_LENGTH_NOT_ENOUGH; 93 | } 94 | return ret; 95 | } 96 | 97 | int ckb_checked_load_header_by_field(void* addr, uint64_t* len, size_t offset, 98 | size_t index, size_t source, 99 | size_t field) { 100 | uint64_t old_len = *len; 101 | int ret = ckb_load_header_by_field(addr, len, offset, index, source, field); 102 | if (ret == CKB_SUCCESS && (*len) > old_len) { 103 | ret = CKB_LENGTH_NOT_ENOUGH; 104 | } 105 | return ret; 106 | } 107 | 108 | int ckb_checked_load_input_by_field(void* addr, uint64_t* len, size_t offset, 109 | size_t index, size_t source, size_t field) { 110 | uint64_t old_len = *len; 111 | int ret = ckb_load_input_by_field(addr, len, offset, index, source, field); 112 | if (ret == CKB_SUCCESS && (*len) > old_len) { 113 | ret = CKB_LENGTH_NOT_ENOUGH; 114 | } 115 | return ret; 116 | } 117 | 118 | int ckb_checked_load_cell_data(void* addr, uint64_t* len, size_t offset, 119 | size_t index, size_t source) { 120 | uint64_t old_len = *len; 121 | int ret = ckb_load_cell_data(addr, len, offset, index, source); 122 | if (ret == CKB_SUCCESS && (*len) > old_len) { 123 | ret = CKB_LENGTH_NOT_ENOUGH; 124 | } 125 | return ret; 126 | } 127 | 128 | int ckb_load_actual_type_witness(uint8_t* buf, uint64_t* len, size_t index, 129 | size_t* type_source) { 130 | *type_source = CKB_SOURCE_GROUP_INPUT; 131 | uint64_t tmp_len = 0; 132 | if (ckb_load_cell_by_field(NULL, &tmp_len, 0, 0, CKB_SOURCE_GROUP_INPUT, 133 | CKB_CELL_FIELD_CAPACITY) == 134 | CKB_INDEX_OUT_OF_BOUND) { 135 | *type_source = CKB_SOURCE_GROUP_OUTPUT; 136 | } 137 | 138 | return ckb_checked_load_witness(buf, len, 0, index, *type_source); 139 | } 140 | 141 | int ckb_calculate_inputs_len() { 142 | uint64_t len = 0; 143 | /* lower bound, at least tx has one input */ 144 | int lo = 0; 145 | /* higher bound */ 146 | int hi = 4; 147 | int ret; 148 | /* try to load input until failing to increase lo and hi */ 149 | while (1) { 150 | len = 0; 151 | ret = ckb_load_input_by_field(NULL, &len, 0, hi, CKB_SOURCE_INPUT, 152 | CKB_INPUT_FIELD_SINCE); 153 | if (ret == CKB_SUCCESS) { 154 | lo = hi; 155 | hi *= 2; 156 | } else { 157 | break; 158 | } 159 | } 160 | 161 | /* now we get our lower bound and higher bound, 162 | count number of inputs by binary search */ 163 | int i; 164 | while (lo + 1 != hi) { 165 | i = (lo + hi) / 2; 166 | len = 0; 167 | ret = ckb_load_input_by_field(NULL, &len, 0, i, CKB_SOURCE_INPUT, 168 | CKB_INPUT_FIELD_SINCE); 169 | if (ret == CKB_SUCCESS) { 170 | lo = i; 171 | } else { 172 | hi = i; 173 | } 174 | } 175 | /* now lo is last input index and hi is length of inputs */ 176 | return hi; 177 | } 178 | 179 | int ckb_look_for_dep_with_hash2(const uint8_t* code_hash, uint8_t hash_type, 180 | size_t* index) { 181 | size_t current = 0; 182 | size_t field = 183 | (hash_type == 1) ? CKB_CELL_FIELD_TYPE_HASH : CKB_CELL_FIELD_DATA_HASH; 184 | while (current < SIZE_MAX) { 185 | uint64_t len = 32; 186 | uint8_t hash[32]; 187 | 188 | int ret = ckb_load_cell_by_field(hash, &len, 0, current, 189 | CKB_SOURCE_CELL_DEP, field); 190 | switch (ret) { 191 | case CKB_ITEM_MISSING: 192 | break; 193 | case CKB_SUCCESS: 194 | if (memcmp(code_hash, hash, 32) == 0) { 195 | /* Found a match */ 196 | *index = current; 197 | return CKB_SUCCESS; 198 | } 199 | break; 200 | default: 201 | return CKB_INDEX_OUT_OF_BOUND; 202 | } 203 | current++; 204 | } 205 | return CKB_INDEX_OUT_OF_BOUND; 206 | } 207 | 208 | int ckb_look_for_dep_with_hash(const uint8_t* data_hash, size_t* index) { 209 | return ckb_look_for_dep_with_hash2(data_hash, 0, index); 210 | } 211 | 212 | int ckb_exec_cell(const uint8_t* code_hash, uint8_t hash_type, uint32_t offset, 213 | uint32_t length, int argc, const char* argv[]) { 214 | size_t index = SIZE_MAX; 215 | int ret = ckb_look_for_dep_with_hash2(code_hash, hash_type, &index); 216 | if (ret != CKB_SUCCESS) { 217 | return ret; 218 | } 219 | size_t bounds = ((size_t)offset << 32) | length; 220 | return ckb_exec(index, CKB_SOURCE_CELL_DEP, 0, bounds, argc, argv); 221 | } 222 | 223 | int ckb_spawn_cell(const uint8_t* code_hash, uint8_t hash_type, uint32_t offset, 224 | uint32_t length, spawn_args_t* spawn_args) { 225 | size_t index = SIZE_MAX; 226 | int ret = ckb_look_for_dep_with_hash2(code_hash, hash_type, &index); 227 | if (ret != CKB_SUCCESS) { 228 | return ret; 229 | } 230 | size_t bounds = ((size_t)offset << 32) | length; 231 | return ckb_spawn(index, CKB_SOURCE_CELL_DEP, 0, bounds, spawn_args); 232 | } 233 | 234 | #endif /* CKB_STDLIB_NO_SYSCALL_IMPL */ 235 | 236 | #endif /* CKB_C_STDLIB_CKB_SYSCALL_UTILS_H_ */ 237 | -------------------------------------------------------------------------------- /molecule/molecule_reader.h: -------------------------------------------------------------------------------- 1 | #ifndef MOLECULE_READER_H 2 | #define MOLECULE_READER_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif /* __cplusplus */ 7 | 8 | #include 9 | #include 10 | 11 | #ifndef MOLECULE_API_DECORATOR 12 | #define __DEFINE_MOLECULE_API_DECORATOR 13 | #define MOLECULE_API_DECORATOR 14 | #endif /* MOLECULE_API_DECORATOR */ 15 | 16 | #define MOLECULE_API_VERSION 7000 17 | #define MOLECULEC_VERSION_MIN 5000 18 | 19 | #if MOLECULE_API_VERSION < MOLECULE_API_VERSION_MIN 20 | #error This file was generated by a newer version of moleculec which is \ 21 | incompatible with current headers in use. Please update the headers. 22 | #endif 23 | 24 | #if MOLECULEC_VERSION < MOLECULEC_VERSION_MIN 25 | #error This file was generated by an older version of moleculec which is \ 26 | incompatible with current headers in use. Please regenerate this file \ 27 | with a newer version of moleculec. 28 | #endif 29 | 30 | /* 31 | * This part is not for normal users. 32 | */ 33 | 34 | // Test if the host is big endian machine. 35 | #define is_le() \ 36 | ((union { \ 37 | uint16_t i; \ 38 | unsigned char c; \ 39 | }){.i = 1} \ 40 | .c) 41 | 42 | /* 43 | * Definitions of types and simple utilities. 44 | */ 45 | 46 | /* Core types */ 47 | 48 | typedef uint32_t mol_num_t; // Item Id 49 | 50 | typedef uint8_t mol_errno; // Error Number 51 | 52 | #define MolNum UINT32_C 53 | 54 | #define MOL_NUM_T_SIZE 4 55 | 56 | // Bytes segment. 57 | typedef struct { 58 | uint8_t *ptr; // Pointer 59 | mol_num_t size; // Full size 60 | } mol_seg_t; 61 | 62 | // Unpacked Union 63 | typedef struct { 64 | mol_num_t item_id; // Item Id 65 | mol_seg_t seg; // Segment 66 | } mol_union_t; 67 | 68 | // Result for returning segment. 69 | typedef struct { 70 | mol_errno errno; // Error Number 71 | mol_seg_t seg; // Segment 72 | } mol_seg_res_t; 73 | 74 | /* Error Numbers */ 75 | 76 | #define MOL_OK 0x00 77 | #define MOL_ERR 0xff 78 | 79 | #define MOL_ERR_TOTAL_SIZE 0x01 80 | #define MOL_ERR_HEADER 0x02 81 | #define MOL_ERR_OFFSET 0x03 82 | #define MOL_ERR_UNKNOWN_ITEM 0x04 83 | #define MOL_ERR_INDEX_OUT_OF_BOUNDS 0x05 84 | #define MOL_ERR_FIELD_COUNT 0x06 85 | #define MOL_ERR_DATA 0x07 86 | 87 | /* Utilities. */ 88 | 89 | MOLECULE_API_DECORATOR mol_num_t mol_unpack_number(const uint8_t *src) { 90 | uint32_t output = 0; 91 | uint8_t *dst = (uint8_t *)&output; 92 | if (is_le()) { 93 | dst[3] = src[3]; 94 | dst[2] = src[2]; 95 | dst[1] = src[1]; 96 | dst[0] = src[0]; 97 | } else { 98 | dst[3] = src[0]; 99 | dst[2] = src[1]; 100 | dst[1] = src[2]; 101 | dst[0] = src[3]; 102 | } 103 | return output; 104 | } 105 | 106 | /* 107 | * Core functions. 108 | */ 109 | 110 | /* Verify Functions. */ 111 | 112 | // Verify Array / Struct. 113 | MOLECULE_API_DECORATOR mol_errno mol_verify_fixed_size(const mol_seg_t *input, 114 | mol_num_t total_size) { 115 | return input->size == total_size ? MOL_OK : MOL_ERR_TOTAL_SIZE; 116 | } 117 | 118 | // Verify FixVec. 119 | MOLECULE_API_DECORATOR mol_errno mol_fixvec_verify(const mol_seg_t *input, 120 | mol_num_t item_size) { 121 | if (input->size < MOL_NUM_T_SIZE) { 122 | return MOL_ERR_HEADER; 123 | } 124 | mol_num_t item_count = mol_unpack_number(input->ptr); 125 | if (item_count == 0) { 126 | return input->size == MOL_NUM_T_SIZE ? MOL_OK : MOL_ERR_TOTAL_SIZE; 127 | } 128 | mol_num_t total_size = MOL_NUM_T_SIZE + item_size * item_count; 129 | return input->size == total_size ? MOL_OK : MOL_ERR_TOTAL_SIZE; 130 | } 131 | 132 | /* Getters. 133 | * 134 | * ### Notice 135 | * 136 | * The input of getters should be checked. 137 | * 138 | * These getters will raise segmentation fault if the input is illegal or 139 | * return an incorrect result. 140 | */ 141 | 142 | // Check if an Option is None. 143 | MOLECULE_API_DECORATOR bool mol_option_is_none(const mol_seg_t *input) { 144 | return input->size == 0; 145 | } 146 | 147 | // Get the inner of a Union. 148 | MOLECULE_API_DECORATOR mol_union_t mol_union_unpack(const mol_seg_t *input) { 149 | mol_union_t ret; 150 | ret.item_id = mol_unpack_number(input->ptr); 151 | ret.seg.ptr = input->ptr + MOL_NUM_T_SIZE; 152 | ret.seg.size = input->size - MOL_NUM_T_SIZE; 153 | return ret; 154 | } 155 | 156 | // Get the length of a FixVec. 157 | MOLECULE_API_DECORATOR mol_num_t mol_fixvec_length(const mol_seg_t *input) { 158 | return mol_unpack_number(input->ptr); 159 | } 160 | 161 | // Get the length of a DynVec. 162 | MOLECULE_API_DECORATOR mol_num_t mol_dynvec_length(const mol_seg_t *input) { 163 | if (input->size == MOL_NUM_T_SIZE) { 164 | return 0; 165 | } else { 166 | return (mol_unpack_number(input->ptr + MOL_NUM_T_SIZE) / 4) - 1; 167 | } 168 | } 169 | 170 | // Get the actual field count of a Table. 171 | MOLECULE_API_DECORATOR mol_num_t 172 | mol_table_actual_field_count(const mol_seg_t *input) { 173 | return mol_dynvec_length(input); 174 | } 175 | 176 | // If a Table has extra fields. 177 | MOLECULE_API_DECORATOR bool mol_table_has_extra_fields(const mol_seg_t *input, 178 | mol_num_t field_count) { 179 | return mol_table_actual_field_count(input) > field_count; 180 | } 181 | 182 | // Slice a segment for Array / Struct by offset. 183 | MOLECULE_API_DECORATOR mol_seg_t mol_slice_by_offset(const mol_seg_t *input, 184 | mol_num_t offset, 185 | mol_num_t size) { 186 | mol_seg_t seg; 187 | seg.ptr = input->ptr + offset; 188 | seg.size = size; 189 | return seg; 190 | } 191 | 192 | // Slice a segment for FixVec by index. 193 | MOLECULE_API_DECORATOR mol_seg_res_t mol_fixvec_slice_by_index( 194 | const mol_seg_t *input, mol_num_t item_size, mol_num_t item_index) { 195 | mol_seg_res_t res; 196 | mol_num_t item_count = mol_unpack_number(input->ptr); 197 | if (item_index >= item_count) { 198 | res.errno = MOL_ERR_INDEX_OUT_OF_BOUNDS; 199 | } else { 200 | res.errno = MOL_OK; 201 | res.seg.ptr = input->ptr + MOL_NUM_T_SIZE + item_size * item_index; 202 | res.seg.size = item_size; 203 | } 204 | return res; 205 | } 206 | 207 | // Slice a segment for DynVec by index. 208 | MOLECULE_API_DECORATOR mol_seg_res_t 209 | mol_dynvec_slice_by_index(const mol_seg_t *input, mol_num_t item_index) { 210 | mol_seg_res_t res; 211 | mol_num_t total_size = mol_unpack_number(input->ptr); 212 | if (total_size == MOL_NUM_T_SIZE) { 213 | res.errno = MOL_ERR_INDEX_OUT_OF_BOUNDS; 214 | } else { 215 | mol_num_t item_count = 216 | (mol_unpack_number(input->ptr + MOL_NUM_T_SIZE) / 4) - 1; 217 | if (item_index >= item_count) { 218 | res.errno = MOL_ERR_INDEX_OUT_OF_BOUNDS; 219 | } else { 220 | mol_num_t item_start = 221 | mol_unpack_number(input->ptr + MOL_NUM_T_SIZE * (item_index + 1)); 222 | if (item_index + 1 == item_count) { 223 | res.errno = MOL_OK; 224 | res.seg.ptr = input->ptr + item_start; 225 | res.seg.size = total_size - item_start; 226 | } else { 227 | mol_num_t item_end = 228 | mol_unpack_number(input->ptr + MOL_NUM_T_SIZE * (item_index + 2)); 229 | res.errno = MOL_OK; 230 | res.seg.ptr = input->ptr + item_start; 231 | res.seg.size = item_end - item_start; 232 | } 233 | } 234 | } 235 | return res; 236 | } 237 | 238 | // Slice a segment for Table by index. 239 | MOLECULE_API_DECORATOR mol_seg_t 240 | mol_table_slice_by_index(const mol_seg_t *input, mol_num_t field_index) { 241 | mol_seg_res_t res = mol_dynvec_slice_by_index(input, field_index); 242 | return res.seg; 243 | } 244 | 245 | // Slice the raw bytes from a `vector ` (FixVec, with a header). 246 | MOLECULE_API_DECORATOR mol_seg_t 247 | mol_fixvec_slice_raw_bytes(const mol_seg_t *input) { 248 | mol_seg_t seg; 249 | seg.ptr = input->ptr + MOL_NUM_T_SIZE; 250 | seg.size = mol_unpack_number(input->ptr); 251 | return seg; 252 | } 253 | 254 | // Check if a segment(`part`) is contained by `total` 255 | MOLECULE_API_DECORATOR bool mol_contained_by(const mol_seg_t *part, 256 | const mol_seg_t *total) { 257 | if (part->ptr < total->ptr) { 258 | return MOL_ERR_OFFSET; 259 | } 260 | if ((part->ptr + part->size) > (total->ptr + total->size)) { 261 | return MOL_ERR_OFFSET; 262 | } 263 | return MOL_OK; 264 | } 265 | 266 | /* 267 | * Undef macros which are internal use only. 268 | */ 269 | 270 | #undef is_le 271 | 272 | #ifdef __DEFINE_MOLECULE_API_DECORATOR 273 | #undef MOLECULE_API_DECORATOR 274 | #undef __DEFINE_MOLECULE_API_DECORATOR 275 | #endif /* __DEFINE_MOLECULE_API_DECORATOR */ 276 | 277 | #ifdef __cplusplus 278 | } 279 | #endif /* __cplusplus */ 280 | 281 | #endif /* MOLECULE_READER_H */ 282 | -------------------------------------------------------------------------------- /ckb_raw_syscalls.h: -------------------------------------------------------------------------------- 1 | #ifndef CKB_C_STDLIB_CKB_RAW_SYSCALLS_H_ 2 | #define CKB_C_STDLIB_CKB_RAW_SYSCALLS_H_ 3 | 4 | #include "ckb_consts.h" 5 | #include "ckb_syscall_apis.h" 6 | 7 | #ifndef CKB_STDLIB_NO_SYSCALL_IMPL 8 | 9 | /* 10 | * From 11 | * https://git.musl-libc.org/cgit/musl/tree/src/include/features.h?id=86373b4999bfd9a9379bc4a3ca877b1c80a2a340#n8 12 | */ 13 | #ifndef weak_alias 14 | #define weak_alias(old, new) \ 15 | extern __typeof(old) new __attribute__((__weak__, __alias__(#old))) 16 | #endif 17 | 18 | #define memory_barrier() asm volatile("fence" ::: "memory") 19 | 20 | long default_internal_syscall(long n, long _a0, long _a1, long _a2, long _a3, 21 | long _a4, long _a5) { 22 | #ifdef __riscv 23 | register long a0 asm("a0") = _a0; 24 | register long a1 asm("a1") = _a1; 25 | register long a2 asm("a2") = _a2; 26 | register long a3 asm("a3") = _a3; 27 | register long a4 asm("a4") = _a4; 28 | register long a5 asm("a5") = _a5; 29 | 30 | #ifdef __riscv_32e 31 | register long syscall_id asm("t0") = n; 32 | #else 33 | register long syscall_id asm("a7") = n; 34 | #endif 35 | 36 | asm volatile("scall" 37 | : "+r"(a0) 38 | : "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5), "r"(syscall_id)); 39 | /* 40 | * Syscalls might modify memory sent as pointer, adding a barrier here ensures 41 | * gcc won't do incorrect optimization. 42 | */ 43 | memory_barrier(); 44 | 45 | return a0; 46 | #else 47 | (void)n; 48 | (void)_a0; 49 | (void)_a1; 50 | (void)_a2; 51 | (void)_a3; 52 | (void)_a4; 53 | (void)_a5; 54 | return -1; 55 | #endif 56 | } 57 | weak_alias(default_internal_syscall, __internal_syscall); 58 | 59 | #define syscall(n, a, b, c, d, e, f) \ 60 | __internal_syscall(n, (long)(a), (long)(b), (long)(c), (long)(d), (long)(e), \ 61 | (long)(f)) 62 | 63 | int default_ckb_exit(int8_t code) { 64 | return syscall(SYS_exit, code, 0, 0, 0, 0, 0); 65 | } 66 | weak_alias(default_ckb_exit, ckb_exit); 67 | 68 | int default_ckb_load_tx_hash(void* addr, uint64_t* len, size_t offset) { 69 | volatile uint64_t inner_len = *len; 70 | int ret = syscall(SYS_ckb_load_tx_hash, addr, &inner_len, offset, 0, 0, 0); 71 | *len = inner_len; 72 | return ret; 73 | } 74 | weak_alias(default_ckb_load_tx_hash, ckb_load_tx_hash); 75 | 76 | int default_ckb_load_script_hash(void* addr, uint64_t* len, size_t offset) { 77 | volatile uint64_t inner_len = *len; 78 | int ret = 79 | syscall(SYS_ckb_load_script_hash, addr, &inner_len, offset, 0, 0, 0); 80 | *len = inner_len; 81 | return ret; 82 | } 83 | weak_alias(default_ckb_load_script_hash, ckb_load_script_hash); 84 | 85 | int default_ckb_load_cell(void* addr, uint64_t* len, size_t offset, 86 | size_t index, size_t source) { 87 | volatile uint64_t inner_len = *len; 88 | int ret = 89 | syscall(SYS_ckb_load_cell, addr, &inner_len, offset, index, source, 0); 90 | *len = inner_len; 91 | return ret; 92 | } 93 | weak_alias(default_ckb_load_cell, ckb_load_cell); 94 | 95 | int default_ckb_load_input(void* addr, uint64_t* len, size_t offset, 96 | size_t index, size_t source) { 97 | volatile uint64_t inner_len = *len; 98 | int ret = 99 | syscall(SYS_ckb_load_input, addr, &inner_len, offset, index, source, 0); 100 | *len = inner_len; 101 | return ret; 102 | } 103 | weak_alias(default_ckb_load_input, ckb_load_input); 104 | 105 | int default_ckb_load_header(void* addr, uint64_t* len, size_t offset, 106 | size_t index, size_t source) { 107 | volatile uint64_t inner_len = *len; 108 | int ret = 109 | syscall(SYS_ckb_load_header, addr, &inner_len, offset, index, source, 0); 110 | *len = inner_len; 111 | return ret; 112 | } 113 | weak_alias(default_ckb_load_header, ckb_load_header); 114 | 115 | int default_ckb_load_witness(void* addr, uint64_t* len, size_t offset, 116 | size_t index, size_t source) { 117 | volatile uint64_t inner_len = *len; 118 | int ret = 119 | syscall(SYS_ckb_load_witness, addr, &inner_len, offset, index, source, 0); 120 | *len = inner_len; 121 | return ret; 122 | } 123 | weak_alias(default_ckb_load_witness, ckb_load_witness); 124 | 125 | int default_ckb_load_script(void* addr, uint64_t* len, size_t offset) { 126 | volatile uint64_t inner_len = *len; 127 | int ret = syscall(SYS_ckb_load_script, addr, &inner_len, offset, 0, 0, 0); 128 | *len = inner_len; 129 | return ret; 130 | } 131 | weak_alias(default_ckb_load_script, ckb_load_script); 132 | 133 | int default_ckb_load_transaction(void* addr, uint64_t* len, size_t offset) { 134 | volatile uint64_t inner_len = *len; 135 | int ret = 136 | syscall(SYS_ckb_load_transaction, addr, &inner_len, offset, 0, 0, 0); 137 | *len = inner_len; 138 | return ret; 139 | } 140 | weak_alias(default_ckb_load_transaction, ckb_load_transaction); 141 | 142 | int default_ckb_load_cell_by_field(void* addr, uint64_t* len, size_t offset, 143 | size_t index, size_t source, size_t field) { 144 | volatile uint64_t inner_len = *len; 145 | int ret = syscall(SYS_ckb_load_cell_by_field, addr, &inner_len, offset, index, 146 | source, field); 147 | *len = inner_len; 148 | return ret; 149 | } 150 | weak_alias(default_ckb_load_cell_by_field, ckb_load_cell_by_field); 151 | 152 | int default_ckb_load_header_by_field(void* addr, uint64_t* len, size_t offset, 153 | size_t index, size_t source, 154 | size_t field) { 155 | volatile uint64_t inner_len = *len; 156 | int ret = syscall(SYS_ckb_load_header_by_field, addr, &inner_len, offset, 157 | index, source, field); 158 | *len = inner_len; 159 | return ret; 160 | } 161 | weak_alias(default_ckb_load_header_by_field, ckb_load_header_by_field); 162 | 163 | int default_ckb_load_input_by_field(void* addr, uint64_t* len, size_t offset, 164 | size_t index, size_t source, size_t field) { 165 | volatile uint64_t inner_len = *len; 166 | int ret = syscall(SYS_ckb_load_input_by_field, addr, &inner_len, offset, 167 | index, source, field); 168 | *len = inner_len; 169 | return ret; 170 | } 171 | weak_alias(default_ckb_load_input_by_field, ckb_load_input_by_field); 172 | 173 | int default_ckb_load_cell_data(void* addr, uint64_t* len, size_t offset, 174 | size_t index, size_t source) { 175 | volatile uint64_t inner_len = *len; 176 | int ret = syscall(SYS_ckb_load_cell_data, addr, &inner_len, offset, index, 177 | source, 0); 178 | *len = inner_len; 179 | return ret; 180 | } 181 | weak_alias(default_ckb_load_cell_data, ckb_load_cell_data); 182 | 183 | int default_ckb_load_cell_data_as_code(void* addr, size_t memory_size, 184 | size_t content_offset, 185 | size_t content_size, size_t index, 186 | size_t source) { 187 | return syscall(SYS_ckb_load_cell_data_as_code, addr, memory_size, 188 | content_offset, content_size, index, source); 189 | } 190 | weak_alias(default_ckb_load_cell_data_as_code, ckb_load_cell_data_as_code); 191 | 192 | int default_ckb_debug(const char* s) { 193 | return syscall(SYS_ckb_debug, s, 0, 0, 0, 0, 0); 194 | } 195 | weak_alias(default_ckb_debug, ckb_debug); 196 | 197 | int default_ckb_vm_version() { 198 | return syscall(SYS_ckb_vm_version, 0, 0, 0, 0, 0, 0); 199 | } 200 | weak_alias(default_ckb_vm_version, ckb_vm_version); 201 | 202 | uint64_t default_ckb_current_cycles() { 203 | return syscall(SYS_ckb_current_cycles, 0, 0, 0, 0, 0, 0); 204 | } 205 | weak_alias(default_ckb_current_cycles, ckb_current_cycles); 206 | 207 | int default_ckb_exec(size_t index, size_t source, size_t place, size_t bounds, 208 | int argc, const char* argv[]) { 209 | return syscall(SYS_ckb_exec, index, source, place, bounds, argc, argv); 210 | } 211 | weak_alias(default_ckb_exec, ckb_exec); 212 | 213 | int default_ckb_spawn(size_t index, size_t source, size_t place, size_t bounds, 214 | spawn_args_t* spawn_args) { 215 | return syscall(SYS_ckb_spawn, index, source, place, bounds, spawn_args, 0); 216 | } 217 | weak_alias(default_ckb_spawn, ckb_spawn); 218 | 219 | int default_ckb_wait(uint64_t pid, int8_t* exit_code) { 220 | return syscall(SYS_ckb_wait, pid, exit_code, 0, 0, 0, 0); 221 | } 222 | weak_alias(default_ckb_wait, ckb_wait); 223 | 224 | uint64_t default_ckb_process_id() { 225 | return syscall(SYS_ckb_process_id, 0, 0, 0, 0, 0, 0); 226 | } 227 | weak_alias(default_ckb_process_id, ckb_process_id); 228 | 229 | int default_ckb_pipe(uint64_t fds[2]) { 230 | return syscall(SYS_ckb_pipe, fds, 0, 0, 0, 0, 0); 231 | } 232 | weak_alias(default_ckb_pipe, ckb_pipe); 233 | 234 | int default_ckb_read(uint64_t fd, void* buffer, size_t* length) { 235 | volatile size_t l = *length; 236 | int ret = syscall(SYS_ckb_read, fd, buffer, &l, 0, 0, 0); 237 | *length = l; 238 | return ret; 239 | } 240 | weak_alias(default_ckb_read, ckb_read); 241 | 242 | int default_ckb_write(uint64_t fd, const void* buffer, size_t* length) { 243 | volatile size_t l = *length; 244 | int ret = syscall(SYS_ckb_write, fd, buffer, &l, 0, 0, 0); 245 | *length = l; 246 | return ret; 247 | } 248 | weak_alias(default_ckb_write, ckb_write); 249 | 250 | int default_ckb_load_block_extension(void* addr, uint64_t* len, size_t offset, 251 | size_t index, size_t source) { 252 | return syscall(SYS_ckb_load_block_extension, addr, len, offset, index, source, 253 | 0); 254 | } 255 | weak_alias(default_ckb_load_block_extension, ckb_load_block_extension); 256 | 257 | int default_ckb_inherited_fds(uint64_t* fds, size_t* length) { 258 | volatile size_t l = *length; 259 | int ret = syscall(SYS_ckb_inherited_fds, fds, &l, 0, 0, 0, 0); 260 | *length = l; 261 | return ret; 262 | } 263 | weak_alias(default_ckb_inherited_fds, ckb_inherited_fds); 264 | 265 | int default_ckb_close(uint64_t fd) { 266 | return syscall(SYS_ckb_close, fd, 0, 0, 0, 0, 0); 267 | } 268 | weak_alias(default_ckb_close, ckb_close); 269 | 270 | #endif /* CKB_STDLIB_NO_SYSCALL_IMPL */ 271 | 272 | #endif /* CKB_C_STDLIB_CKB_RAW_SYSCALLS_H_ */ 273 | -------------------------------------------------------------------------------- /ckb_keccak256.h: -------------------------------------------------------------------------------- 1 | /* sha3 - an implementation of Secure Hash Algorithm 3 (Keccak). 2 | * based on the 3 | * The Keccak SHA-3 submission. Submission to NIST (Round 3), 2011 4 | * by Guido Bertoni, Joan Daemen, Michaël Peeters and Gilles Van Assche 5 | * 6 | * Copyright: 2013 Aleksey Kravchenko 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a 9 | * copy of this software and associated documentation files (the "Software"), 10 | * to deal in the Software without restriction, including without limitation 11 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 | * and/or sell copies of the Software, and to permit persons to whom the 13 | * Software is furnished to do so. 14 | * 15 | * This program is distributed in the hope that it will be useful, but 16 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 17 | * or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk! 18 | */ 19 | 20 | #ifndef __KECCAK256_H_ 21 | #define __KECCAK256_H_ 22 | 23 | #include 24 | #include 25 | 26 | #define sha3_max_permutation_size 25 27 | #define sha3_max_rate_in_qwords 24 28 | 29 | typedef struct SHA3_CTX { 30 | /* 1600 bits algorithm hashing state */ 31 | uint64_t hash[sha3_max_permutation_size]; 32 | /* 1536-bit buffer for leftovers */ 33 | uint64_t message[sha3_max_rate_in_qwords]; 34 | /* count of bytes in the message[] buffer */ 35 | uint16_t rest; 36 | /* size of a message block processed at once */ 37 | // unsigned block_size; 38 | } SHA3_CTX; 39 | 40 | #ifdef __cplusplus 41 | extern "C" { 42 | #endif /* __cplusplus */ 43 | 44 | void keccak_init(SHA3_CTX *ctx); 45 | void keccak_update(SHA3_CTX *ctx, unsigned char *msg, uint16_t size); 46 | void keccak_final(SHA3_CTX *ctx, unsigned char *result); 47 | 48 | #ifdef __cplusplus 49 | } 50 | #endif /* __cplusplus */ 51 | 52 | // keccak256 implementation 53 | 54 | #define BLOCK_SIZE ((1600 - 256 * 2) / 8) 55 | 56 | #define I64(x) x##LL 57 | #define ROTL64(qword, n) ((qword) << (n) ^ ((qword) >> (64 - (n)))) 58 | #define le2me_64(x) (x) 59 | #define IS_ALIGNED_64(p) (0 == (7 & ((const char *)(p) - (const char *)0))) 60 | #define me64_to_le_str(to, from, length) memcpy((to), (from), (length)) 61 | 62 | /* constants */ 63 | 64 | // const uint8_t round_constant_info[] PROGMEM = { 65 | // const uint8_t constants[] PROGMEM = { 66 | const uint8_t constants[] = { 67 | 68 | 1, 69 | 26, 70 | 94, 71 | 112, 72 | 31, 73 | 33, 74 | 121, 75 | 85, 76 | 14, 77 | 12, 78 | 53, 79 | 38, 80 | 63, 81 | 79, 82 | 93, 83 | 83, 84 | 82, 85 | 72, 86 | 22, 87 | 102, 88 | 121, 89 | 88, 90 | 33, 91 | 116, 92 | //}; 93 | 94 | // const uint8_t pi_transform[] PROGMEM = { 95 | 1, 96 | 6, 97 | 9, 98 | 22, 99 | 14, 100 | 20, 101 | 2, 102 | 12, 103 | 13, 104 | 19, 105 | 23, 106 | 15, 107 | 4, 108 | 24, 109 | 21, 110 | 8, 111 | 16, 112 | 5, 113 | 3, 114 | 18, 115 | 17, 116 | 11, 117 | 7, 118 | 10, 119 | //}; 120 | 121 | // const uint8_t rhoTransforms[] PROGMEM = { 122 | 1, 123 | 62, 124 | 28, 125 | 27, 126 | 36, 127 | 44, 128 | 6, 129 | 55, 130 | 20, 131 | 3, 132 | 10, 133 | 43, 134 | 25, 135 | 39, 136 | 41, 137 | 45, 138 | 15, 139 | 21, 140 | 8, 141 | 18, 142 | 2, 143 | 61, 144 | 56, 145 | 14, 146 | }; 147 | 148 | #define TYPE_ROUND_INFO 0 149 | #define TYPE_PI_TRANSFORM 24 150 | #define TYPE_RHO_TRANSFORM 48 151 | 152 | uint8_t getConstant(uint8_t type, uint8_t index) { 153 | return constants[type + index]; 154 | // return pgm_read_byte(&constants[type + index]); 155 | } 156 | 157 | static uint64_t get_round_constant(uint8_t round) { 158 | uint64_t result = 0; 159 | 160 | // uint8_t roundInfo = pgm_read_byte(&round_constant_info[round]); 161 | uint8_t roundInfo = getConstant(TYPE_ROUND_INFO, round); 162 | if (roundInfo & (1 << 6)) { 163 | result |= ((uint64_t)1 << 63); 164 | } 165 | if (roundInfo & (1 << 5)) { 166 | result |= ((uint64_t)1 << 31); 167 | } 168 | if (roundInfo & (1 << 4)) { 169 | result |= ((uint64_t)1 << 15); 170 | } 171 | if (roundInfo & (1 << 3)) { 172 | result |= ((uint64_t)1 << 7); 173 | } 174 | if (roundInfo & (1 << 2)) { 175 | result |= ((uint64_t)1 << 3); 176 | } 177 | if (roundInfo & (1 << 1)) { 178 | result |= ((uint64_t)1 << 1); 179 | } 180 | if (roundInfo & (1 << 0)) { 181 | result |= ((uint64_t)1 << 0); 182 | } 183 | 184 | return result; 185 | } 186 | 187 | /* Initializing a sha3 context for given number of output bits */ 188 | void keccak_init(SHA3_CTX *ctx) { 189 | /* NB: The Keccak capacity parameter = bits * 2 */ 190 | 191 | memset(ctx, 0, sizeof(SHA3_CTX)); 192 | } 193 | 194 | /* Keccak theta() transformation */ 195 | static void keccak_theta(uint64_t *A) { 196 | uint64_t C[5], D[5]; 197 | 198 | for (uint8_t i = 0; i < 5; i++) { 199 | C[i] = A[i]; 200 | for (uint8_t j = 5; j < 25; j += 5) { 201 | C[i] ^= A[i + j]; 202 | } 203 | } 204 | 205 | for (uint8_t i = 0; i < 5; i++) { 206 | D[i] = ROTL64(C[(i + 1) % 5], 1) ^ C[(i + 4) % 5]; 207 | } 208 | 209 | for (uint8_t i = 0; i < 5; i++) { 210 | // for (uint8_t j = 0; j < 25; j += 5) { 211 | for (uint8_t j = 0; j < 25; j += 5) { 212 | A[i + j] ^= D[i]; 213 | } 214 | } 215 | } 216 | 217 | /* Keccak pi() transformation */ 218 | static void keccak_pi(uint64_t *A) { 219 | uint64_t A1 = A[1]; 220 | // for (uint8_t i = 1; i < sizeof(pi_transform); i++) { 221 | for (uint8_t i = 1; i < 24; i++) { 222 | // A[pgm_read_byte(&pi_transform[i - 1])] = 223 | // A[pgm_read_byte(&pi_transform[i])]; 224 | A[getConstant(TYPE_PI_TRANSFORM, i - 1)] = 225 | A[getConstant(TYPE_PI_TRANSFORM, i)]; 226 | } 227 | A[10] = A1; 228 | /* note: A[ 0] is left as is */ 229 | } 230 | 231 | /* 232 | ketch uses 30084 bytes (93%) of program storage space. Maximum is 32256 bytes. 233 | Global variables use 743 bytes (36%) of dynamic memory, leaving 1305 bytes for 234 | local variables. Maximum is 2048 bytes. 235 | */ 236 | /* Keccak chi() transformation */ 237 | static void keccak_chi(uint64_t *A) { 238 | for (uint8_t i = 0; i < 25; i += 5) { 239 | uint64_t A0 = A[0 + i], A1 = A[1 + i]; 240 | A[0 + i] ^= ~A1 & A[2 + i]; 241 | A[1 + i] ^= ~A[2 + i] & A[3 + i]; 242 | A[2 + i] ^= ~A[3 + i] & A[4 + i]; 243 | A[3 + i] ^= ~A[4 + i] & A0; 244 | A[4 + i] ^= ~A0 & A1; 245 | } 246 | } 247 | 248 | static void sha3_permutation(uint64_t *state) { 249 | // for (uint8_t round = 0; round < sizeof(round_constant_info); round++) { 250 | for (uint8_t round = 0; round < 24; round++) { 251 | keccak_theta(state); 252 | 253 | /* apply Keccak rho() transformation */ 254 | for (uint8_t i = 1; i < 25; i++) { 255 | // state[i] = ROTL64(state[i], pgm_read_byte(&rhoTransforms[i - 1])); 256 | state[i] = ROTL64(state[i], getConstant(TYPE_RHO_TRANSFORM, i - 1)); 257 | } 258 | 259 | keccak_pi(state); 260 | keccak_chi(state); 261 | 262 | /* apply iota(state, round) */ 263 | *state ^= get_round_constant(round); 264 | } 265 | } 266 | 267 | /** 268 | * The core transformation. Process the specified block of data. 269 | * 270 | * @param hash the algorithm state 271 | * @param block the message block to process 272 | * @param block_size the size of the processed block in bytes 273 | */ 274 | static void sha3_process_block(uint64_t hash[25], const uint64_t *block) { 275 | for (uint8_t i = 0; i < 17; i++) { 276 | hash[i] ^= le2me_64(block[i]); 277 | } 278 | 279 | /* make a permutation of the hash */ 280 | sha3_permutation(hash); 281 | } 282 | 283 | // #define SHA3_FINALIZED 0x80000000 284 | // #define SHA3_FINALIZED 0x8000 285 | 286 | /** 287 | * Calculate message hash. 288 | * Can be called repeatedly with chunks of the message to be hashed. 289 | * 290 | * @param ctx the algorithm context containing current hashing state 291 | * @param msg message chunk 292 | * @param size length of the message chunk 293 | */ 294 | void keccak_update(SHA3_CTX *ctx, unsigned char *msg, uint16_t size) { 295 | uint16_t idx = (uint16_t)ctx->rest; 296 | 297 | // if (ctx->rest & SHA3_FINALIZED) return; /* too late for additional input */ 298 | ctx->rest = (unsigned)((ctx->rest + size) % BLOCK_SIZE); 299 | 300 | /* fill partial block */ 301 | if (idx) { 302 | uint16_t left = BLOCK_SIZE - idx; 303 | memcpy((char *)ctx->message + idx, msg, (size < left ? size : left)); 304 | if (size < left) return; 305 | 306 | /* process partial block */ 307 | sha3_process_block(ctx->hash, ctx->message); 308 | msg += left; 309 | size -= left; 310 | } 311 | 312 | while (size >= BLOCK_SIZE) { 313 | uint64_t *aligned_message_block; 314 | if (IS_ALIGNED_64(msg)) { 315 | // the most common case is processing of an already aligned message 316 | // without copying it 317 | aligned_message_block = (uint64_t *)(void *)msg; 318 | } else { 319 | memcpy(ctx->message, msg, BLOCK_SIZE); 320 | aligned_message_block = ctx->message; 321 | } 322 | 323 | sha3_process_block(ctx->hash, aligned_message_block); 324 | msg += BLOCK_SIZE; 325 | size -= BLOCK_SIZE; 326 | } 327 | 328 | if (size) { 329 | memcpy(ctx->message, msg, size); /* save leftovers */ 330 | } 331 | } 332 | 333 | /** 334 | * Store calculated hash into the given array. 335 | * 336 | * @param ctx the algorithm context containing current hashing state 337 | * @param result calculated hash in binary form 338 | */ 339 | void keccak_final(SHA3_CTX *ctx, unsigned char *result) { 340 | uint16_t digest_length = 100 - BLOCK_SIZE / 2; 341 | 342 | // if (!(ctx->rest & SHA3_FINALIZED)) { 343 | /* clear the rest of the data queue */ 344 | memset((char *)ctx->message + ctx->rest, 0, BLOCK_SIZE - ctx->rest); 345 | ((char *)ctx->message)[ctx->rest] |= 0x01; 346 | ((char *)ctx->message)[BLOCK_SIZE - 1] |= 0x80; 347 | 348 | /* process final block */ 349 | sha3_process_block(ctx->hash, ctx->message); 350 | // ctx->rest = SHA3_FINALIZED; /* mark context as finalized */ 351 | // } 352 | 353 | if (result) { 354 | me64_to_le_str(result, ctx->hash, digest_length); 355 | } 356 | } 357 | 358 | #endif /* __KECCAK256_H_ */ 359 | -------------------------------------------------------------------------------- /molecule/molecule_builder.h: -------------------------------------------------------------------------------- 1 | #ifndef MOLECULE_BUILDER_H 2 | #define MOLECULE_BUILDER_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif /* __cplusplus */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include "molecule_reader.h" 13 | 14 | #ifndef MOLECULE_API_DECORATOR 15 | #define __DEFINE_MOLECULE_API_DECORATOR 16 | #define MOLECULE_API_DECORATOR 17 | #endif /* MOLECULE_API_DECORATOR */ 18 | 19 | /* 20 | * This part is not for normal users. 21 | */ 22 | 23 | // Test if the host is big endian machine. 24 | #define is_le() \ 25 | ((union { \ 26 | uint16_t i; \ 27 | unsigned char c; \ 28 | }){.i = 1} \ 29 | .c) 30 | 31 | /* 32 | * Definitions of types and simple utilities. 33 | */ 34 | 35 | // The Builder. 36 | // - Can be stack allocated 37 | // - Must be initialized with `MolBuilder_Xxx_init` 38 | // - Must be cleared with `MolBuilder_Xxx_build` or `MolBuilder_Xxx_clear` 39 | // - Can be set with: 40 | // - `MolBuilder_Xxx_set` (For Option) 41 | // - `MolBuilder_Xxx_set_*` (For Union, Array, Struct, Table) 42 | // - `MolBuilder_Xxx_push` (For FixVec, DynVec) 43 | typedef struct { 44 | uint8_t *data_ptr; // Data Pointer 45 | mol_num_t data_used; // Data Used 46 | mol_num_t data_cap; // Data Capacity 47 | 48 | mol_num_t *number_ptr; // A Pointer of Numbers 49 | mol_num_t number_used; // Numbers used 50 | mol_num_t number_cap; // Numbers Capacity 51 | } mol_builder_t; 52 | 53 | /* Utilities. */ 54 | 55 | MOLECULE_API_DECORATOR void mol_pack_number(uint8_t *dst, mol_num_t *num) { 56 | const uint8_t *src = (const uint8_t *)num; 57 | if (is_le()) { 58 | memcpy(dst, src, MOL_NUM_T_SIZE); 59 | } else { 60 | dst[3] = src[0]; 61 | dst[2] = src[1]; 62 | dst[1] = src[2]; 63 | dst[0] = src[3]; 64 | } 65 | } 66 | 67 | /* 68 | * Core functions. 69 | */ 70 | 71 | MOLECULE_API_DECORATOR void mol_builder_discard(mol_builder_t builder) { 72 | free(builder.data_ptr); 73 | free(builder.number_ptr); 74 | } 75 | 76 | MOLECULE_API_DECORATOR void mol_builder_initialize_fixed_size( 77 | mol_builder_t *builder, mol_num_t fixed_size) { 78 | if (fixed_size == 0) { 79 | builder->data_ptr = NULL; 80 | builder->data_used = 0; 81 | builder->data_cap = 0; 82 | } else { 83 | builder->data_ptr = (uint8_t *)malloc(fixed_size); 84 | memset(builder->data_ptr, 0x00, fixed_size); 85 | builder->data_used = fixed_size; 86 | builder->data_cap = fixed_size; 87 | } 88 | builder->number_ptr = NULL; 89 | builder->number_used = 0; 90 | builder->number_cap = 0; 91 | } 92 | 93 | MOLECULE_API_DECORATOR void mol_union_builder_initialize( 94 | mol_builder_t *builder, mol_num_t data_capacity, mol_num_t item_id, 95 | const uint8_t *default_ptr, mol_num_t default_len) { 96 | builder->data_ptr = (uint8_t *)malloc(data_capacity); 97 | builder->data_cap = data_capacity; 98 | mol_pack_number(builder->data_ptr, &item_id); 99 | builder->data_used = MOL_NUM_T_SIZE + default_len; 100 | if (default_ptr == NULL) { 101 | *(builder->data_ptr + MOL_NUM_T_SIZE) = 0; 102 | } else { 103 | memcpy(builder->data_ptr + MOL_NUM_T_SIZE, default_ptr, default_len); 104 | } 105 | builder->number_ptr = NULL; 106 | builder->number_used = 0; 107 | builder->number_cap = 0; 108 | } 109 | 110 | MOLECULE_API_DECORATOR void mol_builder_initialize_with_capacity( 111 | mol_builder_t *builder, mol_num_t data_capacity, 112 | mol_num_t number_capacity) { 113 | builder->data_ptr = (uint8_t *)malloc(data_capacity); 114 | builder->data_used = 0; 115 | builder->data_cap = data_capacity; 116 | builder->number_ptr = (mol_num_t *)malloc(number_capacity); 117 | builder->number_used = 0; 118 | builder->number_cap = number_capacity; 119 | } 120 | 121 | MOLECULE_API_DECORATOR void mol_fixvec_builder_initialize( 122 | mol_builder_t *builder, mol_num_t data_capacity) { 123 | mol_builder_initialize_with_capacity(builder, data_capacity, MOL_NUM_T_SIZE); 124 | builder->number_ptr[0] = 0; 125 | builder->number_used = MOL_NUM_T_SIZE; 126 | } 127 | 128 | MOLECULE_API_DECORATOR void mol_table_builder_initialize( 129 | mol_builder_t *builder, mol_num_t data_capacity, mol_num_t field_count) { 130 | mol_builder_initialize_with_capacity(builder, data_capacity, 131 | MOL_NUM_T_SIZE * field_count * 2); 132 | memset(builder->number_ptr, 0x00, builder->number_cap); 133 | builder->number_used = builder->number_cap; 134 | } 135 | 136 | MOLECULE_API_DECORATOR void mol_option_builder_set(mol_builder_t *builder, 137 | const uint8_t *data_ptr, 138 | mol_num_t data_len) { 139 | builder->data_used = data_len; 140 | if (builder->data_used == 0) { 141 | builder->data_cap = 0; 142 | free(builder->data_ptr); 143 | builder->data_ptr = NULL; 144 | } else { 145 | if (builder->data_cap < builder->data_used) { 146 | builder->data_cap = builder->data_used; 147 | builder->data_ptr = 148 | (uint8_t *)realloc(builder->data_ptr, builder->data_cap); 149 | } 150 | memcpy(builder->data_ptr, data_ptr, builder->data_used); 151 | } 152 | } 153 | 154 | MOLECULE_API_DECORATOR void mol_union_builder_set_byte(mol_builder_t *builder, 155 | mol_num_t item_id, 156 | uint8_t data) { 157 | builder->data_used = MOL_NUM_T_SIZE + 1; 158 | if (builder->data_cap < builder->data_used) { 159 | builder->data_cap = builder->data_used; 160 | builder->data_ptr = 161 | (uint8_t *)realloc(builder->data_ptr, builder->data_cap); 162 | } 163 | mol_pack_number(builder->data_ptr, &item_id); 164 | *(builder->data_ptr + MOL_NUM_T_SIZE) = data; 165 | } 166 | 167 | MOLECULE_API_DECORATOR void mol_union_builder_set(mol_builder_t *builder, 168 | mol_num_t item_id, 169 | const uint8_t *data_ptr, 170 | mol_num_t data_len) { 171 | builder->data_used = MOL_NUM_T_SIZE + data_len; 172 | if (builder->data_cap < builder->data_used) { 173 | builder->data_cap = builder->data_used; 174 | builder->data_ptr = 175 | (uint8_t *)realloc(builder->data_ptr, builder->data_cap); 176 | } 177 | mol_pack_number(builder->data_ptr, &item_id); 178 | memcpy(builder->data_ptr + MOL_NUM_T_SIZE, data_ptr, data_len); 179 | } 180 | 181 | MOLECULE_API_DECORATOR void mol_builder_set_byte_by_offset( 182 | mol_builder_t *builder, mol_num_t offset, uint8_t data) { 183 | *(builder->data_ptr + offset) = data; 184 | } 185 | 186 | MOLECULE_API_DECORATOR void mol_builder_set_by_offset(mol_builder_t *builder, 187 | mol_num_t offset, 188 | const uint8_t *data_ptr, 189 | mol_num_t length) { 190 | memcpy(builder->data_ptr + offset, data_ptr, length); 191 | } 192 | 193 | MOLECULE_API_DECORATOR void mol_fixvec_builder_push_byte(mol_builder_t *builder, 194 | uint8_t data) { 195 | while (builder->data_cap < builder->data_used + 1) { 196 | builder->data_cap *= 2; 197 | builder->data_ptr = 198 | (uint8_t *)realloc(builder->data_ptr, builder->data_cap); 199 | } 200 | builder->number_ptr[0] += 1; 201 | *(builder->data_ptr + builder->data_used) = data; 202 | builder->data_used += 1; 203 | } 204 | 205 | MOLECULE_API_DECORATOR void mol_fixvec_builder_push(mol_builder_t *builder, 206 | const uint8_t *data_ptr, 207 | mol_num_t length) { 208 | while (builder->data_cap < builder->data_used + length) { 209 | builder->data_cap *= 2; 210 | builder->data_ptr = 211 | (uint8_t *)realloc(builder->data_ptr, builder->data_cap); 212 | } 213 | builder->number_ptr[0] += 1; 214 | memcpy(builder->data_ptr + builder->data_used, data_ptr, length); 215 | builder->data_used += length; 216 | } 217 | 218 | MOLECULE_API_DECORATOR void mol_dynvec_builder_push(mol_builder_t *builder, 219 | const uint8_t *data_ptr, 220 | mol_num_t data_len) { 221 | while (builder->data_cap < builder->data_used + data_len) { 222 | builder->data_cap *= 2; 223 | builder->data_ptr = 224 | (uint8_t *)realloc(builder->data_ptr, builder->data_cap); 225 | } 226 | while (builder->number_cap < builder->number_used + MOL_NUM_T_SIZE) { 227 | builder->number_cap *= 2; 228 | builder->number_ptr = 229 | (mol_num_t *)realloc(builder->number_ptr, builder->number_cap); 230 | } 231 | 232 | mol_num_t next_number_index = builder->number_used / MOL_NUM_T_SIZE; 233 | builder->number_ptr[next_number_index] = builder->data_used; 234 | builder->number_used += MOL_NUM_T_SIZE; 235 | 236 | if (data_len != 0) { 237 | memcpy(builder->data_ptr + builder->data_used, data_ptr, data_len); 238 | builder->data_used += data_len; 239 | } 240 | } 241 | 242 | MOLECULE_API_DECORATOR void mol_table_builder_add_byte(mol_builder_t *builder, 243 | mol_num_t field_index, 244 | uint8_t data) { 245 | while (builder->data_cap < builder->data_used + 1) { 246 | builder->data_cap *= 2; 247 | builder->data_ptr = 248 | (uint8_t *)realloc(builder->data_ptr, builder->data_cap); 249 | } 250 | 251 | builder->number_ptr[field_index * 2] = builder->data_used; 252 | builder->number_ptr[field_index * 2 + 1] = 1; 253 | *(builder->data_ptr + builder->data_used) = data; 254 | builder->data_used += 1; 255 | } 256 | 257 | MOLECULE_API_DECORATOR void mol_table_builder_add(mol_builder_t *builder, 258 | mol_num_t field_index, 259 | const uint8_t *data_ptr, 260 | mol_num_t data_len) { 261 | if (data_len == 0) { 262 | builder->number_ptr[field_index * 2] = 0; 263 | builder->number_ptr[field_index * 2 + 1] = 0; 264 | } else { 265 | while (builder->data_cap < builder->data_used + data_len) { 266 | builder->data_cap *= 2; 267 | builder->data_ptr = 268 | (uint8_t *)realloc(builder->data_ptr, builder->data_cap); 269 | } 270 | 271 | builder->number_ptr[field_index * 2] = builder->data_used; 272 | builder->number_ptr[field_index * 2 + 1] = data_len; 273 | memcpy(builder->data_ptr + builder->data_used, data_ptr, data_len); 274 | builder->data_used += data_len; 275 | } 276 | } 277 | 278 | MOLECULE_API_DECORATOR mol_seg_res_t 279 | mol_builder_finalize_simple(mol_builder_t builder) { 280 | mol_seg_res_t res; 281 | res.errno = MOL_OK; 282 | res.seg.ptr = builder.data_ptr; 283 | res.seg.size = builder.data_used; 284 | free(builder.number_ptr); 285 | return res; 286 | } 287 | 288 | MOLECULE_API_DECORATOR mol_seg_res_t 289 | mol_fixvec_builder_finalize(mol_builder_t builder) { 290 | mol_seg_res_t res; 291 | res.errno = MOL_OK; 292 | res.seg.size = MOL_NUM_T_SIZE + builder.data_used; 293 | res.seg.ptr = (uint8_t *)malloc(res.seg.size); 294 | mol_pack_number(res.seg.ptr, &builder.number_ptr[0]); 295 | if (builder.data_used > 0) { 296 | memcpy((res.seg.ptr + MOL_NUM_T_SIZE), builder.data_ptr, builder.data_used); 297 | } 298 | mol_builder_discard(builder); 299 | return res; 300 | } 301 | 302 | MOLECULE_API_DECORATOR mol_seg_res_t 303 | mol_dynvec_builder_finalize(mol_builder_t builder) { 304 | mol_seg_res_t res; 305 | res.errno = MOL_OK; 306 | res.seg.size = MOL_NUM_T_SIZE + builder.number_used + builder.data_used; 307 | res.seg.ptr = (uint8_t *)malloc(res.seg.size); 308 | mol_pack_number(res.seg.ptr, &res.seg.size); 309 | mol_num_t number_count = builder.number_used / MOL_NUM_T_SIZE; 310 | mol_num_t header_size = MOL_NUM_T_SIZE + builder.number_used; 311 | for (mol_num_t number_index = 0; number_index < number_count; 312 | number_index++) { 313 | builder.number_ptr[number_index] += header_size; 314 | } 315 | memcpy((res.seg.ptr + MOL_NUM_T_SIZE), builder.number_ptr, 316 | builder.number_used); 317 | memcpy((res.seg.ptr + MOL_NUM_T_SIZE + builder.number_used), builder.data_ptr, 318 | builder.data_used); 319 | mol_builder_discard(builder); 320 | return res; 321 | } 322 | 323 | /* 324 | * Undef macros which are internal use only. 325 | */ 326 | 327 | #undef is_le 328 | 329 | #ifdef __DEFINE_MOLECULE_API_DECORATOR 330 | #undef MOLECULE_API_DECORATOR 331 | #undef __DEFINE_MOLECULE_API_DECORATOR 332 | #endif /* __DEFINE_MOLECULE_API_DECORATOR */ 333 | 334 | #ifdef __cplusplus 335 | } 336 | #endif /* __cplusplus */ 337 | 338 | #endif /* MOLECULE_BUILDER_H */ 339 | -------------------------------------------------------------------------------- /blake2b.h: -------------------------------------------------------------------------------- 1 | /* 2 | BLAKE2 reference source code package - reference C implementations 3 | 4 | Copyright 2012, Samuel Neves . You may use this under the 5 | terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at 6 | your option. The terms of these licenses can be found at: 7 | 8 | - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 9 | - OpenSSL license : https://www.openssl.org/source/license.html 10 | - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | More information about the BLAKE2 hash function can be found at 13 | https://blake2.net. 14 | */ 15 | 16 | // blake2.h 17 | #ifndef BLAKE2_H 18 | #define BLAKE2_H 19 | 20 | #include 21 | #include 22 | 23 | #if defined(_MSC_VER) 24 | #define BLAKE2_PACKED(x) __pragma(pack(push, 1)) x __pragma(pack(pop)) 25 | #else 26 | #define BLAKE2_PACKED(x) x __attribute__((packed)) 27 | #endif 28 | 29 | #if defined(__cplusplus) 30 | extern "C" { 31 | #endif 32 | 33 | enum blake2b_constant { 34 | BLAKE2B_BLOCKBYTES = 128, 35 | BLAKE2B_OUTBYTES = 64, 36 | BLAKE2B_KEYBYTES = 64, 37 | BLAKE2B_SALTBYTES = 16, 38 | BLAKE2B_PERSONALBYTES = 16 39 | }; 40 | 41 | typedef struct blake2b_state__ { 42 | uint64_t h[8]; 43 | uint64_t t[2]; 44 | uint64_t f[2]; 45 | uint8_t buf[BLAKE2B_BLOCKBYTES]; 46 | size_t buflen; 47 | size_t outlen; 48 | uint8_t last_node; 49 | } blake2b_state; 50 | 51 | BLAKE2_PACKED(struct blake2b_param__ { 52 | uint8_t digest_length; /* 1 */ 53 | uint8_t key_length; /* 2 */ 54 | uint8_t fanout; /* 3 */ 55 | uint8_t depth; /* 4 */ 56 | uint32_t leaf_length; /* 8 */ 57 | uint32_t node_offset; /* 12 */ 58 | uint32_t xof_length; /* 16 */ 59 | uint8_t node_depth; /* 17 */ 60 | uint8_t inner_length; /* 18 */ 61 | uint8_t reserved[14]; /* 32 */ 62 | uint8_t salt[BLAKE2B_SALTBYTES]; /* 48 */ 63 | uint8_t personal[BLAKE2B_PERSONALBYTES]; /* 64 */ 64 | }); 65 | 66 | typedef struct blake2b_param__ blake2b_param; 67 | 68 | /* Padded structs result in a compile-time error */ 69 | enum { BLAKE2_DUMMY_2 = 1 / (sizeof(blake2b_param) == BLAKE2B_OUTBYTES) }; 70 | 71 | /* Streaming API */ 72 | 73 | /* For future code, you should always use ckb_blake2b_init for convenience */ 74 | int ckb_blake2b_init(blake2b_state *S, size_t outlen); 75 | int blake2b_init(blake2b_state *S, size_t outlen); 76 | int blake2b_init_key(blake2b_state *S, size_t outlen, const void *key, 77 | size_t keylen); 78 | int blake2b_init_param(blake2b_state *S, const blake2b_param *P); 79 | int blake2b_update(blake2b_state *S, const void *in, size_t inlen); 80 | int blake2b_final(blake2b_state *S, void *out, size_t outlen); 81 | 82 | /* Simple API */ 83 | int blake2b(void *out, size_t outlen, const void *in, size_t inlen, 84 | const void *key, size_t keylen); 85 | 86 | /* This is simply an alias for blake2b */ 87 | int blake2(void *out, size_t outlen, const void *in, size_t inlen, 88 | const void *key, size_t keylen); 89 | 90 | #if defined(__cplusplus) 91 | } 92 | #endif 93 | 94 | #endif 95 | 96 | // blake2-impl.h 97 | #ifndef BLAKE2_IMPL_H 98 | #define BLAKE2_IMPL_H 99 | 100 | #include 101 | #include 102 | 103 | #if !defined(__cplusplus) && \ 104 | (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L) 105 | #if defined(_MSC_VER) 106 | #define BLAKE2_INLINE __inline 107 | #elif defined(__GNUC__) 108 | #define BLAKE2_INLINE __inline__ 109 | #else 110 | #define BLAKE2_INLINE 111 | #endif 112 | #else 113 | #define BLAKE2_INLINE inline 114 | #endif 115 | 116 | static BLAKE2_INLINE uint64_t load64(const void *src) { 117 | #if defined(NATIVE_LITTLE_ENDIAN) 118 | uint64_t w; 119 | memcpy(&w, src, sizeof w); 120 | return w; 121 | #else 122 | const uint8_t *p = (const uint8_t *)src; 123 | return ((uint64_t)(p[0]) << 0) | ((uint64_t)(p[1]) << 8) | 124 | ((uint64_t)(p[2]) << 16) | ((uint64_t)(p[3]) << 24) | 125 | ((uint64_t)(p[4]) << 32) | ((uint64_t)(p[5]) << 40) | 126 | ((uint64_t)(p[6]) << 48) | ((uint64_t)(p[7]) << 56); 127 | #endif 128 | } 129 | 130 | static BLAKE2_INLINE void store32(void *dst, uint32_t w) { 131 | #if defined(NATIVE_LITTLE_ENDIAN) 132 | memcpy(dst, &w, sizeof w); 133 | #else 134 | uint8_t *p = (uint8_t *)dst; 135 | p[0] = (uint8_t)(w >> 0); 136 | p[1] = (uint8_t)(w >> 8); 137 | p[2] = (uint8_t)(w >> 16); 138 | p[3] = (uint8_t)(w >> 24); 139 | #endif 140 | } 141 | 142 | static BLAKE2_INLINE void store64(void *dst, uint64_t w) { 143 | #if defined(NATIVE_LITTLE_ENDIAN) 144 | memcpy(dst, &w, sizeof w); 145 | #else 146 | uint8_t *p = (uint8_t *)dst; 147 | p[0] = (uint8_t)(w >> 0); 148 | p[1] = (uint8_t)(w >> 8); 149 | p[2] = (uint8_t)(w >> 16); 150 | p[3] = (uint8_t)(w >> 24); 151 | p[4] = (uint8_t)(w >> 32); 152 | p[5] = (uint8_t)(w >> 40); 153 | p[6] = (uint8_t)(w >> 48); 154 | p[7] = (uint8_t)(w >> 56); 155 | #endif 156 | } 157 | 158 | static BLAKE2_INLINE uint64_t rotr64(const uint64_t w, const unsigned c) { 159 | return (w >> c) | (w << (64 - c)); 160 | } 161 | 162 | /* prevents compiler optimizing out memset() */ 163 | static BLAKE2_INLINE void secure_zero_memory(void *v, size_t n) { 164 | static void *(*const volatile memset_v)(void *, int, size_t) = &memset; 165 | memset_v(v, 0, n); 166 | } 167 | 168 | const char *DEFAULT_PERSONAL = "ckb-default-hash"; 169 | int ckb_blake2b_init(blake2b_state *S, size_t outlen) { 170 | blake2b_param P[1]; 171 | 172 | if ((!outlen) || (outlen > BLAKE2B_OUTBYTES)) return -1; 173 | 174 | P->digest_length = (uint8_t)outlen; 175 | P->key_length = 0; 176 | P->fanout = 1; 177 | P->depth = 1; 178 | store32(&P->leaf_length, 0); 179 | store32(&P->node_offset, 0); 180 | store32(&P->xof_length, 0); 181 | P->node_depth = 0; 182 | P->inner_length = 0; 183 | memset(P->reserved, 0, sizeof(P->reserved)); 184 | memset(P->salt, 0, sizeof(P->salt)); 185 | memset(P->personal, 0, sizeof(P->personal)); 186 | for (int i = 0; i < BLAKE2B_PERSONALBYTES; ++i) { 187 | (P->personal)[i] = DEFAULT_PERSONAL[i]; 188 | } 189 | return blake2b_init_param(S, P); 190 | } 191 | 192 | #endif 193 | 194 | // blake2b-ref.c 195 | #ifndef BLAKE2_REF_C 196 | #define BLAKE2_REF_C 197 | 198 | #include 199 | #include 200 | #include 201 | 202 | static const uint64_t blake2b_IV[8] = { 203 | 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL, 204 | 0xa54ff53a5f1d36f1ULL, 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, 205 | 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL}; 206 | 207 | static const uint8_t blake2b_sigma[12][16] = { 208 | {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, 209 | {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, 210 | {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4}, 211 | {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8}, 212 | {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13}, 213 | {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9}, 214 | {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11}, 215 | {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10}, 216 | {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5}, 217 | {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0}, 218 | {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, 219 | {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}}; 220 | 221 | static void blake2b_set_lastnode(blake2b_state *S) { S->f[1] = (uint64_t)-1; } 222 | 223 | /* Some helper functions, not necessarily useful */ 224 | static int blake2b_is_lastblock(const blake2b_state *S) { return S->f[0] != 0; } 225 | 226 | static void blake2b_set_lastblock(blake2b_state *S) { 227 | if (S->last_node) blake2b_set_lastnode(S); 228 | 229 | S->f[0] = (uint64_t)-1; 230 | } 231 | 232 | static void blake2b_increment_counter(blake2b_state *S, const uint64_t inc) { 233 | S->t[0] += inc; 234 | S->t[1] += (S->t[0] < inc); 235 | } 236 | 237 | static void blake2b_init0(blake2b_state *S) { 238 | size_t i; 239 | memset(S, 0, sizeof(blake2b_state)); 240 | 241 | for (i = 0; i < 8; ++i) S->h[i] = blake2b_IV[i]; 242 | } 243 | 244 | /* init xors IV with input parameter block */ 245 | int blake2b_init_param(blake2b_state *S, const blake2b_param *P) { 246 | const uint8_t *p = (const uint8_t *)(P); 247 | size_t i; 248 | 249 | blake2b_init0(S); 250 | 251 | /* IV XOR ParamBlock */ 252 | for (i = 0; i < 8; ++i) S->h[i] ^= load64(p + sizeof(S->h[i]) * i); 253 | 254 | S->outlen = P->digest_length; 255 | return 0; 256 | } 257 | 258 | int blake2b_init(blake2b_state *S, size_t outlen) { 259 | blake2b_param P[1]; 260 | 261 | if ((!outlen) || (outlen > BLAKE2B_OUTBYTES)) return -1; 262 | 263 | P->digest_length = (uint8_t)outlen; 264 | P->key_length = 0; 265 | P->fanout = 1; 266 | P->depth = 1; 267 | store32(&P->leaf_length, 0); 268 | store32(&P->node_offset, 0); 269 | store32(&P->xof_length, 0); 270 | P->node_depth = 0; 271 | P->inner_length = 0; 272 | memset(P->reserved, 0, sizeof(P->reserved)); 273 | memset(P->salt, 0, sizeof(P->salt)); 274 | memset(P->personal, 0, sizeof(P->personal)); 275 | for (int i = 0; i < BLAKE2B_PERSONALBYTES; ++i) { 276 | (P->personal)[i] = DEFAULT_PERSONAL[i]; 277 | } 278 | return blake2b_init_param(S, P); 279 | } 280 | 281 | int blake2b_init_key(blake2b_state *S, size_t outlen, const void *key, 282 | size_t keylen) { 283 | blake2b_param P[1]; 284 | 285 | if ((!outlen) || (outlen > BLAKE2B_OUTBYTES)) return -1; 286 | 287 | if (!key || !keylen || keylen > BLAKE2B_KEYBYTES) return -1; 288 | 289 | P->digest_length = (uint8_t)outlen; 290 | P->key_length = (uint8_t)keylen; 291 | P->fanout = 1; 292 | P->depth = 1; 293 | store32(&P->leaf_length, 0); 294 | store32(&P->node_offset, 0); 295 | store32(&P->xof_length, 0); 296 | P->node_depth = 0; 297 | P->inner_length = 0; 298 | memset(P->reserved, 0, sizeof(P->reserved)); 299 | memset(P->salt, 0, sizeof(P->salt)); 300 | memset(P->personal, 0, sizeof(P->personal)); 301 | 302 | if (blake2b_init_param(S, P) < 0) return -1; 303 | 304 | { 305 | uint8_t block[BLAKE2B_BLOCKBYTES]; 306 | memset(block, 0, BLAKE2B_BLOCKBYTES); 307 | memcpy(block, key, keylen); 308 | blake2b_update(S, block, BLAKE2B_BLOCKBYTES); 309 | secure_zero_memory(block, BLAKE2B_BLOCKBYTES); /* Burn the key from stack */ 310 | } 311 | return 0; 312 | } 313 | 314 | #define G(r, i, a, b, c, d) \ 315 | do { \ 316 | a = a + b + m[blake2b_sigma[r][2 * i + 0]]; \ 317 | d = rotr64(d ^ a, 32); \ 318 | c = c + d; \ 319 | b = rotr64(b ^ c, 24); \ 320 | a = a + b + m[blake2b_sigma[r][2 * i + 1]]; \ 321 | d = rotr64(d ^ a, 16); \ 322 | c = c + d; \ 323 | b = rotr64(b ^ c, 63); \ 324 | } while (0) 325 | 326 | #define ROUND(r) \ 327 | do { \ 328 | G(r, 0, v[0], v[4], v[8], v[12]); \ 329 | G(r, 1, v[1], v[5], v[9], v[13]); \ 330 | G(r, 2, v[2], v[6], v[10], v[14]); \ 331 | G(r, 3, v[3], v[7], v[11], v[15]); \ 332 | G(r, 4, v[0], v[5], v[10], v[15]); \ 333 | G(r, 5, v[1], v[6], v[11], v[12]); \ 334 | G(r, 6, v[2], v[7], v[8], v[13]); \ 335 | G(r, 7, v[3], v[4], v[9], v[14]); \ 336 | } while (0) 337 | 338 | static void blake2b_compress(blake2b_state *S, 339 | const uint8_t block[BLAKE2B_BLOCKBYTES]) { 340 | uint64_t m[16]; 341 | uint64_t v[16]; 342 | size_t i; 343 | 344 | for (i = 0; i < 16; ++i) { 345 | m[i] = load64(block + i * sizeof(m[i])); 346 | } 347 | 348 | for (i = 0; i < 8; ++i) { 349 | v[i] = S->h[i]; 350 | } 351 | 352 | v[8] = blake2b_IV[0]; 353 | v[9] = blake2b_IV[1]; 354 | v[10] = blake2b_IV[2]; 355 | v[11] = blake2b_IV[3]; 356 | v[12] = blake2b_IV[4] ^ S->t[0]; 357 | v[13] = blake2b_IV[5] ^ S->t[1]; 358 | v[14] = blake2b_IV[6] ^ S->f[0]; 359 | v[15] = blake2b_IV[7] ^ S->f[1]; 360 | 361 | ROUND(0); 362 | ROUND(1); 363 | ROUND(2); 364 | ROUND(3); 365 | ROUND(4); 366 | ROUND(5); 367 | ROUND(6); 368 | ROUND(7); 369 | ROUND(8); 370 | ROUND(9); 371 | ROUND(10); 372 | ROUND(11); 373 | 374 | for (i = 0; i < 8; ++i) { 375 | S->h[i] = S->h[i] ^ v[i] ^ v[i + 8]; 376 | } 377 | } 378 | 379 | #undef G 380 | #undef ROUND 381 | 382 | int blake2b_update(blake2b_state *S, const void *pin, size_t inlen) { 383 | const unsigned char *in = (const unsigned char *)pin; 384 | if (inlen > 0) { 385 | size_t left = S->buflen; 386 | size_t fill = BLAKE2B_BLOCKBYTES - left; 387 | if (inlen > fill) { 388 | S->buflen = 0; 389 | memcpy(S->buf + left, in, fill); /* Fill buffer */ 390 | blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES); 391 | blake2b_compress(S, S->buf); /* Compress */ 392 | in += fill; 393 | inlen -= fill; 394 | while (inlen > BLAKE2B_BLOCKBYTES) { 395 | blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES); 396 | blake2b_compress(S, in); 397 | in += BLAKE2B_BLOCKBYTES; 398 | inlen -= BLAKE2B_BLOCKBYTES; 399 | } 400 | } 401 | memcpy(S->buf + S->buflen, in, inlen); 402 | S->buflen += inlen; 403 | } 404 | return 0; 405 | } 406 | 407 | int blake2b_final(blake2b_state *S, void *out, size_t outlen) { 408 | uint8_t buffer[BLAKE2B_OUTBYTES] = {0}; 409 | size_t i; 410 | 411 | if (out == NULL || outlen < S->outlen) return -1; 412 | 413 | if (blake2b_is_lastblock(S)) return -1; 414 | 415 | blake2b_increment_counter(S, S->buflen); 416 | blake2b_set_lastblock(S); 417 | memset(S->buf + S->buflen, 0, BLAKE2B_BLOCKBYTES - S->buflen); /* Padding */ 418 | blake2b_compress(S, S->buf); 419 | 420 | for (i = 0; i < 8; ++i) /* Output full hash to temp buffer */ 421 | store64(buffer + sizeof(S->h[i]) * i, S->h[i]); 422 | 423 | memcpy(out, buffer, S->outlen); 424 | secure_zero_memory(buffer, sizeof(buffer)); 425 | return 0; 426 | } 427 | 428 | /* inlen, at least, should be uint64_t. Others can be size_t. */ 429 | int blake2b(void *out, size_t outlen, const void *in, size_t inlen, 430 | const void *key, size_t keylen) { 431 | blake2b_state S[1]; 432 | 433 | /* Verify parameters */ 434 | if (NULL == in && inlen > 0) return -1; 435 | 436 | if (NULL == out) return -1; 437 | 438 | if (NULL == key && keylen > 0) return -1; 439 | 440 | if (!outlen || outlen > BLAKE2B_OUTBYTES) return -1; 441 | 442 | if (keylen > BLAKE2B_KEYBYTES) return -1; 443 | 444 | if (keylen > 0) { 445 | if (blake2b_init_key(S, outlen, key, keylen) < 0) return -1; 446 | } else { 447 | if (blake2b_init(S, outlen) < 0) return -1; 448 | } 449 | 450 | blake2b_update(S, (const uint8_t *)in, inlen); 451 | blake2b_final(S, out, outlen); 452 | return 0; 453 | } 454 | 455 | int blake2(void *out, size_t outlen, const void *in, size_t inlen, 456 | const void *key, size_t keylen) { 457 | return blake2b(out, outlen, in, inlen, key, keylen); 458 | } 459 | 460 | #if defined(SUPERCOP) 461 | int crypto_hash(unsigned char *out, unsigned char *in, 462 | unsigned long long inlen) { 463 | return blake2b(out, BLAKE2B_OUTBYTES, in, inlen, NULL, 0); 464 | } 465 | #endif 466 | 467 | #endif 468 | -------------------------------------------------------------------------------- /ckb_dlfcn.h: -------------------------------------------------------------------------------- 1 | #ifndef CKB_C_STDLIB_CKB_DLFCN_H_ 2 | #define CKB_C_STDLIB_CKB_DLFCN_H_ 3 | 4 | #include "ckb_syscalls.h" 5 | 6 | int ckb_dlopen(const uint8_t *dep_cell_data_hash, uint8_t *aligned_addr, 7 | size_t aligned_size, void **handle, size_t *consumed_size) { 8 | return ckb_dlopen2(dep_cell_data_hash, 0, aligned_addr, aligned_size, handle, 9 | consumed_size); 10 | } 11 | 12 | #ifndef CKB_STDLIB_NO_SYSCALL_IMPL 13 | 14 | int _ckb_load_cell_code(void *addr, size_t memory_size, size_t content_offset, 15 | size_t content_size, size_t index, size_t source) { 16 | return ckb_load_cell_data_as_code(addr, memory_size, content_offset, 17 | content_size, index, source); 18 | } 19 | 20 | /* 21 | * The ELF parsing code here is inspired from 22 | * https://github.com/riscv/riscv-pk/blob/master/pk/elf.h, original code is in 23 | * BSD license. 24 | */ 25 | 26 | typedef struct { 27 | uint8_t e_ident[16]; 28 | uint16_t e_type; 29 | uint16_t e_machine; 30 | uint32_t e_version; 31 | uint64_t e_entry; 32 | uint64_t e_phoff; 33 | uint64_t e_shoff; 34 | uint32_t e_flags; 35 | uint16_t e_ehsize; 36 | uint16_t e_phentsize; 37 | uint16_t e_phnum; 38 | uint16_t e_shentsize; 39 | uint16_t e_shnum; 40 | uint16_t e_shstrndx; 41 | } Elf64_Ehdr; 42 | 43 | #define SHT_STRTAB 3 44 | #define SHT_RELA 4 45 | #define SHT_DYNSYM 11 46 | 47 | typedef struct { 48 | uint32_t sh_name; 49 | uint32_t sh_type; 50 | uint64_t sh_flags; 51 | uint64_t sh_addr; 52 | uint64_t sh_offset; 53 | uint64_t sh_size; 54 | uint32_t sh_link; 55 | uint32_t sh_info; 56 | uint64_t sh_addralign; 57 | uint64_t sh_entsize; 58 | } Elf64_Shdr; 59 | 60 | #define PT_LOAD 1 61 | #define PF_X 1 62 | 63 | typedef struct { 64 | uint32_t p_type; 65 | uint32_t p_flags; 66 | uint64_t p_offset; 67 | uint64_t p_vaddr; 68 | uint64_t p_paddr; 69 | uint64_t p_filesz; 70 | uint64_t p_memsz; 71 | uint64_t p_align; 72 | } Elf64_Phdr; 73 | 74 | typedef struct { 75 | uint32_t st_name; 76 | uint8_t st_info; 77 | uint8_t st_other; 78 | uint16_t st_shndx; 79 | uint64_t st_value; 80 | uint64_t st_size; 81 | } Elf64_Sym; 82 | 83 | #define R_RISCV_RELATIVE 3 84 | #define R_RISCV_JUMP_SLOT 5 85 | 86 | typedef struct { 87 | uint64_t r_offset; 88 | uint64_t r_info; 89 | int64_t r_addend; 90 | } Elf64_Rela; 91 | 92 | #define RISCV_PGSIZE 4096 93 | 94 | #ifndef MAX 95 | #define MAX(a, b) ((a) > (b) ? (a) : (b)) 96 | #endif 97 | 98 | #ifndef MIN 99 | #define MIN(a, b) ((a) < (b) ? (a) : (b)) 100 | #endif 101 | 102 | #define ERROR_CONTEXT_FAILURE -21 103 | #define ERROR_INVALID_ELF -22 104 | #define ERROR_MEMORY_NOT_ENOUGH -23 105 | #define ERROR_OUT_OF_BOUND -24 106 | #define ERROR_INVALID_ARGS -25 107 | #define ERROR_ELF_NOT_ALIGNED -26 108 | 109 | typedef struct { 110 | Elf64_Sym *dynsyms; 111 | const char *dynstr; 112 | size_t dynsym_size; 113 | uint8_t *base_addr; 114 | size_t size; 115 | } CkbDlfcnContext; 116 | 117 | int check_in_range(const void *p, const CkbDlfcnContext *context) { 118 | uint64_t end; 119 | 120 | void *begin = context->base_addr; 121 | if (__builtin_uaddl_overflow((uint64_t)context->base_addr, context->size, 122 | &end)) { 123 | return 0; 124 | } 125 | if (begin <= p && p < (void *)end) { 126 | return 1; 127 | } else { 128 | return 0; 129 | } 130 | } 131 | 132 | int roundup(uint64_t a, uint64_t b, uint64_t *value) { 133 | if (a == 0) { 134 | *value = 0; 135 | return 0; 136 | } 137 | uint64_t d = (a - 1) / b; 138 | return __builtin_umull_overflow(d + 1, b, value); 139 | } 140 | 141 | uint8_t *addr_offset_checked(uint8_t *aligned_addr, uint64_t aligned_size, 142 | uint64_t offset) { 143 | uint64_t target = 0; 144 | if (offset < aligned_size) { 145 | if (__builtin_uaddl_overflow((uint64_t)aligned_addr, offset, &target)) { 146 | return 0; 147 | } else { 148 | return (uint8_t *)target; 149 | } 150 | } else { 151 | return 0; 152 | } 153 | } 154 | 155 | void *addr_offset_with_context(const void *addr, uint64_t offset, 156 | const CkbDlfcnContext *context) { 157 | uint64_t target = 0; 158 | if (__builtin_uaddl_overflow((uint64_t)addr, offset, &target)) { 159 | return 0; 160 | } else { 161 | if (!check_in_range((const void *)target, context)) { 162 | return 0; 163 | } else { 164 | return (void *)target; 165 | } 166 | } 167 | } 168 | 169 | int ckb_dlopen2(const uint8_t *dep_cell_hash, uint8_t hash_type, 170 | uint8_t *aligned_addr, size_t aligned_size, void **handle, 171 | size_t *consumed_size) { 172 | if (sizeof(CkbDlfcnContext) > RISCV_PGSIZE || aligned_size < RISCV_PGSIZE) { 173 | return ERROR_CONTEXT_FAILURE; 174 | } 175 | if (((uint64_t)aligned_addr) < 8) { 176 | return ERROR_CONTEXT_FAILURE; 177 | } 178 | 179 | if (dep_cell_hash == 0 || aligned_size == 0 || aligned_addr == 0 || 180 | handle == 0 || consumed_size == 0) { 181 | return ERROR_INVALID_ARGS; 182 | } 183 | uint64_t _end = 0; 184 | if (__builtin_uaddl_overflow((uint64_t)aligned_addr, aligned_size, &_end)) { 185 | return ERROR_OUT_OF_BOUND; 186 | } 187 | 188 | CkbDlfcnContext *context = (CkbDlfcnContext *)aligned_addr; 189 | memset(context, 0, sizeof(CkbDlfcnContext)); 190 | aligned_addr += RISCV_PGSIZE; 191 | aligned_size -= RISCV_PGSIZE; 192 | context->base_addr = aligned_addr; 193 | context->size = aligned_size; 194 | 195 | size_t index = SIZE_MAX; 196 | int ret = ckb_look_for_dep_with_hash2(dep_cell_hash, hash_type, &index); 197 | if (ret != CKB_SUCCESS) { 198 | return ret; 199 | } 200 | 201 | /* Basic ELF header parsing */ 202 | Elf64_Ehdr header; 203 | uint64_t len = sizeof(header); 204 | ret = 205 | ckb_load_cell_data((void *)&header, &len, 0, index, CKB_SOURCE_CELL_DEP); 206 | if (ret != CKB_SUCCESS) { 207 | return ret; 208 | } 209 | if (len < sizeof(header)) { 210 | return ERROR_INVALID_ELF; 211 | } 212 | if ((header.e_phentsize != sizeof(Elf64_Phdr)) || 213 | (header.e_shentsize != sizeof(Elf64_Shdr)) || (header.e_phnum > 16) || 214 | (header.e_shnum > 32)) { 215 | return ERROR_INVALID_ELF; 216 | } 217 | /* Parse program headers and load relevant parts */ 218 | Elf64_Phdr program_headers[16]; 219 | len = sizeof(Elf64_Phdr) * header.e_phnum; 220 | ret = ckb_load_cell_data((void *)program_headers, &len, header.e_phoff, index, 221 | CKB_SOURCE_CELL_DEP); 222 | if (ret != CKB_SUCCESS) { 223 | return ret; 224 | } 225 | if (len < sizeof(Elf64_Phdr) * header.e_phnum) { 226 | return ERROR_INVALID_ELF; 227 | } 228 | uint64_t max_consumed_size = 0; 229 | for (int i = 0; i < header.e_phnum; i++) { 230 | const Elf64_Phdr *ph = &program_headers[i]; 231 | if (ph->p_type == PT_LOAD && ph->p_memsz > 0) { 232 | if ((ph->p_flags & PF_X) != 0) { 233 | uint64_t prepad = ph->p_vaddr % RISCV_PGSIZE; 234 | uint64_t vaddr = ph->p_vaddr - prepad; 235 | uint64_t memsz = 0; 236 | if (roundup(prepad + ph->p_memsz, RISCV_PGSIZE, &memsz)) { 237 | return ERROR_INVALID_ELF; 238 | } 239 | unsigned long size = 0; 240 | if (__builtin_uaddl_overflow(vaddr, memsz, &size)) { 241 | return ERROR_INVALID_ELF; 242 | } 243 | if (size > aligned_size) { 244 | return ERROR_MEMORY_NOT_ENOUGH; 245 | } 246 | uint8_t *addr2 = addr_offset_checked(aligned_addr, aligned_size, vaddr); 247 | if (addr2 == 0) { 248 | return ERROR_INVALID_ELF; 249 | } 250 | /* 251 | * There is a slight defect in current syscall: if the padding 252 | * required for memory alignment is bigger than the ELF starting 253 | * offset to load, there is not a way for current syscall to correctly 254 | * load the ELF. We use a check here to guard for the condition, and 255 | * exit when it is not satisfied. A better solution might to explicitly 256 | * ask for page aligned code section in linker, or wait for a fixed 257 | * syscall version. 258 | */ 259 | if (ph->p_offset < prepad) { 260 | return ERROR_ELF_NOT_ALIGNED; 261 | } 262 | ret = ckb_load_cell_data_as_code(addr2, memsz, ph->p_offset - prepad, 263 | ph->p_filesz + prepad, index, 264 | CKB_SOURCE_CELL_DEP); 265 | if (ret != CKB_SUCCESS) { 266 | return ret; 267 | } 268 | max_consumed_size = MAX(max_consumed_size, vaddr + memsz); 269 | } else { 270 | uint64_t filesz = ph->p_filesz; 271 | uint64_t memsz = ph->p_memsz; 272 | uint64_t size = 0; 273 | uint64_t gap_len = 0; 274 | if (filesz > memsz) { 275 | return ERROR_INVALID_ELF; 276 | } 277 | gap_len = memsz - filesz; 278 | 279 | if (__builtin_uaddl_overflow(ph->p_vaddr, memsz, &size)) { 280 | return ERROR_INVALID_ELF; 281 | } 282 | uint64_t consumed_end = 0; 283 | if (roundup(size, RISCV_PGSIZE, &consumed_end)) { 284 | return ERROR_INVALID_ELF; 285 | } 286 | if (consumed_end > aligned_size) { 287 | return ERROR_MEMORY_NOT_ENOUGH; 288 | } 289 | uint8_t *addr2 = 290 | addr_offset_checked(aligned_addr, aligned_size, ph->p_vaddr); 291 | if (addr2 == 0) { 292 | return ERROR_INVALID_ELF; 293 | } 294 | uint64_t read_len = filesz; 295 | ret = ckb_load_cell_data(addr2, &read_len, ph->p_offset, index, 296 | CKB_SOURCE_CELL_DEP); 297 | if (ret != CKB_SUCCESS) { 298 | return ret; 299 | } 300 | if (read_len < filesz) { 301 | return ERROR_INVALID_ELF; 302 | } 303 | if (gap_len > 0) { 304 | uint8_t *addr3 = addr_offset_with_context(addr2, filesz, context); 305 | uint8_t *addr4 = 306 | addr_offset_with_context(addr3, gap_len - 1, context); 307 | if (addr3 != 0 && addr4 != 0) { 308 | memset(addr3, 0, gap_len); 309 | } else { 310 | return ERROR_INVALID_ELF; 311 | } 312 | } 313 | max_consumed_size = MAX(max_consumed_size, consumed_end); 314 | } 315 | } 316 | } 317 | /* 318 | * Parse sectioin header & relocation headers, 319 | * Perform necessary relocations. 320 | */ 321 | Elf64_Shdr section_headers[32]; 322 | len = sizeof(Elf64_Shdr) * header.e_shnum; 323 | ret = ckb_load_cell_data((void *)section_headers, &len, header.e_shoff, index, 324 | CKB_SOURCE_CELL_DEP); 325 | if (ret != CKB_SUCCESS) { 326 | return ret; 327 | } 328 | if (len < sizeof(Elf64_Shdr) * header.e_shnum) { 329 | return ERROR_INVALID_ELF; 330 | } 331 | if (header.e_shstrndx >= 32 || header.e_shstrndx >= header.e_shnum) { 332 | return ERROR_INVALID_ELF; 333 | } 334 | /* 335 | * First load shstrtab tab, this is temporary code only needed in ELF loading 336 | * phase here. 337 | */ 338 | Elf64_Shdr *shshrtab = §ion_headers[header.e_shstrndx]; 339 | char shrtab[4096]; 340 | if (shshrtab->sh_size > 4096) { 341 | return ERROR_INVALID_ELF; 342 | } 343 | uint64_t shrtab_len = shshrtab->sh_size; 344 | ret = ckb_load_cell_data((void *)shrtab, &shrtab_len, shshrtab->sh_offset, 345 | index, CKB_SOURCE_CELL_DEP); 346 | if (ret != CKB_SUCCESS) { 347 | return ret; 348 | } 349 | if (shrtab_len < shshrtab->sh_size) { 350 | return ERROR_INVALID_ELF; 351 | } 352 | for (int i = 0; i < header.e_shnum; i++) { 353 | const Elf64_Shdr *sh = §ion_headers[i]; 354 | if (sh->sh_type == SHT_RELA) { 355 | if (sh->sh_entsize != sizeof(Elf64_Rela)) { 356 | return ERROR_INVALID_ELF; 357 | } 358 | size_t relocation_size = sh->sh_size / sh->sh_entsize; 359 | uint64_t current_offset = sh->sh_offset; 360 | while (relocation_size > 0) { 361 | Elf64_Rela relocations[64]; 362 | size_t load_size = MIN(relocation_size, 64); 363 | uint64_t load_length = load_size * sizeof(Elf64_Rela); 364 | ret = ckb_load_cell_data((void *)relocations, &load_length, 365 | current_offset, index, CKB_SOURCE_CELL_DEP); 366 | if (ret != CKB_SUCCESS) { 367 | return ret; 368 | } 369 | if (load_length < load_size * sizeof(Elf64_Rela)) { 370 | return ERROR_INVALID_ELF; 371 | } 372 | relocation_size -= load_size; 373 | current_offset += load_size * sizeof(Elf64_Rela); 374 | for (size_t j = 0; j < load_size; j++) { 375 | Elf64_Rela *r = &relocations[j]; 376 | uint32_t t = (uint32_t)r->r_info; 377 | if (t != R_RISCV_RELATIVE && t != R_RISCV_JUMP_SLOT) { 378 | /* 379 | * Only relative and jump slot relocations are supported now, 380 | * we might add more later. 381 | */ 382 | return ERROR_INVALID_ELF; 383 | } 384 | if (r->r_offset >= (aligned_size - sizeof(uint64_t)) || 385 | r->r_addend >= (int64_t)(aligned_size) || r->r_addend < 0) { 386 | return ERROR_INVALID_ELF; 387 | } 388 | uint64_t temp = (uint64_t)(aligned_addr + r->r_addend); 389 | memcpy(aligned_addr + r->r_offset, &temp, sizeof(uint64_t)); 390 | } 391 | } 392 | } else if (sh->sh_type == SHT_DYNSYM) { 393 | /* We assume one ELF file only has one DYNSYM section now */ 394 | if (sh->sh_entsize != sizeof(Elf64_Sym)) { 395 | return ERROR_INVALID_ELF; 396 | } 397 | uint8_t *addr2 = 398 | addr_offset_checked(aligned_addr, aligned_size, sh->sh_addr); 399 | if (addr2 == 0) { 400 | return ERROR_INVALID_ELF; 401 | } 402 | context->dynsyms = (Elf64_Sym *)addr2; 403 | context->dynsym_size = sh->sh_size / sh->sh_entsize; 404 | 405 | uint8_t *addr3 = addr_offset_with_context(addr2, sh->sh_size, context); 406 | if (addr3 == 0) { 407 | return ERROR_INVALID_ELF; 408 | } 409 | } else if (sh->sh_type == SHT_STRTAB) { 410 | static char DYNSTR[] = ".dynstr"; 411 | if (sh->sh_name < (4096 - sizeof(DYNSTR)) && 412 | shshrtab->sh_size >= sizeof(DYNSTR) && 413 | sh->sh_name < (shshrtab->sh_size - sizeof(DYNSTR))) { 414 | const char *current_str = shrtab + sh->sh_name; 415 | if (strcmp(DYNSTR, current_str) == 0) { 416 | const uint8_t *addr2 = 417 | addr_offset_checked(aligned_addr, aligned_size, sh->sh_addr); 418 | if (addr2 == 0) { 419 | return ERROR_INVALID_ELF; 420 | } 421 | context->dynstr = (const char *)addr2; 422 | } 423 | } 424 | } 425 | } 426 | if (context->dynsyms == NULL || context->dynstr == NULL) { 427 | return ERROR_INVALID_ELF; 428 | } 429 | *handle = (void *)context; 430 | *consumed_size = max_consumed_size + RISCV_PGSIZE; 431 | return CKB_SUCCESS; 432 | } 433 | 434 | void *ckb_dlsym(void *handle, const char *symbol) { 435 | if (handle == NULL || symbol == NULL) { 436 | return NULL; 437 | } 438 | CkbDlfcnContext *context = (CkbDlfcnContext *)handle; 439 | 440 | if (context->base_addr == NULL || context->size == 0 || 441 | context->dynstr == NULL || context->dynsym_size == 0 || 442 | context->dynsyms == NULL) { 443 | return NULL; 444 | } 445 | if (!check_in_range(context->dynstr, context)) { 446 | return NULL; 447 | } 448 | uint64_t _end = 0; 449 | if (__builtin_uaddl_overflow((uint64_t)context->base_addr, context->size, 450 | &_end)) { 451 | return NULL; 452 | } 453 | 454 | for (uint64_t i = 0; i < context->dynsym_size; i++) { 455 | Elf64_Sym *sym = &context->dynsyms[i]; 456 | const char *str = 457 | addr_offset_with_context(context->dynstr, sym->st_name, context); 458 | const void *str_end = 459 | addr_offset_with_context(str, strlen(symbol), context); 460 | if ((str == 0) || (str_end == 0)) return NULL; 461 | if (strcmp(str, symbol) == 0) { 462 | void *p = 463 | addr_offset_with_context(context->base_addr, sym->st_value, context); 464 | if (p == 0) { 465 | return 0; 466 | } else { 467 | return p; 468 | } 469 | } 470 | } 471 | 472 | return NULL; 473 | } 474 | 475 | #endif /* CKB_STDLIB_NO_SYSCALL_IMPL */ 476 | 477 | #endif /* CKB_C_STDLIB_CKB_DLFCN_H_ */ 478 | -------------------------------------------------------------------------------- /simulator/rsa_sighash_all_usesim.c: -------------------------------------------------------------------------------- 1 | #include 2 | #define ASSERT assert 3 | 4 | #include "../c/rsa_sighash_all.c" 5 | #include "mbedtls/ctr_drbg.h" 6 | #include "mbedtls/entropy.h" 7 | #include "mbedtls/md.h" 8 | 9 | void dump_as_carray(uint8_t* ptr, size_t size) { 10 | for (size_t i = 0; i < size; i++) { 11 | if (i == (size - 1)) { 12 | mbedtls_printf("0x%02X\n", ptr[i]); 13 | } else { 14 | mbedtls_printf("0x%02X,", ptr[i]); 15 | } 16 | } 17 | } 18 | 19 | static unsigned char get_hex(unsigned char c) { 20 | if (c >= '0' && c <= '9') 21 | return c - '0'; 22 | else if (c >= 'A' && c <= 'F') 23 | return c - 'A' + 10; 24 | else if (c >= 'a' && c <= 'f') 25 | return c - 'a' + 10; 26 | else 27 | return 0; 28 | } 29 | 30 | static int scan_hex(const char* s, unsigned char* value) { 31 | if (s[0] == '\0' || s[1] == '\0') return 0; 32 | 33 | unsigned char high_part = get_hex(s[0]); 34 | unsigned char low_part = get_hex(s[1]); 35 | 36 | *value = (high_part << 4) + low_part; 37 | return 1; 38 | } 39 | 40 | static uint32_t read_string(const char* str, uint8_t* buf, uint32_t buf_size) { 41 | size_t sig_len = strlen(str); 42 | const char* ptr = str; 43 | const char* end = str + sig_len; 44 | 45 | uint32_t i = 0; 46 | while (1) { 47 | unsigned char c = 0; 48 | int consumed = scan_hex(ptr, &c); 49 | if (consumed == 0) break; 50 | if (i >= buf_size) break; 51 | buf[i++] = (uint8_t)c; 52 | ptr += consumed * 2; 53 | if (ptr >= end) break; 54 | } 55 | return i; 56 | } 57 | 58 | void mbedtls_mpi_dump(const char* prefix, const mbedtls_mpi* X) { 59 | size_t n; 60 | char s[1024]; 61 | memset(s, 0, sizeof(s)); 62 | 63 | mbedtls_mpi_write_string(X, 16, s, sizeof(s) - 2, &n); 64 | mbedtls_printf("%s%s\n", prefix, s); 65 | } 66 | 67 | void dup_buffer(const unsigned char* src, int src_len, unsigned char* dest, 68 | int dup_count) { 69 | for (int i = 0; i < dup_count; i++) { 70 | for (int j = 0; j < src_len; j++) { 71 | dest[i * src_len + j] = src[j]; 72 | } 73 | } 74 | } 75 | 76 | int ecdsa_sighash_random(void); 77 | 78 | typedef struct mbedtls_test_rnd_pseudo_info { 79 | uint32_t key[16]; 80 | uint32_t v0, v1; 81 | } mbedtls_test_rnd_pseudo_info; 82 | 83 | int mbedtls_test_rnd_pseudo_rand(void* rng_state, unsigned char* output, 84 | size_t len) { 85 | for (size_t i = 0; i < len; i++) { 86 | output[i] = (unsigned char)rand(); 87 | } 88 | return 0; 89 | } 90 | 91 | void srand(unsigned seed); 92 | long time(long*); 93 | 94 | int ecdsa_sighash_random(void) { 95 | int err = 0; 96 | int id = MBEDTLS_ECP_DP_SECP256R1; 97 | Secp256r1Info info; 98 | mbedtls_ecp_group grp; 99 | mbedtls_ecp_point Q; 100 | mbedtls_mpi d, r, s; 101 | mbedtls_test_rnd_pseudo_info rnd_info; 102 | unsigned char buf[32]; 103 | 104 | int alloc_buff_size = 1024 * 1024; 105 | unsigned char alloc_buff[alloc_buff_size]; 106 | mbedtls_memory_buffer_alloc_init(alloc_buff, alloc_buff_size); 107 | 108 | srand(time(NULL)); 109 | 110 | mbedtls_ecp_group_init(&grp); 111 | mbedtls_ecp_point_init(&Q); 112 | mbedtls_mpi_init(&d); 113 | mbedtls_mpi_init(&r); 114 | mbedtls_mpi_init(&s); 115 | memset(&rnd_info, 0x00, sizeof(mbedtls_test_rnd_pseudo_info)); 116 | memset(buf, 0, sizeof(buf)); 117 | 118 | ASSERT(mbedtls_test_rnd_pseudo_rand(&rnd_info, buf, sizeof(buf)) == 0); 119 | ASSERT(mbedtls_ecp_group_load(&grp, id) == 0); 120 | ASSERT(mbedtls_ecp_gen_keypair(&grp, &d, &Q, &mbedtls_test_rnd_pseudo_rand, 121 | &rnd_info) == 0); 122 | 123 | ASSERT(mbedtls_ecdsa_sign(&grp, &r, &s, &d, buf, sizeof(buf), 124 | &mbedtls_test_rnd_pseudo_rand, &rnd_info) == 0); 125 | 126 | serialize_secp256r1info(&Q, &r, &s, &info); 127 | 128 | mbedtls_ecp_group_free(&grp); 129 | mbedtls_ecp_point_free(&Q); 130 | mbedtls_mpi_free(&d); 131 | mbedtls_mpi_free(&r); 132 | mbedtls_mpi_free(&s); 133 | 134 | if (false) { 135 | mbedtls_ecp_point new_Q; 136 | mbedtls_mpi new_r; 137 | mbedtls_mpi new_s; 138 | 139 | deserialize_secp256r1info(&new_Q, &new_r, &new_s, &info); 140 | ASSERT(mbedtls_ecdsa_verify(&grp, buf, sizeof(buf), &new_Q, &new_r, 141 | &new_s) == 0); 142 | } else { 143 | info.algorithm_id = CKB_VERIFY_SECP256R1; 144 | // dump_as_carray((uint8_t *)&info, sizeof(info)); 145 | // dump_as_carray(buf, sizeof(buf)); 146 | err = validate_signature_secp256r1(NULL, (const unsigned char*)&info, 147 | sizeof(info), buf, sizeof(buf), NULL, 148 | NULL); 149 | CHECK(err); 150 | } 151 | err = CKB_SUCCESS; 152 | exit: 153 | if (err == CKB_SUCCESS) { 154 | mbedtls_printf("ecdsa_sighash_random() passed.\n"); 155 | } else { 156 | mbedtls_printf("ecdsa_sighash_random() failed.\n"); 157 | } 158 | return err; 159 | } 160 | 161 | #define EXPONENT 65537 162 | 163 | int fake_random_entropy_poll(void* data, unsigned char* output, size_t len, 164 | size_t* olen) { 165 | *output = (unsigned char)rand(); 166 | *olen = len; 167 | return 0; 168 | } 169 | 170 | int gen_rsa_key(uint32_t key_size, mbedtls_rsa_context* rsa) { 171 | int err = 0; 172 | mbedtls_entropy_context entropy; 173 | mbedtls_ctr_drbg_context ctr_drbg; 174 | const char* pers = "rsa_genkey"; 175 | 176 | mbedtls_ctr_drbg_init(&ctr_drbg); 177 | mbedtls_entropy_init(&entropy); 178 | mbedtls_rsa_init(rsa, MBEDTLS_RSA_PKCS_V15, 0); 179 | 180 | err = mbedtls_entropy_add_source(&entropy, fake_random_entropy_poll, NULL, 32, 181 | MBEDTLS_ENTROPY_SOURCE_STRONG); 182 | CHECK(err); 183 | 184 | err = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, 185 | (const unsigned char*)pers, strlen(pers)); 186 | CHECK(err); 187 | 188 | err = mbedtls_rsa_gen_key(rsa, mbedtls_ctr_drbg_random, &ctr_drbg, key_size, 189 | EXPONENT); 190 | CHECK(err); 191 | 192 | err = 0; 193 | 194 | exit: 195 | mbedtls_ctr_drbg_free(&ctr_drbg); 196 | mbedtls_entropy_free(&entropy); 197 | return err; 198 | } 199 | 200 | int rsa_sign(mbedtls_rsa_context* rsa, const uint8_t* msg_buf, 201 | uint32_t msg_size, uint8_t* sig) { 202 | int err = 0; 203 | 204 | uint8_t hash_buf[32] = {0}; 205 | uint32_t hash_size = 32; 206 | unsigned char hash_result[MBEDTLS_MD_MAX_SIZE]; 207 | mbedtls_mpi N, P, Q, E; 208 | mbedtls_test_rnd_pseudo_info rnd_info; 209 | 210 | memset(&rnd_info, 0, sizeof(mbedtls_test_rnd_pseudo_info)); 211 | ASSERT(mbedtls_rsa_check_privkey(rsa) == 0); 212 | err = md_string(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), msg_buf, 213 | msg_size, hash_buf); 214 | CHECK(err); 215 | 216 | err = mbedtls_rsa_pkcs1_sign(rsa, &mbedtls_test_rnd_pseudo_rand, &rnd_info, 217 | MBEDTLS_RSA_PRIVATE, MBEDTLS_MD_SHA256, 218 | hash_size, hash_buf, sig); 219 | CHECK(err); 220 | err = CKB_SUCCESS; 221 | exit: 222 | return err; 223 | } 224 | 225 | int rsa_verify(mbedtls_rsa_context* rsa, const uint8_t* msg_buf, 226 | uint32_t msg_size, const uint8_t* sig) { 227 | int err = 0; 228 | uint8_t hash_buf[32] = {0}; 229 | uint32_t hash_size = 32; 230 | 231 | ASSERT(mbedtls_rsa_check_pubkey(rsa) == 0); 232 | err = md_string(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), msg_buf, 233 | msg_size, hash_buf); 234 | CHECK(err); 235 | err = mbedtls_rsa_pkcs1_verify(rsa, NULL, NULL, MBEDTLS_RSA_PUBLIC, 236 | MBEDTLS_MD_SHA256, hash_size, hash_buf, sig); 237 | CHECK(err); 238 | 239 | err = 0; 240 | exit: 241 | return err; 242 | } 243 | 244 | int rsa_random(void) { 245 | int err = 0; 246 | 247 | int alloc_buff_size = 1024 * 1024; 248 | unsigned char alloc_buff[alloc_buff_size]; 249 | mbedtls_memory_buffer_alloc_init(alloc_buff, alloc_buff_size); 250 | 251 | uint32_t key_size = 1024; 252 | uint32_t byte_size = key_size / 8; 253 | 254 | uint8_t msg[32] = {1, 2, 3, 4}; 255 | uint8_t sig[byte_size]; 256 | mbedtls_rsa_context rsa; 257 | err = gen_rsa_key(key_size, &rsa); 258 | CHECK(err); 259 | 260 | err = rsa_sign(&rsa, msg, sizeof(msg), sig); 261 | CHECK(err); 262 | 263 | err = rsa_verify(&rsa, msg, sizeof(msg), sig); 264 | CHECK(err); 265 | 266 | err = 0; 267 | exit: 268 | if (err == CKB_SUCCESS) { 269 | mbedtls_printf("rsa_random() passed.\n"); 270 | } else { 271 | mbedtls_printf("rsa_random() failed.\n"); 272 | } 273 | return err; 274 | } 275 | 276 | void export_public_key(const mbedtls_rsa_context* rsa, RsaInfo* info) { 277 | mbedtls_mpi N, E; 278 | mbedtls_mpi_init(&N); 279 | mbedtls_mpi_init(&E); 280 | int ret = mbedtls_rsa_export(rsa, &N, NULL, NULL, NULL, &E); 281 | ASSERT(ret == 0); 282 | mbedtls_mpi_write_binary_le(&N, info->N, info->key_size / 8); 283 | mbedtls_mpi_write_binary_le(&E, (unsigned char*)&info->E, sizeof(info->E)); 284 | } 285 | 286 | int rsa_sighash_random(void) { 287 | int err = 0; 288 | 289 | int alloc_buff_size = 1024 * 1024; 290 | unsigned char alloc_buff[alloc_buff_size]; 291 | mbedtls_memory_buffer_alloc_init(alloc_buff, alloc_buff_size); 292 | 293 | uint32_t key_size = 1024; 294 | uint32_t byte_size = key_size / 8; 295 | 296 | uint8_t msg[32] = {1, 2, 3, 4}; 297 | uint8_t sig[byte_size]; 298 | mbedtls_rsa_context rsa; 299 | err = gen_rsa_key(key_size, &rsa); 300 | CHECK(err); 301 | 302 | err = rsa_sign(&rsa, msg, sizeof(msg), sig); 303 | CHECK(err); 304 | 305 | RsaInfo info; 306 | info.algorithm_id = CKB_VERIFY_RSA; 307 | info.key_size = key_size; 308 | export_public_key(&rsa, &info); 309 | 310 | uint8_t* ptr = get_rsa_signature(&info); 311 | memcpy(ptr, sig, sizeof(sig)); 312 | 313 | uint8_t output[20]; 314 | size_t output_len = 20; 315 | err = validate_signature(NULL, (uint8_t*)&info, sizeof(info), msg, 316 | sizeof(msg), output, &output_len); 317 | CHECK(err); 318 | 319 | err = 0; 320 | exit: 321 | if (err == CKB_SUCCESS) { 322 | mbedtls_printf("rsa_sighash_random() passed.\n"); 323 | } else { 324 | mbedtls_printf("rsa_sighash_random() failed.\n"); 325 | } 326 | return err; 327 | } 328 | 329 | int rsa_sighash_all(void) { 330 | int err = 0; 331 | uint8_t output[BLAKE160_SIZE]; 332 | 333 | err = validate_rsa_sighash_all(output); 334 | CHECK2(err == ERROR_RSA_VERIFY_FAILED, err); 335 | 336 | err = 0; 337 | exit: 338 | if (err == 0) { 339 | mbedtls_printf( 340 | "rsa_sighash_all() passed. (Ignore the failed messages above)\n"); 341 | } else { 342 | mbedtls_printf("rsa_sighash_all() failed.\n"); 343 | } 344 | return err; 345 | } 346 | 347 | int iso97962_test2(void) { 348 | int err = 0; 349 | const char* N_str = 350 | "9cf68418644a5418529373350bafd57ddbf5626527b95e8ea3217d8dac8fbcb7db107eda" 351 | "5e47979b7e4343ed6441950f7fbd921075579104ba081f1a9af950b4c0ee67c2eef2068d" 352 | "9fe2d9d0cfdcbb9be7066e19cc945600e9fd41fc50e771f437ce4bdde63e7acf2a828a4b" 353 | "f38b9f907a252b3dfef550919da1819033f9c619"; 354 | const char* E_str = "10001"; 355 | const char* msg_str = "B30D0D9FA0C8BBDF"; 356 | const char* sig_str = 357 | "46E52F52599A97B7DBBB8BCDD3A3BE6857F4CEF41B0723BE9FBD404DCF471DFC00D2DBF2" 358 | "F5DA6A9B8C1A41893A569873CAD2E90EECEC84DEE85DCDE76041390D1E1328751F2832C8" 359 | "3699986744AF68087EFFB21CD9526317424C136911144AE31B00F1764F1C5CCD974D52F6" 360 | "278B029197C5746E62F67C544FA5C9B66E2A8AFB"; 361 | const char* plaintext_str = 362 | "6A51762ED9802385DD5AE676C603778A037FFDCCD2BA92E32DD3AECE0C31AF76CFF88F75" 363 | "B257930255EA361218BEDCC4B1A96BBC9BCCF77BF6BA4B4A7F847F475F81C1FDD30C74B6" 364 | "AC97732C32D4B23C4BF8200270F5F15FED198E80AA5089807B9861E374D3871509C9965A" 365 | "AD886D9FB5A345873A4EB58EEFA5C35A4C3B55BC"; 366 | 367 | mbedtls_rsa_context rsa; 368 | mbedtls_mpi N; 369 | mbedtls_mpi E; 370 | 371 | uint8_t msg[8]; 372 | uint8_t sig[128]; 373 | uint8_t block[128]; 374 | uint32_t sig_len = 0; 375 | uint32_t msg_len = 0; 376 | uint8_t m1[128]; 377 | uint32_t m1_len = 128; 378 | uint8_t full_msg[1024]; 379 | uint8_t new_msg[1024]; 380 | uint32_t new_msg_len = 1024; 381 | 382 | int alloc_buff_size = 1024 * 1024; 383 | unsigned char alloc_buff[alloc_buff_size]; 384 | mbedtls_memory_buffer_alloc_init(alloc_buff, alloc_buff_size); 385 | 386 | mbedtls_mpi_init(&N); 387 | mbedtls_mpi_init(&E); 388 | 389 | mbedtls_mpi_read_string(&N, 16, N_str); 390 | mbedtls_mpi_read_string(&E, 16, E_str); 391 | mbedtls_rsa_init(&rsa, MBEDTLS_RSA_PKCS_V15, 0); 392 | mbedtls_rsa_import(&rsa, &N, NULL, NULL, NULL, &E); 393 | 394 | sig_len = read_string(sig_str, sig, sizeof(sig)); 395 | ASSERT(sig_len == 128); 396 | msg_len = read_string(msg_str, msg, sizeof(msg)); 397 | ASSERT(msg_len == 8); 398 | 399 | err = mbedtls_rsa_public(&rsa, sig, block); 400 | CHECK(err); 401 | 402 | ISO97962Encoding enc = {0}; 403 | iso97962_init(&enc, 1024, MBEDTLS_MD_SHA1, false); 404 | err = iso97962_verify(&enc, block, sizeof(block), msg, msg_len, m1, &m1_len); 405 | CHECK2(err == 0 || err == ERROR_ISO97962_MISMATCH_HASH, 406 | ERROR_ISO97962_INVALID_ARG9); 407 | 408 | memcpy(full_msg, m1, m1_len); 409 | memcpy(full_msg + m1_len, msg, sizeof(msg)); 410 | 411 | err = iso97962_verify(&enc, block, sizeof(block), full_msg, 412 | m1_len + sizeof(msg), new_msg, &new_msg_len); 413 | CHECK(err); 414 | 415 | err = 0; 416 | exit: 417 | if (err == 0) { 418 | mbedtls_printf("iso97962_test2() passed.\n"); 419 | } else { 420 | mbedtls_printf("iso97962_test2() failed.\n"); 421 | } 422 | return err; 423 | } 424 | 425 | int iso97962_test(void) { 426 | int err = 0; 427 | ISO97962Encoding enc = {0}; 428 | iso97962_init(&enc, 1024, MBEDTLS_MD_SHA1, false); 429 | uint8_t msg[] = {1, 2, 3, 4, 5, 6, 7, 8}; 430 | uint32_t msg_len = sizeof(msg); 431 | 432 | uint8_t block[128] = {0}; 433 | err = iso97962_sign(&enc, msg, sizeof(msg), block, sizeof(block)); 434 | CHECK(err); 435 | uint8_t new_msg[128]; 436 | uint32_t new_msg_len = 128; 437 | err = iso97962_verify(&enc, block, sizeof(block), NULL, 0, new_msg, 438 | &new_msg_len); 439 | CHECK(err); 440 | ASSERT(new_msg_len == msg_len); 441 | ASSERT(memcmp(msg, new_msg, msg_len) == 0); 442 | 443 | err = 0; 444 | exit: 445 | if (err == 0) { 446 | mbedtls_printf("iso97962_test() passed.\n"); 447 | } else { 448 | mbedtls_printf("iso97962_test() failed.\n"); 449 | } 450 | return err; 451 | } 452 | 453 | int iso97962_test3(uint32_t key_size, const char* N_str, const char* E_str, 454 | const char* msg_str, const char* sig_str) { 455 | int err = 0; 456 | 457 | mbedtls_mpi N; 458 | mbedtls_mpi E; 459 | 460 | uint8_t msg[4096]; 461 | uint32_t msg_len = 0; 462 | 463 | uint8_t sig[4096]; 464 | uint32_t sig_len = 0; 465 | 466 | uint8_t new_msg[1024]; 467 | size_t new_msg_len = 1024; 468 | 469 | int alloc_buff_size = 1024 * 1024; 470 | unsigned char alloc_buff[alloc_buff_size]; 471 | mbedtls_memory_buffer_alloc_init(alloc_buff, alloc_buff_size); 472 | 473 | mbedtls_mpi_init(&N); 474 | mbedtls_mpi_init(&E); 475 | mbedtls_mpi_read_string(&N, 16, N_str); 476 | mbedtls_mpi_read_string(&E, 16, E_str); 477 | 478 | sig_len = read_string(sig_str, sig, sizeof(sig)); 479 | ASSERT(sig_len == key_size); 480 | msg_len = read_string(msg_str, msg, sizeof(msg)); 481 | ASSERT(msg_len > 0 && msg_len < key_size); 482 | 483 | RsaInfo info; 484 | info.key_size = key_size * 8; // in bit 485 | info.algorithm_id = CKB_VERIFY_ISO9796_2; 486 | mbedtls_mpi_write_binary_le(&N, (uint8_t*)info.N, key_size); 487 | mbedtls_mpi_write_binary_le(&E, (uint8_t*)&info.E, sizeof(info.E)); 488 | 489 | ASSERT(sig_len == key_size); 490 | memcpy(info.sig, sig, sig_len); 491 | 492 | err = validate_signature(NULL, (uint8_t*)&info, sizeof(info), msg, msg_len, 493 | new_msg, &new_msg_len); 494 | CHECK(err); 495 | 496 | err = 0; 497 | exit: 498 | return err; 499 | } 500 | 501 | int main(int argc, const char* argv[]) { 502 | int err = 0; 503 | err = ecdsa_sighash_random(); 504 | CHECK(err); 505 | 506 | err = rsa_random(); 507 | CHECK(err); 508 | 509 | err = rsa_sighash_random(); 510 | CHECK(err); 511 | 512 | err = rsa_sighash_all(); 513 | CHECK(err); 514 | 515 | err = iso97962_test(); 516 | CHECK(err); 517 | 518 | err = iso97962_test2(); 519 | CHECK(err); 520 | 521 | // RSA public key, N 522 | const char* N_str = 523 | "9cf68418644a5418529373350bafd57ddbf5626527b95e8ea3217d8dac8fbcb7db107eda" 524 | "5e47979b7e4343ed6441950f7fbd921075579104ba081f1a9af950b4c0ee67c2eef2068d" 525 | "9fe2d9d0cfdcbb9be7066e19cc945600e9fd41fc50e771f437ce4bdde63e7acf2a828a4b" 526 | "f38b9f907a252b3dfef550919da1819033f9c619"; 527 | // RSA public key, E, 65537 528 | const char* E_str = "10001"; 529 | // input small message 530 | const char* msg_str = "B30D0D9FA0C8BBDF"; 531 | // input signature 532 | const char* sig_str = 533 | "46E52F52599A97B7DBBB8BCDD3A3BE6857F4CEF41B0723BE9FBD404DCF471DFC00D2DBF2" 534 | "F5DA6A9B8C1A41893A569873CAD2E90EECEC84DEE85DCDE76041390D1E1328751F2832C8" 535 | "3699986744AF68087EFFB21CD9526317424C136911144AE31B00F1764F1C5CCD974D52F6" 536 | "278B029197C5746E62F67C544FA5C9B66E2A8AFB"; 537 | err = iso97962_test3(128, N_str, E_str, msg_str, sig_str); 538 | CHECK(err); 539 | 540 | err = 0; 541 | exit: 542 | return err; 543 | } 544 | -------------------------------------------------------------------------------- /simulator/cJSON.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2009-2017 Dave Gamble and cJSON contributors 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #ifndef cJSON__h 24 | #define cJSON__h 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | #if !defined(__WINDOWS__) && \ 31 | (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)) 32 | #define __WINDOWS__ 33 | #endif 34 | 35 | #ifdef __WINDOWS__ 36 | 37 | /* When compiling for windows, we specify a specific calling convention to avoid 38 | issues where we are being called from a project with a different default calling 39 | convention. For windows you have 3 define options: 40 | 41 | CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever 42 | dllexport symbols CJSON_EXPORT_SYMBOLS - Define this on library build when you 43 | want to dllexport symbols (default) CJSON_IMPORT_SYMBOLS - Define this if you 44 | want to dllimport symbol 45 | 46 | For *nix builds that support visibility attribute, you can define similar 47 | behavior by 48 | 49 | setting default visibility to hidden by adding 50 | -fvisibility=hidden (for gcc) 51 | or 52 | -xldscope=hidden (for sun cc) 53 | to CFLAGS 54 | 55 | then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way 56 | CJSON_EXPORT_SYMBOLS does 57 | 58 | */ 59 | 60 | #define CJSON_CDECL __cdecl 61 | #define CJSON_STDCALL __stdcall 62 | 63 | /* export symbols by default, this is necessary for copy pasting the C and 64 | * header file */ 65 | #if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && \ 66 | !defined(CJSON_EXPORT_SYMBOLS) 67 | #define CJSON_EXPORT_SYMBOLS 68 | #endif 69 | 70 | #if defined(CJSON_HIDE_SYMBOLS) 71 | #define CJSON_PUBLIC(type) type CJSON_STDCALL 72 | #elif defined(CJSON_EXPORT_SYMBOLS) 73 | #define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL 74 | #elif defined(CJSON_IMPORT_SYMBOLS) 75 | #define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL 76 | #endif 77 | #else /* !__WINDOWS__ */ 78 | #define CJSON_CDECL 79 | #define CJSON_STDCALL 80 | 81 | #if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined(__SUNPRO_C)) && \ 82 | defined(CJSON_API_VISIBILITY) 83 | #define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type 84 | #else 85 | #define CJSON_PUBLIC(type) type 86 | #endif 87 | #endif 88 | 89 | /* project version */ 90 | #define CJSON_VERSION_MAJOR 1 91 | #define CJSON_VERSION_MINOR 7 92 | #define CJSON_VERSION_PATCH 14 93 | 94 | #include 95 | 96 | /* cJSON Types: */ 97 | #define cJSON_Invalid (0) 98 | #define cJSON_False (1 << 0) 99 | #define cJSON_True (1 << 1) 100 | #define cJSON_NULL (1 << 2) 101 | #define cJSON_Number (1 << 3) 102 | #define cJSON_String (1 << 4) 103 | #define cJSON_Array (1 << 5) 104 | #define cJSON_Object (1 << 6) 105 | #define cJSON_Raw (1 << 7) /* raw json */ 106 | 107 | #define cJSON_IsReference 256 108 | #define cJSON_StringIsConst 512 109 | 110 | /* The cJSON structure: */ 111 | typedef struct cJSON { 112 | /* next/prev allow you to walk array/object chains. Alternatively, use 113 | * GetArraySize/GetArrayItem/GetObjectItem */ 114 | struct cJSON *next; 115 | struct cJSON *prev; 116 | /* An array or object item will have a child pointer pointing to a chain of 117 | * the items in the array/object. */ 118 | struct cJSON *child; 119 | 120 | /* The type of the item, as above. */ 121 | int type; 122 | 123 | /* The item's string, if type==cJSON_String and type == cJSON_Raw */ 124 | char *valuestring; 125 | /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */ 126 | int valueint; 127 | /* The item's number, if type==cJSON_Number */ 128 | double valuedouble; 129 | 130 | /* The item's name string, if this item is the child of, or is in the list of 131 | * subitems of an object. */ 132 | char *string; 133 | } cJSON; 134 | 135 | typedef struct cJSON_Hooks { 136 | /* malloc/free are CDECL on Windows regardless of the default calling 137 | * convention of the compiler, so ensure the hooks allow passing those 138 | * functions directly. */ 139 | void *(CJSON_CDECL *malloc_fn)(size_t sz); 140 | void(CJSON_CDECL *free_fn)(void *ptr); 141 | } cJSON_Hooks; 142 | 143 | typedef int cJSON_bool; 144 | 145 | /* Limits how deeply nested arrays/objects can be before cJSON rejects to parse 146 | * them. This is to prevent stack overflows. */ 147 | #ifndef CJSON_NESTING_LIMIT 148 | #define CJSON_NESTING_LIMIT 1000 149 | #endif 150 | 151 | /* returns the version of cJSON as a string */ 152 | CJSON_PUBLIC(const char *) cJSON_Version(void); 153 | 154 | /* Supply malloc, realloc and free functions to cJSON */ 155 | CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks *hooks); 156 | 157 | /* Memory Management: the caller is always responsible to free the results from 158 | * all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib 159 | * free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is 160 | * cJSON_PrintPreallocated, where the caller has full responsibility of the 161 | * buffer. */ 162 | /* Supply a block of JSON, and this returns a cJSON object you can interrogate. 163 | */ 164 | CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value); 165 | CJSON_PUBLIC(cJSON *) 166 | cJSON_ParseWithLength(const char *value, size_t buffer_length); 167 | /* ParseWithOpts allows you to require (and check) that the JSON is null 168 | * terminated, and to retrieve the pointer to the final byte parsed. */ 169 | /* If you supply a ptr in return_parse_end and parsing fails, then 170 | * return_parse_end will contain a pointer to the error so will match 171 | * cJSON_GetErrorPtr(). */ 172 | CJSON_PUBLIC(cJSON *) 173 | cJSON_ParseWithOpts(const char *value, const char **return_parse_end, 174 | cJSON_bool require_null_terminated); 175 | CJSON_PUBLIC(cJSON *) 176 | cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, 177 | const char **return_parse_end, 178 | cJSON_bool require_null_terminated); 179 | 180 | /* Render a cJSON entity to text for transfer/storage. */ 181 | CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item); 182 | /* Render a cJSON entity to text for transfer/storage without any formatting. */ 183 | CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item); 184 | /* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess 185 | * at the final size. guessing well reduces reallocation. fmt=0 gives 186 | * unformatted, =1 gives formatted */ 187 | CJSON_PUBLIC(char *) 188 | cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt); 189 | /* Render a cJSON entity to text using a buffer already allocated in memory with 190 | * given length. Returns 1 on success and 0 on failure. */ 191 | /* NOTE: cJSON is not always 100% accurate in estimating how much memory it will 192 | * use, so to be safe allocate 5 bytes more than you actually need */ 193 | CJSON_PUBLIC(cJSON_bool) 194 | cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, 195 | const cJSON_bool format); 196 | /* Delete a cJSON entity and all subentities. */ 197 | CJSON_PUBLIC(void) cJSON_Delete(cJSON *item); 198 | 199 | /* Returns the number of items in an array (or object). */ 200 | CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array); 201 | /* Retrieve item number "index" from array "array". Returns NULL if 202 | * unsuccessful. */ 203 | CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index); 204 | /* Get item "string" from object. Case insensitive. */ 205 | CJSON_PUBLIC(cJSON *) 206 | cJSON_GetObjectItem(const cJSON *const object, const char *const string); 207 | CJSON_PUBLIC(cJSON *) 208 | cJSON_GetObjectItemCaseSensitive(const cJSON *const object, 209 | const char *const string); 210 | CJSON_PUBLIC(cJSON_bool) 211 | cJSON_HasObjectItem(const cJSON *object, const char *string); 212 | /* For analysing failed parses. This returns a pointer to the parse error. 213 | * You'll probably need to look a few chars back to make sense of it. Defined 214 | * when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ 215 | CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); 216 | 217 | /* Check item type and return its value */ 218 | CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON *const item); 219 | CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON *const item); 220 | 221 | /* These functions check the type of an item */ 222 | CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON *const item); 223 | CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON *const item); 224 | CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON *const item); 225 | CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON *const item); 226 | CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON *const item); 227 | CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON *const item); 228 | CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON *const item); 229 | CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON *const item); 230 | CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON *const item); 231 | CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON *const item); 232 | 233 | /* These calls create a cJSON item of the appropriate type. */ 234 | CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void); 235 | CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void); 236 | CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void); 237 | CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean); 238 | CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num); 239 | CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string); 240 | /* raw json */ 241 | CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw); 242 | CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void); 243 | CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void); 244 | 245 | /* Create a string where valuestring references a string so 246 | * it will not be freed by cJSON_Delete */ 247 | CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string); 248 | /* Create an object/array that only references it's elements so 249 | * they will not be freed by cJSON_Delete */ 250 | CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child); 251 | CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child); 252 | 253 | /* These utilities create an Array of count items. 254 | * The parameter count cannot be greater than the number of elements in the 255 | * number array, otherwise array access will be out of bounds.*/ 256 | CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count); 257 | CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count); 258 | CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count); 259 | CJSON_PUBLIC(cJSON *) 260 | cJSON_CreateStringArray(const char *const *strings, int count); 261 | 262 | /* Append item to the specified array/object. */ 263 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item); 264 | CJSON_PUBLIC(cJSON_bool) 265 | cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); 266 | /* Use this when string is definitely const (i.e. a literal, or as good as), and 267 | * will definitely survive the cJSON object. WARNING: When this function was 268 | * used, make sure to always check that (item->type & cJSON_StringIsConst) is 269 | * zero before writing to `item->string` */ 270 | CJSON_PUBLIC(cJSON_bool) 271 | cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); 272 | /* Append reference to item to the specified array/object. Use this when you 273 | * want to add an existing cJSON to a new cJSON, but don't want to corrupt your 274 | * existing cJSON. */ 275 | CJSON_PUBLIC(cJSON_bool) 276 | cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); 277 | CJSON_PUBLIC(cJSON_bool) 278 | cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); 279 | 280 | /* Remove/Detach items from Arrays/Objects. */ 281 | CJSON_PUBLIC(cJSON *) 282 | cJSON_DetachItemViaPointer(cJSON *parent, cJSON *const item); 283 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which); 284 | CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which); 285 | CJSON_PUBLIC(cJSON *) 286 | cJSON_DetachItemFromObject(cJSON *object, const char *string); 287 | CJSON_PUBLIC(cJSON *) 288 | cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string); 289 | CJSON_PUBLIC(void) 290 | cJSON_DeleteItemFromObject(cJSON *object, const char *string); 291 | CJSON_PUBLIC(void) 292 | cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string); 293 | 294 | /* Update array items. */ 295 | CJSON_PUBLIC(cJSON_bool) 296 | cJSON_InsertItemInArray( 297 | cJSON *array, int which, 298 | cJSON *newitem); /* Shifts pre-existing items to the right. */ 299 | CJSON_PUBLIC(cJSON_bool) 300 | cJSON_ReplaceItemViaPointer(cJSON *const parent, cJSON *const item, 301 | cJSON *replacement); 302 | CJSON_PUBLIC(cJSON_bool) 303 | cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); 304 | CJSON_PUBLIC(cJSON_bool) 305 | cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem); 306 | CJSON_PUBLIC(cJSON_bool) 307 | cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, 308 | cJSON *newitem); 309 | 310 | /* Duplicate a cJSON item */ 311 | CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse); 312 | /* Duplicate will create a new, identical cJSON item to the one you pass, in new 313 | * memory that will need to be released. With recurse!=0, it will duplicate any 314 | * children connected to the item. 315 | * The item->next and ->prev pointers are always zero on return from Duplicate. 316 | */ 317 | /* Recursively compare two cJSON items for equality. If either a or b is NULL or 318 | * invalid, they will be considered unequal. 319 | * case_sensitive determines if object keys are treated case sensitive (1) or 320 | * case insensitive (0) */ 321 | CJSON_PUBLIC(cJSON_bool) 322 | cJSON_Compare(const cJSON *const a, const cJSON *const b, 323 | const cJSON_bool case_sensitive); 324 | 325 | /* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from 326 | * strings. The input pointer json cannot point to a read-only address area, 327 | * such as a string constant, 328 | * but should point to a readable and writable adress area. */ 329 | CJSON_PUBLIC(void) cJSON_Minify(char *json); 330 | 331 | /* Helper functions for creating and adding items to an object at the same time. 332 | * They return the added item or NULL on failure. */ 333 | CJSON_PUBLIC(cJSON *) 334 | cJSON_AddNullToObject(cJSON *const object, const char *const name); 335 | CJSON_PUBLIC(cJSON *) 336 | cJSON_AddTrueToObject(cJSON *const object, const char *const name); 337 | CJSON_PUBLIC(cJSON *) 338 | cJSON_AddFalseToObject(cJSON *const object, const char *const name); 339 | CJSON_PUBLIC(cJSON *) 340 | cJSON_AddBoolToObject(cJSON *const object, const char *const name, 341 | const cJSON_bool boolean); 342 | CJSON_PUBLIC(cJSON *) 343 | cJSON_AddNumberToObject(cJSON *const object, const char *const name, 344 | const double number); 345 | CJSON_PUBLIC(cJSON *) 346 | cJSON_AddStringToObject(cJSON *const object, const char *const name, 347 | const char *const string); 348 | CJSON_PUBLIC(cJSON *) 349 | cJSON_AddRawToObject(cJSON *const object, const char *const name, 350 | const char *const raw); 351 | CJSON_PUBLIC(cJSON *) 352 | cJSON_AddObjectToObject(cJSON *const object, const char *const name); 353 | CJSON_PUBLIC(cJSON *) 354 | cJSON_AddArrayToObject(cJSON *const object, const char *const name); 355 | 356 | /* When assigning an integer value, it needs to be propagated to valuedouble 357 | * too. */ 358 | #define cJSON_SetIntValue(object, number) \ 359 | ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number)) 360 | /* helper for the cJSON_SetNumberValue macro */ 361 | CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number); 362 | #define cJSON_SetNumberValue(object, number) \ 363 | ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number)) 364 | /* Change the valuestring of a cJSON_String object, only takes effect when type 365 | * of object is cJSON_String */ 366 | CJSON_PUBLIC(char *) 367 | cJSON_SetValuestring(cJSON *object, const char *valuestring); 368 | 369 | /* Macro for iterating over an array or object */ 370 | #define cJSON_ArrayForEach(element, array) \ 371 | for (element = (array != NULL) ? (array)->child : NULL; element != NULL; \ 372 | element = element->next) 373 | 374 | /* malloc/free objects using the malloc/free functions that have been set with 375 | * cJSON_InitHooks */ 376 | CJSON_PUBLIC(void *) cJSON_malloc(size_t size); 377 | CJSON_PUBLIC(void) cJSON_free(void *object); 378 | 379 | #ifdef __cplusplus 380 | } 381 | #endif 382 | 383 | #endif 384 | -------------------------------------------------------------------------------- /molecule/molecule2_reader.h: -------------------------------------------------------------------------------- 1 | #ifndef MOLECULE2_READER_H 2 | #define MOLECULE2_READER_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif /* __cplusplus */ 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #ifndef mol2_printf 14 | #define mol2_printf printf 15 | #endif 16 | #ifndef MOL2_EXIT 17 | #define MOL2_EXIT exit 18 | #endif 19 | 20 | #ifndef MOL2_PANIC 21 | #define MOL2_PANIC(err) \ 22 | do { \ 23 | mol2_printf("Error at %s: %d\n", __FILE__, __LINE__); \ 24 | MOL2_EXIT(err); \ 25 | } while (0) 26 | #endif 27 | 28 | /* 29 | * This part is not for normal users. 30 | */ 31 | // 32 | // referenced API or macros 33 | // 34 | #ifndef ASSERT 35 | #define ASSERT(s) ((void)0) 36 | #endif 37 | 38 | #ifndef MIN 39 | #define MIN(a, b) ((a > b) ? (b) : (a)) 40 | #endif 41 | #ifndef MAX 42 | #define MAX(a, b) ((a > b) ? (a) : (b)) 43 | #endif 44 | 45 | typedef uint32_t mol2_num_t; // Item Id 46 | typedef uint8_t mol2_errno; // Error Number 47 | #define MOL2_NUM_T_SIZE 4 48 | 49 | // predefined type 50 | // If the types defined in schema is fundamental type: 51 | // 1. dynvec of byte() or 52 | // 2. array([byte; N]) 53 | // They will be converted to the type mol2_cursor_t automatically 54 | // 3. byte 55 | // it will be converted to uint8_t. 56 | 57 | // predefined type 58 | // If the types defined in schema: 59 | // 1. the name is same as below (case insensitive) 60 | // 2. the type is matched (e.g. Uint32 should have type with [byte; 4]) 61 | // they will be converted to the corresponding types automatically instead of 62 | // just returning raw byte array. 63 | // 64 | typedef uint64_t Uint64; // [byte; 8] 65 | typedef int64_t Int64; // [byte; 8] 66 | typedef uint32_t Uint32; // [byte; 4] 67 | typedef int32_t Int32; // [byte; 4] 68 | typedef uint16_t Uint16; // [byte; 2] 69 | typedef int16_t Int16; // [byte; 2] 70 | typedef uint8_t Uint8; // [byte; 1] 71 | typedef int8_t Int8; // [byte; 1] 72 | 73 | /* Error Numbers */ 74 | 75 | #define MOL2_OK 0x00 76 | #define MOL2_ERR 0xff 77 | 78 | #define MOL2_ERR_TOTAL_SIZE 0x01 79 | #define MOL2_ERR_HEADER 0x02 80 | #define MOL2_ERR_OFFSET 0x03 81 | #define MOL2_ERR_UNKNOWN_ITEM 0x04 82 | #define MOL2_ERR_INDEX_OUT_OF_BOUNDS 0x05 83 | #define MOL2_ERR_FIELD_COUNT 0x06 84 | #define MOL2_ERR_DATA 0x07 85 | #define MOL2_ERR_OVERFLOW 0x08 86 | 87 | // converting function 88 | // format: convert_to_${Type} 89 | #define SWAP(a, b, t) \ 90 | { \ 91 | (t) = (a); \ 92 | (a) = (b); \ 93 | (b) = (t); \ 94 | } 95 | #define is_le2() \ 96 | ((union { \ 97 | uint16_t i; \ 98 | unsigned char c; \ 99 | }){.i = 1} \ 100 | .c) 101 | 102 | void change_endian(uint8_t *ptr, int size); 103 | /** 104 | * read from a data source, with offset, up to "len" bytes into ptr. 105 | * the memory size of "ptr" is "len". 106 | * 107 | * Return the length actually written. It may be smaller than "len". 108 | * 109 | * The "args" will be passed into "read" function as the first argument. 110 | */ 111 | typedef uint32_t (*mol2_source_t)(uintptr_t arg[], uint8_t *ptr, uint32_t len, 112 | uint32_t offset); 113 | 114 | #define MAX_CACHE_SIZE 2048 115 | #define MIN_CACHE_SIZE 64 116 | 117 | // data source with cache support 118 | typedef struct mol2_data_source_t { 119 | // function "read" might have more arguments 120 | uintptr_t args[4]; 121 | // total size of the data source. It is always true: 122 | // offset+size <= total_size 123 | uint32_t total_size; 124 | 125 | mol2_source_t read; 126 | // start point of the cache 127 | // if [offset, size) is in [start_point, start_point+cache_size), it returns 128 | // memory in cache directly otherwise, it will try to load first (like cache 129 | // miss) 130 | uint32_t start_point; 131 | uint32_t cache_size; 132 | // it's normally same as MAX_CACHE_SIZE. 133 | // modify it for testing purpose 134 | uint32_t max_cache_size; 135 | // variable length structure 136 | // it's true length is calculated by "MOL2_DATA_SOURCE_LEN". 137 | uint8_t cache[]; 138 | } mol2_data_source_t; 139 | 140 | #define MOL2_DATA_SOURCE_LEN(cache_size) \ 141 | (sizeof(mol2_data_source_t) + (cache_size)) 142 | 143 | #define DEFAULT_DATA_SOURCE_LENGTH (sizeof(mol2_data_source_t) + MAX_CACHE_SIZE) 144 | 145 | /** 146 | * --------------- MUST READ ---------------------- 147 | * This is the most important data struct in this file, MUST READ! 148 | * The data_source is to fetch data from external, like memory, disk, or some 149 | * others. It is with cache support. You can get an idea how to implement one 150 | * from functions: "mol2_source_memory" and "mol2_make_cursor_from_memory". 151 | * 152 | * The offset and size, is an "view"/"slice" of the data source. 153 | * 154 | * When a new cursor is generated from an old one, 155 | * the "data_source" must be copied. The offset and size can be different. 156 | * Currently, there is no way to convert one data source to another. 157 | * 158 | */ 159 | typedef struct mol2_cursor_t { 160 | uint32_t offset; // offset of slice 161 | uint32_t size; // size of slice 162 | mol2_data_source_t *data_source; 163 | } mol2_cursor_t; 164 | 165 | // a sample source over memory 166 | uint32_t mol2_source_memory(uintptr_t args[], uint8_t *ptr, uint32_t len, 167 | uint32_t offset); 168 | mol2_cursor_t mol2_make_cursor_from_memory(const void *memory, uint32_t size); 169 | 170 | uint32_t mol2_read_at(const mol2_cursor_t *cur, uint8_t *buff, 171 | uint32_t buff_len); 172 | 173 | // Bytes segment. 174 | typedef struct { 175 | uint8_t *ptr; // Pointer 176 | mol2_num_t size; // Full size 177 | } mol2_seg_t; 178 | 179 | // Unpacked Union 180 | typedef struct { 181 | mol2_num_t item_id; // Item Id 182 | mol2_cursor_t cursor; // Cursor 183 | } mol2_union_t; 184 | 185 | // Result for returning segment. 186 | typedef struct { 187 | mol2_errno errno; // Error Number 188 | mol2_cursor_t cur; // Cursor 189 | } mol2_cursor_res_t; 190 | 191 | void mol2_add_offset(mol2_cursor_t *cur, uint32_t offset); 192 | void mol2_sub_size(mol2_cursor_t *cur, uint32_t shrinked_size); 193 | void mol2_validate(const mol2_cursor_t *cur); 194 | 195 | mol2_num_t mol2_unpack_number(const mol2_cursor_t *cursor); 196 | 197 | mol2_errno mol2_verify_fixed_size(const mol2_cursor_t *input, 198 | mol2_num_t total_size); 199 | 200 | mol2_errno mol2_fixvec_verify(const mol2_cursor_t *input, mol2_num_t item_size); 201 | 202 | bool mol2_option_is_none(const mol2_cursor_t *input); 203 | mol2_union_t mol2_union_unpack(const mol2_cursor_t *input); 204 | mol2_num_t mol2_fixvec_length(const mol2_cursor_t *input); 205 | mol2_num_t mol2_dynvec_length(const mol2_cursor_t *input); 206 | mol2_num_t mol2_table_actual_field_count(const mol2_cursor_t *input); 207 | bool mol2_table_has_extra_fields(const mol2_cursor_t *input, 208 | mol2_num_t field_count); 209 | mol2_cursor_t mol2_slice_by_offset(const mol2_cursor_t *input, 210 | mol2_num_t offset, mol2_num_t size); 211 | 212 | mol2_cursor_res_t mol2_fixvec_slice_by_index(const mol2_cursor_t *input, 213 | mol2_num_t item_size, 214 | mol2_num_t item_index); 215 | 216 | mol2_cursor_res_t mol2_dynvec_slice_by_index(const mol2_cursor_t *input, 217 | mol2_num_t item_index); 218 | 219 | mol2_cursor_t mol2_table_slice_by_index(const mol2_cursor_t *input, 220 | mol2_num_t field_index); 221 | 222 | mol2_cursor_t mol2_fixvec_slice_raw_bytes(const mol2_cursor_t *input); 223 | Uint64 convert_to_Uint64(mol2_cursor_t *cur); 224 | Int64 convert_to_Int64(mol2_cursor_t *cur); 225 | Uint32 convert_to_Uint32(mol2_cursor_t *cur); 226 | Int32 convert_to_Int32(mol2_cursor_t *cur); 227 | Uint16 convert_to_Uint16(mol2_cursor_t *cur); 228 | Int16 convert_to_Int16(mol2_cursor_t *cur); 229 | Uint8 convert_to_Uint8(mol2_cursor_t *cur); 230 | Int8 convert_to_Int8(mol2_cursor_t *cur); 231 | mol2_cursor_t convert_to_array(mol2_cursor_t *cur); 232 | mol2_cursor_t convert_to_rawbytes(mol2_cursor_t *cur); 233 | 234 | #ifndef MOLECULEC_C2_DECLARATION_ONLY 235 | 236 | // cur->offset = cur->offset + offset 237 | void mol2_add_offset(mol2_cursor_t *cur, uint32_t offset) { 238 | uint32_t res; 239 | if (__builtin_add_overflow(cur->offset, offset, &res)) { 240 | MOL2_PANIC(MOL2_ERR_OVERFLOW); 241 | } 242 | cur->offset = res; 243 | } 244 | 245 | // cur->size = cur->size - shrinked_size 246 | void mol2_sub_size(mol2_cursor_t *cur, uint32_t shrinked_size) { 247 | uint32_t res; 248 | if (__builtin_sub_overflow(cur->size, shrinked_size, &res)) { 249 | MOL2_PANIC(MOL2_ERR_OVERFLOW); 250 | } 251 | cur->size = res; 252 | } 253 | 254 | // mol2_unpack_number(cur) / 4 - 1 255 | uint32_t mol2_get_item_count(mol2_cursor_t *cur) { 256 | uint32_t count = mol2_unpack_number(cur) / 4; 257 | if (count == 0) { 258 | MOL2_PANIC(MOL2_ERR_OVERFLOW); 259 | } 260 | return count - 1; 261 | } 262 | // item_size * item_count + offset 263 | uint32_t mol2_calculate_offset(uint32_t item_size, uint32_t item_count, 264 | uint32_t offset) { 265 | uint32_t mul_res; 266 | if (__builtin_mul_overflow(item_size, item_count, &mul_res)) { 267 | MOL2_PANIC(MOL2_ERR_OVERFLOW); 268 | } 269 | uint32_t sum_res; 270 | if (__builtin_add_overflow(mul_res, offset, &sum_res)) { 271 | MOL2_PANIC(MOL2_ERR_OVERFLOW); 272 | } 273 | return sum_res; 274 | } 275 | 276 | void mol2_validate(const mol2_cursor_t *cur) { 277 | uint32_t res; 278 | if (__builtin_add_overflow(cur->offset, cur->size, &res)) { 279 | MOL2_PANIC(MOL2_ERR_OVERFLOW); 280 | } 281 | if (res > cur->data_source->total_size) { 282 | mol2_printf("total_size(%d) > offset(%d) + size(%d)\n", 283 | cur->data_source->total_size, cur->offset, cur->size); 284 | MOL2_PANIC(MOL2_ERR_INDEX_OUT_OF_BOUNDS); 285 | } 286 | } 287 | 288 | mol2_errno mol2_verify_fixed_size(const mol2_cursor_t *input, 289 | mol2_num_t total_size) { 290 | return input->size == total_size ? MOL2_OK : MOL2_ERR_TOTAL_SIZE; 291 | } 292 | 293 | mol2_errno mol2_fixvec_verify(const mol2_cursor_t *input, 294 | mol2_num_t item_size) { 295 | if (input->size < MOL2_NUM_T_SIZE) { 296 | return MOL2_ERR_HEADER; 297 | } 298 | mol2_num_t item_count = mol2_unpack_number(input); 299 | if (item_count == 0) { 300 | return input->size == MOL2_NUM_T_SIZE ? MOL2_OK : MOL2_ERR_TOTAL_SIZE; 301 | } 302 | // mol2_num_t total_size = mol2_NUM_T_SIZE + item_size * item_count; 303 | mol2_num_t total_size = 304 | mol2_calculate_offset(item_size, item_count, MOL2_NUM_T_SIZE); 305 | return input->size == total_size ? MOL2_OK : MOL2_ERR_TOTAL_SIZE; 306 | } 307 | 308 | bool mol2_option_is_none(const mol2_cursor_t *input) { 309 | return input->size == 0; 310 | } 311 | 312 | mol2_union_t mol2_union_unpack(const mol2_cursor_t *input) { 313 | mol2_union_t ret; 314 | ret.item_id = mol2_unpack_number(input); 315 | ret.cursor = *input; // must copy 316 | // ret.cursor.offset = input->offset + mol2_NUM_T_SIZE; 317 | // ret.cursor.size = input->size - mol2_NUM_T_SIZE; 318 | mol2_add_offset(&ret.cursor, MOL2_NUM_T_SIZE); 319 | mol2_sub_size(&ret.cursor, MOL2_NUM_T_SIZE); 320 | mol2_validate(&ret.cursor); 321 | return ret; 322 | } 323 | 324 | mol2_num_t mol2_fixvec_length(const mol2_cursor_t *input) { 325 | return mol2_unpack_number(input); 326 | } 327 | 328 | mol2_num_t mol2_dynvec_length(const mol2_cursor_t *input) { 329 | if (input->size == MOL2_NUM_T_SIZE) { 330 | return 0; 331 | } else { 332 | mol2_cursor_t cur = *input; 333 | mol2_add_offset(&cur, MOL2_NUM_T_SIZE); 334 | mol2_sub_size(&cur, MOL2_NUM_T_SIZE); 335 | mol2_validate(&cur); 336 | // return (mol2_unpack_number(&cur) / 4) - 1; 337 | return mol2_get_item_count(&cur); 338 | } 339 | } 340 | 341 | mol2_num_t mol2_table_actual_field_count(const mol2_cursor_t *input) { 342 | return mol2_dynvec_length(input); 343 | } 344 | 345 | bool mol2_table_has_extra_fields(const mol2_cursor_t *input, 346 | mol2_num_t field_count) { 347 | return mol2_table_actual_field_count(input) > field_count; 348 | } 349 | 350 | mol2_cursor_t mol2_slice_by_offset(const mol2_cursor_t *input, 351 | mol2_num_t offset, mol2_num_t size) { 352 | mol2_cursor_t cur = *input; 353 | 354 | // cur.offset = input->offset + offset; 355 | mol2_add_offset(&cur, offset); 356 | cur.size = size; 357 | mol2_validate(&cur); 358 | return cur; 359 | } 360 | 361 | mol2_cursor_res_t mol2_slice_by_offset2(const mol2_cursor_t *input, 362 | mol2_num_t offset, mol2_num_t size) { 363 | mol2_cursor_t cur = *input; 364 | 365 | // cur.offset = input->offset + offset; 366 | mol2_add_offset(&cur, offset); 367 | cur.size = size; 368 | mol2_validate(&cur); 369 | 370 | mol2_cursor_res_t res; 371 | res.errno = MOL2_OK; 372 | res.cur = cur; 373 | return res; 374 | } 375 | 376 | mol2_cursor_res_t mol2_fixvec_slice_by_index(const mol2_cursor_t *input, 377 | mol2_num_t item_size, 378 | mol2_num_t item_index) { 379 | mol2_cursor_res_t res; 380 | res.cur = *input; 381 | mol2_num_t item_count = mol2_unpack_number(input); 382 | if (item_index >= item_count) { 383 | res.errno = MOL2_ERR_INDEX_OUT_OF_BOUNDS; 384 | } else { 385 | res.errno = MOL2_OK; 386 | // res.cur.offset = input->offset + mol2_NUM_T_SIZE + item_size * 387 | // item_index; 388 | uint32_t offset = 389 | mol2_calculate_offset(item_size, item_index, MOL2_NUM_T_SIZE); 390 | mol2_add_offset(&res.cur, offset); 391 | res.cur.size = item_size; 392 | mol2_validate(&res.cur); 393 | } 394 | return res; 395 | } 396 | 397 | mol2_cursor_res_t mol2_dynvec_slice_by_index(const mol2_cursor_t *input, 398 | mol2_num_t item_index) { 399 | mol2_cursor_res_t res; 400 | res.cur = *input; 401 | struct mol2_cursor_t temp = *input; 402 | 403 | mol2_num_t total_size = mol2_unpack_number(input); 404 | if (total_size == MOL2_NUM_T_SIZE) { 405 | res.errno = MOL2_ERR_INDEX_OUT_OF_BOUNDS; 406 | } else { 407 | // temp.offset = input->offset + mol2_NUM_T_SIZE; 408 | mol2_add_offset(&temp, MOL2_NUM_T_SIZE); 409 | // mol2_num_t item_count = (mol2_unpack_number(&temp) / 4) - 1; 410 | mol2_num_t item_count = mol2_get_item_count(&temp); 411 | 412 | if (item_index >= item_count) { 413 | res.errno = MOL2_ERR_INDEX_OUT_OF_BOUNDS; 414 | } else { 415 | temp.offset = input->offset; 416 | uint32_t temp_offset = 417 | mol2_calculate_offset(MOL2_NUM_T_SIZE, item_index + 1, 0); 418 | mol2_add_offset(&temp, temp_offset); 419 | 420 | mol2_num_t item_start = mol2_unpack_number(&temp); 421 | if (item_index + 1 == item_count) { 422 | res.errno = MOL2_OK; 423 | res.cur.offset = input->offset; 424 | mol2_add_offset(&res.cur, item_start); 425 | res.cur.size = total_size; 426 | mol2_sub_size(&res.cur, item_start); 427 | } else { 428 | temp.offset = input->offset; 429 | uint32_t calc_offset = 430 | mol2_calculate_offset(MOL2_NUM_T_SIZE, item_index + 2, 0); 431 | mol2_add_offset(&temp, calc_offset); 432 | 433 | mol2_num_t item_end = mol2_unpack_number(&temp); 434 | res.errno = MOL2_OK; 435 | res.cur.offset = input->offset; 436 | mol2_add_offset(&res.cur, item_start); 437 | res.cur.size = item_end; 438 | mol2_sub_size(&res.cur, item_start); 439 | } 440 | } 441 | } 442 | if (res.errno == MOL2_OK) { 443 | mol2_validate(&res.cur); 444 | } 445 | return res; 446 | } 447 | 448 | mol2_cursor_t mol2_table_slice_by_index(const mol2_cursor_t *input, 449 | mol2_num_t field_index) { 450 | mol2_cursor_res_t res = mol2_dynvec_slice_by_index(input, field_index); 451 | ASSERT(res.errno == 0); 452 | return res.cur; 453 | } 454 | 455 | mol2_cursor_t mol2_fixvec_slice_raw_bytes(const mol2_cursor_t *input) { 456 | mol2_cursor_t cur = *input; 457 | mol2_add_offset(&cur, MOL2_NUM_T_SIZE); 458 | cur.size = mol2_unpack_number(input); 459 | mol2_validate(&cur); 460 | return cur; 461 | } 462 | 463 | Uint64 convert_to_Uint64(mol2_cursor_t *cur) { 464 | uint64_t ret; 465 | uint32_t len = mol2_read_at(cur, (uint8_t *)&ret, sizeof(ret)); 466 | if (len != sizeof(ret)) { 467 | MOL2_PANIC(MOL2_ERR_DATA); 468 | } 469 | change_endian((uint8_t *)&ret, sizeof(ret)); 470 | return ret; 471 | } 472 | 473 | Int64 convert_to_Int64(mol2_cursor_t *cur) { 474 | int64_t ret; 475 | uint32_t len = mol2_read_at(cur, (uint8_t *)&ret, sizeof(ret)); 476 | if (len != sizeof(ret)) { 477 | MOL2_PANIC(MOL2_ERR_DATA); 478 | } 479 | change_endian((uint8_t *)&ret, sizeof(ret)); 480 | return ret; 481 | } 482 | 483 | Uint32 convert_to_Uint32(mol2_cursor_t *cur) { 484 | uint32_t ret; 485 | uint32_t len = mol2_read_at(cur, (uint8_t *)&ret, sizeof(ret)); 486 | if (len != sizeof(ret)) { 487 | MOL2_PANIC(MOL2_ERR_DATA); 488 | } 489 | change_endian((uint8_t *)&ret, sizeof(ret)); 490 | return ret; 491 | } 492 | 493 | Int32 convert_to_Int32(mol2_cursor_t *cur) { 494 | int32_t ret; 495 | uint32_t len = mol2_read_at(cur, (uint8_t *)&ret, sizeof(ret)); 496 | if (len != sizeof(ret)) { 497 | MOL2_PANIC(MOL2_ERR_DATA); 498 | } 499 | change_endian((uint8_t *)&ret, sizeof(ret)); 500 | return ret; 501 | } 502 | 503 | Uint16 convert_to_Uint16(mol2_cursor_t *cur) { 504 | uint16_t ret; 505 | uint32_t len = mol2_read_at(cur, (uint8_t *)&ret, sizeof(ret)); 506 | if (len != sizeof(ret)) { 507 | MOL2_PANIC(MOL2_ERR_DATA); 508 | } 509 | change_endian((uint8_t *)&ret, sizeof(ret)); 510 | return ret; 511 | } 512 | 513 | Int16 convert_to_Int16(mol2_cursor_t *cur) { 514 | int16_t ret; 515 | uint32_t len = mol2_read_at(cur, (uint8_t *)&ret, sizeof(ret)); 516 | ASSERT(len == sizeof(ret)); 517 | if (len != sizeof(ret)) { 518 | MOL2_PANIC(MOL2_ERR_DATA); 519 | } 520 | return ret; 521 | } 522 | 523 | Uint8 convert_to_Uint8(mol2_cursor_t *cur) { 524 | uint8_t ret; 525 | uint32_t len = mol2_read_at(cur, (uint8_t *)&ret, sizeof(ret)); 526 | if (len != sizeof(ret)) { 527 | MOL2_PANIC(MOL2_ERR_DATA); 528 | } 529 | change_endian((uint8_t *)&ret, sizeof(ret)); 530 | return ret; 531 | } 532 | 533 | Int8 convert_to_Int8(mol2_cursor_t *cur) { 534 | int8_t ret; 535 | uint32_t len = mol2_read_at(cur, (uint8_t *)&ret, sizeof(ret)); 536 | if (len != sizeof(ret)) { 537 | MOL2_PANIC(MOL2_ERR_DATA); 538 | } 539 | change_endian((uint8_t *)&ret, sizeof(ret)); 540 | return ret; 541 | } 542 | 543 | mol2_cursor_t convert_to_array(mol2_cursor_t *cur) { return *cur; } 544 | 545 | mol2_cursor_t convert_to_rawbytes(mol2_cursor_t *cur) { 546 | return mol2_fixvec_slice_raw_bytes(cur); 547 | } 548 | 549 | void change_endian(uint8_t *ptr, int size) { 550 | if (is_le2()) return; 551 | if (size == 0) return; 552 | 553 | if (size % 2 != 0) { 554 | MOL2_PANIC(MOL2_ERR_DATA); 555 | } 556 | uint8_t t = 0; 557 | for (int i = 0; i < size / 2; i++) { 558 | SWAP(ptr[i], ptr[size - 1 - i], t); 559 | } 560 | } 561 | 562 | // this is a sample implementation over memory 563 | uint32_t mol2_source_memory(uintptr_t args[], uint8_t *ptr, uint32_t len, 564 | uint32_t offset) { 565 | uint32_t mem_len = (uint32_t)args[1]; 566 | ASSERT(offset < mem_len); 567 | uint32_t remaining_len = mem_len - offset; 568 | 569 | uint32_t min_len = MIN(remaining_len, len); 570 | uint8_t *start_mem = (uint8_t *)args[0]; 571 | ASSERT((offset + min_len) <= mem_len); 572 | memcpy(ptr, start_mem + offset, min_len); 573 | return min_len; 574 | } 575 | 576 | // this is a sample implementation over memory 577 | mol2_cursor_t mol2_make_cursor_from_memory(const void *memory, uint32_t size) { 578 | mol2_cursor_t cur; 579 | cur.offset = 0; 580 | cur.size = size; 581 | // init data source 582 | static mol2_data_source_t s_data_source = {0}; 583 | 584 | s_data_source.read = mol2_source_memory; 585 | s_data_source.total_size = size; 586 | s_data_source.args[0] = (uintptr_t)memory; 587 | s_data_source.args[1] = (uintptr_t)size; 588 | 589 | s_data_source.cache_size = 0; 590 | s_data_source.start_point = 0; 591 | s_data_source.max_cache_size = MAX_CACHE_SIZE; 592 | cur.data_source = &s_data_source; 593 | return cur; 594 | } 595 | 596 | /** 597 | * mol2_read_at reads MIN(cur->size, buff_len) bytes from data source 598 | * "cur" into buff. It returns that number. 599 | * 600 | * If the return number is smaller than MIN(cur->size, buff_len), the data 601 | * source might encounter problem. There are some reasons: 602 | * 1. The data in data source is not consistent with molecule file (too 603 | * small). 604 | * 2. I/O error. It's impossible for memory data source or Syscall 605 | * 606 | * If a cache miss is triggered: use "read" to load from data source to the 607 | * the cache. Then use copy from cache to "buff". 608 | **/ 609 | uint32_t mol2_read_at(const mol2_cursor_t *cur, uint8_t *buff, 610 | uint32_t buff_len) { 611 | uint32_t read_len = MIN(cur->size, buff_len); 612 | 613 | mol2_data_source_t *ds = cur->data_source; 614 | // beyond cache size, "read" it directly. 615 | if (read_len > ds->max_cache_size) { 616 | return ds->read(ds->args, buff, read_len, cur->offset); 617 | } 618 | 619 | // cache miss 620 | if (cur->offset < ds->start_point || 621 | ((cur->offset + read_len) > ds->start_point + ds->cache_size)) { 622 | uint32_t size = 623 | ds->read(ds->args, ds->cache, ds->max_cache_size, cur->offset); 624 | if (size < read_len) { 625 | MOL2_PANIC(MOL2_ERR_DATA); 626 | return 0; 627 | } 628 | // update cache setting 629 | ds->cache_size = size; 630 | ds->start_point = cur->offset; 631 | if (ds->cache_size > ds->max_cache_size) { 632 | MOL2_PANIC(MOL2_ERR_OVERFLOW); 633 | return 0; 634 | } 635 | } 636 | // cache hit 637 | if (cur->offset < ds->start_point || 638 | (cur->offset - ds->start_point) > ds->max_cache_size) { 639 | MOL2_PANIC(MOL2_ERR_OVERFLOW); 640 | return 0; 641 | } 642 | uint8_t *read_point = ds->cache + cur->offset - ds->start_point; 643 | if ((read_point + read_len) > (ds->cache + ds->cache_size)) { 644 | MOL2_PANIC(MOL2_ERR_OVERFLOW); 645 | return 0; 646 | } 647 | 648 | memcpy(buff, read_point, read_len); 649 | return read_len; 650 | } 651 | 652 | mol2_num_t mol2_unpack_number(const mol2_cursor_t *cursor) { 653 | uint8_t src[4]; 654 | uint32_t len = mol2_read_at(cursor, src, 4); 655 | if (len != 4) { 656 | MOL2_PANIC(MOL2_ERR_DATA); 657 | } 658 | if (is_le2()) { 659 | return *(const uint32_t *)src; 660 | } else { 661 | uint32_t output = 0; 662 | uint8_t *dst = (uint8_t *)&output; 663 | dst[3] = src[0]; 664 | dst[2] = src[1]; 665 | dst[1] = src[2]; 666 | dst[0] = src[3]; 667 | return output; 668 | } 669 | } 670 | 671 | #endif // MOLECULEC_C2_DECLARATION_ONLY 672 | 673 | /* 674 | * Undef macros which are internal use only. 675 | */ 676 | 677 | #undef is_le2 678 | 679 | #ifdef __cplusplus 680 | } 681 | #endif /* __cplusplus */ 682 | 683 | #endif /* MOLECULE2_READER_H */ 684 | -------------------------------------------------------------------------------- /simulator/ckb_syscall_simulator.c: -------------------------------------------------------------------------------- 1 | 2 | // make assert working under release 3 | #undef NDEBUG 4 | // #define CKB_SIMULATOR_VERBOSE 5 | 6 | #include "ckb_syscall_simulator.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "blake2b_decl_only.h" 14 | #include "blockchain-api2.h" 15 | #include "cJSON.h" 16 | #include "molecule_decl_only.h" 17 | 18 | #define FAIL(msg) \ 19 | do { \ 20 | assert(false); \ 21 | printf("Failed at %s:%d: %s\n", __FILE__, __LINE__, (msg)); \ 22 | } while (0) 23 | 24 | #define MAX_GRROUP_SIZE 1024 25 | #define HASH_SIZE 32 26 | #define BLAKE160_SIZE 20 27 | #define SCRIPT_SIZE 32768 28 | 29 | static cJSON* s_json = NULL; 30 | static cJSON* s_tx_json = NULL; 31 | static uint8_t s_tx_hash[HASH_SIZE] = {0}; 32 | // true: lock script 33 | // false: type script 34 | static bool s_is_lock_script = true; 35 | // index of lock script or type script 36 | static uint32_t s_script_index = 0; 37 | 38 | static uint32_t s_in_group_index[MAX_GRROUP_SIZE]; 39 | static uint32_t s_in_group_size = 0; 40 | 41 | #define MAX_HASH_ITEM_SIZE 1024 42 | typedef struct data_hash_item_t { 43 | uint8_t hash[HASH_SIZE]; 44 | uint64_t len; 45 | uint8_t* data; 46 | } data_hash_item_t; 47 | data_hash_item_t s_data_hash[MAX_HASH_ITEM_SIZE] = {0}; 48 | size_t s_data_hash_len = 0; 49 | 50 | // ----------------------- 51 | bool is_in_group(uint32_t index); 52 | int init_json_data_source(const char* file_name); 53 | int load_script(void* addr, uint64_t* len, size_t offset, bool is_lock, 54 | uint32_t script_index, bool from_cell_deps); 55 | 56 | cJSON* get_item_at(cJSON* j, size_t index) { 57 | if (j == NULL) { 58 | FAIL("It can't be NULL"); 59 | return NULL; 60 | } 61 | cJSON* elm = j->child; 62 | size_t target = 0; 63 | while (elm != NULL) { 64 | if (target == index) return elm; 65 | elm = elm->next; 66 | target++; 67 | } 68 | return NULL; 69 | } 70 | 71 | unsigned char decode_hex(char s) { 72 | if (s >= '0' && s <= '9') { 73 | return s - '0'; 74 | } else if (s >= 'a' && s <= 'f') { 75 | return s - 'a' + 10; 76 | } else if (s >= 'A' && s <= 'F') { 77 | return s - 'A' + 10; 78 | } else { 79 | FAIL("Invalid hex character"); 80 | } 81 | return 0; 82 | } 83 | 84 | unsigned char compose_byte(const char* s) { 85 | return decode_hex(s[0]) << 4 | decode_hex(s[1]); 86 | } 87 | 88 | void load_data(const char* str, unsigned char* addr, uint64_t* len, 89 | size_t offset) { 90 | size_t str_len = strlen(str); 91 | if (str_len < 2 || str[0] != '0' || str[1] != 'x') { 92 | FAIL("The data part must be started with 0x"); 93 | return; 94 | } 95 | ASSERT((str_len % 2) == 0); 96 | size_t data_len = (str_len - 2) / 2; 97 | ASSERT(offset <= data_len); 98 | 99 | size_t start = 2 + offset * 2; 100 | for (size_t i = 0; i < *len; i++) { 101 | if ((offset + i) >= data_len) { 102 | *len = i; 103 | break; 104 | } 105 | addr[i] = compose_byte(&str[start + i * 2]); 106 | } 107 | } 108 | 109 | size_t calculate_size(const char* str) { 110 | assert(strlen(str) % 2 == 0); 111 | return (strlen(str) - 2) / 2; 112 | } 113 | 114 | void load_offset(uint8_t* source_buff, uint64_t source_size, void* addr, 115 | uint64_t* len, size_t offset) { 116 | assert(source_size > offset); 117 | assert(*len > 0); 118 | 119 | uint64_t size = MIN(source_size - offset, *len); 120 | memcpy(addr, source_buff + offset, size); 121 | *len = size; 122 | } 123 | 124 | void blake2b_hash(void* ptr, size_t size, uint8_t* hash) { 125 | blake2b_state ctx; 126 | ckb_blake2b_init(&ctx, HASH_SIZE); 127 | blake2b_update(&ctx, ptr, size); 128 | blake2b_final(&ctx, hash, HASH_SIZE); 129 | } 130 | 131 | void print_hex(uint8_t* ptr, size_t size) { 132 | printf("0x"); 133 | for (size_t i = 0; i < size; i++) { 134 | printf("%02x", ptr[i]); 135 | } 136 | printf("\n"); 137 | } 138 | 139 | // todo: free 140 | mol_seg_t build_Bytes(uint8_t* ptr, uint32_t len) { 141 | mol_builder_t b; 142 | mol_seg_res_t res; 143 | MolBuilder_Bytes_init(&b); 144 | for (uint32_t i = 0; i < len; i++) { 145 | MolBuilder_Bytes_push(&b, ptr[i]); 146 | } 147 | res = MolBuilder_Bytes_build(b); 148 | assert(res.errno == 0); 149 | return res.seg; 150 | } 151 | 152 | mol_seg_t build_script(uint8_t* code_hash, uint8_t hash_type, uint8_t* args, 153 | uint32_t args_len) { 154 | mol_builder_t b; 155 | mol_seg_res_t res; 156 | 157 | MolBuilder_Script_init(&b); 158 | MolBuilder_Script_set_code_hash(&b, code_hash, 32); 159 | MolBuilder_Script_set_hash_type(&b, hash_type); 160 | mol_seg_t bytes = build_Bytes(args, args_len); 161 | MolBuilder_Script_set_args(&b, bytes.ptr, bytes.size); 162 | 163 | res = MolBuilder_Script_build(b); 164 | assert(res.errno == 0); 165 | return res.seg; 166 | } 167 | 168 | int ckb_exit(int8_t code) { 169 | printf("ckb_exit\n"); 170 | exit(0); 171 | return CKB_SUCCESS; 172 | } 173 | 174 | int ckb_load_tx_hash(void* addr, uint64_t* len, size_t offset) { 175 | load_offset(s_tx_hash, HASH_SIZE, addr, len, offset); 176 | return CKB_SUCCESS; 177 | } 178 | 179 | int ckb_load_script_hash(void* addr, uint64_t* len, size_t offset) { 180 | assert(*len >= HASH_SIZE); 181 | 182 | uint8_t script[SCRIPT_SIZE]; 183 | uint64_t script_size = 0; 184 | int ret = ckb_load_script(script, &script_size, 0); 185 | assert(ret == CKB_SUCCESS); 186 | 187 | uint8_t hash[HASH_SIZE]; 188 | blake2b_hash(script, script_size, hash); 189 | 190 | load_offset(hash, HASH_SIZE, addr, len, offset); 191 | return CKB_SUCCESS; 192 | } 193 | 194 | // TODO: currently it's not used, will be implemented 195 | int ckb_load_cell(void* addr, uint64_t* len, size_t offset, size_t index, 196 | size_t source) { 197 | return 0; 198 | } 199 | 200 | // TODO: currently it's not used, will be implemented 201 | int ckb_load_input(void* addr, uint64_t* len, size_t offset, size_t index, 202 | size_t source) { 203 | return 0; 204 | } 205 | 206 | // TODO: currently it's not used, will be implemented 207 | int ckb_load_header(void* addr, uint64_t* len, size_t offset, size_t index, 208 | size_t source) { 209 | return 0; 210 | } 211 | 212 | int ckb_load_witness(void* addr, uint64_t* len, size_t offset, size_t index, 213 | size_t source) { 214 | cJSON* tx = cJSON_GetObjectItem(s_tx_json, "tx"); 215 | cJSON* witness = cJSON_GetObjectItem(tx, "witnesses"); 216 | size_t new_index = index; 217 | if (source == CKB_SOURCE_GROUP_INPUT) { 218 | if (index >= s_in_group_size) return CKB_INDEX_OUT_OF_BOUND; 219 | new_index = s_in_group_index[index]; 220 | } else { 221 | assert(source == CKB_SOURCE_INPUT); 222 | } 223 | 224 | cJSON* witness_item = get_item_at(witness, new_index); 225 | if (witness_item == NULL) { 226 | return CKB_INDEX_OUT_OF_BOUND; 227 | } 228 | load_data(witness_item->valuestring, addr, len, offset); 229 | return CKB_SUCCESS; 230 | } 231 | 232 | bool compare_script(cJSON* a, cJSON* b) { 233 | assert(a); 234 | assert(b); 235 | cJSON* a_args = cJSON_GetObjectItem(a, "args"); 236 | cJSON* a_code_hash = cJSON_GetObjectItem(a, "code_hash"); 237 | cJSON* a_hash_type = cJSON_GetObjectItem(a, "hash_type"); 238 | 239 | cJSON* b_args = cJSON_GetObjectItem(b, "args"); 240 | cJSON* b_code_hash = cJSON_GetObjectItem(b, "code_hash"); 241 | cJSON* b_hash_type = cJSON_GetObjectItem(b, "hash_type"); 242 | 243 | return (strcmp(a_args->valuestring, b_args->valuestring) == 0) && 244 | (strcmp(a_code_hash->valuestring, b_code_hash->valuestring) == 0) && 245 | (strcmp(a_hash_type->valuestring, b_hash_type->valuestring) == 0); 246 | } 247 | 248 | void prepare_group(bool is_lock_script, uint32_t script_index) { 249 | cJSON* mock_info = cJSON_GetObjectItem(s_tx_json, "mock_info"); 250 | assert(mock_info); 251 | cJSON* inputs = cJSON_GetObjectItem(mock_info, "inputs"); 252 | assert(inputs); 253 | 254 | cJSON* input = get_item_at(inputs, script_index); 255 | assert(input); 256 | cJSON* output = cJSON_GetObjectItem(input, "output"); 257 | assert(output); 258 | const char* lock_or_type = is_lock_script ? "lock" : "type"; 259 | cJSON* target = cJSON_GetObjectItem(output, lock_or_type); 260 | 261 | uint32_t index = 0; 262 | cJSON_ArrayForEach(input, inputs) { 263 | output = cJSON_GetObjectItem(input, "output"); 264 | cJSON* temp = cJSON_GetObjectItem(output, lock_or_type); 265 | if (compare_script(temp, target)) { 266 | s_in_group_index[s_in_group_size] = index; 267 | s_in_group_size++; 268 | } 269 | index++; 270 | } 271 | } 272 | 273 | bool is_in_group(uint32_t index) { 274 | for (uint32_t i = 0; i < s_in_group_size; i++) { 275 | if (index == s_in_group_index[i]) return true; 276 | } 277 | return false; 278 | } 279 | 280 | void prepare_hash(void) { 281 | cJSON* mock_info = cJSON_GetObjectItem(s_tx_json, "mock_info"); 282 | assert(mock_info); 283 | cJSON* cell_deps = cJSON_GetObjectItem(mock_info, "cell_deps"); 284 | assert(cell_deps); 285 | size_t index = 0; 286 | for (cJSON* it = cell_deps->child; it != NULL; it = it->next) { 287 | assert(index < MAX_HASH_ITEM_SIZE); 288 | data_hash_item_t* item = &s_data_hash[index]; 289 | 290 | cJSON* data = cJSON_GetObjectItem(it, "data"); 291 | item->len = calculate_size(data->valuestring); 292 | item->data = malloc(item->len); 293 | load_data(data->valuestring, item->data, &item->len, 0); 294 | blake2b_hash(item->data, item->len, item->hash); 295 | #ifdef CKB_SIMULATOR_VERBOSE 296 | printf("Cell data hash at index %zu:", index); 297 | print_hex(item->hash, HASH_SIZE); 298 | #endif 299 | index++; 300 | } 301 | s_data_hash_len = index; 302 | 303 | uint8_t script[SCRIPT_SIZE]; 304 | uint64_t script_size = SCRIPT_SIZE; 305 | uint32_t idx = 0; 306 | uint8_t hash[HASH_SIZE] = {0}; 307 | while (true) { 308 | int ret = load_script(script, &script_size, 0, false, idx, true); 309 | if (ret == CKB_INDEX_OUT_OF_BOUND) break; 310 | if (ret == CKB_ITEM_MISSING) { 311 | // it's null 312 | } else { 313 | assert(ret == CKB_SUCCESS); 314 | blake2b_hash(script, script_size, hash); 315 | #ifdef CKB_SIMULATOR_VERBOSE 316 | printf("script hash at index %d: ", idx); 317 | print_hex(hash, HASH_SIZE); 318 | #endif 319 | } 320 | idx++; 321 | } 322 | } 323 | 324 | int load_script(void* addr, uint64_t* len, size_t offset, bool is_lock, 325 | uint32_t script_index, bool from_cell_deps) { 326 | cJSON* mock_info = cJSON_GetObjectItem(s_tx_json, "mock_info"); 327 | const char* field = from_cell_deps ? "cell_deps" : "inputs"; 328 | cJSON* inputs = cJSON_GetObjectItem(mock_info, field); 329 | cJSON* input_at_index = get_item_at(inputs, script_index); 330 | if (input_at_index == NULL) return CKB_INDEX_OUT_OF_BOUND; 331 | 332 | cJSON* output = cJSON_GetObjectItem(input_at_index, "output"); 333 | const char* lock_or_type = is_lock ? "lock" : "type"; 334 | cJSON* lock_or_type_json = cJSON_GetObjectItem(output, lock_or_type); 335 | assert(lock_or_type_json != NULL); 336 | if (cJSON_IsNull(lock_or_type_json)) { 337 | return CKB_ITEM_MISSING; 338 | } 339 | cJSON* args_json = cJSON_GetObjectItem(lock_or_type_json, "args"); 340 | cJSON* code_hash_json = cJSON_GetObjectItem(lock_or_type_json, "code_hash"); 341 | cJSON* hash_type_json = cJSON_GetObjectItem(lock_or_type_json, "hash_type"); 342 | // to be confirmed 343 | int hash_type = 0; 344 | if (strcmp(hash_type_json->valuestring, "type") == 0) { 345 | hash_type = 1; 346 | } 347 | 348 | uint8_t code_hash[HASH_SIZE] = {0}; 349 | uint64_t code_hash_len = HASH_SIZE; 350 | load_data(code_hash_json->valuestring, code_hash, &code_hash_len, 0); 351 | 352 | uint64_t args_len = calculate_size(args_json->valuestring); 353 | uint8_t args[args_len]; 354 | load_data(args_json->valuestring, args, &args_len, 0); 355 | mol_seg_t script = build_script(code_hash, hash_type, args, args_len); 356 | 357 | load_offset(script.ptr, script.size, addr, len, offset); 358 | return CKB_SUCCESS; 359 | } 360 | 361 | int ckb_load_script(void* addr, uint64_t* len, size_t offset) { 362 | return load_script(addr, len, offset, s_is_lock_script, s_script_index, 363 | false); 364 | } 365 | 366 | int ckb_load_cell_by_field(void* addr, uint64_t* len, size_t offset, 367 | size_t index, size_t source, size_t field) { 368 | if (source == CKB_SOURCE_CELL_DEP) { 369 | if (field == CKB_CELL_FIELD_DATA_HASH) { 370 | if (index >= s_data_hash_len) { 371 | return CKB_INDEX_OUT_OF_BOUND; 372 | } 373 | load_offset(s_data_hash[index].hash, HASH_SIZE, addr, len, offset); 374 | } else { 375 | assert(false); 376 | } 377 | } else if (source == CKB_SOURCE_INPUT) { 378 | if (field == CKB_CELL_FIELD_LOCK_HASH) { 379 | // make sure it's from 0, otherwise, it consumes a lot of cpu. (computer 380 | // hash size more than once) 381 | assert(offset == 0); 382 | assert(*len >= HASH_SIZE); 383 | 384 | uint8_t lock_script[SCRIPT_SIZE]; 385 | uint64_t lock_script_len = SCRIPT_SIZE; 386 | int ret = load_script(lock_script, &lock_script_len, 0, s_is_lock_script, 387 | index, false); 388 | if (ret != CKB_SUCCESS) return ret; 389 | 390 | uint8_t hash[HASH_SIZE]; 391 | blake2b_hash(lock_script, lock_script_len, hash); 392 | 393 | load_offset(hash, HASH_SIZE, addr, len, 0); 394 | } else { 395 | // TODO: currently it's not used, will be implemented 396 | assert(false); 397 | } 398 | } else { 399 | assert(false); 400 | } 401 | 402 | return 0; 403 | } 404 | 405 | // TODO: currently it's not used, will be implemented 406 | int ckb_load_header_by_field(void* addr, uint64_t* len, size_t offset, 407 | size_t index, size_t source, size_t field) { 408 | return 0; 409 | } 410 | 411 | int ckb_load_input_by_field(void* addr, uint64_t* len, size_t offset, 412 | size_t index, size_t source, size_t field) { 413 | if (field == CKB_INPUT_FIELD_SINCE) { 414 | cJSON* tx = cJSON_GetObjectItem(s_tx_json, "tx"); 415 | cJSON* inputs = cJSON_GetObjectItem(tx, "inputs"); 416 | assert(inputs != NULL); 417 | size_t new_index = index; 418 | if (source == CKB_SOURCE_GROUP_INPUT) { 419 | if (index >= s_in_group_size) return CKB_INDEX_OUT_OF_BOUND; 420 | new_index = s_in_group_index[index]; 421 | } else { 422 | assert(source == CKB_SOURCE_INPUT); 423 | } 424 | 425 | cJSON* input = get_item_at(inputs, new_index); 426 | if (input == NULL) { 427 | return CKB_INDEX_OUT_OF_BOUND; 428 | } else { 429 | cJSON* since = cJSON_GetObjectItem(input, "since"); 430 | load_data(since->valuestring, addr, len, offset); 431 | } 432 | } else { 433 | assert(false); 434 | } 435 | return CKB_SUCCESS; 436 | } 437 | 438 | // TODO: currently it's not used, will be implemented 439 | int ckb_load_cell_code(void* addr, size_t memory_size, size_t content_offset, 440 | size_t content_size, size_t index, size_t source) { 441 | return 0; 442 | } 443 | 444 | int ckb_load_cell_data(void* addr, uint64_t* len, size_t offset, size_t index, 445 | size_t source) { 446 | if (source == CKB_SOURCE_CELL_DEP) { 447 | if (index >= s_data_hash_len) { 448 | return CKB_INDEX_OUT_OF_BOUND; 449 | } 450 | load_offset(s_data_hash[index].data, s_data_hash[index].len, addr, len, 451 | offset); 452 | } else if (source == CKB_SOURCE_GROUP_INPUT) { 453 | cJSON* mock_info = cJSON_GetObjectItem(s_tx_json, "mock_info"); 454 | cJSON* inputs = cJSON_GetObjectItem(mock_info, "inputs"); 455 | cJSON* input_at_index = get_item_at(inputs, index); 456 | if (input_at_index == NULL) return CKB_INDEX_OUT_OF_BOUND; 457 | cJSON* data = cJSON_GetObjectItem(input_at_index, "data"); 458 | load_data(data->valuestring, addr, len, offset); 459 | } else if (source == CKB_SOURCE_GROUP_OUTPUT) { 460 | cJSON* tx = cJSON_GetObjectItem(s_tx_json, "tx"); 461 | cJSON* outputs_data = cJSON_GetObjectItem(tx, "outputs_data"); 462 | cJSON* output_at_index = get_item_at(outputs_data, index); 463 | if (output_at_index == NULL) return CKB_INDEX_OUT_OF_BOUND; 464 | load_data(output_at_index->valuestring, addr, len, offset); 465 | } else { 466 | assert(false); 467 | } 468 | return 0; 469 | } 470 | 471 | int ckb_debug(const char* s) { return 0; } 472 | 473 | // TODO: currently it's not used, will be implemented 474 | int load_actual_type_witness(uint8_t* buf, uint64_t* len, size_t index, 475 | size_t* type_source) { 476 | return 0; 477 | } 478 | 479 | int ckb_look_for_dep_with_hash(const uint8_t* data_hash, size_t* index) { 480 | return ckb_look_for_dep_with_hash2(data_hash, 0, index); 481 | } 482 | 483 | int ckb_checked_load_cell_by_field(void* addr, uint64_t* len, size_t offset, 484 | size_t index, size_t source, size_t field) { 485 | uint64_t old_len = *len; 486 | int ret = ckb_load_cell_by_field(addr, len, offset, index, source, field); 487 | if (ret == CKB_SUCCESS && (*len) > old_len) { 488 | ret = CKB_LENGTH_NOT_ENOUGH; 489 | } 490 | return ret; 491 | } 492 | 493 | int ckb_calculate_inputs_len() { 494 | uint64_t len = 0; 495 | /* lower bound, at least tx has one input */ 496 | int lo = 0; 497 | /* higher bound */ 498 | int hi = 4; 499 | int ret; 500 | /* try to load input until failing to increase lo and hi */ 501 | while (1) { 502 | ret = ckb_load_input_by_field(NULL, &len, 0, hi, CKB_SOURCE_INPUT, 503 | CKB_INPUT_FIELD_SINCE); 504 | if (ret == CKB_SUCCESS) { 505 | lo = hi; 506 | hi *= 2; 507 | } else { 508 | break; 509 | } 510 | } 511 | 512 | /* now we get our lower bound and higher bound, 513 | count number of inputs by binary search */ 514 | int i; 515 | while (lo + 1 != hi) { 516 | i = (lo + hi) / 2; 517 | ret = ckb_load_input_by_field(NULL, &len, 0, i, CKB_SOURCE_INPUT, 518 | CKB_INPUT_FIELD_SINCE); 519 | if (ret == CKB_SUCCESS) { 520 | lo = i; 521 | } else { 522 | hi = i; 523 | } 524 | } 525 | /* now lo is last input index and hi is length of inputs */ 526 | return hi; 527 | } 528 | 529 | int ckb_look_for_dep_with_hash2(const uint8_t* code_hash, uint8_t hash_type, 530 | size_t* index) { 531 | size_t current = 0; 532 | size_t field = 533 | (hash_type == 1) ? CKB_CELL_FIELD_TYPE_HASH : CKB_CELL_FIELD_DATA_HASH; 534 | while (current < SIZE_MAX) { 535 | uint64_t len = 32; 536 | uint8_t hash[32]; 537 | 538 | int ret = ckb_load_cell_by_field(hash, &len, 0, current, 539 | CKB_SOURCE_CELL_DEP, field); 540 | switch (ret) { 541 | case CKB_ITEM_MISSING: 542 | break; 543 | case CKB_SUCCESS: 544 | if (memcmp(code_hash, hash, 32) == 0) { 545 | /* Found a match */ 546 | *index = current; 547 | return CKB_SUCCESS; 548 | } 549 | break; 550 | default: 551 | return CKB_INDEX_OUT_OF_BOUND; 552 | } 553 | current++; 554 | } 555 | return CKB_INDEX_OUT_OF_BOUND; 556 | } 557 | 558 | #define READALL_CHUNK 262144 559 | #define READALL_OK 0 /* Success */ 560 | #define READALL_INVALID -1 /* Invalid parameters */ 561 | #define READALL_ERROR -2 /* Stream error */ 562 | #define READALL_TOOMUCH -3 /* Too much input */ 563 | #define READALL_NOMEM -4 /* Out of memory */ 564 | 565 | int readall(FILE* in, char** dataptr, size_t* sizeptr) { 566 | char *data = NULL, *temp = NULL; 567 | size_t size = 0; 568 | size_t used = 0; 569 | size_t n = 0; 570 | 571 | /* None of the parameters can be NULL. */ 572 | if (in == NULL || dataptr == NULL || sizeptr == NULL) return READALL_INVALID; 573 | 574 | /* A read error already occurred? */ 575 | if (ferror(in)) return READALL_ERROR; 576 | 577 | while (1) { 578 | if (used + READALL_CHUNK + 1 > size) { 579 | size = used + READALL_CHUNK + 1; 580 | 581 | if (size <= used) { 582 | free(data); 583 | return READALL_TOOMUCH; 584 | } 585 | 586 | temp = realloc(data, size); 587 | if (temp == NULL) { 588 | free(data); 589 | return READALL_NOMEM; 590 | } 591 | data = temp; 592 | } 593 | 594 | n = fread(data + used, 1, READALL_CHUNK, in); 595 | if (n == 0) break; 596 | 597 | used += n; 598 | } 599 | 600 | if (ferror(in)) { 601 | free(data); 602 | return READALL_ERROR; 603 | } 604 | 605 | temp = realloc(data, used + 1); 606 | if (temp == NULL) { 607 | free(data); 608 | return READALL_NOMEM; 609 | } 610 | data = temp; 611 | data[used] = '\0'; 612 | 613 | *dataptr = data; 614 | *sizeptr = used; 615 | 616 | return READALL_OK; 617 | } 618 | 619 | int init_json_data_source(const char* file_name) { 620 | FILE* input = NULL; 621 | if (file_name == NULL) { 622 | input = stdin; 623 | } else { 624 | input = fopen(file_name, "rb"); 625 | } 626 | char* json_ptr = NULL; 627 | size_t json_size = 0; 628 | int ret = readall(input, &json_ptr, &json_size); 629 | if (ret != 0) { 630 | return ret; 631 | } 632 | s_json = cJSON_ParseWithLength(json_ptr, json_size); 633 | if (s_json == NULL) { 634 | char msg[128] = {0}; 635 | sprintf(msg, "Failed to parse json file: %s", file_name); 636 | FAIL(msg); 637 | return -1; 638 | } 639 | fclose(input); 640 | free(json_ptr); 641 | 642 | // --------- 643 | 644 | cJSON* tx_hash = cJSON_GetObjectItem(s_json, "main"); 645 | cJSON* fn = cJSON_GetObjectItem(s_json, tx_hash->valuestring); 646 | input = fopen(fn->valuestring, "rb"); 647 | ret = readall(input, &json_ptr, &json_size); 648 | assert(ret == READALL_OK); 649 | s_tx_json = cJSON_ParseWithLength(json_ptr, json_size); 650 | if (s_tx_json == NULL) { 651 | char msg[128] = {0}; 652 | sprintf(msg, "Failed to parse json file: %s", fn->valuestring); 653 | FAIL(msg); 654 | return -1; 655 | } 656 | uint64_t tx_hash_len = HASH_SIZE; 657 | load_data(tx_hash->valuestring, s_tx_hash, &tx_hash_len, 0); 658 | assert(tx_hash_len == HASH_SIZE); 659 | 660 | cJSON* is_lock_script = cJSON_GetObjectItem(s_json, "is_lock_script"); 661 | assert(is_lock_script != NULL); 662 | assert(cJSON_IsBool(is_lock_script)); 663 | s_is_lock_script = cJSON_IsTrue(is_lock_script); 664 | 665 | cJSON* script_index = cJSON_GetObjectItem(s_json, "script_index"); 666 | assert(script_index != NULL); 667 | s_script_index = script_index->valueint; 668 | 669 | prepare_group(s_is_lock_script, s_script_index); 670 | fclose(input); 671 | free(json_ptr); 672 | 673 | return 0; 674 | } 675 | 676 | void test_script(void) { 677 | unsigned char script[SCRIPT_SIZE]; 678 | uint64_t len = SCRIPT_SIZE; 679 | int ret = ckb_load_script(script, &len, 0); 680 | assert(ret == CKB_SUCCESS); 681 | assert(len < SCRIPT_SIZE); 682 | 683 | mol_seg_t script_seg; 684 | script_seg.ptr = (uint8_t*)script; 685 | script_seg.size = len; 686 | 687 | assert(MolReader_Script_verify(&script_seg, false) == MOL_OK); 688 | 689 | mol_seg_t args_seg = MolReader_Script_get_args(&script_seg); 690 | mol_seg_t args_bytes_seg = MolReader_Bytes_raw_bytes(&args_seg); 691 | assert(args_bytes_seg.size == BLAKE160_SIZE); 692 | 693 | assert(args_bytes_seg.ptr[0] == 0x27); 694 | assert(args_bytes_seg.ptr[1] == 0xf5); 695 | assert(args_bytes_seg.ptr[18] == 0x9e); 696 | assert(args_bytes_seg.ptr[19] == 0xc9); 697 | } 698 | 699 | // the test data is from: 700 | // npx ckb-transaction-dumper -x 701 | // 0xa98c212cf055cedbbb665d475c0561b56c68ea735c8aa830c493264effaf18bd 702 | 703 | int unit_test(int argc, const char* argv[]) { 704 | unsigned char witness[1024] = {0}; 705 | uint64_t witness_len = 1024; 706 | ckb_load_witness(witness, &witness_len, 0, 0, 0); 707 | assert(witness_len == 85); 708 | assert(witness[0] == 0x55); 709 | assert(witness[1] == 0x00); 710 | assert(witness[83] == 0xe7); 711 | assert(witness[84] == 0x01); 712 | test_script(); 713 | return 0; 714 | } 715 | 716 | // this is the entry function of contract. 717 | extern int simulator_main(void); 718 | 719 | int main(int argc, const char* argv[]) { 720 | const char* file_name = NULL; 721 | if (argc == 2 && argv[1] != NULL) file_name = argv[1]; 722 | if (file_name == NULL) { 723 | printf("Running with stdin ...\n"); 724 | } else { 725 | printf("Running with file: %s\n", file_name); 726 | } 727 | int ret = init_json_data_source(file_name); 728 | assert(ret == 0); 729 | prepare_hash(); 730 | 731 | if (false) { 732 | ret = unit_test(argc, argv); 733 | } else { 734 | ret = simulator_main(); 735 | } 736 | 737 | if (ret == 0) { 738 | printf("succeeded!\n"); 739 | } else { 740 | printf("failed, error code: %d\n", ret); 741 | } 742 | return ret; 743 | } 744 | --------------------------------------------------------------------------------