-
Notifications
You must be signed in to change notification settings - Fork 22
/
secp256k1_blake160_sighash_all.c
196 lines (169 loc) · 5.36 KB
/
secp256k1_blake160_sighash_all.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
#include "ckb_syscalls.h"
#include "blake2b.h"
#include "protocol_reader.h"
#undef ns
#define ns(x) FLATBUFFERS_WRAP_NAMESPACE(Ckb_Protocol, x)
#define ERROR_UNKNOWN -1
#define ERROR_WRONG_NUMBER_OF_ARGUMENTS -2
#define ERROR_PUBKEY_BLAKE160_HASH -3
#define ERROR_SYSCALL -4
#define ERROR_SECP_ABORT -5
#define ERROR_SECP_INITIALIZE -6
#define ERROR_SECP_PARSE_PUBKEY -7
#define ERROR_SECP_PARSE_SIGNATURE -8
#define ERROR_SECP_VERIFICATION -9
#define ERROR_BUFFER_NOT_ENOUGH -10
#define ERROR_ENCODING -11
#define BLAKE2B_BLOCK_SIZE 32
#define BLAKE160_SIZE 20
#define PUBKEY_SIZE 33
#define TEMP_SIZE 1024
/* 32 KB */
#define WITNESS_SIZE 32768
/* Stripping as much unneeded bytes from secp256k1 as possible */
#define CUSTOM_ABORT 1
#define CUSTOM_PRINT_ERR 1
void custom_abort()
{
syscall(SYS_exit, ERROR_SECP_ABORT, 0, 0, 0, 0, 0);
}
int custom_print_err(const char * arg, ...)
{
(void) arg;
return 0;
}
#include <secp256k1_static.h>
/*
* We are including secp256k1 implementation directly so gcc can strip
* unused functions. For some unknown reasons, if we link in libsecp256k1.a
* directly, the final binary will include all functions rather than those used.
*/
#include <secp256k1.c>
static int extract_bytes(ns(Bytes_table_t) bytes, unsigned char *buffer, volatile size_t *s)
{
flatbuffers_uint8_vec_t seq = ns(Bytes_seq(bytes));
size_t len = flatbuffers_uint8_vec_len(seq);
if (len > *s) {
return ERROR_BUFFER_NOT_ENOUGH;
}
for (size_t i = 0; i < len; i++) {
buffer[i] = flatbuffers_uint8_vec_at(seq, i);
}
*s = len;
return CKB_SUCCESS;
}
/*
* Arguments are listed in the following order:
* 0. program name
* 1. pubkey blake160 hash, blake2b hash of pubkey first 20 bytes, used to shield the real
* pubkey in lock script.
*
* Witness:
* 2. pubkey, real pubkey used to identify token owner
* 3. signature, signature used to present ownership
* 4. signature size, in little endian 64 bit unsigned integer
*/
int main(int argc, char* argv[])
{
int ret;
size_t index = 0;
uint64_t signature_size = 0;
volatile uint64_t len = 0;
unsigned char tx_hash[BLAKE2B_BLOCK_SIZE];
unsigned char temp[TEMP_SIZE];
unsigned char witness[WITNESS_SIZE];
ns(Witness_table_t) witness_table;
ns(Bytes_vec_t) args;
if (argc != 2) {
return ERROR_WRONG_NUMBER_OF_ARGUMENTS;
}
secp256k1_context context;
if (secp256k1_context_initialize(&context, SECP256K1_CONTEXT_VERIFY) == 0) {
return ERROR_SECP_INITIALIZE;
}
len = BLAKE2B_BLOCK_SIZE;
ret = ckb_load_tx_hash(tx_hash, &len, 0);
if (ret != CKB_SUCCESS) {
return ERROR_SYSCALL;
}
while (1) {
len = 0;
/*
* Actually we don't need this syscall, we are just making it to grab all
* input indices for current group, from which we can load the actual
* witness data we need. `since` field is chosen here since it has a fixed
* size of 8 bytes, which is both predictable, and also provides minimal
* cycle consumption.
*/
ret = ckb_load_cell_by_field(NULL, &len, 0, index, CKB_SOURCE_GROUP_INPUT,
CKB_INPUT_FIELD_SINCE);
if (ret == CKB_INDEX_OUT_OF_BOUND) {
return 0;
}
if (ret != CKB_SUCCESS) {
return ERROR_SYSCALL;
}
/* Now we load actual witness data using the same input index above. */
len = WITNESS_SIZE;
ret = ckb_load_witness(witness, &len, 0, index, CKB_SOURCE_GROUP_INPUT);
if (ret != CKB_SUCCESS) {
return ERROR_SYSCALL;
}
if (!(witness_table = ns(Witness_as_root(witness)))) {
return ERROR_ENCODING;
}
args = ns(Witness_data(witness_table));
if (ns(Bytes_vec_len(args)) < 2) {
return ERROR_WRONG_NUMBER_OF_ARGUMENTS;
}
/* Check pubkey hash */
len = TEMP_SIZE;
ret = extract_bytes(ns(Bytes_vec_at(args, 0)), temp, &len);
if (ret != CKB_SUCCESS) {
return ERROR_ENCODING;
}
blake2b_state blake2b_ctx;
blake2b_init(&blake2b_ctx, BLAKE2B_BLOCK_SIZE);
blake2b_update(&blake2b_ctx, temp, len);
blake2b_final(&blake2b_ctx, temp, BLAKE2B_BLOCK_SIZE);
if (memcmp(argv[1], temp, BLAKE160_SIZE) != 0) {
return ERROR_PUBKEY_BLAKE160_HASH;
}
/* load pubkey */
len = TEMP_SIZE;
ret = extract_bytes(ns(Bytes_vec_at(args, 0)), temp, &len);
if (ret != CKB_SUCCESS) {
return ERROR_ENCODING;
}
secp256k1_pubkey pubkey;
if (secp256k1_ec_pubkey_parse(&context, &pubkey, temp, len) == 0) {
return ERROR_SECP_PARSE_PUBKEY;
}
/* Load signature */
len = TEMP_SIZE;
ret = extract_bytes(ns(Bytes_vec_at(args, 1)), temp, &len);
if (ret != CKB_SUCCESS) {
return ERROR_ENCODING;
}
secp256k1_ecdsa_signature signature;
if (secp256k1_ecdsa_signature_parse_der(&context, &signature, temp, len) == 0) {
return ERROR_SECP_PARSE_SIGNATURE;
}
blake2b_init(&blake2b_ctx, BLAKE2B_BLOCK_SIZE);
blake2b_update(&blake2b_ctx, tx_hash, BLAKE2B_BLOCK_SIZE);
for (size_t i = 2; i < ns(Bytes_vec_len(args)); i++) {
len = TEMP_SIZE;
ret = extract_bytes(ns(Bytes_vec_at(args, i)), temp, &len);
if (ret != CKB_SUCCESS) {
return ERROR_ENCODING;
}
blake2b_update(&blake2b_ctx, temp, len);
}
blake2b_final(&blake2b_ctx, temp, BLAKE2B_BLOCK_SIZE);
if (secp256k1_ecdsa_verify(&context, &signature, temp, &pubkey) != 1) {
return ERROR_SECP_VERIFICATION;
}
index += 1;
}
return ERROR_UNKNOWN;
}