v0.0.34 - Add qrexec bridge subcommand and --bridge-source-trusted flag for persistent-signer qrexec transport
This commit is contained in:
@@ -1,5 +1,13 @@
|
||||
#include <Adafruit_TinyUSB.h>
|
||||
|
||||
extern "C" {
|
||||
#include "src/nostr_core/nostr_common.h"
|
||||
#include "src/nostr_core/utils.h"
|
||||
#include "src/nostr_core/nip006.h"
|
||||
#include "src/nostr_core/nip001.h"
|
||||
#include "src/cjson/cJSON.h"
|
||||
}
|
||||
|
||||
#include "display.h"
|
||||
#include "mnemonic_kb.h"
|
||||
|
||||
@@ -81,10 +89,22 @@ static uint16_t s_enter_selected_indices[12] = {0};
|
||||
static bool s_enter_committed[12] = {false};
|
||||
|
||||
static void signer_enter_ready_screen();
|
||||
static void set_device_mode(device_mode_t mode, bool blink_led);
|
||||
|
||||
// -------------------- Transport framing ----------------------
|
||||
static uint8_t s_rx_buf[2048];
|
||||
static size_t s_rx_len = 0;
|
||||
enum rpc_transport_t {
|
||||
RPC_TRANSPORT_WEBUSB = 0,
|
||||
RPC_TRANSPORT_SERIAL = 1,
|
||||
};
|
||||
|
||||
static rpc_transport_t s_rpc_reply_transport = RPC_TRANSPORT_WEBUSB;
|
||||
|
||||
static uint8_t s_rx_web_buf[2048];
|
||||
static size_t s_rx_web_len = 0;
|
||||
|
||||
static uint8_t s_rx_serial_buf[2048];
|
||||
static size_t s_rx_serial_len = 0;
|
||||
|
||||
static uint8_t s_tx_buf[2048];
|
||||
|
||||
// ---------------------- Encoder state ------------------------
|
||||
@@ -234,21 +254,107 @@ static bool json_extract_string(const char *json, const char *key, char *out, si
|
||||
return true;
|
||||
}
|
||||
|
||||
// Deterministic placeholder key derivation for transport integration testing.
|
||||
static void pseudo_pubkey_hex(char out_hex_64[65]) {
|
||||
uint32_t h = 2166136261u;
|
||||
for (size_t i = 0; i < strlen(s_mnemonic); i++) {
|
||||
h ^= (uint8_t)s_mnemonic[i];
|
||||
h *= 16777619u;
|
||||
static bool json_extract_int(const char *json, const char *key, int *out) {
|
||||
if (!json || !key || !out) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 32; i++) {
|
||||
uint8_t b = (uint8_t)((h >> ((i % 4) * 8)) ^ (i * 37));
|
||||
static const char *hex = "0123456789abcdef";
|
||||
out_hex_64[i * 2] = hex[(b >> 4) & 0x0F];
|
||||
out_hex_64[i * 2 + 1] = hex[b & 0x0F];
|
||||
char needle[64];
|
||||
snprintf(needle, sizeof(needle), "\"%s\"", key);
|
||||
const char *k = strstr(json, needle);
|
||||
if (!k) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *colon = strchr(k, ':');
|
||||
if (!colon) {
|
||||
return false;
|
||||
}
|
||||
|
||||
colon++;
|
||||
while (*colon == ' ' || *colon == '\t' || *colon == '\r' || *colon == '\n') {
|
||||
colon++;
|
||||
}
|
||||
|
||||
char *endptr = nullptr;
|
||||
long v = strtol(colon, &endptr, 10);
|
||||
if (endptr == colon) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*out = (int)v;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool json_extract_first_param_object(const char *json, char *out, size_t out_sz) {
|
||||
if (!json || !out || out_sz < 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *params = strstr(json, "\"params\"");
|
||||
if (!params) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *arr = strchr(params, '[');
|
||||
if (!arr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *start = strchr(arr, '{');
|
||||
if (!start) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int depth = 0;
|
||||
bool in_string = false;
|
||||
bool escape = false;
|
||||
const char *p = start;
|
||||
|
||||
for (; *p; ++p) {
|
||||
const char c = *p;
|
||||
|
||||
if (in_string) {
|
||||
if (escape) {
|
||||
escape = false;
|
||||
} else if (c == '\\') {
|
||||
escape = true;
|
||||
} else if (c == '"') {
|
||||
in_string = false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == '"') {
|
||||
in_string = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == '{') {
|
||||
depth++;
|
||||
} else if (c == '}') {
|
||||
depth--;
|
||||
if (depth == 0) {
|
||||
const size_t n = (size_t)(p - start + 1);
|
||||
if (n >= out_sz) {
|
||||
return false;
|
||||
}
|
||||
memcpy(out, start, n);
|
||||
out[n] = '\0';
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void secure_zero(void *p, size_t n) {
|
||||
if (!p || n == 0) return;
|
||||
volatile uint8_t *vp = reinterpret_cast<volatile uint8_t *>(p);
|
||||
while (n--) {
|
||||
*vp++ = 0;
|
||||
}
|
||||
out_hex_64[64] = '\0';
|
||||
}
|
||||
|
||||
static void signer_apply_seed(const char *mnemonic) {
|
||||
@@ -289,35 +395,68 @@ static bool wait_for_user_approval(uint32_t timeout_ms) {
|
||||
static void send_json_response(const char *json) {
|
||||
size_t n = strlen(json);
|
||||
if (n > (sizeof(s_tx_buf) - 4)) return;
|
||||
|
||||
write_u32_be(s_tx_buf, (uint32_t)n);
|
||||
memcpy(s_tx_buf + 4, json, n);
|
||||
usb_web.write(s_tx_buf, n + 4);
|
||||
usb_web.flush();
|
||||
|
||||
if (s_rpc_reply_transport == RPC_TRANSPORT_SERIAL) {
|
||||
Serial.write(s_tx_buf, n + 4);
|
||||
Serial.flush();
|
||||
} else {
|
||||
usb_web.write(s_tx_buf, n + 4);
|
||||
usb_web.flush();
|
||||
}
|
||||
|
||||
s_diag_responses_tx++;
|
||||
}
|
||||
|
||||
static void send_rpc_result(const char *id, const char *result_json) {
|
||||
char out[2048];
|
||||
const char *rpc_id = (id && id[0]) ? id : "0";
|
||||
const char *result = (result_json && result_json[0]) ? result_json : "null";
|
||||
snprintf(out, sizeof(out), "{\"jsonrpc\":\"2.0\",\"id\":\"%s\",\"result\":%s}", rpc_id, result);
|
||||
send_json_response(out);
|
||||
}
|
||||
|
||||
static void send_rpc_error(const char *id, int code, const char *message) {
|
||||
char out[1024];
|
||||
const char *rpc_id = (id && id[0]) ? id : "0";
|
||||
const char *msg = (message && message[0]) ? message : "error";
|
||||
snprintf(out, sizeof(out),
|
||||
"{\"jsonrpc\":\"2.0\",\"id\":\"%s\",\"error\":{\"code\":%d,\"message\":\"%s\"}}",
|
||||
rpc_id, code, msg);
|
||||
send_json_response(out);
|
||||
}
|
||||
|
||||
static void handle_rpc(const char *req_json) {
|
||||
char rpc_id[96] = {0};
|
||||
(void)json_extract_string(req_json, "id", rpc_id, sizeof(rpc_id));
|
||||
|
||||
int nostr_index = 0;
|
||||
(void)json_extract_int(req_json, "nostr_index", &nostr_index);
|
||||
|
||||
char method[64] = {0};
|
||||
if (!json_extract_string(req_json, "method", method, sizeof(method))) {
|
||||
send_json_response("{\"error\":{\"code\":-32600,\"message\":\"invalid request\"}}");
|
||||
send_rpc_error(rpc_id, -32600, "invalid request");
|
||||
// display_set_status("RPC invalid request");
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(method, "ping") == 0) {
|
||||
send_json_response("{\"result\":\"pong\"}");
|
||||
send_rpc_result(rpc_id, "\"pong\"");
|
||||
// display_set_status("RPC ping");
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(method, "get_status") == 0) {
|
||||
char resp[256];
|
||||
snprintf(resp, sizeof(resp),
|
||||
"{\"result\":{\"mode\":\"%s\",\"seed_loaded\":%s,\"auto_approve\":%s}}",
|
||||
char result[256];
|
||||
snprintf(result, sizeof(result),
|
||||
"{\"mode\":\"%s\",\"seed_loaded\":%s,\"auto_approve\":%s,\"nostr_index\":%d}",
|
||||
s_mode == MODE_MEDIA ? "media" : "signer",
|
||||
s_seed_loaded ? "true" : "false",
|
||||
s_auto_approve ? "true" : "false");
|
||||
send_json_response(resp);
|
||||
s_auto_approve ? "true" : "false",
|
||||
nostr_index);
|
||||
send_rpc_result(rpc_id, result);
|
||||
// display_set_status("RPC get_status");
|
||||
return;
|
||||
}
|
||||
@@ -325,7 +464,7 @@ static void handle_rpc(const char *req_json) {
|
||||
if (strcmp(method, "set_mnemonic") == 0) {
|
||||
char phrase[256] = {0};
|
||||
if (!json_extract_string(req_json, "mnemonic", phrase, sizeof(phrase))) {
|
||||
send_json_response("{\"error\":{\"code\":-32602,\"message\":\"missing mnemonic\"}}");
|
||||
send_rpc_error(rpc_id, -32602, "missing mnemonic");
|
||||
// display_set_status("Mnemonic missing");
|
||||
return;
|
||||
}
|
||||
@@ -334,21 +473,21 @@ static void handle_rpc(const char *req_json) {
|
||||
if (s_mode == MODE_SIGNER && s_seed_loaded) {
|
||||
signer_enter_ready_screen();
|
||||
}
|
||||
send_json_response("{\"result\":\"ok\"}");
|
||||
send_rpc_result(rpc_id, "\"ok\"");
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(method, "set_auto_approve") == 0) {
|
||||
if (strstr(req_json, "\"value\":true") != nullptr) {
|
||||
s_auto_approve = true;
|
||||
send_json_response("{\"result\":true}");
|
||||
send_rpc_result(rpc_id, "true");
|
||||
// display_set_status("Auto-approve ON");
|
||||
} else if (strstr(req_json, "\"value\":false") != nullptr) {
|
||||
s_auto_approve = false;
|
||||
send_json_response("{\"result\":false}");
|
||||
send_rpc_result(rpc_id, "false");
|
||||
// display_set_status("Auto-approve OFF");
|
||||
} else {
|
||||
send_json_response("{\"error\":{\"code\":-32602,\"message\":\"missing value\"}}");
|
||||
send_rpc_error(rpc_id, -32602, "missing value");
|
||||
// display_set_status("Auto-approve invalid");
|
||||
}
|
||||
return;
|
||||
@@ -356,38 +495,45 @@ static void handle_rpc(const char *req_json) {
|
||||
|
||||
if (strcmp(method, "get_public_key") == 0) {
|
||||
if (!s_seed_loaded) {
|
||||
send_json_response("{\"error\":{\"code\":2014,\"message\":\"seed not loaded\"}}");
|
||||
// display_set_status("No seed");
|
||||
send_rpc_error(rpc_id, 2014, "seed not loaded");
|
||||
return;
|
||||
}
|
||||
|
||||
char pubhex[65];
|
||||
pseudo_pubkey_hex(pubhex);
|
||||
unsigned char private_key[32] = {0};
|
||||
unsigned char public_key[32] = {0};
|
||||
if (nostr_derive_keys_from_mnemonic(s_mnemonic, nostr_index, private_key, public_key) != NOSTR_SUCCESS) {
|
||||
secure_zero(private_key, sizeof(private_key));
|
||||
secure_zero(public_key, sizeof(public_key));
|
||||
send_rpc_error(rpc_id, -32603, "key derivation failed");
|
||||
return;
|
||||
}
|
||||
|
||||
char resp[192];
|
||||
snprintf(resp, sizeof(resp), "{\"result\":{\"pubkey\":\"%s\"}}", pubhex);
|
||||
send_json_response(resp);
|
||||
// display_set_status("Pubkey served");
|
||||
char pubhex[65] = {0};
|
||||
nostr_bytes_to_hex(public_key, 32, pubhex);
|
||||
|
||||
secure_zero(private_key, sizeof(private_key));
|
||||
secure_zero(public_key, sizeof(public_key));
|
||||
|
||||
char result[96];
|
||||
snprintf(result, sizeof(result), "\"%s\"", pubhex);
|
||||
send_rpc_result(rpc_id, result);
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(method, "sign_event") == 0) {
|
||||
if (!s_seed_loaded) {
|
||||
send_json_response("{\"error\":{\"code\":2014,\"message\":\"seed not loaded\"}}");
|
||||
// display_set_status("Sign blocked:no seed");
|
||||
send_rpc_error(rpc_id, 2014, "seed not loaded");
|
||||
return;
|
||||
}
|
||||
|
||||
if (s_mode != MODE_SIGNER) {
|
||||
send_json_response("{\"error\":{\"code\":2015,\"message\":\"not in signer mode\"}}");
|
||||
// display_set_status("Sign blocked:mode");
|
||||
send_rpc_error(rpc_id, 2015, "not in signer mode");
|
||||
return;
|
||||
}
|
||||
|
||||
bool approved = s_auto_approve ? true : wait_for_user_approval(30000);
|
||||
if (!approved) {
|
||||
send_json_response("{\"error\":{\"code\":2001,\"message\":\"user denied or timeout\"}}");
|
||||
// Return signer UI screen after approval prompt
|
||||
send_rpc_error(rpc_id, 2001, "user denied or timeout");
|
||||
if (s_signer_ui_state == SIGNER_UI_MENU) {
|
||||
display_show_signer_menu(s_signer_menu_selected);
|
||||
} else if (s_signer_ui_state == SIGNER_UI_READY) {
|
||||
@@ -396,8 +542,81 @@ static void handle_rpc(const char *req_json) {
|
||||
return;
|
||||
}
|
||||
|
||||
send_json_response("{\"result\":{\"sig\":\"dev_signature_placeholder\"}}");
|
||||
// display_set_status("Event signed");
|
||||
char event_obj[1400] = {0};
|
||||
if (!json_extract_first_param_object(req_json, event_obj, sizeof(event_obj))) {
|
||||
send_rpc_error(rpc_id, -32602, "missing event object");
|
||||
return;
|
||||
}
|
||||
|
||||
cJSON *event_in = cJSON_Parse(event_obj);
|
||||
if (!event_in || !cJSON_IsObject(event_in)) {
|
||||
if (event_in) cJSON_Delete(event_in);
|
||||
send_rpc_error(rpc_id, -32602, "invalid event object");
|
||||
return;
|
||||
}
|
||||
|
||||
cJSON *kind_item = cJSON_GetObjectItemCaseSensitive(event_in, "kind");
|
||||
cJSON *content_item = cJSON_GetObjectItemCaseSensitive(event_in, "content");
|
||||
cJSON *tags_item = cJSON_GetObjectItemCaseSensitive(event_in, "tags");
|
||||
cJSON *created_at_item = cJSON_GetObjectItemCaseSensitive(event_in, "created_at");
|
||||
|
||||
if (!cJSON_IsNumber(kind_item) || !cJSON_IsString(content_item)) {
|
||||
cJSON_Delete(event_in);
|
||||
send_rpc_error(rpc_id, -32602, "event missing kind/content");
|
||||
return;
|
||||
}
|
||||
|
||||
int kind = kind_item->valueint;
|
||||
const char *content = content_item->valuestring ? content_item->valuestring : "";
|
||||
time_t created_at = (time_t)time(nullptr);
|
||||
if (cJSON_IsNumber(created_at_item)) {
|
||||
created_at = (time_t)created_at_item->valuedouble;
|
||||
}
|
||||
|
||||
cJSON *tags_dup = nullptr;
|
||||
if (cJSON_IsArray(tags_item)) {
|
||||
tags_dup = cJSON_Duplicate(tags_item, 1);
|
||||
if (!tags_dup) {
|
||||
cJSON_Delete(event_in);
|
||||
send_rpc_error(rpc_id, -32603, "tags allocation failed");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char private_key[32] = {0};
|
||||
unsigned char public_key[32] = {0};
|
||||
if (nostr_derive_keys_from_mnemonic(s_mnemonic, nostr_index, private_key, public_key) != NOSTR_SUCCESS) {
|
||||
if (tags_dup) cJSON_Delete(tags_dup);
|
||||
cJSON_Delete(event_in);
|
||||
secure_zero(private_key, sizeof(private_key));
|
||||
secure_zero(public_key, sizeof(public_key));
|
||||
send_rpc_error(rpc_id, -32603, "key derivation failed");
|
||||
return;
|
||||
}
|
||||
|
||||
cJSON *signed_event = nostr_create_and_sign_event(kind, content, tags_dup, private_key, created_at);
|
||||
|
||||
secure_zero(private_key, sizeof(private_key));
|
||||
secure_zero(public_key, sizeof(public_key));
|
||||
if (tags_dup) cJSON_Delete(tags_dup);
|
||||
cJSON_Delete(event_in);
|
||||
|
||||
if (!signed_event) {
|
||||
send_rpc_error(rpc_id, -32603, "event signing failed");
|
||||
return;
|
||||
}
|
||||
|
||||
char *signed_event_json = cJSON_PrintUnformatted(signed_event);
|
||||
cJSON_Delete(signed_event);
|
||||
|
||||
if (!signed_event_json) {
|
||||
send_rpc_error(rpc_id, -32603, "event serialization failed");
|
||||
return;
|
||||
}
|
||||
|
||||
send_rpc_result(rpc_id, signed_event_json);
|
||||
free(signed_event_json);
|
||||
|
||||
if (s_signer_ui_state == SIGNER_UI_MENU) {
|
||||
display_show_signer_menu(s_signer_menu_selected);
|
||||
} else if (s_signer_ui_state == SIGNER_UI_READY) {
|
||||
@@ -406,20 +625,52 @@ static void handle_rpc(const char *req_json) {
|
||||
return;
|
||||
}
|
||||
|
||||
send_json_response("{\"error\":{\"code\":-32601,\"message\":\"method not found\"}}");
|
||||
send_rpc_error(rpc_id, -32601, "method not found");
|
||||
// display_set_status("RPC method missing");
|
||||
}
|
||||
|
||||
static void pump_framed_requests(uint8_t *rx_buf, size_t *rx_len, rpc_transport_t transport) {
|
||||
while (*rx_len >= 4) {
|
||||
const uint32_t body_len = read_u32_be(rx_buf);
|
||||
if (body_len > (sizeof(s_rx_web_buf) - 4)) {
|
||||
*rx_len = 0;
|
||||
s_rpc_reply_transport = transport;
|
||||
send_json_response("{\"error\":{\"code\":-32000,\"message\":\"frame too large\"}}");
|
||||
// display_set_status("Frame too large");
|
||||
return;
|
||||
}
|
||||
|
||||
if (*rx_len < (size_t)(4 + body_len)) {
|
||||
return;
|
||||
}
|
||||
|
||||
s_diag_frames_rx++;
|
||||
|
||||
char req[1536];
|
||||
size_t n = body_len;
|
||||
if (n >= sizeof(req)) n = sizeof(req) - 1;
|
||||
memcpy(req, rx_buf + 4, n);
|
||||
req[n] = '\0';
|
||||
|
||||
const size_t remain = *rx_len - (4 + body_len);
|
||||
memmove(rx_buf, rx_buf + 4 + body_len, remain);
|
||||
*rx_len = remain;
|
||||
|
||||
s_rpc_reply_transport = transport;
|
||||
handle_rpc(req);
|
||||
}
|
||||
}
|
||||
|
||||
static void webusb_pump_frames() {
|
||||
while (usb_web.available()) {
|
||||
if (s_rx_len >= sizeof(s_rx_buf)) {
|
||||
s_rx_len = 0;
|
||||
if (s_rx_web_len >= sizeof(s_rx_web_buf)) {
|
||||
s_rx_web_len = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
int c = usb_web.read();
|
||||
const int c = usb_web.read();
|
||||
if (c < 0) break;
|
||||
s_rx_buf[s_rx_len++] = (uint8_t)c;
|
||||
s_rx_web_buf[s_rx_web_len++] = (uint8_t)c;
|
||||
|
||||
// DIAG: a byte arrived from the host. Pulse LED + count it so we can
|
||||
// confirm, with no host tooling, that request bytes reach the device.
|
||||
@@ -427,32 +678,25 @@ static void webusb_pump_frames() {
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
}
|
||||
|
||||
while (s_rx_len >= 4) {
|
||||
s_diag_frames_rx++;
|
||||
uint32_t body_len = read_u32_be(s_rx_buf);
|
||||
if (body_len > (sizeof(s_rx_buf) - 4)) {
|
||||
s_rx_len = 0;
|
||||
send_json_response("{\"error\":{\"code\":-32000,\"message\":\"frame too large\"}}");
|
||||
// display_set_status("Frame too large");
|
||||
return;
|
||||
pump_framed_requests(s_rx_web_buf, &s_rx_web_len, RPC_TRANSPORT_WEBUSB);
|
||||
}
|
||||
|
||||
static void serial_pump_frames() {
|
||||
while (Serial.available() > 0) {
|
||||
if (s_rx_serial_len >= sizeof(s_rx_serial_buf)) {
|
||||
s_rx_serial_len = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (s_rx_len < (size_t)(4 + body_len)) {
|
||||
return;
|
||||
}
|
||||
const int c = Serial.read();
|
||||
if (c < 0) break;
|
||||
s_rx_serial_buf[s_rx_serial_len++] = (uint8_t)c;
|
||||
|
||||
char req[1536];
|
||||
size_t n = body_len;
|
||||
if (n >= sizeof(req)) n = sizeof(req) - 1;
|
||||
memcpy(req, s_rx_buf + 4, n);
|
||||
req[n] = '\0';
|
||||
|
||||
size_t remain = s_rx_len - (4 + body_len);
|
||||
memmove(s_rx_buf, s_rx_buf + 4 + body_len, remain);
|
||||
s_rx_len = remain;
|
||||
|
||||
handle_rpc(req);
|
||||
s_diag_bytes_rx++;
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
}
|
||||
|
||||
pump_framed_requests(s_rx_serial_buf, &s_rx_serial_len, RPC_TRANSPORT_SERIAL);
|
||||
}
|
||||
|
||||
static void signer_enter_menu_screen() {
|
||||
@@ -579,6 +823,24 @@ static void build_entered_mnemonic(char *out, size_t out_sz) {
|
||||
}
|
||||
}
|
||||
|
||||
static void set_device_mode(device_mode_t mode, bool blink_led) {
|
||||
s_mode = mode;
|
||||
|
||||
display_set_mode(s_mode == MODE_SIGNER);
|
||||
if (s_mode == MODE_SIGNER) {
|
||||
display_set_view(DISPLAY_VIEW_SIGNER);
|
||||
signer_enter_menu_screen();
|
||||
// display_set_status("Signer mode");
|
||||
} else {
|
||||
display_set_view(DISPLAY_VIEW_VOLUME);
|
||||
// display_set_status("Media mode");
|
||||
}
|
||||
|
||||
if (blink_led) {
|
||||
led_blink(s_mode == MODE_SIGNER ? 3 : 1, 80, 80);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_mode_switch_chord() {
|
||||
const bool play = btn_pressed(PIN_BTN_PLAY);
|
||||
const bool prev = btn_pressed(PIN_BTN_PREV);
|
||||
@@ -589,19 +851,7 @@ static void handle_mode_switch_chord() {
|
||||
}
|
||||
|
||||
s_mode_switch_latched = true;
|
||||
s_mode = (s_mode == MODE_MEDIA) ? MODE_SIGNER : MODE_MEDIA;
|
||||
|
||||
display_set_mode(s_mode == MODE_SIGNER);
|
||||
if (s_mode == MODE_SIGNER) {
|
||||
display_set_view(DISPLAY_VIEW_SIGNER);
|
||||
signer_enter_menu_screen();
|
||||
// display_set_status("Signer mode");
|
||||
} else {
|
||||
display_set_view(DISPLAY_VIEW_VOLUME);
|
||||
// display_set_status("Media mode");
|
||||
}
|
||||
|
||||
led_blink(s_mode == MODE_SIGNER ? 3 : 1, 80, 80);
|
||||
set_device_mode((s_mode == MODE_MEDIA) ? MODE_SIGNER : MODE_MEDIA, true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -826,6 +1076,12 @@ void setup() {
|
||||
pinMode(PIN_BTN_NEXT, INPUT_PULLUP);
|
||||
pinMode(PIN_BTN_PREV, INPUT_PULLUP);
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
if (nostr_init() != NOSTR_SUCCESS) {
|
||||
// Keep running transport/UI so host can still diagnose, but signing will fail.
|
||||
}
|
||||
|
||||
usb_web.setLandingPage(&landing_url);
|
||||
usb_web.setStringDescriptor("n_signer WebUSB");
|
||||
usb_web.begin();
|
||||
@@ -881,6 +1137,7 @@ void loop() {
|
||||
signer_mode_tick();
|
||||
}
|
||||
|
||||
serial_pump_frames();
|
||||
webusb_pump_frames();
|
||||
|
||||
// DIAG: periodically surface transport activity on the OLED status line so
|
||||
|
||||
3191
firmware/kb2040_hidden_signer/src/cjson/cJSON.c
Normal file
3191
firmware/kb2040_hidden_signer/src/cjson/cJSON.c
Normal file
File diff suppressed because it is too large
Load Diff
306
firmware/kb2040_hidden_signer/src/cjson/cJSON.h
Normal file
306
firmware/kb2040_hidden_signer/src/cjson/cJSON.h
Normal file
@@ -0,0 +1,306 @@
|
||||
/*
|
||||
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef cJSON__h
|
||||
#define cJSON__h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
|
||||
#define __WINDOWS__
|
||||
#endif
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
|
||||
/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options:
|
||||
|
||||
CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
|
||||
CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default)
|
||||
CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol
|
||||
|
||||
For *nix builds that support visibility attribute, you can define similar behavior by
|
||||
|
||||
setting default visibility to hidden by adding
|
||||
-fvisibility=hidden (for gcc)
|
||||
or
|
||||
-xldscope=hidden (for sun cc)
|
||||
to CFLAGS
|
||||
|
||||
then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does
|
||||
|
||||
*/
|
||||
|
||||
#define CJSON_CDECL __cdecl
|
||||
#define CJSON_STDCALL __stdcall
|
||||
|
||||
/* export symbols by default, this is necessary for copy pasting the C and header file */
|
||||
#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS)
|
||||
#define CJSON_EXPORT_SYMBOLS
|
||||
#endif
|
||||
|
||||
#if defined(CJSON_HIDE_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) type CJSON_STDCALL
|
||||
#elif defined(CJSON_EXPORT_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL
|
||||
#elif defined(CJSON_IMPORT_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL
|
||||
#endif
|
||||
#else /* !__WINDOWS__ */
|
||||
#define CJSON_CDECL
|
||||
#define CJSON_STDCALL
|
||||
|
||||
#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)
|
||||
#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type
|
||||
#else
|
||||
#define CJSON_PUBLIC(type) type
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* project version */
|
||||
#define CJSON_VERSION_MAJOR 1
|
||||
#define CJSON_VERSION_MINOR 7
|
||||
#define CJSON_VERSION_PATCH 18
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/* cJSON Types: */
|
||||
#define cJSON_Invalid (0)
|
||||
#define cJSON_False (1 << 0)
|
||||
#define cJSON_True (1 << 1)
|
||||
#define cJSON_NULL (1 << 2)
|
||||
#define cJSON_Number (1 << 3)
|
||||
#define cJSON_String (1 << 4)
|
||||
#define cJSON_Array (1 << 5)
|
||||
#define cJSON_Object (1 << 6)
|
||||
#define cJSON_Raw (1 << 7) /* raw json */
|
||||
|
||||
#define cJSON_IsReference 256
|
||||
#define cJSON_StringIsConst 512
|
||||
|
||||
/* The cJSON structure: */
|
||||
typedef struct cJSON
|
||||
{
|
||||
/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
|
||||
struct cJSON *next;
|
||||
struct cJSON *prev;
|
||||
/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
|
||||
struct cJSON *child;
|
||||
|
||||
/* The type of the item, as above. */
|
||||
int type;
|
||||
|
||||
/* The item's string, if type==cJSON_String and type == cJSON_Raw */
|
||||
char *valuestring;
|
||||
/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
|
||||
int valueint;
|
||||
/* The item's number, if type==cJSON_Number */
|
||||
double valuedouble;
|
||||
|
||||
/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
|
||||
char *string;
|
||||
} cJSON;
|
||||
|
||||
typedef struct cJSON_Hooks
|
||||
{
|
||||
/* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */
|
||||
void *(CJSON_CDECL *malloc_fn)(size_t sz);
|
||||
void (CJSON_CDECL *free_fn)(void *ptr);
|
||||
} cJSON_Hooks;
|
||||
|
||||
typedef int cJSON_bool;
|
||||
|
||||
/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.
|
||||
* This is to prevent stack overflows. */
|
||||
#ifndef CJSON_NESTING_LIMIT
|
||||
#define CJSON_NESTING_LIMIT 1000
|
||||
#endif
|
||||
|
||||
/* Limits the length of circular references can be before cJSON rejects to parse them.
|
||||
* This is to prevent stack overflows. */
|
||||
#ifndef CJSON_CIRCULAR_LIMIT
|
||||
#define CJSON_CIRCULAR_LIMIT 10000
|
||||
#endif
|
||||
|
||||
/* returns the version of cJSON as a string */
|
||||
CJSON_PUBLIC(const char*) cJSON_Version(void);
|
||||
|
||||
/* Supply malloc, realloc and free functions to cJSON */
|
||||
CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
|
||||
|
||||
/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */
|
||||
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length);
|
||||
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
|
||||
/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated);
|
||||
|
||||
/* Render a cJSON entity to text for transfer/storage. */
|
||||
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
|
||||
/* Render a cJSON entity to text for transfer/storage without any formatting. */
|
||||
CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
|
||||
/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
|
||||
CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
|
||||
/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */
|
||||
/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
|
||||
/* Delete a cJSON entity and all subentities. */
|
||||
CJSON_PUBLIC(void) cJSON_Delete(cJSON *item);
|
||||
|
||||
/* Returns the number of items in an array (or object). */
|
||||
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
|
||||
/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
|
||||
/* Get item "string" from object. Case insensitive. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string);
|
||||
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
|
||||
CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
|
||||
|
||||
/* Check item type and return its value */
|
||||
CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item);
|
||||
CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item);
|
||||
|
||||
/* These functions check the type of an item */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item);
|
||||
|
||||
/* These calls create a cJSON item of the appropriate type. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
|
||||
/* raw json */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
|
||||
|
||||
/* Create a string where valuestring references a string so
|
||||
* it will not be freed by cJSON_Delete */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string);
|
||||
/* Create an object/array that only references it's elements so
|
||||
* they will not be freed by cJSON_Delete */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
|
||||
|
||||
/* These utilities create an Array of count items.
|
||||
* The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count);
|
||||
|
||||
/* Append item to the specified array/object. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
|
||||
/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object.
|
||||
* WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before
|
||||
* writing to `item->string` */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
|
||||
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
|
||||
|
||||
/* Remove/Detach items from Arrays/Objects. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);
|
||||
|
||||
/* Update array items. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem);
|
||||
|
||||
/* Duplicate a cJSON item */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse);
|
||||
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
|
||||
* need to be released. With recurse!=0, it will duplicate any children connected to the item.
|
||||
* The item->next and ->prev pointers are always zero on return from Duplicate. */
|
||||
/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal.
|
||||
* case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive);
|
||||
|
||||
/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings.
|
||||
* The input pointer json cannot point to a read-only address area, such as a string constant,
|
||||
* but should point to a readable and writable address area. */
|
||||
CJSON_PUBLIC(void) cJSON_Minify(char *json);
|
||||
|
||||
/* Helper functions for creating and adding items to an object at the same time.
|
||||
* They return the added item or NULL on failure. */
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);
|
||||
|
||||
/* When assigning an integer value, it needs to be propagated to valuedouble too. */
|
||||
#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
|
||||
/* helper for the cJSON_SetNumberValue macro */
|
||||
CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
|
||||
#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
|
||||
/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */
|
||||
CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring);
|
||||
|
||||
/* If the object is not a boolean type this does nothing and returns cJSON_Invalid else it returns the new type*/
|
||||
#define cJSON_SetBoolValue(object, boolValue) ( \
|
||||
(object != NULL && ((object)->type & (cJSON_False|cJSON_True))) ? \
|
||||
(object)->type=((object)->type &(~(cJSON_False|cJSON_True)))|((boolValue)?cJSON_True:cJSON_False) : \
|
||||
cJSON_Invalid\
|
||||
)
|
||||
|
||||
/* Macro for iterating over an array or object */
|
||||
#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)
|
||||
|
||||
/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */
|
||||
CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
|
||||
CJSON_PUBLIC(void) cJSON_free(void *object);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,320 @@
|
||||
#include "../../secp256k1/include/secp256k1.h"
|
||||
#include "../../secp256k1/include/secp256k1_schnorrsig.h"
|
||||
#include "../../secp256k1/include/secp256k1_ecdh.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include "../nostr_platform.h"
|
||||
|
||||
/*
|
||||
* PRIVATE INTERNAL FUNCTIONS - NOT EXPORTED
|
||||
* These functions are for internal library use only.
|
||||
*/
|
||||
|
||||
/** Opaque data structure that holds a parsed and valid public key.
|
||||
* Guaranteed to be 64 bytes in size, and can be safely copied/moved.
|
||||
*/
|
||||
typedef struct nostr_secp256k1_pubkey {
|
||||
unsigned char data[64];
|
||||
} nostr_secp256k1_pubkey;
|
||||
|
||||
/** Opaque data structure that holds a parsed keypair.
|
||||
* Guaranteed to be 96 bytes in size, and can be safely copied/moved.
|
||||
*/
|
||||
typedef struct nostr_secp256k1_keypair {
|
||||
unsigned char data[96];
|
||||
} nostr_secp256k1_keypair;
|
||||
|
||||
/** Opaque data structure that holds a parsed x-only public key.
|
||||
* Guaranteed to be 64 bytes in size, and can be safely copied/moved.
|
||||
*/
|
||||
typedef struct nostr_secp256k1_xonly_pubkey {
|
||||
unsigned char data[64];
|
||||
} nostr_secp256k1_xonly_pubkey;
|
||||
|
||||
// Global context for secp256k1 operations
|
||||
static secp256k1_context* g_ctx = NULL;
|
||||
|
||||
int nostr_secp256k1_context_create(void) {
|
||||
if (g_ctx != NULL) {
|
||||
return 1; // Already initialized
|
||||
}
|
||||
|
||||
g_ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
||||
if (g_ctx == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Add randomization to the context using platform entropy.
|
||||
unsigned char randomize[32];
|
||||
if (nostr_platform_random(randomize, sizeof(randomize)) != 0) {
|
||||
secp256k1_context_destroy(g_ctx);
|
||||
g_ctx = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!secp256k1_context_randomize(g_ctx, randomize)) {
|
||||
secp256k1_context_destroy(g_ctx);
|
||||
g_ctx = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void nostr_secp256k1_context_destroy(void) {
|
||||
if (g_ctx != NULL) {
|
||||
secp256k1_context_destroy(g_ctx);
|
||||
g_ctx = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int nostr_secp256k1_ec_seckey_verify(const unsigned char *seckey) {
|
||||
if (g_ctx == NULL || seckey == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return secp256k1_ec_seckey_verify(g_ctx, seckey);
|
||||
}
|
||||
|
||||
int nostr_secp256k1_ec_pubkey_create(nostr_secp256k1_pubkey *pubkey, const unsigned char *seckey) {
|
||||
if (g_ctx == NULL || pubkey == NULL || seckey == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_pubkey internal_pubkey;
|
||||
if (!secp256k1_ec_pubkey_create(g_ctx, &internal_pubkey, seckey)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Copy the internal representation to our wrapper
|
||||
memcpy(pubkey->data, &internal_pubkey, sizeof(secp256k1_pubkey));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int nostr_secp256k1_keypair_create(nostr_secp256k1_keypair *keypair, const unsigned char *seckey) {
|
||||
if (g_ctx == NULL || keypair == NULL || seckey == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_keypair internal_keypair;
|
||||
if (!secp256k1_keypair_create(g_ctx, &internal_keypair, seckey)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Copy the internal representation to our wrapper
|
||||
memcpy(keypair->data, &internal_keypair, sizeof(secp256k1_keypair));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int nostr_secp256k1_keypair_xonly_pub(nostr_secp256k1_xonly_pubkey *pubkey, const nostr_secp256k1_keypair *keypair) {
|
||||
if (g_ctx == NULL || pubkey == NULL || keypair == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_keypair internal_keypair;
|
||||
secp256k1_xonly_pubkey internal_xonly;
|
||||
|
||||
// Copy from our wrapper to internal representation
|
||||
memcpy(&internal_keypair, keypair->data, sizeof(secp256k1_keypair));
|
||||
|
||||
if (!secp256k1_keypair_xonly_pub(g_ctx, &internal_xonly, NULL, &internal_keypair)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Copy the internal representation to our wrapper
|
||||
memcpy(pubkey->data, &internal_xonly, sizeof(secp256k1_xonly_pubkey));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int nostr_secp256k1_xonly_pubkey_parse(nostr_secp256k1_xonly_pubkey *pubkey, const unsigned char *input32) {
|
||||
if (g_ctx == NULL || pubkey == NULL || input32 == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_xonly_pubkey internal_xonly;
|
||||
if (!secp256k1_xonly_pubkey_parse(g_ctx, &internal_xonly, input32)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Copy the internal representation to our wrapper
|
||||
memcpy(pubkey->data, &internal_xonly, sizeof(secp256k1_xonly_pubkey));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int nostr_secp256k1_xonly_pubkey_serialize(unsigned char *output32, const nostr_secp256k1_xonly_pubkey *pubkey) {
|
||||
if (g_ctx == NULL || output32 == NULL || pubkey == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_xonly_pubkey internal_xonly;
|
||||
|
||||
// Copy from our wrapper to internal representation
|
||||
memcpy(&internal_xonly, pubkey->data, sizeof(secp256k1_xonly_pubkey));
|
||||
|
||||
return secp256k1_xonly_pubkey_serialize(g_ctx, output32, &internal_xonly);
|
||||
}
|
||||
|
||||
int nostr_secp256k1_schnorrsig_sign32(unsigned char *sig64, const unsigned char *msghash32, const nostr_secp256k1_keypair *keypair, const unsigned char *aux_rand32) {
|
||||
if (g_ctx == NULL || sig64 == NULL || msghash32 == NULL || keypair == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_keypair internal_keypair;
|
||||
|
||||
// Copy from our wrapper to internal representation
|
||||
memcpy(&internal_keypair, keypair->data, sizeof(secp256k1_keypair));
|
||||
|
||||
return secp256k1_schnorrsig_sign32(g_ctx, sig64, msghash32, &internal_keypair, aux_rand32);
|
||||
}
|
||||
|
||||
int nostr_secp256k1_schnorrsig_verify(const unsigned char *sig64, const unsigned char *msghash32, const nostr_secp256k1_xonly_pubkey *pubkey) {
|
||||
if (g_ctx == NULL || sig64 == NULL || msghash32 == NULL || pubkey == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_xonly_pubkey internal_xonly;
|
||||
|
||||
// Copy from our wrapper to internal representation
|
||||
memcpy(&internal_xonly, pubkey->data, sizeof(secp256k1_xonly_pubkey));
|
||||
|
||||
return secp256k1_schnorrsig_verify(g_ctx, sig64, msghash32, 32, &internal_xonly);
|
||||
}
|
||||
|
||||
int nostr_secp256k1_ec_pubkey_serialize_compressed(unsigned char *output, const nostr_secp256k1_pubkey *pubkey) {
|
||||
if (g_ctx == NULL || output == NULL || pubkey == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_pubkey internal_pubkey;
|
||||
size_t outputlen = 33;
|
||||
|
||||
// Copy from our wrapper to internal representation
|
||||
memcpy(&internal_pubkey, pubkey->data, sizeof(secp256k1_pubkey));
|
||||
|
||||
return secp256k1_ec_pubkey_serialize(g_ctx, output, &outputlen, &internal_pubkey, SECP256K1_EC_COMPRESSED);
|
||||
}
|
||||
|
||||
int nostr_secp256k1_ec_seckey_tweak_add(unsigned char *seckey, const unsigned char *tweak) {
|
||||
if (g_ctx == NULL || seckey == NULL || tweak == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return secp256k1_ec_seckey_tweak_add(g_ctx, seckey, tweak);
|
||||
}
|
||||
|
||||
int nostr_secp256k1_ec_pubkey_parse(nostr_secp256k1_pubkey *pubkey, const unsigned char *input, size_t inputlen) {
|
||||
if (g_ctx == NULL || pubkey == NULL || input == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_pubkey internal_pubkey;
|
||||
if (!secp256k1_ec_pubkey_parse(g_ctx, &internal_pubkey, input, inputlen)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Copy the internal representation to our wrapper
|
||||
memcpy(pubkey->data, &internal_pubkey, sizeof(secp256k1_pubkey));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int nostr_secp256k1_ecdh(unsigned char *result, const nostr_secp256k1_pubkey *pubkey, const unsigned char *seckey, void *hashfp, void *data) {
|
||||
if (g_ctx == NULL || result == NULL || pubkey == NULL || seckey == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_pubkey internal_pubkey;
|
||||
|
||||
// Copy from our wrapper to internal representation
|
||||
memcpy(&internal_pubkey, pubkey->data, sizeof(secp256k1_pubkey));
|
||||
|
||||
return secp256k1_ecdh(g_ctx, result, &internal_pubkey, seckey, hashfp, data);
|
||||
}
|
||||
|
||||
int nostr_secp256k1_ec_pubkey_tweak_mul(nostr_secp256k1_pubkey* pubkey, const unsigned char* tweak32) {
|
||||
if (g_ctx == NULL || pubkey == NULL || tweak32 == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_pubkey internal_pubkey;
|
||||
memcpy(&internal_pubkey, pubkey->data, sizeof(secp256k1_pubkey));
|
||||
|
||||
if (!secp256k1_ec_pubkey_tweak_mul(g_ctx, &internal_pubkey, tweak32)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(pubkey->data, &internal_pubkey, sizeof(secp256k1_pubkey));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int nostr_secp256k1_ec_pubkey_negate(nostr_secp256k1_pubkey* pubkey) {
|
||||
if (g_ctx == NULL || pubkey == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_pubkey internal_pubkey;
|
||||
memcpy(&internal_pubkey, pubkey->data, sizeof(secp256k1_pubkey));
|
||||
|
||||
if (!secp256k1_ec_pubkey_negate(g_ctx, &internal_pubkey)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(pubkey->data, &internal_pubkey, sizeof(secp256k1_pubkey));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int nostr_secp256k1_ec_pubkey_combine(nostr_secp256k1_pubkey* out,
|
||||
const nostr_secp256k1_pubkey* const* ins,
|
||||
size_t n) {
|
||||
if (g_ctx == NULL || out == NULL || ins == NULL || n == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_pubkey* parsed = (secp256k1_pubkey*)calloc(n, sizeof(secp256k1_pubkey));
|
||||
const secp256k1_pubkey** ptrs = (const secp256k1_pubkey**)calloc(n, sizeof(secp256k1_pubkey*));
|
||||
if (!parsed || !ptrs) {
|
||||
free(parsed);
|
||||
free(ptrs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
if (!ins[i]) {
|
||||
free(parsed);
|
||||
free(ptrs);
|
||||
return 0;
|
||||
}
|
||||
memcpy(&parsed[i], ins[i]->data, sizeof(secp256k1_pubkey));
|
||||
ptrs[i] = &parsed[i];
|
||||
}
|
||||
|
||||
secp256k1_pubkey combined;
|
||||
int ok = secp256k1_ec_pubkey_combine(g_ctx, &combined, ptrs, n);
|
||||
|
||||
free(parsed);
|
||||
free(ptrs);
|
||||
|
||||
if (!ok) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(out->data, &combined, sizeof(secp256k1_pubkey));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int nostr_secp256k1_get_random_bytes(unsigned char *buf, size_t len) {
|
||||
if (buf == NULL || len == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (nostr_platform_random(buf, len) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
345
firmware/kb2040_hidden_signer/src/nostr_core/nip001.c
Normal file
345
firmware/kb2040_hidden_signer/src/nostr_core/nip001.c
Normal file
@@ -0,0 +1,345 @@
|
||||
/*
|
||||
* NOSTR Core Library - NIP-001: Basic Protocol Flow
|
||||
*
|
||||
* Event creation, signing, serialization and core protocol functions
|
||||
*/
|
||||
|
||||
#include "nip001.h"
|
||||
#include "utils.h"
|
||||
#include "../cjson/cJSON.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include "../nostr_core/nostr_common.h"
|
||||
|
||||
// Forward declarations for crypto functions (private API)
|
||||
// These functions are implemented in crypto/ but not exposed through public headers
|
||||
typedef struct {
|
||||
unsigned char data[64];
|
||||
} nostr_secp256k1_xonly_pubkey;
|
||||
|
||||
int nostr_secp256k1_xonly_pubkey_parse(nostr_secp256k1_xonly_pubkey* pubkey, const unsigned char* input32);
|
||||
int nostr_secp256k1_schnorrsig_verify(const unsigned char* sig64, const unsigned char* msg32, const nostr_secp256k1_xonly_pubkey* pubkey);
|
||||
|
||||
// Declare utility functions
|
||||
void nostr_bytes_to_hex(const unsigned char* bytes, size_t len, char* hex);
|
||||
int nostr_hex_to_bytes(const char* hex, unsigned char* bytes, size_t len);
|
||||
int nostr_sha256(const unsigned char* data, size_t len, unsigned char* hash);
|
||||
int nostr_ec_public_key_from_private_key(const unsigned char* private_key, unsigned char* public_key);
|
||||
int nostr_ec_sign(const unsigned char* private_key, const unsigned char* hash, unsigned char* signature);
|
||||
|
||||
/**
|
||||
* Create and sign a NOSTR event
|
||||
*/
|
||||
cJSON* nostr_create_and_sign_event(int kind, const char* content, cJSON* tags, const unsigned char* private_key, time_t timestamp) {
|
||||
if (!private_key) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!content) {
|
||||
content = ""; // Default to empty content
|
||||
}
|
||||
|
||||
// Convert private key to public key
|
||||
unsigned char public_key[32];
|
||||
if (nostr_ec_public_key_from_private_key(private_key, public_key) != 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Convert public key to hex
|
||||
char pubkey_hex[65];
|
||||
nostr_bytes_to_hex(public_key, 32, pubkey_hex);
|
||||
|
||||
// Create event structure
|
||||
cJSON* event = cJSON_CreateObject();
|
||||
if (!event) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Use provided timestamp or current time if timestamp is 0
|
||||
time_t event_time = (timestamp == 0) ? time(NULL) : timestamp;
|
||||
|
||||
cJSON_AddStringToObject(event, "pubkey", pubkey_hex);
|
||||
cJSON_AddNumberToObject(event, "created_at", (double)event_time);
|
||||
cJSON_AddNumberToObject(event, "kind", kind);
|
||||
|
||||
// Add tags (copy provided tags or create empty array)
|
||||
if (tags) {
|
||||
cJSON_AddItemToObject(event, "tags", cJSON_Duplicate(tags, 1));
|
||||
} else {
|
||||
cJSON_AddItemToObject(event, "tags", cJSON_CreateArray());
|
||||
}
|
||||
|
||||
cJSON_AddStringToObject(event, "content", content);
|
||||
|
||||
// ============================================================================
|
||||
// INLINE SERIALIZATION AND SIGNING LOGIC
|
||||
// ============================================================================
|
||||
|
||||
// Get event fields for serialization
|
||||
cJSON* pubkey_item = cJSON_GetObjectItem(event, "pubkey");
|
||||
cJSON* created_at_item = cJSON_GetObjectItem(event, "created_at");
|
||||
cJSON* kind_item = cJSON_GetObjectItem(event, "kind");
|
||||
cJSON* tags_item = cJSON_GetObjectItem(event, "tags");
|
||||
cJSON* content_item = cJSON_GetObjectItem(event, "content");
|
||||
|
||||
if (!pubkey_item || !created_at_item || !kind_item || !tags_item || !content_item) {
|
||||
cJSON_Delete(event);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Create serialization array: [0, pubkey, created_at, kind, tags, content]
|
||||
cJSON* serialize_array = cJSON_CreateArray();
|
||||
if (!serialize_array) {
|
||||
cJSON_Delete(event);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cJSON_AddItemToArray(serialize_array, cJSON_CreateNumber(0));
|
||||
cJSON_AddItemToArray(serialize_array, cJSON_Duplicate(pubkey_item, 1));
|
||||
cJSON_AddItemToArray(serialize_array, cJSON_Duplicate(created_at_item, 1));
|
||||
cJSON_AddItemToArray(serialize_array, cJSON_Duplicate(kind_item, 1));
|
||||
cJSON_AddItemToArray(serialize_array, cJSON_Duplicate(tags_item, 1));
|
||||
cJSON_AddItemToArray(serialize_array, cJSON_Duplicate(content_item, 1));
|
||||
|
||||
char* serialize_string = cJSON_PrintUnformatted(serialize_array);
|
||||
cJSON_Delete(serialize_array);
|
||||
|
||||
if (!serialize_string) {
|
||||
cJSON_Delete(event);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Hash the serialized event
|
||||
unsigned char event_hash[32];
|
||||
if (nostr_sha256((const unsigned char*)serialize_string, strlen(serialize_string), event_hash) != 0) {
|
||||
free(serialize_string);
|
||||
cJSON_Delete(event);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Convert hash to hex for event ID
|
||||
char event_id[65];
|
||||
nostr_bytes_to_hex(event_hash, 32, event_id);
|
||||
|
||||
// Sign the hash using ECDSA
|
||||
unsigned char signature[64];
|
||||
if (nostr_ec_sign(private_key, event_hash, signature) != 0) {
|
||||
free(serialize_string);
|
||||
cJSON_Delete(event);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Convert signature to hex
|
||||
char sig_hex[129];
|
||||
nostr_bytes_to_hex(signature, 64, sig_hex);
|
||||
|
||||
// Add ID and signature to the event
|
||||
cJSON_AddStringToObject(event, "id", event_id);
|
||||
cJSON_AddStringToObject(event, "sig", sig_hex);
|
||||
|
||||
free(serialize_string);
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the structure of a NOSTR event
|
||||
* Checks required fields, types, and basic format validation
|
||||
*/
|
||||
int nostr_validate_event_structure(cJSON* event) {
|
||||
if (!event || !cJSON_IsObject(event)) {
|
||||
return NOSTR_ERROR_EVENT_INVALID_STRUCTURE;
|
||||
}
|
||||
|
||||
// Check required fields exist
|
||||
cJSON* id_item = cJSON_GetObjectItem(event, "id");
|
||||
cJSON* pubkey_item = cJSON_GetObjectItem(event, "pubkey");
|
||||
cJSON* created_at_item = cJSON_GetObjectItem(event, "created_at");
|
||||
cJSON* kind_item = cJSON_GetObjectItem(event, "kind");
|
||||
cJSON* tags_item = cJSON_GetObjectItem(event, "tags");
|
||||
cJSON* content_item = cJSON_GetObjectItem(event, "content");
|
||||
cJSON* sig_item = cJSON_GetObjectItem(event, "sig");
|
||||
|
||||
if (!id_item || !pubkey_item || !created_at_item || !kind_item ||
|
||||
!tags_item || !content_item || !sig_item) {
|
||||
return NOSTR_ERROR_EVENT_INVALID_STRUCTURE;
|
||||
}
|
||||
|
||||
// Validate field types
|
||||
if (!cJSON_IsString(id_item)) return NOSTR_ERROR_EVENT_INVALID_ID;
|
||||
if (!cJSON_IsString(pubkey_item)) return NOSTR_ERROR_EVENT_INVALID_PUBKEY;
|
||||
if (!cJSON_IsNumber(created_at_item)) return NOSTR_ERROR_EVENT_INVALID_CREATED_AT;
|
||||
if (!cJSON_IsNumber(kind_item)) return NOSTR_ERROR_EVENT_INVALID_KIND;
|
||||
if (!cJSON_IsArray(tags_item)) return NOSTR_ERROR_EVENT_INVALID_TAGS;
|
||||
if (!cJSON_IsString(content_item)) return NOSTR_ERROR_EVENT_INVALID_CONTENT;
|
||||
if (!cJSON_IsString(sig_item)) return NOSTR_ERROR_EVENT_INVALID_SIGNATURE;
|
||||
|
||||
// Validate hex string lengths
|
||||
const char* id_str = cJSON_GetStringValue(id_item);
|
||||
const char* pubkey_str = cJSON_GetStringValue(pubkey_item);
|
||||
const char* sig_str = cJSON_GetStringValue(sig_item);
|
||||
|
||||
if (!id_str || strlen(id_str) != 64) return NOSTR_ERROR_EVENT_INVALID_ID;
|
||||
if (!pubkey_str || strlen(pubkey_str) != 64) return NOSTR_ERROR_EVENT_INVALID_PUBKEY;
|
||||
if (!sig_str || strlen(sig_str) != 128) return NOSTR_ERROR_EVENT_INVALID_SIGNATURE;
|
||||
|
||||
// Validate hex characters (lowercase)
|
||||
for (int i = 0; i < 64; i++) {
|
||||
char c = id_str[i];
|
||||
if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'))) {
|
||||
return NOSTR_ERROR_EVENT_INVALID_ID;
|
||||
}
|
||||
c = pubkey_str[i];
|
||||
if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'))) {
|
||||
return NOSTR_ERROR_EVENT_INVALID_PUBKEY;
|
||||
}
|
||||
}
|
||||
|
||||
// Validate signature hex characters (lowercase) - 128 characters
|
||||
for (int i = 0; i < 128; i++) {
|
||||
char c = sig_str[i];
|
||||
if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'))) {
|
||||
return NOSTR_ERROR_EVENT_INVALID_SIGNATURE;
|
||||
}
|
||||
}
|
||||
|
||||
// Validate created_at is a valid timestamp (positive number)
|
||||
double created_at = cJSON_GetNumberValue(created_at_item);
|
||||
if (created_at < 0) return NOSTR_ERROR_EVENT_INVALID_CREATED_AT;
|
||||
|
||||
// Validate kind is valid (0-65535)
|
||||
double kind = cJSON_GetNumberValue(kind_item);
|
||||
if (kind < 0 || kind > 65535 || kind != (int)kind) {
|
||||
return NOSTR_ERROR_EVENT_INVALID_KIND;
|
||||
}
|
||||
|
||||
// Validate tags array structure (array of arrays of strings)
|
||||
cJSON* tag_item;
|
||||
cJSON_ArrayForEach(tag_item, tags_item) {
|
||||
if (!cJSON_IsArray(tag_item)) {
|
||||
return NOSTR_ERROR_EVENT_INVALID_TAGS;
|
||||
}
|
||||
cJSON* tag_element;
|
||||
cJSON_ArrayForEach(tag_element, tag_item) {
|
||||
if (!cJSON_IsString(tag_element)) {
|
||||
return NOSTR_ERROR_EVENT_INVALID_TAGS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NOSTR_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the cryptographic signature of a NOSTR event
|
||||
* Validates event ID and signature according to NIP-01
|
||||
*/
|
||||
int nostr_verify_event_signature(cJSON* event) {
|
||||
if (!event) {
|
||||
return NOSTR_ERROR_INVALID_INPUT;
|
||||
}
|
||||
|
||||
// Get event fields
|
||||
cJSON* id_item = cJSON_GetObjectItem(event, "id");
|
||||
cJSON* pubkey_item = cJSON_GetObjectItem(event, "pubkey");
|
||||
cJSON* created_at_item = cJSON_GetObjectItem(event, "created_at");
|
||||
cJSON* kind_item = cJSON_GetObjectItem(event, "kind");
|
||||
cJSON* tags_item = cJSON_GetObjectItem(event, "tags");
|
||||
cJSON* content_item = cJSON_GetObjectItem(event, "content");
|
||||
cJSON* sig_item = cJSON_GetObjectItem(event, "sig");
|
||||
|
||||
if (!id_item || !pubkey_item || !created_at_item || !kind_item ||
|
||||
!tags_item || !content_item || !sig_item) {
|
||||
return NOSTR_ERROR_EVENT_INVALID_STRUCTURE;
|
||||
}
|
||||
|
||||
// Create serialization array: [0, pubkey, created_at, kind, tags, content]
|
||||
cJSON* serialize_array = cJSON_CreateArray();
|
||||
if (!serialize_array) {
|
||||
return NOSTR_ERROR_MEMORY_FAILED;
|
||||
}
|
||||
|
||||
cJSON_AddItemToArray(serialize_array, cJSON_CreateNumber(0));
|
||||
cJSON_AddItemToArray(serialize_array, cJSON_Duplicate(pubkey_item, 1));
|
||||
cJSON_AddItemToArray(serialize_array, cJSON_Duplicate(created_at_item, 1));
|
||||
cJSON_AddItemToArray(serialize_array, cJSON_Duplicate(kind_item, 1));
|
||||
cJSON_AddItemToArray(serialize_array, cJSON_Duplicate(tags_item, 1));
|
||||
cJSON_AddItemToArray(serialize_array, cJSON_Duplicate(content_item, 1));
|
||||
|
||||
char* serialize_string = cJSON_PrintUnformatted(serialize_array);
|
||||
cJSON_Delete(serialize_array);
|
||||
|
||||
if (!serialize_string) {
|
||||
return NOSTR_ERROR_MEMORY_FAILED;
|
||||
}
|
||||
|
||||
// Hash the serialized event
|
||||
unsigned char event_hash[32];
|
||||
if (nostr_sha256((const unsigned char*)serialize_string, strlen(serialize_string), event_hash) != 0) {
|
||||
free(serialize_string);
|
||||
return NOSTR_ERROR_CRYPTO_FAILED;
|
||||
}
|
||||
|
||||
// Convert hash to hex for event ID verification
|
||||
char calculated_id[65];
|
||||
nostr_bytes_to_hex(event_hash, 32, calculated_id);
|
||||
|
||||
// Compare with provided event ID
|
||||
const char* provided_id = cJSON_GetStringValue(id_item);
|
||||
if (!provided_id || strcmp(calculated_id, provided_id) != 0) {
|
||||
free(serialize_string);
|
||||
return NOSTR_ERROR_EVENT_INVALID_ID;
|
||||
}
|
||||
|
||||
// Verify signature
|
||||
const char* pubkey_str = cJSON_GetStringValue(pubkey_item);
|
||||
const char* sig_str = cJSON_GetStringValue(sig_item);
|
||||
|
||||
if (!pubkey_str || !sig_str) {
|
||||
free(serialize_string);
|
||||
return NOSTR_ERROR_EVENT_INVALID_STRUCTURE;
|
||||
}
|
||||
|
||||
// Convert hex strings to bytes
|
||||
unsigned char pubkey_bytes[32];
|
||||
unsigned char sig_bytes[64];
|
||||
|
||||
if (nostr_hex_to_bytes(pubkey_str, pubkey_bytes, 32) != 0 ||
|
||||
nostr_hex_to_bytes(sig_str, sig_bytes, 64) != 0) {
|
||||
free(serialize_string);
|
||||
return NOSTR_ERROR_CRYPTO_FAILED;
|
||||
}
|
||||
|
||||
// Parse the public key into secp256k1 format
|
||||
nostr_secp256k1_xonly_pubkey xonly_pubkey;
|
||||
if (!nostr_secp256k1_xonly_pubkey_parse(&xonly_pubkey, pubkey_bytes)) {
|
||||
free(serialize_string);
|
||||
return NOSTR_ERROR_EVENT_INVALID_PUBKEY;
|
||||
}
|
||||
|
||||
// Verify Schnorr signature
|
||||
if (!nostr_secp256k1_schnorrsig_verify(sig_bytes, event_hash, &xonly_pubkey)) {
|
||||
free(serialize_string);
|
||||
return NOSTR_ERROR_EVENT_INVALID_SIGNATURE;
|
||||
}
|
||||
|
||||
free(serialize_string);
|
||||
return NOSTR_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete validation of a NOSTR event
|
||||
* Performs both structure and cryptographic validation
|
||||
*/
|
||||
int nostr_validate_event(cJSON* event) {
|
||||
// First validate structure (fast check)
|
||||
int structure_result = nostr_validate_event_structure(event);
|
||||
if (structure_result != NOSTR_SUCCESS) {
|
||||
return structure_result;
|
||||
}
|
||||
|
||||
// Then verify signature (expensive check)
|
||||
return nostr_verify_event_signature(event);
|
||||
}
|
||||
23
firmware/kb2040_hidden_signer/src/nostr_core/nip001.h
Normal file
23
firmware/kb2040_hidden_signer/src/nostr_core/nip001.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* NOSTR Core Library - NIP-001: Basic Protocol Flow
|
||||
*
|
||||
* Event creation, signing, serialization and core protocol functions
|
||||
*/
|
||||
|
||||
#ifndef NIP001_H
|
||||
#define NIP001_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
#include "../cjson/cJSON.h"
|
||||
|
||||
|
||||
// Function declarations
|
||||
cJSON* nostr_create_and_sign_event(int kind, const char* content, cJSON* tags, const unsigned char* private_key, time_t timestamp);
|
||||
|
||||
// Event validation functions
|
||||
int nostr_validate_event_structure(cJSON* event);
|
||||
int nostr_verify_event_signature(cJSON* event);
|
||||
int nostr_validate_event(cJSON* event);
|
||||
|
||||
#endif // NIP001_H
|
||||
104
firmware/kb2040_hidden_signer/src/nostr_core/nip006.c
Normal file
104
firmware/kb2040_hidden_signer/src/nostr_core/nip006.c
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* NOSTR Core Library - NIP-006: Key Derivation from Mnemonic
|
||||
*/
|
||||
|
||||
#include "nip006.h"
|
||||
#include "utils.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
#include "../nostr_core/nostr_common.h"
|
||||
#include "nostr_platform.h"
|
||||
|
||||
int nostr_generate_keypair(unsigned char* private_key, unsigned char* public_key) {
|
||||
if (!private_key || !public_key) {
|
||||
return NOSTR_ERROR_INVALID_INPUT;
|
||||
}
|
||||
|
||||
if (nostr_platform_random(private_key, 32) != 0) {
|
||||
return NOSTR_ERROR_IO_FAILED;
|
||||
}
|
||||
|
||||
// Validate private key
|
||||
if (nostr_ec_private_key_verify(private_key) != 0) {
|
||||
return NOSTR_ERROR_CRYPTO_FAILED;
|
||||
}
|
||||
|
||||
// Generate public key from private key (already x-only for NOSTR)
|
||||
if (nostr_ec_public_key_from_private_key(private_key, public_key) != 0) {
|
||||
return NOSTR_ERROR_CRYPTO_FAILED;
|
||||
}
|
||||
|
||||
return NOSTR_SUCCESS;
|
||||
}
|
||||
|
||||
int nostr_generate_mnemonic_and_keys(char* mnemonic, size_t mnemonic_size,
|
||||
int account, unsigned char* private_key,
|
||||
unsigned char* public_key) {
|
||||
if (!mnemonic || mnemonic_size < 256 || !private_key || !public_key) {
|
||||
return NOSTR_ERROR_INVALID_INPUT;
|
||||
}
|
||||
|
||||
// Generate entropy for 12-word mnemonic
|
||||
unsigned char entropy[16];
|
||||
if (nostr_platform_random(entropy, sizeof(entropy)) != 0) {
|
||||
return NOSTR_ERROR_IO_FAILED;
|
||||
}
|
||||
|
||||
// Generate mnemonic from entropy
|
||||
if (nostr_bip39_mnemonic_from_bytes(entropy, sizeof(entropy), mnemonic) != 0) {
|
||||
return NOSTR_ERROR_CRYPTO_FAILED;
|
||||
}
|
||||
|
||||
// Derive keys from the generated mnemonic
|
||||
return nostr_derive_keys_from_mnemonic(mnemonic, account, private_key, public_key);
|
||||
}
|
||||
|
||||
int nostr_derive_keys_from_mnemonic(const char* mnemonic, int account,
|
||||
unsigned char* private_key, unsigned char* public_key) {
|
||||
if (!mnemonic || !private_key || !public_key) {
|
||||
return NOSTR_ERROR_INVALID_INPUT;
|
||||
}
|
||||
|
||||
// Validate mnemonic
|
||||
if (nostr_bip39_mnemonic_validate(mnemonic) != 0) {
|
||||
return NOSTR_ERROR_INVALID_INPUT;
|
||||
}
|
||||
|
||||
// Convert mnemonic to seed
|
||||
unsigned char seed[64];
|
||||
if (nostr_bip39_mnemonic_to_seed(mnemonic, "", seed, sizeof(seed)) != 0) {
|
||||
return NOSTR_ERROR_CRYPTO_FAILED;
|
||||
}
|
||||
|
||||
// Derive master key from seed
|
||||
nostr_hd_key_t master_key;
|
||||
if (nostr_bip32_key_from_seed(seed, sizeof(seed), &master_key) != 0) {
|
||||
return NOSTR_ERROR_CRYPTO_FAILED;
|
||||
}
|
||||
|
||||
// NIP-06 path: m/44'/1237'/account'/0/0
|
||||
nostr_hd_key_t derived_key;
|
||||
uint32_t path[] = {
|
||||
0x80000000 + 44, // 44' (hardened)
|
||||
0x80000000 + 1237, // 1237' (hardened)
|
||||
0x80000000 + account, // account' (hardened)
|
||||
0, // 0 (not hardened)
|
||||
0 // 0 (not hardened)
|
||||
};
|
||||
|
||||
if (nostr_bip32_derive_path(&master_key, path, sizeof(path) / sizeof(path[0]), &derived_key) != 0) {
|
||||
return NOSTR_ERROR_CRYPTO_FAILED;
|
||||
}
|
||||
|
||||
// Extract private key and public key
|
||||
memcpy(private_key, derived_key.private_key, 32);
|
||||
memcpy(public_key, derived_key.public_key + 1, 32); // Remove compression prefix for x-only
|
||||
|
||||
return NOSTR_SUCCESS;
|
||||
}
|
||||
|
||||
// Note: nostr_detect_input_type, nostr_decode_nsec, and nostr_decode_npub
|
||||
// are implemented in NIP-019 to avoid multiple definitions
|
||||
30
firmware/kb2040_hidden_signer/src/nostr_core/nip006.h
Normal file
30
firmware/kb2040_hidden_signer/src/nostr_core/nip006.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* NOSTR Core Library - NIP-006: Key Derivation from Mnemonic
|
||||
*/
|
||||
|
||||
#ifndef NIP006_H
|
||||
#define NIP006_H
|
||||
|
||||
#include "nip001.h"
|
||||
#include <stdint.h>
|
||||
|
||||
// Input type detection
|
||||
typedef enum {
|
||||
NOSTR_INPUT_UNKNOWN = 0,
|
||||
NOSTR_INPUT_NSEC_HEX,
|
||||
NOSTR_INPUT_NSEC_BECH32,
|
||||
NOSTR_INPUT_MNEMONIC
|
||||
} nostr_input_type_t;
|
||||
|
||||
// Function declarations
|
||||
int nostr_generate_keypair(unsigned char* private_key, unsigned char* public_key);
|
||||
int nostr_generate_mnemonic_and_keys(char* mnemonic, size_t mnemonic_size,
|
||||
int account, unsigned char* private_key,
|
||||
unsigned char* public_key);
|
||||
int nostr_derive_keys_from_mnemonic(const char* mnemonic, int account,
|
||||
unsigned char* private_key, unsigned char* public_key);
|
||||
nostr_input_type_t nostr_detect_input_type(const char* input);
|
||||
int nostr_decode_nsec(const char* input, unsigned char* private_key);
|
||||
int nostr_decode_npub(const char* input, unsigned char* public_key);
|
||||
|
||||
#endif // NIP006_H
|
||||
265
firmware/kb2040_hidden_signer/src/nostr_core/nip019.c
Normal file
265
firmware/kb2040_hidden_signer/src/nostr_core/nip019.c
Normal file
@@ -0,0 +1,265 @@
|
||||
/*
|
||||
* NOSTR Core Library - NIP-019: Bech32-encoded Entities
|
||||
*/
|
||||
|
||||
#include "nip019.h"
|
||||
#include "utils.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "../nostr_core/nostr_common.h"
|
||||
|
||||
#define BECH32_CONST 1
|
||||
|
||||
static const char bech32_charset[] = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
|
||||
|
||||
static const int8_t bech32_charset_rev[128] = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1,
|
||||
-1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
|
||||
1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1,
|
||||
-1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1,
|
||||
1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1
|
||||
};
|
||||
|
||||
static uint32_t bech32_polymod_step(uint32_t pre) {
|
||||
uint8_t b = pre >> 25;
|
||||
return ((pre & 0x1FFFFFF) << 5) ^
|
||||
(-((b >> 0) & 1) & 0x3b6a57b2UL) ^
|
||||
(-((b >> 1) & 1) & 0x26508e6dUL) ^
|
||||
(-((b >> 2) & 1) & 0x1ea119faUL) ^
|
||||
(-((b >> 3) & 1) & 0x3d4233ddUL) ^
|
||||
(-((b >> 4) & 1) & 0x2a1462b3UL);
|
||||
}
|
||||
|
||||
static int convert_bits(uint8_t *out, size_t *outlen, int outbits, const uint8_t *in, size_t inlen, int inbits, int pad) {
|
||||
uint32_t val = 0;
|
||||
int bits = 0;
|
||||
uint32_t maxv = (((uint32_t)1) << outbits) - 1;
|
||||
*outlen = 0;
|
||||
while (inlen--) {
|
||||
val = (val << inbits) | *(in++);
|
||||
bits += inbits;
|
||||
while (bits >= outbits) {
|
||||
bits -= outbits;
|
||||
out[(*outlen)++] = (val >> bits) & maxv;
|
||||
}
|
||||
}
|
||||
if (pad) {
|
||||
if (bits) {
|
||||
out[(*outlen)++] = (val << (outbits - bits)) & maxv;
|
||||
}
|
||||
} else if (((val << (outbits - bits)) & maxv) || bits >= inbits) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int bech32_encode(char *output, const char *hrp, const uint8_t *data, size_t data_len) {
|
||||
uint32_t chk = 1;
|
||||
size_t i, hrp_len = strlen(hrp);
|
||||
|
||||
for (i = 0; i < hrp_len; ++i) {
|
||||
int ch = hrp[i];
|
||||
if (ch < 33 || ch > 126) return 0;
|
||||
if (ch >= 'A' && ch <= 'Z') return 0;
|
||||
chk = bech32_polymod_step(chk) ^ (ch >> 5);
|
||||
}
|
||||
|
||||
chk = bech32_polymod_step(chk);
|
||||
for (i = 0; i < hrp_len; ++i) {
|
||||
chk = bech32_polymod_step(chk) ^ (hrp[i] & 0x1f);
|
||||
*(output++) = hrp[i];
|
||||
}
|
||||
|
||||
*(output++) = '1';
|
||||
for (i = 0; i < data_len; ++i) {
|
||||
if (*data >> 5) return 0;
|
||||
chk = bech32_polymod_step(chk) ^ (*data);
|
||||
*(output++) = bech32_charset[*(data++)];
|
||||
}
|
||||
|
||||
for (i = 0; i < 6; ++i) {
|
||||
chk = bech32_polymod_step(chk);
|
||||
}
|
||||
|
||||
chk ^= BECH32_CONST;
|
||||
for (i = 0; i < 6; ++i) {
|
||||
*(output++) = bech32_charset[(chk >> ((5 - i) * 5)) & 0x1f];
|
||||
}
|
||||
|
||||
*output = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int bech32_decode(const char* input, const char* hrp, unsigned char* data, size_t* data_len) {
|
||||
if (!input || !hrp || !data || !data_len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t input_len = strlen(input);
|
||||
size_t hrp_len = strlen(hrp);
|
||||
|
||||
if (input_len < hrp_len + 7) return 0;
|
||||
if (strncmp(input, hrp, hrp_len) != 0) return 0;
|
||||
if (input[hrp_len] != '1') return 0;
|
||||
|
||||
const char* data_part = input + hrp_len + 1;
|
||||
size_t data_part_len = input_len - hrp_len - 1;
|
||||
|
||||
uint8_t values[256];
|
||||
for (size_t i = 0; i < data_part_len; i++) {
|
||||
unsigned char c = (unsigned char)data_part[i];
|
||||
if (c >= 128) return 0;
|
||||
int8_t val = bech32_charset_rev[c];
|
||||
if (val == -1) return 0;
|
||||
values[i] = (uint8_t)val;
|
||||
}
|
||||
|
||||
if (data_part_len < 6) return 0;
|
||||
|
||||
uint32_t chk = 1;
|
||||
for (size_t i = 0; i < hrp_len; i++) {
|
||||
chk = bech32_polymod_step(chk) ^ (hrp[i] >> 5);
|
||||
}
|
||||
chk = bech32_polymod_step(chk);
|
||||
for (size_t i = 0; i < hrp_len; i++) {
|
||||
chk = bech32_polymod_step(chk) ^ (hrp[i] & 0x1f);
|
||||
}
|
||||
for (size_t i = 0; i < data_part_len; i++) {
|
||||
chk = bech32_polymod_step(chk) ^ values[i];
|
||||
}
|
||||
|
||||
if (chk != BECH32_CONST) return 0;
|
||||
|
||||
size_t payload_len = data_part_len - 6;
|
||||
size_t decoded_len;
|
||||
if (!convert_bits(data, &decoded_len, 8, values, payload_len, 5, 0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*data_len = decoded_len;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int nostr_key_to_bech32(const unsigned char* key, const char* hrp, char* output) {
|
||||
if (!key || !hrp || !output) {
|
||||
return NOSTR_ERROR_INVALID_INPUT;
|
||||
}
|
||||
|
||||
uint8_t conv[64];
|
||||
size_t conv_len;
|
||||
|
||||
if (!convert_bits(conv, &conv_len, 5, key, 32, 8, 1)) {
|
||||
return NOSTR_ERROR_CRYPTO_FAILED;
|
||||
}
|
||||
|
||||
if (!bech32_encode(output, hrp, conv, conv_len)) {
|
||||
return NOSTR_ERROR_CRYPTO_FAILED;
|
||||
}
|
||||
|
||||
return NOSTR_SUCCESS;
|
||||
}
|
||||
|
||||
nostr_input_type_t nostr_detect_input_type(const char* input) {
|
||||
if (!input || strlen(input) == 0) {
|
||||
return NOSTR_INPUT_UNKNOWN;
|
||||
}
|
||||
|
||||
size_t len = strlen(input);
|
||||
|
||||
// Check for bech32 nsec
|
||||
if (len > 5 && strncmp(input, "nsec1", 5) == 0) {
|
||||
return NOSTR_INPUT_NSEC_BECH32;
|
||||
}
|
||||
|
||||
// Check for hex nsec (64 characters, all hex)
|
||||
if (len == 64) {
|
||||
int is_hex = 1;
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
if (!isxdigit((unsigned char)input[i])) {
|
||||
is_hex = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (is_hex) {
|
||||
return NOSTR_INPUT_NSEC_HEX;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for mnemonic (space-separated words)
|
||||
int word_count = 0;
|
||||
char temp[1024];
|
||||
strncpy(temp, input, sizeof(temp) - 1);
|
||||
temp[sizeof(temp) - 1] = '\0';
|
||||
|
||||
char* token = strtok(temp, " ");
|
||||
while (token != NULL) {
|
||||
word_count++;
|
||||
token = strtok(NULL, " ");
|
||||
}
|
||||
|
||||
// BIP39 mnemonics are typically 12, 18, or 24 words
|
||||
if (word_count >= 12 && word_count <= 24) {
|
||||
return NOSTR_INPUT_MNEMONIC;
|
||||
}
|
||||
|
||||
return NOSTR_INPUT_UNKNOWN;
|
||||
}
|
||||
|
||||
int nostr_decode_nsec(const char* input, unsigned char* private_key) {
|
||||
if (!input || !private_key) {
|
||||
return NOSTR_ERROR_INVALID_INPUT;
|
||||
}
|
||||
|
||||
nostr_input_type_t type = nostr_detect_input_type(input);
|
||||
|
||||
if (type == NOSTR_INPUT_NSEC_HEX) {
|
||||
if (nostr_hex_to_bytes(input, private_key, 32) != NOSTR_SUCCESS) {
|
||||
return NOSTR_ERROR_INVALID_INPUT;
|
||||
}
|
||||
} else if (type == NOSTR_INPUT_NSEC_BECH32) {
|
||||
size_t decoded_len;
|
||||
if (!bech32_decode(input, "nsec", private_key, &decoded_len)) {
|
||||
return NOSTR_ERROR_INVALID_INPUT;
|
||||
}
|
||||
if (decoded_len != 32) {
|
||||
return NOSTR_ERROR_INVALID_INPUT;
|
||||
}
|
||||
} else {
|
||||
return NOSTR_ERROR_INVALID_INPUT;
|
||||
}
|
||||
|
||||
// TODO: Add private key validation if crypto functions are available
|
||||
|
||||
return NOSTR_SUCCESS;
|
||||
}
|
||||
|
||||
int nostr_decode_npub(const char* input, unsigned char* public_key) {
|
||||
if (!input || !public_key) {
|
||||
return NOSTR_ERROR_INVALID_INPUT;
|
||||
}
|
||||
|
||||
nostr_input_type_t type = nostr_detect_input_type(input);
|
||||
|
||||
if (type == NOSTR_INPUT_NSEC_HEX) { // Actually public key hex
|
||||
if (nostr_hex_to_bytes(input, public_key, 32) != NOSTR_SUCCESS) {
|
||||
return NOSTR_ERROR_INVALID_INPUT;
|
||||
}
|
||||
} else if (strncmp(input, "npub1", 4) == 0) { // Bech32 npub
|
||||
size_t decoded_len;
|
||||
if (!bech32_decode(input, "npub", public_key, &decoded_len)) {
|
||||
return NOSTR_ERROR_INVALID_INPUT;
|
||||
}
|
||||
if (decoded_len != 32) {
|
||||
return NOSTR_ERROR_INVALID_INPUT;
|
||||
}
|
||||
} else {
|
||||
return NOSTR_ERROR_INVALID_INPUT;
|
||||
}
|
||||
|
||||
return NOSTR_SUCCESS;
|
||||
}
|
||||
17
firmware/kb2040_hidden_signer/src/nostr_core/nip019.h
Normal file
17
firmware/kb2040_hidden_signer/src/nostr_core/nip019.h
Normal file
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* NOSTR Core Library - NIP-019: Bech32-encoded Entities
|
||||
*/
|
||||
|
||||
#ifndef NIP019_H
|
||||
#define NIP019_H
|
||||
|
||||
#include "nip001.h"
|
||||
#include "nip006.h" // For nostr_input_type_t enum
|
||||
|
||||
// Function declarations
|
||||
int nostr_key_to_bech32(const unsigned char* key, const char* hrp, char* output);
|
||||
nostr_input_type_t nostr_detect_input_type(const char* input);
|
||||
int nostr_decode_nsec(const char* input, unsigned char* private_key);
|
||||
int nostr_decode_npub(const char* input, unsigned char* public_key);
|
||||
|
||||
#endif // NIP019_H
|
||||
106
firmware/kb2040_hidden_signer/src/nostr_core/nostr_common.c
Normal file
106
firmware/kb2040_hidden_signer/src/nostr_core/nostr_common.c
Normal file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* NOSTR Core Library - Common Utilities
|
||||
*
|
||||
* Common functions and utilities shared across the library
|
||||
*/
|
||||
|
||||
#include "nostr_common.h"
|
||||
#include "utils.h"
|
||||
|
||||
/**
|
||||
* Convert error code to human-readable string
|
||||
* Handles all error codes defined in nostr_common.h
|
||||
*/
|
||||
const char* nostr_strerror(int error_code) {
|
||||
switch (error_code) {
|
||||
case NOSTR_SUCCESS: return "Success";
|
||||
case NOSTR_ERROR_INVALID_INPUT: return "Invalid input";
|
||||
case NOSTR_ERROR_CRYPTO_FAILED: return "Cryptographic operation failed";
|
||||
case NOSTR_ERROR_MEMORY_FAILED: return "Memory allocation failed";
|
||||
case NOSTR_ERROR_IO_FAILED: return "I/O operation failed";
|
||||
case NOSTR_ERROR_NETWORK_FAILED: return "Network operation failed";
|
||||
case NOSTR_ERROR_NIP04_INVALID_FORMAT: return "NIP-04 invalid format";
|
||||
case NOSTR_ERROR_NIP04_DECRYPT_FAILED: return "NIP-04 decryption failed";
|
||||
case NOSTR_ERROR_NIP04_BUFFER_TOO_SMALL: return "NIP-04 buffer too small";
|
||||
case NOSTR_ERROR_NIP44_INVALID_FORMAT: return "NIP-44: Invalid format";
|
||||
case NOSTR_ERROR_NIP44_DECRYPT_FAILED: return "NIP-44: Decryption failed";
|
||||
case NOSTR_ERROR_NIP44_BUFFER_TOO_SMALL: return "NIP-44: Buffer too small";
|
||||
case NOSTR_ERROR_NIP05_INVALID_IDENTIFIER: return "NIP-05: Invalid identifier format";
|
||||
case NOSTR_ERROR_NIP05_HTTP_FAILED: return "NIP-05: HTTP request failed";
|
||||
case NOSTR_ERROR_NIP05_JSON_PARSE_FAILED: return "NIP-05: JSON parsing failed";
|
||||
case NOSTR_ERROR_NIP05_NAME_NOT_FOUND: return "NIP-05: Name not found in .well-known";
|
||||
case NOSTR_ERROR_NIP05_PUBKEY_MISMATCH: return "NIP-05: Public key mismatch";
|
||||
case NOSTR_ERROR_EVENT_INVALID_STRUCTURE: return "Event has invalid structure";
|
||||
case NOSTR_ERROR_EVENT_INVALID_ID: return "Event has invalid ID";
|
||||
case NOSTR_ERROR_EVENT_INVALID_PUBKEY: return "Event has invalid public key";
|
||||
case NOSTR_ERROR_EVENT_INVALID_SIGNATURE: return "Event has invalid signature";
|
||||
case NOSTR_ERROR_EVENT_INVALID_CREATED_AT: return "Event has invalid timestamp";
|
||||
case NOSTR_ERROR_EVENT_INVALID_KIND: return "Event has invalid kind";
|
||||
case NOSTR_ERROR_EVENT_INVALID_TAGS: return "Event has invalid tags";
|
||||
case NOSTR_ERROR_EVENT_INVALID_CONTENT: return "Event has invalid content";
|
||||
case NOSTR_ERROR_NIP13_INSUFFICIENT: return "NIP-13: Insufficient PoW difficulty";
|
||||
case NOSTR_ERROR_NIP13_NO_NONCE_TAG: return "NIP-13: Missing nonce tag";
|
||||
case NOSTR_ERROR_NIP13_INVALID_NONCE_TAG: return "NIP-13: Invalid nonce tag format";
|
||||
case NOSTR_ERROR_NIP13_TARGET_MISMATCH: return "NIP-13: Target difficulty mismatch";
|
||||
case NOSTR_ERROR_NIP13_CALCULATION: return "NIP-13: PoW calculation error";
|
||||
case NOSTR_ERROR_NIP42_INVALID_CHALLENGE: return "NIP-42: Invalid challenge";
|
||||
case NOSTR_ERROR_NIP42_CHALLENGE_EXPIRED: return "NIP-42: Challenge expired";
|
||||
case NOSTR_ERROR_NIP42_AUTH_EVENT_INVALID: return "NIP-42: Authentication event invalid";
|
||||
case NOSTR_ERROR_NIP42_URL_MISMATCH: return "NIP-42: Relay URL mismatch";
|
||||
case NOSTR_ERROR_NIP42_TIME_TOLERANCE: return "NIP-42: Timestamp outside tolerance";
|
||||
case NOSTR_ERROR_NIP42_NOT_AUTHENTICATED: return "NIP-42: Client not authenticated";
|
||||
case NOSTR_ERROR_NIP42_INVALID_MESSAGE_FORMAT: return "NIP-42: Invalid message format";
|
||||
case NOSTR_ERROR_NIP42_CHALLENGE_TOO_SHORT: return "NIP-42: Challenge too short";
|
||||
case NOSTR_ERROR_NIP42_CHALLENGE_TOO_LONG: return "NIP-42: Challenge too long";
|
||||
case NOSTR_ERROR_NIP46_INVALID_BUNKER_URL: return "NIP-46: Invalid bunker URL";
|
||||
case NOSTR_ERROR_NIP46_INVALID_NOSTRCONNECT: return "NIP-46: Invalid nostrconnect URL";
|
||||
case NOSTR_ERROR_NIP46_INVALID_REQUEST: return "NIP-46: Invalid request payload";
|
||||
case NOSTR_ERROR_NIP46_INVALID_RESPONSE: return "NIP-46: Invalid response payload";
|
||||
case NOSTR_ERROR_NIP46_ENCRYPTION_FAILED: return "NIP-46: Encryption failed";
|
||||
case NOSTR_ERROR_NIP46_DECRYPTION_FAILED: return "NIP-46: Decryption failed";
|
||||
case NOSTR_ERROR_NIP46_CONNECTION_FAILED: return "NIP-46: Connection failed";
|
||||
case NOSTR_ERROR_NIP46_TIMEOUT: return "NIP-46: Timeout";
|
||||
case NOSTR_ERROR_NIP46_SECRET_MISMATCH: return "NIP-46: Secret mismatch";
|
||||
case NOSTR_ERROR_NIP46_UNKNOWN_METHOD: return "NIP-46: Unknown method";
|
||||
case NOSTR_ERROR_NIP46_AUTH_CHALLENGE: return "NIP-46: Auth challenge required";
|
||||
case NOSTR_ERROR_NIP46_NOT_CONNECTED: return "NIP-46: Not connected";
|
||||
case NOSTR_ERROR_NIP60_INVALID_WALLET: return "NIP-60: Invalid wallet event";
|
||||
case NOSTR_ERROR_NIP60_INVALID_TOKEN: return "NIP-60: Invalid token event";
|
||||
case NOSTR_ERROR_NIP60_INVALID_HISTORY: return "NIP-60: Invalid history event";
|
||||
case NOSTR_ERROR_NIP60_INVALID_QUOTE: return "NIP-60: Invalid quote event";
|
||||
case NOSTR_ERROR_NIP60_DECRYPT_FAILED: return "NIP-60: Decryption failed";
|
||||
case NOSTR_ERROR_NIP60_INVALID_PROOFS: return "NIP-60: Invalid proofs payload";
|
||||
case NOSTR_ERROR_NIP60_INSUFFICIENT_FUNDS: return "NIP-60: Insufficient funds";
|
||||
case NOSTR_ERROR_NIP61_INVALID_INFO: return "NIP-61: Invalid info event";
|
||||
case NOSTR_ERROR_NIP61_INVALID_NUTZAP: return "NIP-61: Invalid nutzap event";
|
||||
case NOSTR_ERROR_NIP61_MINT_MISMATCH: return "NIP-61: Mint mismatch";
|
||||
case NOSTR_ERROR_NIP61_PUBKEY_MISMATCH: return "NIP-61: Pubkey mismatch";
|
||||
case NOSTR_ERROR_NIP61_VERIFICATION_FAILED: return "NIP-61: Verification failed";
|
||||
case NOSTR_ERROR_CASHU_HTTP_FAILED: return "Cashu: HTTP request failed";
|
||||
case NOSTR_ERROR_CASHU_JSON_PARSE_FAILED: return "Cashu: JSON parsing failed";
|
||||
case NOSTR_ERROR_CASHU_MINT_ERROR: return "Cashu: Mint returned an error";
|
||||
case NOSTR_ERROR_CASHU_QUOTE_NOT_PAID: return "Cashu: Quote not paid";
|
||||
case NOSTR_ERROR_CASHU_QUOTE_EXPIRED: return "Cashu: Quote expired";
|
||||
case NOSTR_ERROR_CASHU_PROOFS_SPENT: return "Cashu: One or more proofs are already spent";
|
||||
case NOSTR_ERROR_CASHU_CRYPTO_FAILED: return "Cashu: Cryptographic operation failed";
|
||||
case NOSTR_ERROR_CASHU_INVALID_KEYSET: return "Cashu: Invalid keyset";
|
||||
default: return "Unknown error";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the NOSTR library
|
||||
*/
|
||||
int nostr_init(void) {
|
||||
if (nostr_crypto_init() != 0) {
|
||||
return NOSTR_ERROR_CRYPTO_FAILED;
|
||||
}
|
||||
return NOSTR_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup the NOSTR library
|
||||
*/
|
||||
void nostr_cleanup(void) {
|
||||
nostr_crypto_cleanup();
|
||||
}
|
||||
131
firmware/kb2040_hidden_signer/src/nostr_core/nostr_common.h
Normal file
131
firmware/kb2040_hidden_signer/src/nostr_core/nostr_common.h
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* NOSTR Core - Common Definitions
|
||||
* Shared error constants and basic types for the modular NOSTR library
|
||||
*/
|
||||
|
||||
#ifndef NOSTR_COMMON_H
|
||||
#define NOSTR_COMMON_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// Return codes
|
||||
#define NOSTR_SUCCESS 0
|
||||
#define NOSTR_ERROR_INVALID_INPUT -1
|
||||
#define NOSTR_ERROR_CRYPTO_FAILED -2
|
||||
#define NOSTR_ERROR_MEMORY_FAILED -3
|
||||
#define NOSTR_ERROR_IO_FAILED -4
|
||||
#define NOSTR_ERROR_NETWORK_FAILED -5
|
||||
#define NOSTR_ERROR_NIP04_INVALID_FORMAT -10
|
||||
#define NOSTR_ERROR_NIP04_DECRYPT_FAILED -11
|
||||
#define NOSTR_ERROR_NIP04_BUFFER_TOO_SMALL -12
|
||||
#define NOSTR_ERROR_NIP44_INVALID_FORMAT -13
|
||||
#define NOSTR_ERROR_NIP44_DECRYPT_FAILED -14
|
||||
#define NOSTR_ERROR_NIP44_BUFFER_TOO_SMALL -15
|
||||
#define NOSTR_ERROR_NIP05_INVALID_IDENTIFIER -16
|
||||
#define NOSTR_ERROR_NIP05_HTTP_FAILED -17
|
||||
#define NOSTR_ERROR_NIP05_JSON_PARSE_FAILED -18
|
||||
#define NOSTR_ERROR_NIP05_NAME_NOT_FOUND -19
|
||||
#define NOSTR_ERROR_NIP05_PUBKEY_MISMATCH -20
|
||||
#define NOSTR_ERROR_EVENT_INVALID_STRUCTURE -30
|
||||
#define NOSTR_ERROR_EVENT_INVALID_ID -31
|
||||
#define NOSTR_ERROR_EVENT_INVALID_PUBKEY -32
|
||||
#define NOSTR_ERROR_EVENT_INVALID_SIGNATURE -33
|
||||
#define NOSTR_ERROR_EVENT_INVALID_CREATED_AT -34
|
||||
#define NOSTR_ERROR_EVENT_INVALID_KIND -35
|
||||
#define NOSTR_ERROR_EVENT_INVALID_TAGS -36
|
||||
#define NOSTR_ERROR_EVENT_INVALID_CONTENT -37
|
||||
|
||||
// Authentication Rules System Error Codes
|
||||
#define NOSTR_ERROR_AUTH_RULES_DISABLED -50
|
||||
#define NOSTR_ERROR_AUTH_RULES_DENIED -51
|
||||
#define NOSTR_ERROR_AUTH_RULES_DB_FAILED -52
|
||||
#define NOSTR_ERROR_AUTH_RULES_INVALID_RULE -53
|
||||
#define NOSTR_ERROR_AUTH_RULES_CACHE_FAILED -54
|
||||
#define NOSTR_ERROR_AUTH_RULES_BACKEND_NOT_FOUND -55
|
||||
|
||||
// NIP-13 PoW-specific error codes
|
||||
#define NOSTR_ERROR_NIP13_INSUFFICIENT -100
|
||||
#define NOSTR_ERROR_NIP13_NO_NONCE_TAG -101
|
||||
#define NOSTR_ERROR_NIP13_INVALID_NONCE_TAG -102
|
||||
#define NOSTR_ERROR_NIP13_TARGET_MISMATCH -103
|
||||
#define NOSTR_ERROR_NIP13_CALCULATION -104
|
||||
|
||||
// NIP-42 Authentication-specific error codes
|
||||
#define NOSTR_ERROR_NIP42_INVALID_CHALLENGE -200
|
||||
#define NOSTR_ERROR_NIP42_CHALLENGE_EXPIRED -201
|
||||
#define NOSTR_ERROR_NIP42_AUTH_EVENT_INVALID -202
|
||||
#define NOSTR_ERROR_NIP42_URL_MISMATCH -203
|
||||
#define NOSTR_ERROR_NIP42_TIME_TOLERANCE -204
|
||||
#define NOSTR_ERROR_NIP42_NOT_AUTHENTICATED -205
|
||||
#define NOSTR_ERROR_NIP42_INVALID_MESSAGE_FORMAT -206
|
||||
#define NOSTR_ERROR_NIP42_CHALLENGE_TOO_SHORT -207
|
||||
#define NOSTR_ERROR_NIP42_CHALLENGE_TOO_LONG -208
|
||||
|
||||
// NIP-46 Remote Signing error codes
|
||||
#define NOSTR_ERROR_NIP46_INVALID_BUNKER_URL -300
|
||||
#define NOSTR_ERROR_NIP46_INVALID_NOSTRCONNECT -301
|
||||
#define NOSTR_ERROR_NIP46_INVALID_REQUEST -302
|
||||
#define NOSTR_ERROR_NIP46_INVALID_RESPONSE -303
|
||||
#define NOSTR_ERROR_NIP46_ENCRYPTION_FAILED -304
|
||||
#define NOSTR_ERROR_NIP46_DECRYPTION_FAILED -305
|
||||
#define NOSTR_ERROR_NIP46_CONNECTION_FAILED -306
|
||||
#define NOSTR_ERROR_NIP46_TIMEOUT -307
|
||||
#define NOSTR_ERROR_NIP46_SECRET_MISMATCH -308
|
||||
#define NOSTR_ERROR_NIP46_UNKNOWN_METHOD -309
|
||||
#define NOSTR_ERROR_NIP46_AUTH_CHALLENGE -310
|
||||
#define NOSTR_ERROR_NIP46_NOT_CONNECTED -311
|
||||
|
||||
// NIP-60 Cashu Wallet error codes
|
||||
#define NOSTR_ERROR_NIP60_INVALID_WALLET -400
|
||||
#define NOSTR_ERROR_NIP60_INVALID_TOKEN -401
|
||||
#define NOSTR_ERROR_NIP60_INVALID_HISTORY -402
|
||||
#define NOSTR_ERROR_NIP60_INVALID_QUOTE -403
|
||||
#define NOSTR_ERROR_NIP60_DECRYPT_FAILED -404
|
||||
#define NOSTR_ERROR_NIP60_INVALID_PROOFS -405
|
||||
#define NOSTR_ERROR_NIP60_INSUFFICIENT_FUNDS -406
|
||||
|
||||
// NIP-61 Nutzap error codes
|
||||
#define NOSTR_ERROR_NIP61_INVALID_INFO -410
|
||||
#define NOSTR_ERROR_NIP61_INVALID_NUTZAP -411
|
||||
#define NOSTR_ERROR_NIP61_MINT_MISMATCH -412
|
||||
#define NOSTR_ERROR_NIP61_PUBKEY_MISMATCH -413
|
||||
#define NOSTR_ERROR_NIP61_VERIFICATION_FAILED -414
|
||||
|
||||
// Cashu Mint client error codes
|
||||
#define NOSTR_ERROR_CASHU_HTTP_FAILED -420
|
||||
#define NOSTR_ERROR_CASHU_JSON_PARSE_FAILED -421
|
||||
#define NOSTR_ERROR_CASHU_MINT_ERROR -422
|
||||
#define NOSTR_ERROR_CASHU_QUOTE_NOT_PAID -423
|
||||
#define NOSTR_ERROR_CASHU_QUOTE_EXPIRED -424
|
||||
#define NOSTR_ERROR_CASHU_PROOFS_SPENT -425
|
||||
#define NOSTR_ERROR_CASHU_CRYPTO_FAILED -426
|
||||
#define NOSTR_ERROR_CASHU_INVALID_KEYSET -427
|
||||
|
||||
// Constants
|
||||
#define NOSTR_PRIVATE_KEY_SIZE 32
|
||||
#define NOSTR_PUBLIC_KEY_SIZE 32
|
||||
#define NOSTR_HEX_KEY_SIZE 65 // 64 + null terminator
|
||||
#define NOSTR_BECH32_KEY_SIZE 100
|
||||
#define NOSTR_MAX_CONTENT_SIZE 2048
|
||||
#define NOSTR_MAX_URL_SIZE 256
|
||||
#define NIP05_DEFAULT_TIMEOUT 10
|
||||
|
||||
// NIP-04 Constants
|
||||
#define NOSTR_NIP04_MAX_PLAINTEXT_SIZE 1048576 // 1MB
|
||||
#define NOSTR_NIP04_MAX_ENCRYPTED_SIZE 22369621 // ~21.3MB (accounts for base64 overhead + IV)
|
||||
|
||||
// NIP-44 Constants
|
||||
#define NOSTR_NIP44_MAX_PLAINTEXT_SIZE 65535 // 64KB - 1 (NIP-44 spec compliant)
|
||||
|
||||
// Forward declaration for cJSON (to avoid requiring cJSON.h in header)
|
||||
struct cJSON;
|
||||
|
||||
// Function declarations
|
||||
const char* nostr_strerror(int error_code);
|
||||
|
||||
// Library initialization functions
|
||||
int nostr_init(void);
|
||||
void nostr_cleanup(void);
|
||||
|
||||
#endif // NOSTR_COMMON_H
|
||||
@@ -0,0 +1,20 @@
|
||||
#ifndef NOSTR_PLATFORM_H
|
||||
#define NOSTR_PLATFORM_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Fill buffer with cryptographically secure random bytes.
|
||||
* Returns 0 on success, -1 on failure.
|
||||
*/
|
||||
int nostr_platform_random(unsigned char *buf, size_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NOSTR_PLATFORM_H */
|
||||
1577
firmware/kb2040_hidden_signer/src/nostr_core/utils.c
Normal file
1577
firmware/kb2040_hidden_signer/src/nostr_core/utils.c
Normal file
File diff suppressed because it is too large
Load Diff
189
firmware/kb2040_hidden_signer/src/nostr_core/utils.h
Normal file
189
firmware/kb2040_hidden_signer/src/nostr_core/utils.h
Normal file
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* NOSTR Core Library - Utilities
|
||||
*
|
||||
* General utility functions used across multiple NIPs
|
||||
*/
|
||||
|
||||
#ifndef NOSTR_UTILS_H
|
||||
#define NOSTR_UTILS_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// =============================================================================
|
||||
// UTILITY FUNCTIONS
|
||||
// =============================================================================
|
||||
|
||||
// Convert bytes to hexadecimal string
|
||||
void nostr_bytes_to_hex(const unsigned char *bytes, size_t len, char *hex);
|
||||
|
||||
// Convert hexadecimal string to bytes
|
||||
int nostr_hex_to_bytes(const char *hex, unsigned char *bytes, size_t len);
|
||||
|
||||
// Base64 encoding function
|
||||
size_t base64_encode(const unsigned char *data, size_t len, char *output,
|
||||
size_t output_size);
|
||||
|
||||
// Base64 decoding function
|
||||
size_t base64_decode(const char *input, unsigned char *output);
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// CORE CRYPTO FUNCTIONS
|
||||
// =============================================================================
|
||||
|
||||
// Initialize crypto subsystem
|
||||
int nostr_crypto_init(void);
|
||||
|
||||
// Cleanup crypto subsystem
|
||||
void nostr_crypto_cleanup(void);
|
||||
|
||||
// SHA-256 hash function
|
||||
int nostr_sha256(const unsigned char *data, size_t len, unsigned char *hash);
|
||||
|
||||
// =============================================================================
|
||||
// STREAMING SHA-256 FUNCTIONS
|
||||
// =============================================================================
|
||||
|
||||
// SHA-256 streaming context
|
||||
typedef struct {
|
||||
uint32_t state[8]; // Current hash state
|
||||
unsigned char buffer[64]; // Input buffer for incomplete blocks
|
||||
uint64_t bitlen; // Total bits processed
|
||||
size_t buflen; // Current buffer length
|
||||
} nostr_sha256_ctx_t;
|
||||
|
||||
// Initialize SHA-256 streaming context
|
||||
int nostr_sha256_init(nostr_sha256_ctx_t* ctx);
|
||||
|
||||
// Update SHA-256 context with new data
|
||||
int nostr_sha256_update(nostr_sha256_ctx_t* ctx, const unsigned char* data, size_t len);
|
||||
|
||||
// Finalize SHA-256 and output hash
|
||||
int nostr_sha256_final(nostr_sha256_ctx_t* ctx, unsigned char* hash);
|
||||
|
||||
// Stream SHA-256 hash of a file
|
||||
int nostr_sha256_file_stream(const char* filename, unsigned char* hash);
|
||||
|
||||
// HMAC-SHA256
|
||||
int nostr_hmac_sha256(const unsigned char *key, size_t key_len,
|
||||
const unsigned char *data, size_t data_len,
|
||||
unsigned char *output);
|
||||
|
||||
// HMAC-SHA512
|
||||
int nostr_hmac_sha512(const unsigned char *key, size_t key_len,
|
||||
const unsigned char *data, size_t data_len,
|
||||
unsigned char *output);
|
||||
|
||||
// PBKDF2 with HMAC-SHA512
|
||||
int nostr_pbkdf2_hmac_sha512(const unsigned char *password, size_t password_len,
|
||||
const unsigned char *salt, size_t salt_len,
|
||||
int iterations, unsigned char *output,
|
||||
size_t output_len);
|
||||
|
||||
// SHA-512 implementation (for testing)
|
||||
int nostr_sha512(const unsigned char *data, size_t len, unsigned char *hash);
|
||||
|
||||
// =============================================================================
|
||||
// SECP256K1 ELLIPTIC CURVE FUNCTIONS
|
||||
// =============================================================================
|
||||
|
||||
// Verify private key is valid
|
||||
int nostr_ec_private_key_verify(const unsigned char *private_key);
|
||||
|
||||
// Generate public key from private key
|
||||
int nostr_ec_public_key_from_private_key(const unsigned char *private_key,
|
||||
unsigned char *public_key);
|
||||
|
||||
// Sign data with ECDSA
|
||||
int nostr_ec_sign(const unsigned char *private_key, const unsigned char *hash,
|
||||
unsigned char *signature);
|
||||
|
||||
// RFC 6979 deterministic nonce generation
|
||||
int nostr_rfc6979_generate_k(const unsigned char *private_key,
|
||||
const unsigned char *message_hash,
|
||||
unsigned char *k_out);
|
||||
|
||||
int nostr_schnorr_sign(const unsigned char* private_key,
|
||||
const unsigned char* hash,
|
||||
unsigned char* signature);
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// HKDF KEY DERIVATION FUNCTIONS
|
||||
// =============================================================================
|
||||
|
||||
// HKDF Extract step
|
||||
int nostr_hkdf_extract(const unsigned char *salt, size_t salt_len,
|
||||
const unsigned char *ikm, size_t ikm_len,
|
||||
unsigned char *prk);
|
||||
|
||||
// HKDF Expand step
|
||||
int nostr_hkdf_expand(const unsigned char *prk, size_t prk_len,
|
||||
const unsigned char *info, size_t info_len,
|
||||
unsigned char *okm, size_t okm_len);
|
||||
|
||||
// HKDF (Extract + Expand)
|
||||
int nostr_hkdf(const unsigned char *salt, size_t salt_len,
|
||||
const unsigned char *ikm, size_t ikm_len,
|
||||
const unsigned char *info, size_t info_len, unsigned char *okm,
|
||||
size_t okm_len);
|
||||
|
||||
// ECDH shared secret computation (for debugging)
|
||||
int ecdh_shared_secret(const unsigned char *private_key,
|
||||
const unsigned char *public_key_x,
|
||||
unsigned char *shared_secret);
|
||||
|
||||
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// BIP39 MNEMONIC FUNCTIONS
|
||||
// =============================================================================
|
||||
|
||||
// Generate mnemonic from entropy
|
||||
int nostr_bip39_mnemonic_from_bytes(const unsigned char *entropy,
|
||||
size_t entropy_len, char *mnemonic);
|
||||
|
||||
// Validate mnemonic
|
||||
int nostr_bip39_mnemonic_validate(const char *mnemonic);
|
||||
|
||||
// Convert mnemonic to seed
|
||||
int nostr_bip39_mnemonic_to_seed(const char *mnemonic, const char *passphrase,
|
||||
unsigned char *seed, size_t seed_len);
|
||||
|
||||
// =============================================================================
|
||||
// BIP32 HD WALLET FUNCTIONS
|
||||
// =============================================================================
|
||||
|
||||
typedef struct {
|
||||
unsigned char private_key[32];
|
||||
unsigned char public_key[33];
|
||||
unsigned char chain_code[32];
|
||||
uint32_t depth;
|
||||
uint32_t parent_fingerprint;
|
||||
uint32_t child_number;
|
||||
} nostr_hd_key_t;
|
||||
|
||||
// Create master key from seed
|
||||
int nostr_bip32_key_from_seed(const unsigned char *seed, size_t seed_len,
|
||||
nostr_hd_key_t *master_key);
|
||||
|
||||
// Derive child key from parent
|
||||
int nostr_bip32_derive_child(const nostr_hd_key_t *parent_key,
|
||||
uint32_t child_number, nostr_hd_key_t *child_key);
|
||||
|
||||
// Derive key from path
|
||||
int nostr_bip32_derive_path(const nostr_hd_key_t *master_key,
|
||||
const uint32_t *path, size_t path_len,
|
||||
nostr_hd_key_t *derived_key);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // NOSTR_UTILS_H
|
||||
79
firmware/kb2040_hidden_signer/src/platform/rp2040.c
Normal file
79
firmware/kb2040_hidden_signer/src/platform/rp2040.c
Normal file
@@ -0,0 +1,79 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../nostr_core/nostr_platform.h"
|
||||
|
||||
#if defined(ARDUINO)
|
||||
#include <Arduino.h>
|
||||
#endif
|
||||
|
||||
#if defined(__has_include)
|
||||
# if __has_include("pico/rand.h")
|
||||
# include "pico/rand.h"
|
||||
# define NOSTR_HAVE_PICO_RAND 1
|
||||
# endif
|
||||
# if __has_include("hardware/adc.h")
|
||||
# include "hardware/adc.h"
|
||||
# define NOSTR_HAVE_PICO_ADC 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
static uint32_t xorshift32(uint32_t *state) {
|
||||
uint32_t x = *state ? *state : 0xA5A5A5A5u;
|
||||
x ^= x << 13;
|
||||
x ^= x >> 17;
|
||||
x ^= x << 5;
|
||||
*state = x;
|
||||
return x;
|
||||
}
|
||||
|
||||
int nostr_platform_random(unsigned char *buf, size_t len) {
|
||||
if (!buf) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t i = 0;
|
||||
|
||||
#if defined(NOSTR_HAVE_PICO_RAND)
|
||||
while (i + 4 <= len) {
|
||||
uint32_t r = get_rand_32();
|
||||
memcpy(buf + i, &r, 4);
|
||||
i += 4;
|
||||
}
|
||||
if (i < len) {
|
||||
uint32_t r = get_rand_32();
|
||||
memcpy(buf + i, &r, len - i);
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
uint32_t seed = 0x13579BDFu;
|
||||
|
||||
#if defined(ARDUINO)
|
||||
seed ^= (uint32_t)micros();
|
||||
seed ^= ((uint32_t)millis() << 16);
|
||||
seed ^= (uint32_t)(uintptr_t)&seed;
|
||||
#endif
|
||||
|
||||
#if defined(NOSTR_HAVE_PICO_ADC)
|
||||
adc_init();
|
||||
adc_set_temp_sensor_enabled(true);
|
||||
adc_select_input(4);
|
||||
for (int k = 0; k < 16; ++k) {
|
||||
seed ^= ((uint32_t)adc_read() << ((k & 3) * 8));
|
||||
}
|
||||
#endif
|
||||
|
||||
while (i < len) {
|
||||
uint32_t r = xorshift32(&seed);
|
||||
#if defined(ARDUINO)
|
||||
r ^= (uint32_t)micros();
|
||||
#endif
|
||||
size_t take = (len - i >= 4) ? 4 : (len - i);
|
||||
memcpy(buf + i, &r, take);
|
||||
i += take;
|
||||
}
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
929
firmware/kb2040_hidden_signer/src/secp256k1/include/secp256k1.h
Normal file
929
firmware/kb2040_hidden_signer/src/secp256k1/include/secp256k1.h
Normal file
@@ -0,0 +1,929 @@
|
||||
#ifndef SECP256K1_H
|
||||
#define SECP256K1_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/** Unless explicitly stated all pointer arguments must not be NULL.
|
||||
*
|
||||
* The following rules specify the order of arguments in API calls:
|
||||
*
|
||||
* 1. Context pointers go first, followed by output arguments, combined
|
||||
* output/input arguments, and finally input-only arguments.
|
||||
* 2. Array lengths always immediately follow the argument whose length
|
||||
* they describe, even if this violates rule 1.
|
||||
* 3. Within the OUT/OUTIN/IN groups, pointers to data that is typically generated
|
||||
* later go first. This means: signatures, public nonces, secret nonces,
|
||||
* messages, public keys, secret keys, tweaks.
|
||||
* 4. Arguments that are not data pointers go last, from more complex to less
|
||||
* complex: function pointers, algorithm names, messages, void pointers,
|
||||
* counts, flags, booleans.
|
||||
* 5. Opaque data pointers follow the function pointer they are to be passed to.
|
||||
*/
|
||||
|
||||
/** Opaque data structure that holds context information
|
||||
*
|
||||
* The primary purpose of context objects is to store randomization data for
|
||||
* enhanced protection against side-channel leakage. This protection is only
|
||||
* effective if the context is randomized after its creation. See
|
||||
* secp256k1_context_create for creation of contexts and
|
||||
* secp256k1_context_randomize for randomization.
|
||||
*
|
||||
* A secondary purpose of context objects is to store pointers to callback
|
||||
* functions that the library will call when certain error states arise. See
|
||||
* secp256k1_context_set_error_callback as well as
|
||||
* secp256k1_context_set_illegal_callback for details. Future library versions
|
||||
* may use context objects for additional purposes.
|
||||
*
|
||||
* A constructed context can safely be used from multiple threads
|
||||
* simultaneously, but API calls that take a non-const pointer to a context
|
||||
* need exclusive access to it. In particular this is the case for
|
||||
* secp256k1_context_destroy, secp256k1_context_preallocated_destroy,
|
||||
* and secp256k1_context_randomize.
|
||||
*
|
||||
* Regarding randomization, either do it once at creation time (in which case
|
||||
* you do not need any locking for the other calls), or use a read-write lock.
|
||||
*/
|
||||
typedef struct secp256k1_context_struct secp256k1_context;
|
||||
|
||||
/** Opaque data structure that holds a parsed and valid public key.
|
||||
*
|
||||
* The exact representation of data inside is implementation defined and not
|
||||
* guaranteed to be portable between different platforms or versions. It is
|
||||
* however guaranteed to be 64 bytes in size, and can be safely copied/moved.
|
||||
* If you need to convert to a format suitable for storage or transmission,
|
||||
* use secp256k1_ec_pubkey_serialize and secp256k1_ec_pubkey_parse. To
|
||||
* compare keys, use secp256k1_ec_pubkey_cmp.
|
||||
*/
|
||||
typedef struct secp256k1_pubkey {
|
||||
unsigned char data[64];
|
||||
} secp256k1_pubkey;
|
||||
|
||||
/** Opaque data structure that holds a parsed ECDSA signature.
|
||||
*
|
||||
* The exact representation of data inside is implementation defined and not
|
||||
* guaranteed to be portable between different platforms or versions. It is
|
||||
* however guaranteed to be 64 bytes in size, and can be safely copied/moved.
|
||||
* If you need to convert to a format suitable for storage, transmission, or
|
||||
* comparison, use the secp256k1_ecdsa_signature_serialize_* and
|
||||
* secp256k1_ecdsa_signature_parse_* functions.
|
||||
*/
|
||||
typedef struct secp256k1_ecdsa_signature {
|
||||
unsigned char data[64];
|
||||
} secp256k1_ecdsa_signature;
|
||||
|
||||
/** A pointer to a function to deterministically generate a nonce.
|
||||
*
|
||||
* Returns: 1 if a nonce was successfully generated. 0 will cause signing to fail.
|
||||
* Out: nonce32: pointer to a 32-byte array to be filled by the function.
|
||||
* In: msg32: the 32-byte message hash being verified (will not be NULL)
|
||||
* key32: pointer to a 32-byte secret key (will not be NULL)
|
||||
* algo16: pointer to a 16-byte array describing the signature
|
||||
* algorithm (will be NULL for ECDSA for compatibility).
|
||||
* data: Arbitrary data pointer that is passed through.
|
||||
* attempt: how many iterations we have tried to find a nonce.
|
||||
* This will almost always be 0, but different attempt values
|
||||
* are required to result in a different nonce.
|
||||
*
|
||||
* Except for test cases, this function should compute some cryptographic hash of
|
||||
* the message, the algorithm, the key and the attempt.
|
||||
*/
|
||||
typedef int (*secp256k1_nonce_function)(
|
||||
unsigned char *nonce32,
|
||||
const unsigned char *msg32,
|
||||
const unsigned char *key32,
|
||||
const unsigned char *algo16,
|
||||
void *data,
|
||||
unsigned int attempt
|
||||
);
|
||||
|
||||
# if !defined(SECP256K1_GNUC_PREREQ)
|
||||
# if defined(__GNUC__)&&defined(__GNUC_MINOR__)
|
||||
# define SECP256K1_GNUC_PREREQ(_maj,_min) \
|
||||
((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min))
|
||||
# else
|
||||
# define SECP256K1_GNUC_PREREQ(_maj,_min) 0
|
||||
# endif
|
||||
# endif
|
||||
|
||||
/* When this header is used at build-time the SECP256K1_BUILD define needs to be set
|
||||
* to correctly setup export attributes and nullness checks. This is normally done
|
||||
* by secp256k1.c but to guard against this header being included before secp256k1.c
|
||||
* has had a chance to set the define (e.g. via test harnesses that just includes
|
||||
* secp256k1.c) we set SECP256K1_NO_BUILD when this header is processed without the
|
||||
* BUILD define so this condition can be caught.
|
||||
*/
|
||||
#ifndef SECP256K1_BUILD
|
||||
# define SECP256K1_NO_BUILD
|
||||
#endif
|
||||
|
||||
/* Symbol visibility. */
|
||||
#if !defined(SECP256K1_API) && defined(SECP256K1_NO_API_VISIBILITY_ATTRIBUTES)
|
||||
/* The user has requested that we don't specify visibility attributes in
|
||||
* the public API.
|
||||
*
|
||||
* Since all our non-API declarations use the static qualifier, this means
|
||||
* that the user can use -fvisibility=<value> to set the visibility of the
|
||||
* API symbols. For instance, -fvisibility=hidden can be useful *even for
|
||||
* the API symbols*, e.g., when building a static library which is linked
|
||||
* into a shared library, and the latter should not re-export the
|
||||
* libsecp256k1 API.
|
||||
*
|
||||
* While visibility is a concept that applies only to shared libraries,
|
||||
* setting visibility will still make a difference when building a static
|
||||
* library: the visibility settings will be stored in the static library,
|
||||
* solely for the potential case that the static library will be linked into
|
||||
* a shared library. In that case, the stored visibility settings will
|
||||
* resurface and be honored for the shared library. */
|
||||
# define SECP256K1_API extern
|
||||
#endif
|
||||
#if !defined(SECP256K1_API)
|
||||
# if defined(SECP256K1_BUILD)
|
||||
/* On Windows, assume a shared library only if explicitly requested.
|
||||
* 1. If using Libtool, it defines DLL_EXPORT automatically.
|
||||
* 2. In other cases, SECP256K1_DLL_EXPORT must be defined. */
|
||||
# if defined(_WIN32) && (defined(SECP256K1_DLL_EXPORT) || defined(DLL_EXPORT))
|
||||
/* GCC for Windows (e.g., MinGW) accepts the __declspec syntax for
|
||||
* MSVC compatibility. A __declspec declaration implies (but is not
|
||||
* exactly equivalent to) __attribute__ ((visibility("default"))),
|
||||
* and so we actually want __declspec even on GCC, see "Microsoft
|
||||
* Windows Function Attributes" in the GCC manual and the
|
||||
* recommendations in https://gcc.gnu.org/wiki/Visibility . */
|
||||
# define SECP256K1_API extern __declspec(dllexport)
|
||||
/* Avoid __attribute__ ((visibility("default"))) on Windows to get rid
|
||||
* of warnings when compiling with -flto due to a bug in GCC, see
|
||||
* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116478 . */
|
||||
# elif !defined(_WIN32) && defined (__GNUC__) && (__GNUC__ >= 4)
|
||||
# define SECP256K1_API extern __attribute__ ((visibility("default")))
|
||||
# else
|
||||
# define SECP256K1_API extern
|
||||
# endif
|
||||
# else
|
||||
/* On Windows, SECP256K1_STATIC must be defined when consuming
|
||||
* libsecp256k1 as a static library. Note that SECP256K1_STATIC is a
|
||||
* "consumer-only" macro, and it has no meaning when building
|
||||
* libsecp256k1. */
|
||||
# if defined(_WIN32) && !defined(SECP256K1_STATIC)
|
||||
# define SECP256K1_API extern __declspec(dllimport)
|
||||
# else
|
||||
# define SECP256K1_API extern
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Warning attributes
|
||||
* NONNULL is not used if SECP256K1_BUILD is set to avoid the compiler optimizing out
|
||||
* some paranoid null checks. */
|
||||
# if defined(__GNUC__) && SECP256K1_GNUC_PREREQ(3, 4)
|
||||
# define SECP256K1_WARN_UNUSED_RESULT __attribute__ ((__warn_unused_result__))
|
||||
# else
|
||||
# define SECP256K1_WARN_UNUSED_RESULT
|
||||
# endif
|
||||
# if !defined(SECP256K1_BUILD) && defined(__GNUC__) && SECP256K1_GNUC_PREREQ(3, 4)
|
||||
# define SECP256K1_ARG_NONNULL(_x) __attribute__ ((__nonnull__(_x)))
|
||||
# else
|
||||
# define SECP256K1_ARG_NONNULL(_x)
|
||||
# endif
|
||||
|
||||
/* Attribute for marking functions, types, and variables as deprecated */
|
||||
#if !defined(SECP256K1_BUILD) && defined(__has_attribute)
|
||||
# if __has_attribute(__deprecated__)
|
||||
# define SECP256K1_DEPRECATED(_msg) __attribute__ ((__deprecated__(_msg)))
|
||||
# else
|
||||
# define SECP256K1_DEPRECATED(_msg)
|
||||
# endif
|
||||
#else
|
||||
# define SECP256K1_DEPRECATED(_msg)
|
||||
#endif
|
||||
|
||||
/* All flags' lower 8 bits indicate what they're for. Do not use directly. */
|
||||
#define SECP256K1_FLAGS_TYPE_MASK ((1 << 8) - 1)
|
||||
#define SECP256K1_FLAGS_TYPE_CONTEXT (1 << 0)
|
||||
#define SECP256K1_FLAGS_TYPE_COMPRESSION (1 << 1)
|
||||
/* The higher bits contain the actual data. Do not use directly. */
|
||||
#define SECP256K1_FLAGS_BIT_CONTEXT_VERIFY (1 << 8)
|
||||
#define SECP256K1_FLAGS_BIT_CONTEXT_SIGN (1 << 9)
|
||||
#define SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY (1 << 10)
|
||||
#define SECP256K1_FLAGS_BIT_COMPRESSION (1 << 8)
|
||||
|
||||
/** Context flags to pass to secp256k1_context_create, secp256k1_context_preallocated_size, and
|
||||
* secp256k1_context_preallocated_create. */
|
||||
#define SECP256K1_CONTEXT_NONE (SECP256K1_FLAGS_TYPE_CONTEXT)
|
||||
|
||||
/** Deprecated context flags. These flags are treated equivalent to SECP256K1_CONTEXT_NONE. */
|
||||
#define SECP256K1_CONTEXT_VERIFY (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_VERIFY)
|
||||
#define SECP256K1_CONTEXT_SIGN (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_SIGN)
|
||||
|
||||
/* Testing flag. Do not use. */
|
||||
#define SECP256K1_CONTEXT_DECLASSIFY (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY)
|
||||
|
||||
/** Flag to pass to secp256k1_ec_pubkey_serialize. */
|
||||
#define SECP256K1_EC_COMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION | SECP256K1_FLAGS_BIT_COMPRESSION)
|
||||
#define SECP256K1_EC_UNCOMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION)
|
||||
|
||||
/** Prefix byte used to tag various encoded curvepoints for specific purposes */
|
||||
#define SECP256K1_TAG_PUBKEY_EVEN 0x02
|
||||
#define SECP256K1_TAG_PUBKEY_ODD 0x03
|
||||
#define SECP256K1_TAG_PUBKEY_UNCOMPRESSED 0x04
|
||||
#define SECP256K1_TAG_PUBKEY_HYBRID_EVEN 0x06
|
||||
#define SECP256K1_TAG_PUBKEY_HYBRID_ODD 0x07
|
||||
|
||||
/** A built-in constant secp256k1 context object with static storage duration, to be
|
||||
* used in conjunction with secp256k1_selftest.
|
||||
*
|
||||
* This context object offers *only limited functionality* , i.e., it cannot be used
|
||||
* for API functions that perform computations involving secret keys, e.g., signing
|
||||
* and public key generation. If this restriction applies to a specific API function,
|
||||
* it is mentioned in its documentation. See secp256k1_context_create if you need a
|
||||
* full context object that supports all functionality offered by the library.
|
||||
*
|
||||
* It is highly recommended to call secp256k1_selftest before using this context.
|
||||
*/
|
||||
SECP256K1_API const secp256k1_context * const secp256k1_context_static;
|
||||
|
||||
/** Deprecated alias for secp256k1_context_static. */
|
||||
SECP256K1_API const secp256k1_context * const secp256k1_context_no_precomp
|
||||
SECP256K1_DEPRECATED("Use secp256k1_context_static instead");
|
||||
|
||||
/** Perform basic self tests (to be used in conjunction with secp256k1_context_static)
|
||||
*
|
||||
* This function performs self tests that detect some serious usage errors and
|
||||
* similar conditions, e.g., when the library is compiled for the wrong endianness.
|
||||
* This is a last resort measure to be used in production. The performed tests are
|
||||
* very rudimentary and are not intended as a replacement for running the test
|
||||
* binaries.
|
||||
*
|
||||
* It is highly recommended to call this before using secp256k1_context_static.
|
||||
* It is not necessary to call this function before using a context created with
|
||||
* secp256k1_context_create (or secp256k1_context_preallocated_create), which will
|
||||
* take care of performing the self tests.
|
||||
*
|
||||
* If the tests fail, this function will call the default error callback to abort the
|
||||
* program (see secp256k1_context_set_error_callback).
|
||||
*/
|
||||
SECP256K1_API void secp256k1_selftest(void);
|
||||
|
||||
|
||||
/** Create a secp256k1 context object (in dynamically allocated memory).
|
||||
*
|
||||
* This function uses malloc to allocate memory. It is guaranteed that malloc is
|
||||
* called at most once for every call of this function. If you need to avoid dynamic
|
||||
* memory allocation entirely, see secp256k1_context_static and the functions in
|
||||
* secp256k1_preallocated.h.
|
||||
*
|
||||
* Returns: pointer to a newly created context object.
|
||||
* In: flags: Always set to SECP256K1_CONTEXT_NONE (see below).
|
||||
*
|
||||
* The only valid non-deprecated flag in recent library versions is
|
||||
* SECP256K1_CONTEXT_NONE, which will create a context sufficient for all functionality
|
||||
* offered by the library. All other (deprecated) flags will be treated as equivalent
|
||||
* to the SECP256K1_CONTEXT_NONE flag. Though the flags parameter primarily exists for
|
||||
* historical reasons, future versions of the library may introduce new flags.
|
||||
*
|
||||
* If the context is intended to be used for API functions that perform computations
|
||||
* involving secret keys, e.g., signing and public key generation, then it is highly
|
||||
* recommended to call secp256k1_context_randomize on the context before calling
|
||||
* those API functions. This will provide enhanced protection against side-channel
|
||||
* leakage, see secp256k1_context_randomize for details.
|
||||
*
|
||||
* Do not create a new context object for each operation, as construction and
|
||||
* randomization can take non-negligible time.
|
||||
*/
|
||||
SECP256K1_API secp256k1_context *secp256k1_context_create(
|
||||
unsigned int flags
|
||||
) SECP256K1_WARN_UNUSED_RESULT;
|
||||
|
||||
/** Copy a secp256k1 context object (into dynamically allocated memory).
|
||||
*
|
||||
* This function uses malloc to allocate memory. It is guaranteed that malloc is
|
||||
* called at most once for every call of this function. If you need to avoid dynamic
|
||||
* memory allocation entirely, see the functions in secp256k1_preallocated.h.
|
||||
*
|
||||
* Cloning secp256k1_context_static is not possible, and should not be emulated by
|
||||
* the caller (e.g., using memcpy). Create a new context instead.
|
||||
*
|
||||
* Returns: pointer to a newly created context object.
|
||||
* Args: ctx: pointer to a context to copy (not secp256k1_context_static).
|
||||
*/
|
||||
SECP256K1_API secp256k1_context *secp256k1_context_clone(
|
||||
const secp256k1_context *ctx
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT;
|
||||
|
||||
/** Destroy a secp256k1 context object (created in dynamically allocated memory).
|
||||
*
|
||||
* The context pointer may not be used afterwards.
|
||||
*
|
||||
* The context to destroy must have been created using secp256k1_context_create
|
||||
* or secp256k1_context_clone. If the context has instead been created using
|
||||
* secp256k1_context_preallocated_create or secp256k1_context_preallocated_clone, the
|
||||
* behaviour is undefined. In that case, secp256k1_context_preallocated_destroy must
|
||||
* be used instead.
|
||||
*
|
||||
* Args: ctx: pointer to a context to destroy, constructed using
|
||||
* secp256k1_context_create or secp256k1_context_clone
|
||||
* (i.e., not secp256k1_context_static).
|
||||
*/
|
||||
SECP256K1_API void secp256k1_context_destroy(
|
||||
secp256k1_context *ctx
|
||||
) SECP256K1_ARG_NONNULL(1);
|
||||
|
||||
/** Set a callback function to be called when an illegal argument is passed to
|
||||
* an API call. It will only trigger for violations that are mentioned
|
||||
* explicitly in the header.
|
||||
*
|
||||
* The philosophy is that these shouldn't be dealt with through a specific
|
||||
* return value, as calling code should not have branches to deal with the case
|
||||
* that this code itself is broken.
|
||||
*
|
||||
* On the other hand, during debug stage, one would want to be informed about
|
||||
* such mistakes, and the default (crashing) may be inadvisable. Should this
|
||||
* callback return instead of crashing, the return value and output arguments
|
||||
* of the API function call are undefined. Moreover, the same API call may
|
||||
* trigger the callback again in this case.
|
||||
*
|
||||
* When this function has not been called (or called with fun==NULL), then the
|
||||
* default callback will be used. The library provides a default callback which
|
||||
* writes the message to stderr and calls abort. This default callback can be
|
||||
* replaced at link time if the preprocessor macro
|
||||
* USE_EXTERNAL_DEFAULT_CALLBACKS is defined, which is the case if the build
|
||||
* has been configured with --enable-external-default-callbacks (GNU Autotools) or
|
||||
* -DSECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS=ON (CMake). Then the
|
||||
* following two symbols must be provided to link against:
|
||||
* - void secp256k1_default_illegal_callback_fn(const char *message, void *data);
|
||||
* - void secp256k1_default_error_callback_fn(const char *message, void *data);
|
||||
* The library may call a default callback even before a proper callback data
|
||||
* pointer could have been set using secp256k1_context_set_illegal_callback or
|
||||
* secp256k1_context_set_error_callback, e.g., when the creation of a context
|
||||
* fails. In this case, the corresponding default callback will be called with
|
||||
* the data pointer argument set to NULL.
|
||||
*
|
||||
* Args: ctx: pointer to a context object.
|
||||
* In: fun: pointer to a function to call when an illegal argument is
|
||||
* passed to the API, taking a message and an opaque pointer.
|
||||
* (NULL restores the default callback.)
|
||||
* data: the opaque pointer to pass to fun above, must be NULL for the
|
||||
* default callback.
|
||||
*
|
||||
* See also secp256k1_context_set_error_callback.
|
||||
*/
|
||||
SECP256K1_API void secp256k1_context_set_illegal_callback(
|
||||
secp256k1_context *ctx,
|
||||
void (*fun)(const char *message, void *data),
|
||||
const void *data
|
||||
) SECP256K1_ARG_NONNULL(1);
|
||||
|
||||
/** Set a callback function to be called when an internal consistency check
|
||||
* fails.
|
||||
*
|
||||
* The default callback writes an error message to stderr and calls abort
|
||||
* to abort the program.
|
||||
*
|
||||
* This can only trigger in case of a hardware failure, miscompilation,
|
||||
* memory corruption, serious bug in the library, or other error that would
|
||||
* result in undefined behaviour. It will not trigger due to mere
|
||||
* incorrect usage of the API (see secp256k1_context_set_illegal_callback
|
||||
* for that). After this callback returns, anything may happen, including
|
||||
* crashing.
|
||||
*
|
||||
* Args: ctx: pointer to a context object.
|
||||
* In: fun: pointer to a function to call when an internal error occurs,
|
||||
* taking a message and an opaque pointer (NULL restores the
|
||||
* default callback, see secp256k1_context_set_illegal_callback
|
||||
* for details).
|
||||
* data: the opaque pointer to pass to fun above, must be NULL for the
|
||||
* default callback.
|
||||
*
|
||||
* See also secp256k1_context_set_illegal_callback.
|
||||
*/
|
||||
SECP256K1_API void secp256k1_context_set_error_callback(
|
||||
secp256k1_context *ctx,
|
||||
void (*fun)(const char *message, void *data),
|
||||
const void *data
|
||||
) SECP256K1_ARG_NONNULL(1);
|
||||
|
||||
/** A pointer to a function implementing SHA256's internal compression function.
|
||||
*
|
||||
* This function processes one or more contiguous 64-byte message blocks and
|
||||
* updates the internal SHA256 state accordingly. The function is not responsible
|
||||
* for counting consumed blocks or bytes, nor for performing padding.
|
||||
*
|
||||
* In/Out: state: pointer to eight 32-bit words representing the current internal state;
|
||||
* the state is updated in place.
|
||||
* In: blocks64: pointer to concatenation of n_blocks blocks, of 64 bytes each.
|
||||
* no alignment guarantees are made for this pointer.
|
||||
* n_blocks: number of contiguous 64-byte blocks to process.
|
||||
*/
|
||||
typedef void (*secp256k1_sha256_compression_function)(
|
||||
uint32_t *state,
|
||||
const unsigned char *blocks64,
|
||||
size_t n_blocks
|
||||
);
|
||||
|
||||
/**
|
||||
* Set a callback function to override the internal SHA256 compression function.
|
||||
*
|
||||
* This installs a function to replace the built-in block-compression
|
||||
* step used by the library's internal SHA256 implementation.
|
||||
* The provided callback must exactly implement the effect of n_blocks
|
||||
* repeated applications of the SHA256 compression function.
|
||||
*
|
||||
* This API exists to support environments that wish to route the
|
||||
* SHA256 compression step through a hardware-accelerated or otherwise
|
||||
* specialized implementation. It is NOT meant for replacing SHA256
|
||||
* with a different hash function.
|
||||
*
|
||||
* Args: ctx: pointer to a context object.
|
||||
* In: fn_compression: pointer to a function implementing the compression function;
|
||||
* passing NULL restores the default implementation.
|
||||
*/
|
||||
SECP256K1_API void secp256k1_context_set_sha256_compression(
|
||||
secp256k1_context *ctx,
|
||||
secp256k1_sha256_compression_function fn_compression
|
||||
) SECP256K1_ARG_NONNULL(1);
|
||||
|
||||
/** Parse a variable-length public key into the pubkey object.
|
||||
*
|
||||
* Returns: 1 if the public key was fully valid.
|
||||
* 0 if the public key could not be parsed or is invalid.
|
||||
* Args: ctx: pointer to a context object.
|
||||
* Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to a
|
||||
* parsed version of input. If not, its value is undefined.
|
||||
* In: input: pointer to a serialized public key
|
||||
* inputlen: length of the array pointed to by input
|
||||
*
|
||||
* This function supports parsing compressed (33 bytes, header byte 0x02 or
|
||||
* 0x03), uncompressed (65 bytes, header byte 0x04), or hybrid (65 bytes, header
|
||||
* byte 0x06 or 0x07) format public keys.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_parse(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_pubkey *pubkey,
|
||||
const unsigned char *input,
|
||||
size_t inputlen
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Serialize a pubkey object into a serialized byte sequence.
|
||||
*
|
||||
* Returns: 1 always.
|
||||
* Args: ctx: pointer to a context object.
|
||||
* Out: output: pointer to a 65-byte (if compressed==0) or 33-byte (if
|
||||
* compressed==1) byte array to place the serialized key
|
||||
* in.
|
||||
* In/Out: outputlen: pointer to an integer which is initially set to the
|
||||
* size of output, and is overwritten with the written
|
||||
* size.
|
||||
* In: pubkey: pointer to a secp256k1_pubkey containing an
|
||||
* initialized public key.
|
||||
* flags: SECP256K1_EC_COMPRESSED if serialization should be in
|
||||
* compressed format, otherwise SECP256K1_EC_UNCOMPRESSED.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_ec_pubkey_serialize(
|
||||
const secp256k1_context *ctx,
|
||||
unsigned char *output,
|
||||
size_t *outputlen,
|
||||
const secp256k1_pubkey *pubkey,
|
||||
unsigned int flags
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Compare two public keys using lexicographic (of compressed serialization) order
|
||||
*
|
||||
* Returns: <0 if the first public key is less than the second
|
||||
* >0 if the first public key is greater than the second
|
||||
* 0 if the two public keys are equal
|
||||
* Args: ctx: pointer to a context object
|
||||
* In: pubkey1: first public key to compare
|
||||
* pubkey2: second public key to compare
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_cmp(
|
||||
const secp256k1_context *ctx,
|
||||
const secp256k1_pubkey *pubkey1,
|
||||
const secp256k1_pubkey *pubkey2
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Sort public keys using lexicographic (of compressed serialization) order
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid. 1 otherwise.
|
||||
*
|
||||
* Args: ctx: pointer to a context object
|
||||
* In: pubkeys: array of pointers to pubkeys to sort
|
||||
* n_pubkeys: number of elements in the pubkeys array
|
||||
*/
|
||||
SECP256K1_API int secp256k1_ec_pubkey_sort(
|
||||
const secp256k1_context *ctx,
|
||||
const secp256k1_pubkey **pubkeys,
|
||||
size_t n_pubkeys
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
|
||||
|
||||
/** Parse an ECDSA signature in compact (64 bytes) format.
|
||||
*
|
||||
* Returns: 1 when the signature could be parsed, 0 otherwise.
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: sig: pointer to a signature object
|
||||
* In: input64: pointer to the 64-byte array to parse
|
||||
*
|
||||
* The signature must consist of a 32-byte big endian R value, followed by a
|
||||
* 32-byte big endian S value. If R or S fall outside of [0..order-1], the
|
||||
* encoding is invalid. R and S with value 0 are allowed in the encoding.
|
||||
*
|
||||
* After the call, sig will always be initialized. If parsing failed or R or
|
||||
* S are zero, the resulting sig value is guaranteed to fail verification for
|
||||
* any message and public key.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_ecdsa_signature_parse_compact(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_ecdsa_signature *sig,
|
||||
const unsigned char *input64
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Parse a DER ECDSA signature.
|
||||
*
|
||||
* Returns: 1 when the signature could be parsed, 0 otherwise.
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: sig: pointer to a signature object
|
||||
* In: input: pointer to the signature to be parsed
|
||||
* inputlen: the length of the array pointed to be input
|
||||
*
|
||||
* This function will accept any valid DER encoded signature, even if the
|
||||
* encoded numbers are out of range.
|
||||
*
|
||||
* After the call, sig will always be initialized. If parsing failed or the
|
||||
* encoded numbers are out of range, signature verification with it is
|
||||
* guaranteed to fail for every message and public key.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_ecdsa_signature_parse_der(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_ecdsa_signature *sig,
|
||||
const unsigned char *input,
|
||||
size_t inputlen
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Serialize an ECDSA signature in DER format.
|
||||
*
|
||||
* Returns: 1 if enough space was available to serialize, 0 otherwise
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: output: pointer to an array to store the DER serialization
|
||||
* In/Out: outputlen: pointer to a length integer. Initially, this integer
|
||||
* should be set to the length of output. After the call
|
||||
* it will be set to the length of the serialization (even
|
||||
* if 0 was returned).
|
||||
* In: sig: pointer to an initialized signature object
|
||||
*/
|
||||
SECP256K1_API int secp256k1_ecdsa_signature_serialize_der(
|
||||
const secp256k1_context *ctx,
|
||||
unsigned char *output,
|
||||
size_t *outputlen,
|
||||
const secp256k1_ecdsa_signature *sig
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Serialize an ECDSA signature in compact (64 byte) format.
|
||||
*
|
||||
* Returns: 1
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: output64: pointer to a 64-byte array to store the compact serialization
|
||||
* In: sig: pointer to an initialized signature object
|
||||
*
|
||||
* See secp256k1_ecdsa_signature_parse_compact for details about the encoding.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_ecdsa_signature_serialize_compact(
|
||||
const secp256k1_context *ctx,
|
||||
unsigned char *output64,
|
||||
const secp256k1_ecdsa_signature *sig
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Verify an ECDSA signature.
|
||||
*
|
||||
* Returns: 1: correct signature
|
||||
* 0: incorrect or unparseable signature
|
||||
* Args: ctx: pointer to a context object
|
||||
* In: sig: the signature being verified.
|
||||
* msghash32: the 32-byte message hash being verified.
|
||||
* The verifier must make sure to apply a cryptographic
|
||||
* hash function to the message by itself and not accept an
|
||||
* msghash32 value directly. Otherwise, it would be easy to
|
||||
* create a "valid" signature without knowledge of the
|
||||
* secret key. See also
|
||||
* https://bitcoin.stackexchange.com/a/81116/35586 for more
|
||||
* background on this topic.
|
||||
* pubkey: pointer to an initialized public key to verify with.
|
||||
*
|
||||
* To avoid accepting malleable signatures, only ECDSA signatures in lower-S
|
||||
* form are accepted.
|
||||
*
|
||||
* If you need to accept ECDSA signatures from sources that do not obey this
|
||||
* rule, apply secp256k1_ecdsa_signature_normalize to the signature prior to
|
||||
* verification, but be aware that doing so results in malleable signatures.
|
||||
*
|
||||
* For details, see the comments for that function.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify(
|
||||
const secp256k1_context *ctx,
|
||||
const secp256k1_ecdsa_signature *sig,
|
||||
const unsigned char *msghash32,
|
||||
const secp256k1_pubkey *pubkey
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Convert a signature to a normalized lower-S form.
|
||||
*
|
||||
* Returns: 1 if sigin was not normalized, 0 if it already was.
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: sigout: pointer to a signature to fill with the normalized form,
|
||||
* or copy if the input was already normalized. (can be NULL if
|
||||
* you're only interested in whether the input was already
|
||||
* normalized).
|
||||
* In: sigin: pointer to a signature to check/normalize (can be identical to sigout)
|
||||
*
|
||||
* With ECDSA a third-party can forge a second distinct signature of the same
|
||||
* message, given a single initial signature, but without knowing the key. This
|
||||
* is done by negating the S value modulo the order of the curve, 'flipping'
|
||||
* the sign of the random point R which is not included in the signature.
|
||||
*
|
||||
* Forgery of the same message isn't universally problematic, but in systems
|
||||
* where message malleability or uniqueness of signatures is important this can
|
||||
* cause issues. This forgery can be blocked by all verifiers forcing signers
|
||||
* to use a normalized form.
|
||||
*
|
||||
* The lower-S form reduces the size of signatures slightly on average when
|
||||
* variable length encodings (such as DER) are used and is cheap to verify,
|
||||
* making it a good choice. Security of always using lower-S is assured because
|
||||
* anyone can trivially modify a signature after the fact to enforce this
|
||||
* property anyway.
|
||||
*
|
||||
* The lower S value is always between 0x1 and
|
||||
* 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0,
|
||||
* inclusive.
|
||||
*
|
||||
* No other forms of ECDSA malleability are known and none seem likely, but
|
||||
* there is no formal proof that ECDSA, even with this additional restriction,
|
||||
* is free of other malleability. Commonly used serialization schemes will also
|
||||
* accept various non-unique encodings, so care should be taken when this
|
||||
* property is required for an application.
|
||||
*
|
||||
* The secp256k1_ecdsa_sign function will by default create signatures in the
|
||||
* lower-S form, and secp256k1_ecdsa_verify will not accept others. In case
|
||||
* signatures come from a system that cannot enforce this property,
|
||||
* secp256k1_ecdsa_signature_normalize must be called before verification.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_ecdsa_signature_normalize(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_ecdsa_signature *sigout,
|
||||
const secp256k1_ecdsa_signature *sigin
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** An implementation of RFC6979 (using HMAC-SHA256) as nonce generation function.
|
||||
* If a data pointer is passed, it is assumed to be a pointer to 32 bytes of
|
||||
* extra entropy.
|
||||
*/
|
||||
SECP256K1_API const secp256k1_nonce_function secp256k1_nonce_function_rfc6979;
|
||||
|
||||
/** A default safe nonce generation function (currently equal to secp256k1_nonce_function_rfc6979). */
|
||||
SECP256K1_API const secp256k1_nonce_function secp256k1_nonce_function_default;
|
||||
|
||||
/** Create an ECDSA signature.
|
||||
*
|
||||
* Returns: 1: signature created
|
||||
* 0: the nonce generation function failed, or the secret key was invalid.
|
||||
* Args: ctx: pointer to a context object (not secp256k1_context_static).
|
||||
* Out: sig: pointer to an array where the signature will be placed.
|
||||
* In: msghash32: the 32-byte message hash being signed.
|
||||
* seckey: pointer to a 32-byte secret key.
|
||||
* noncefp: pointer to a nonce generation function. If NULL,
|
||||
* secp256k1_nonce_function_default is used.
|
||||
* ndata: pointer to arbitrary data used by the nonce generation function
|
||||
* (can be NULL). If it is non-NULL and
|
||||
* secp256k1_nonce_function_default is used, then ndata must be a
|
||||
* pointer to 32-bytes of additional data.
|
||||
*
|
||||
* The created signature is always in lower-S form. See
|
||||
* secp256k1_ecdsa_signature_normalize for more details.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_ecdsa_sign(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_ecdsa_signature *sig,
|
||||
const unsigned char *msghash32,
|
||||
const unsigned char *seckey,
|
||||
secp256k1_nonce_function noncefp,
|
||||
const void *ndata
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Verify an elliptic curve secret key.
|
||||
*
|
||||
* A secret key is valid if it is not 0 and less than the secp256k1 curve order
|
||||
* when interpreted as an integer (most significant byte first). The
|
||||
* probability of choosing a 32-byte string uniformly at random which is an
|
||||
* invalid secret key is negligible. However, if it does happen it should
|
||||
* be assumed that the randomness source is severely broken and there should
|
||||
* be no retry.
|
||||
*
|
||||
* Returns: 1: secret key is valid
|
||||
* 0: secret key is invalid
|
||||
* Args: ctx: pointer to a context object.
|
||||
* In: seckey: pointer to a 32-byte secret key.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_verify(
|
||||
const secp256k1_context *ctx,
|
||||
const unsigned char *seckey
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
|
||||
|
||||
/** Compute the public key for a secret key.
|
||||
*
|
||||
* Returns: 1: secret was valid, public key stores.
|
||||
* 0: secret was invalid, try again.
|
||||
* Args: ctx: pointer to a context object (not secp256k1_context_static).
|
||||
* Out: pubkey: pointer to the created public key.
|
||||
* In: seckey: pointer to a 32-byte secret key.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_pubkey *pubkey,
|
||||
const unsigned char *seckey
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Negates a secret key in place.
|
||||
*
|
||||
* Returns: 0 if the given secret key is invalid according to
|
||||
* secp256k1_ec_seckey_verify. 1 otherwise
|
||||
* Args: ctx: pointer to a context object
|
||||
* In/Out: seckey: pointer to the 32-byte secret key to be negated. If the
|
||||
* secret key is invalid according to
|
||||
* secp256k1_ec_seckey_verify, this function returns 0 and
|
||||
* seckey will be set to some unspecified value.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_negate(
|
||||
const secp256k1_context *ctx,
|
||||
unsigned char *seckey
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
|
||||
|
||||
/** Negates a public key in place.
|
||||
*
|
||||
* Returns: 1 always
|
||||
* Args: ctx: pointer to a context object
|
||||
* In/Out: pubkey: pointer to the public key to be negated.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_ec_pubkey_negate(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_pubkey *pubkey
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
|
||||
|
||||
/** Tweak a secret key by adding tweak to it.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid or the resulting secret key would be
|
||||
* invalid (only when the tweak is the negation of the secret key). 1
|
||||
* otherwise.
|
||||
* Args: ctx: pointer to a context object.
|
||||
* In/Out: seckey: pointer to a 32-byte secret key. If the secret key is
|
||||
* invalid according to secp256k1_ec_seckey_verify, this
|
||||
* function returns 0. seckey will be set to some unspecified
|
||||
* value if this function returns 0.
|
||||
* In: tweak32: pointer to a 32-byte tweak, which must be valid according to
|
||||
* secp256k1_ec_seckey_verify or 32 zero bytes. For uniformly
|
||||
* random 32-byte tweaks, the chance of being invalid is
|
||||
* negligible (around 1 in 2^128).
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_tweak_add(
|
||||
const secp256k1_context *ctx,
|
||||
unsigned char *seckey,
|
||||
const unsigned char *tweak32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Tweak a public key by adding tweak times the generator to it.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid or the resulting public key would be
|
||||
* invalid (only when the tweak is the negation of the corresponding
|
||||
* secret key). 1 otherwise.
|
||||
* Args: ctx: pointer to a context object.
|
||||
* In/Out: pubkey: pointer to a public key object. pubkey will be set to an
|
||||
* invalid value if this function returns 0.
|
||||
* In: tweak32: pointer to a 32-byte tweak, which must be valid according to
|
||||
* secp256k1_ec_seckey_verify or 32 zero bytes. For uniformly
|
||||
* random 32-byte tweaks, the chance of being invalid is
|
||||
* negligible (around 1 in 2^128).
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_pubkey *pubkey,
|
||||
const unsigned char *tweak32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Tweak a secret key by multiplying it by a tweak.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid. 1 otherwise.
|
||||
* Args: ctx: pointer to a context object.
|
||||
* In/Out: seckey: pointer to a 32-byte secret key. If the secret key is
|
||||
* invalid according to secp256k1_ec_seckey_verify, this
|
||||
* function returns 0. seckey will be set to some unspecified
|
||||
* value if this function returns 0.
|
||||
* In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according to
|
||||
* secp256k1_ec_seckey_verify, this function returns 0. For
|
||||
* uniformly random 32-byte arrays the chance of being invalid
|
||||
* is negligible (around 1 in 2^128).
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_tweak_mul(
|
||||
const secp256k1_context *ctx,
|
||||
unsigned char *seckey,
|
||||
const unsigned char *tweak32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Tweak a public key by multiplying it by a tweak value.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid. 1 otherwise.
|
||||
* Args: ctx: pointer to a context object.
|
||||
* In/Out: pubkey: pointer to a public key object. pubkey will be set to an
|
||||
* invalid value if this function returns 0.
|
||||
* In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according to
|
||||
* secp256k1_ec_seckey_verify, this function returns 0. For
|
||||
* uniformly random 32-byte arrays the chance of being invalid
|
||||
* is negligible (around 1 in 2^128).
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_pubkey *pubkey,
|
||||
const unsigned char *tweak32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Randomizes the context to provide enhanced protection against side-channel leakage.
|
||||
*
|
||||
* Returns: 1: randomization successful
|
||||
* 0: error
|
||||
* Args: ctx: pointer to a context object (not secp256k1_context_static).
|
||||
* In: seed32: pointer to a 32-byte random seed (NULL resets to initial state).
|
||||
*
|
||||
* While secp256k1 code is written and tested to be constant-time no matter what
|
||||
* secret values are, it is possible that a compiler may output code which is not,
|
||||
* and also that the CPU may not emit the same radio frequencies or draw the same
|
||||
* amount of power for all values. Randomization of the context shields against
|
||||
* side-channel observations which aim to exploit secret-dependent behaviour in
|
||||
* certain computations which involve secret keys.
|
||||
*
|
||||
* It is highly recommended to call this function on contexts returned from
|
||||
* secp256k1_context_create or secp256k1_context_clone (or from the corresponding
|
||||
* functions in secp256k1_preallocated.h) before using these contexts to call API
|
||||
* functions that perform computations involving secret keys, e.g., signing and
|
||||
* public key generation. It is possible to call this function more than once on
|
||||
* the same context, and doing so before every few computations involving secret
|
||||
* keys is recommended as a defense-in-depth measure. Randomization of the static
|
||||
* context secp256k1_context_static is not supported.
|
||||
*
|
||||
* Currently, the random seed is mainly used for blinding multiplications of a
|
||||
* secret scalar with the elliptic curve base point. Multiplications of this
|
||||
* kind are performed by exactly those API functions which are documented to
|
||||
* require a context that is not secp256k1_context_static. As a rule of thumb,
|
||||
* these are all functions which take a secret key (or a keypair) as an input.
|
||||
* A notable exception to that rule is the ECDH module, which relies on a different
|
||||
* kind of elliptic curve point multiplication and thus does not benefit from
|
||||
* enhanced protection against side-channel leakage currently.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize(
|
||||
secp256k1_context *ctx,
|
||||
const unsigned char *seed32
|
||||
) SECP256K1_ARG_NONNULL(1);
|
||||
|
||||
/** Add a number of public keys together.
|
||||
*
|
||||
* Returns: 1: the sum of the public keys is valid.
|
||||
* 0: the sum of the public keys is not valid.
|
||||
* Args: ctx: pointer to a context object.
|
||||
* Out: out: pointer to a public key object for placing the resulting public key.
|
||||
* In: ins: pointer to array of pointers to public keys.
|
||||
* n: the number of public keys to add together (must be at least 1).
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_combine(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_pubkey *out,
|
||||
const secp256k1_pubkey * const *ins,
|
||||
size_t n
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Compute a tagged hash as defined in BIP-340.
|
||||
*
|
||||
* This is useful for creating a message hash and achieving domain separation
|
||||
* through an application-specific tag. This function returns
|
||||
* SHA256(SHA256(tag)||SHA256(tag)||msg). Therefore, tagged hash
|
||||
* implementations optimized for a specific tag can precompute the SHA256 state
|
||||
* after hashing the tag hashes.
|
||||
*
|
||||
* Returns: 1 always.
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: hash32: pointer to a 32-byte array to store the resulting hash
|
||||
* In: tag: pointer to an array containing the tag
|
||||
* taglen: length of the tag array
|
||||
* msg: pointer to an array containing the message
|
||||
* msglen: length of the message array
|
||||
*/
|
||||
SECP256K1_API int secp256k1_tagged_sha256(
|
||||
const secp256k1_context *ctx,
|
||||
unsigned char *hash32,
|
||||
const unsigned char *tag,
|
||||
size_t taglen,
|
||||
const unsigned char *msg,
|
||||
size_t msglen
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SECP256K1_H */
|
||||
@@ -0,0 +1,63 @@
|
||||
#ifndef SECP256K1_ECDH_H
|
||||
#define SECP256K1_ECDH_H
|
||||
|
||||
#include "secp256k1.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** A pointer to a function that hashes an EC point to obtain an ECDH secret
|
||||
*
|
||||
* Returns: 1 if the point was successfully hashed.
|
||||
* 0 will cause secp256k1_ecdh to fail and return 0.
|
||||
* Other return values are not allowed, and the behaviour of
|
||||
* secp256k1_ecdh is undefined for other return values.
|
||||
* Out: output: pointer to an array to be filled by the function
|
||||
* In: x32: pointer to a 32-byte x coordinate
|
||||
* y32: pointer to a 32-byte y coordinate
|
||||
* data: arbitrary data pointer that is passed through
|
||||
*/
|
||||
typedef int (*secp256k1_ecdh_hash_function)(
|
||||
unsigned char *output,
|
||||
const unsigned char *x32,
|
||||
const unsigned char *y32,
|
||||
void *data
|
||||
);
|
||||
|
||||
/** An implementation of SHA256 hash function that applies to compressed public key.
|
||||
* Populates the output parameter with 32 bytes. */
|
||||
SECP256K1_API const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_sha256;
|
||||
|
||||
/** A default ECDH hash function (currently equal to secp256k1_ecdh_hash_function_sha256).
|
||||
* Populates the output parameter with 32 bytes. */
|
||||
SECP256K1_API const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_default;
|
||||
|
||||
/** Compute an EC Diffie-Hellman secret in constant time
|
||||
*
|
||||
* Returns: 1: exponentiation was successful
|
||||
* 0: scalar was invalid (zero or overflow) or hashfp returned 0
|
||||
* Args: ctx: pointer to a context object.
|
||||
* Out: output: pointer to an array to be filled by hashfp.
|
||||
* In: pubkey: pointer to a secp256k1_pubkey containing an initialized public key.
|
||||
* seckey: a 32-byte scalar with which to multiply the point.
|
||||
* hashfp: pointer to a hash function. If NULL,
|
||||
* secp256k1_ecdh_hash_function_sha256 is used
|
||||
* (in which case, 32 bytes will be written to output).
|
||||
* data: arbitrary data pointer that is passed through to hashfp
|
||||
* (can be NULL for secp256k1_ecdh_hash_function_sha256).
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdh(
|
||||
const secp256k1_context *ctx,
|
||||
unsigned char *output,
|
||||
const secp256k1_pubkey *pubkey,
|
||||
const unsigned char *seckey,
|
||||
secp256k1_ecdh_hash_function hashfp,
|
||||
void *data
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SECP256K1_ECDH_H */
|
||||
@@ -0,0 +1,200 @@
|
||||
#ifndef SECP256K1_ELLSWIFT_H
|
||||
#define SECP256K1_ELLSWIFT_H
|
||||
|
||||
#include "secp256k1.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* This module provides an implementation of ElligatorSwift as well as a
|
||||
* version of x-only ECDH using it (including compatibility with BIP324).
|
||||
*
|
||||
* ElligatorSwift is described in https://eprint.iacr.org/2022/759 by
|
||||
* Chavez-Saab, Rodriguez-Henriquez, and Tibouchi. It permits encoding
|
||||
* uniformly chosen public keys as 64-byte arrays which are indistinguishable
|
||||
* from uniformly random arrays.
|
||||
*
|
||||
* Let f be the function from pairs of field elements to point X coordinates,
|
||||
* defined as follows (all operations modulo p = 2^256 - 2^32 - 977)
|
||||
* f(u,t):
|
||||
* - Let C = 0xa2d2ba93507f1df233770c2a797962cc61f6d15da14ecd47d8d27ae1cd5f852,
|
||||
* a square root of -3.
|
||||
* - If u=0, set u=1 instead.
|
||||
* - If t=0, set t=1 instead.
|
||||
* - If u^3 + t^2 + 7 = 0, multiply t by 2.
|
||||
* - Let X = (u^3 + 7 - t^2) / (2 * t)
|
||||
* - Let Y = (X + t) / (C * u)
|
||||
* - Return the first in [u + 4 * Y^2, (-X/Y - u) / 2, (X/Y - u) / 2] that is an
|
||||
* X coordinate on the curve (at least one of them is, for any u and t).
|
||||
*
|
||||
* Then an ElligatorSwift encoding of x consists of the 32-byte big-endian
|
||||
* encodings of field elements u and t concatenated, where f(u,t) = x.
|
||||
* The encoding algorithm is described in the paper, and effectively picks a
|
||||
* uniformly random pair (u,t) among those which encode x.
|
||||
*
|
||||
* If the Y coordinate is relevant, it is given the same parity as t.
|
||||
*
|
||||
* Changes w.r.t. the paper:
|
||||
* - The u=0, t=0, and u^3+t^2+7=0 conditions result in decoding to the point
|
||||
* at infinity in the paper. Here they are remapped to finite points.
|
||||
* - The paper uses an additional encoding bit for the parity of y. Here the
|
||||
* parity of t is used (negating t does not affect the decoded x coordinate,
|
||||
* so this is possible).
|
||||
*
|
||||
* For mathematical background about the scheme, see the doc/ellswift.md file.
|
||||
*/
|
||||
|
||||
/** A pointer to a function used by secp256k1_ellswift_xdh to hash the shared X
|
||||
* coordinate along with the encoded public keys to a uniform shared secret.
|
||||
*
|
||||
* Returns: 1 if a shared secret was successfully computed.
|
||||
* 0 will cause secp256k1_ellswift_xdh to fail and return 0.
|
||||
* Other return values are not allowed, and the behaviour of
|
||||
* secp256k1_ellswift_xdh is undefined for other return values.
|
||||
* Out: output: pointer to an array to be filled by the function
|
||||
* In: x32: pointer to the 32-byte serialized X coordinate
|
||||
* of the resulting shared point (will not be NULL)
|
||||
* ell_a64: pointer to the 64-byte encoded public key of party A
|
||||
* (will not be NULL)
|
||||
* ell_b64: pointer to the 64-byte encoded public key of party B
|
||||
* (will not be NULL)
|
||||
* data: arbitrary data pointer that is passed through
|
||||
*/
|
||||
typedef int (*secp256k1_ellswift_xdh_hash_function)(
|
||||
unsigned char *output,
|
||||
const unsigned char *x32,
|
||||
const unsigned char *ell_a64,
|
||||
const unsigned char *ell_b64,
|
||||
void *data
|
||||
);
|
||||
|
||||
/** An implementation of an secp256k1_ellswift_xdh_hash_function which uses
|
||||
* SHA256(prefix64 || ell_a64 || ell_b64 || x32), where prefix64 is the 64-byte
|
||||
* array pointed to by data. */
|
||||
SECP256K1_API const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_prefix;
|
||||
|
||||
/** An implementation of an secp256k1_ellswift_xdh_hash_function compatible with
|
||||
* BIP324. It returns H_tag(ell_a64 || ell_b64 || x32), where H_tag is the
|
||||
* BIP340 tagged hash function with tag "bip324_ellswift_xonly_ecdh". Equivalent
|
||||
* to secp256k1_ellswift_xdh_hash_function_prefix with prefix64 set to
|
||||
* SHA256("bip324_ellswift_xonly_ecdh")||SHA256("bip324_ellswift_xonly_ecdh").
|
||||
* The data argument is ignored. */
|
||||
SECP256K1_API const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_bip324;
|
||||
|
||||
/** Construct a 64-byte ElligatorSwift encoding of a given pubkey.
|
||||
*
|
||||
* Returns: 1 always.
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: ell64: pointer to a 64-byte array to be filled
|
||||
* In: pubkey: pointer to a secp256k1_pubkey containing an
|
||||
* initialized public key
|
||||
* rnd32: pointer to 32 bytes of randomness
|
||||
*
|
||||
* It is recommended that rnd32 consists of 32 uniformly random bytes, not
|
||||
* known to any adversary trying to detect whether public keys are being
|
||||
* encoded, though 16 bytes of randomness (padded to an array of 32 bytes,
|
||||
* e.g., with zeros) suffice to make the result indistinguishable from
|
||||
* uniform. The randomness in rnd32 must not be a deterministic function of
|
||||
* the pubkey (it can be derived from the private key, though).
|
||||
*
|
||||
* It is not guaranteed that the computed encoding is stable across versions
|
||||
* of the library, even if all arguments to this function (including rnd32)
|
||||
* are the same.
|
||||
*
|
||||
* This function runs in variable time.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_ellswift_encode(
|
||||
const secp256k1_context *ctx,
|
||||
unsigned char *ell64,
|
||||
const secp256k1_pubkey *pubkey,
|
||||
const unsigned char *rnd32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Decode a 64-bytes ElligatorSwift encoded public key.
|
||||
*
|
||||
* Returns: always 1
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: pubkey: pointer to a secp256k1_pubkey that will be filled
|
||||
* In: ell64: pointer to a 64-byte array to decode
|
||||
*
|
||||
* This function runs in variable time.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_ellswift_decode(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_pubkey *pubkey,
|
||||
const unsigned char *ell64
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Compute an ElligatorSwift public key for a secret key.
|
||||
*
|
||||
* Returns: 1: secret was valid, public key was stored.
|
||||
* 0: secret was invalid, try again.
|
||||
* Args: ctx: pointer to a context object (not secp256k1_context_static)
|
||||
* Out: ell64: pointer to a 64-byte array to receive the ElligatorSwift
|
||||
* public key
|
||||
* In: seckey32: pointer to a 32-byte secret key
|
||||
* auxrnd32: (optional) pointer to 32 bytes of randomness
|
||||
*
|
||||
* Constant time in seckey and auxrnd32, but not in the resulting public key.
|
||||
*
|
||||
* It is recommended that auxrnd32 contains 32 uniformly random bytes, though
|
||||
* it is optional (and does result in encodings that are indistinguishable from
|
||||
* uniform even without any auxrnd32). It differs from the (mandatory) rnd32
|
||||
* argument to secp256k1_ellswift_encode in this regard.
|
||||
*
|
||||
* This function can be used instead of calling secp256k1_ec_pubkey_create
|
||||
* followed by secp256k1_ellswift_encode. It is safer, as it uses the secret
|
||||
* key as entropy for the encoding (supplemented with auxrnd32, if provided).
|
||||
*
|
||||
* Like secp256k1_ellswift_encode, this function does not guarantee that the
|
||||
* computed encoding is stable across versions of the library, even if all
|
||||
* arguments (including auxrnd32) are the same.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ellswift_create(
|
||||
const secp256k1_context *ctx,
|
||||
unsigned char *ell64,
|
||||
const unsigned char *seckey32,
|
||||
const unsigned char *auxrnd32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Given a private key, and ElligatorSwift public keys sent in both directions,
|
||||
* compute a shared secret using x-only Elliptic Curve Diffie-Hellman (ECDH).
|
||||
*
|
||||
* Returns: 1: shared secret was successfully computed
|
||||
* 0: secret was invalid or hashfp returned 0
|
||||
* Args: ctx: pointer to a context object.
|
||||
* Out: output: pointer to an array to be filled by hashfp.
|
||||
* In: ell_a64: pointer to the 64-byte encoded public key of party A
|
||||
* (will not be NULL)
|
||||
* ell_b64: pointer to the 64-byte encoded public key of party B
|
||||
* (will not be NULL)
|
||||
* seckey32: pointer to our 32-byte secret key
|
||||
* party: boolean indicating which party we are: zero if we are
|
||||
* party A, non-zero if we are party B. seckey32 must be
|
||||
* the private key corresponding to that party's ell_?64.
|
||||
* This correspondence is not checked.
|
||||
* hashfp: pointer to a hash function.
|
||||
* data: arbitrary data pointer passed through to hashfp.
|
||||
*
|
||||
* Constant time in seckey32.
|
||||
*
|
||||
* This function is more efficient than decoding the public keys, and performing
|
||||
* ECDH on them.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ellswift_xdh(
|
||||
const secp256k1_context *ctx,
|
||||
unsigned char *output,
|
||||
const unsigned char *ell_a64,
|
||||
const unsigned char *ell_b64,
|
||||
const unsigned char *seckey32,
|
||||
int party,
|
||||
secp256k1_ellswift_xdh_hash_function hashfp,
|
||||
void *data
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(7);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SECP256K1_ELLSWIFT_H */
|
||||
@@ -0,0 +1,250 @@
|
||||
#ifndef SECP256K1_EXTRAKEYS_H
|
||||
#define SECP256K1_EXTRAKEYS_H
|
||||
|
||||
#include "secp256k1.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Opaque data structure that holds a parsed and valid "x-only" public key.
|
||||
* An x-only pubkey encodes a point whose Y coordinate is even. It is
|
||||
* serialized using only its X coordinate (32 bytes). See BIP-340 for more
|
||||
* information about x-only pubkeys.
|
||||
*
|
||||
* The exact representation of data inside is implementation defined and not
|
||||
* guaranteed to be portable between different platforms or versions. It is
|
||||
* however guaranteed to be 64 bytes in size, and can be safely copied/moved.
|
||||
* If you need to convert to a format suitable for storage, transmission, use
|
||||
* use secp256k1_xonly_pubkey_serialize and secp256k1_xonly_pubkey_parse. To
|
||||
* compare keys, use secp256k1_xonly_pubkey_cmp.
|
||||
*/
|
||||
typedef struct secp256k1_xonly_pubkey {
|
||||
unsigned char data[64];
|
||||
} secp256k1_xonly_pubkey;
|
||||
|
||||
/** Opaque data structure that holds a keypair consisting of a secret and a
|
||||
* public key.
|
||||
*
|
||||
* The exact representation of data inside is implementation defined and not
|
||||
* guaranteed to be portable between different platforms or versions. It is
|
||||
* however guaranteed to be 96 bytes in size, and can be safely copied/moved.
|
||||
*/
|
||||
typedef struct secp256k1_keypair {
|
||||
unsigned char data[96];
|
||||
} secp256k1_keypair;
|
||||
|
||||
/** Parse a 32-byte sequence into a xonly_pubkey object.
|
||||
*
|
||||
* Returns: 1 if the public key was fully valid.
|
||||
* 0 if the public key could not be parsed or is invalid.
|
||||
*
|
||||
* Args: ctx: pointer to a context object.
|
||||
* Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to a
|
||||
* parsed version of input. If not, it's set to an invalid value.
|
||||
* In: input32: pointer to a serialized xonly_pubkey.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_parse(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_xonly_pubkey *pubkey,
|
||||
const unsigned char *input32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Serialize an xonly_pubkey object into a 32-byte sequence.
|
||||
*
|
||||
* Returns: 1 always.
|
||||
*
|
||||
* Args: ctx: pointer to a context object.
|
||||
* Out: output32: pointer to a 32-byte array to place the serialized key in.
|
||||
* In: pubkey: pointer to a secp256k1_xonly_pubkey containing an initialized public key.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_xonly_pubkey_serialize(
|
||||
const secp256k1_context *ctx,
|
||||
unsigned char *output32,
|
||||
const secp256k1_xonly_pubkey *pubkey
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Compare two x-only public keys using lexicographic order
|
||||
*
|
||||
* Returns: <0 if the first public key is less than the second
|
||||
* >0 if the first public key is greater than the second
|
||||
* 0 if the two public keys are equal
|
||||
* Args: ctx: pointer to a context object.
|
||||
* In: pubkey1: first public key to compare
|
||||
* pubkey2: second public key to compare
|
||||
*/
|
||||
SECP256K1_API int secp256k1_xonly_pubkey_cmp(
|
||||
const secp256k1_context *ctx,
|
||||
const secp256k1_xonly_pubkey *pk1,
|
||||
const secp256k1_xonly_pubkey *pk2
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Converts a secp256k1_pubkey into a secp256k1_xonly_pubkey.
|
||||
*
|
||||
* Returns: 1 always.
|
||||
*
|
||||
* Args: ctx: pointer to a context object.
|
||||
* Out: xonly_pubkey: pointer to an x-only public key object for placing the converted public key.
|
||||
* pk_parity: Ignored if NULL. Otherwise, pointer to an integer that
|
||||
* will be set to 1 if the point encoded by xonly_pubkey is
|
||||
* the negation of the pubkey and set to 0 otherwise.
|
||||
* In: pubkey: pointer to a public key that is converted.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_xonly_pubkey_from_pubkey(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_xonly_pubkey *xonly_pubkey,
|
||||
int *pk_parity,
|
||||
const secp256k1_pubkey *pubkey
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Tweak an x-only public key by adding the generator multiplied with tweak32
|
||||
* to it.
|
||||
*
|
||||
* Note that the resulting point can not in general be represented by an x-only
|
||||
* pubkey because it may have an odd Y coordinate. Instead, the output_pubkey
|
||||
* is a normal secp256k1_pubkey.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid or the resulting public key would be
|
||||
* invalid (only when the tweak is the negation of the corresponding
|
||||
* secret key). 1 otherwise.
|
||||
*
|
||||
* Args: ctx: pointer to a context object.
|
||||
* Out: output_pubkey: pointer to a public key to store the result. Will be set
|
||||
* to an invalid value if this function returns 0.
|
||||
* In: internal_pubkey: pointer to an x-only pubkey to apply the tweak to.
|
||||
* tweak32: pointer to a 32-byte tweak, which must be valid
|
||||
* according to secp256k1_ec_seckey_verify or 32 zero
|
||||
* bytes. For uniformly random 32-byte tweaks, the chance of
|
||||
* being invalid is negligible (around 1 in 2^128).
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_pubkey *output_pubkey,
|
||||
const secp256k1_xonly_pubkey *internal_pubkey,
|
||||
const unsigned char *tweak32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Checks that a tweaked pubkey is the result of calling
|
||||
* secp256k1_xonly_pubkey_tweak_add with internal_pubkey and tweak32.
|
||||
*
|
||||
* The tweaked pubkey is represented by its 32-byte x-only serialization and
|
||||
* its pk_parity, which can both be obtained by converting the result of
|
||||
* tweak_add to a secp256k1_xonly_pubkey.
|
||||
*
|
||||
* Note that this alone does _not_ verify that the tweaked pubkey is a
|
||||
* commitment. If the tweak is not chosen in a specific way, the tweaked pubkey
|
||||
* can easily be the result of a different internal_pubkey and tweak.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid or the tweaked pubkey is not the
|
||||
* result of tweaking the internal_pubkey with tweak32. 1 otherwise.
|
||||
* Args: ctx: pointer to a context object.
|
||||
* In: tweaked_pubkey32: pointer to a serialized xonly_pubkey.
|
||||
* tweaked_pk_parity: the parity of the tweaked pubkey (whose serialization
|
||||
* is passed in as tweaked_pubkey32). This must match the
|
||||
* pk_parity value that is returned when calling
|
||||
* secp256k1_xonly_pubkey with the tweaked pubkey, or
|
||||
* this function will fail.
|
||||
* internal_pubkey: pointer to an x-only public key object to apply the tweak to.
|
||||
* tweak32: pointer to a 32-byte tweak.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add_check(
|
||||
const secp256k1_context *ctx,
|
||||
const unsigned char *tweaked_pubkey32,
|
||||
int tweaked_pk_parity,
|
||||
const secp256k1_xonly_pubkey *internal_pubkey,
|
||||
const unsigned char *tweak32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
|
||||
|
||||
/** Compute the keypair for a valid secret key.
|
||||
*
|
||||
* See the documentation of `secp256k1_ec_seckey_verify` for more information
|
||||
* about the validity of secret keys.
|
||||
*
|
||||
* Returns: 1: secret key is valid
|
||||
* 0: secret key is invalid
|
||||
* Args: ctx: pointer to a context object (not secp256k1_context_static).
|
||||
* Out: keypair: pointer to the created keypair.
|
||||
* In: seckey: pointer to a 32-byte secret key.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_create(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_keypair *keypair,
|
||||
const unsigned char *seckey
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Get the secret key from a keypair.
|
||||
*
|
||||
* Returns: 1 always.
|
||||
* Args: ctx: pointer to a context object.
|
||||
* Out: seckey: pointer to a 32-byte buffer for the secret key.
|
||||
* In: keypair: pointer to a keypair.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_keypair_sec(
|
||||
const secp256k1_context *ctx,
|
||||
unsigned char *seckey,
|
||||
const secp256k1_keypair *keypair
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Get the public key from a keypair.
|
||||
*
|
||||
* Returns: 1 always.
|
||||
* Args: ctx: pointer to a context object.
|
||||
* Out: pubkey: pointer to a pubkey object, set to the keypair public key.
|
||||
* In: keypair: pointer to a keypair.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_keypair_pub(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_pubkey *pubkey,
|
||||
const secp256k1_keypair *keypair
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Get the x-only public key from a keypair.
|
||||
*
|
||||
* This is the same as calling secp256k1_keypair_pub and then
|
||||
* secp256k1_xonly_pubkey_from_pubkey.
|
||||
*
|
||||
* Returns: 1 always.
|
||||
* Args: ctx: pointer to a context object.
|
||||
* Out: pubkey: pointer to an xonly_pubkey object, set to the keypair
|
||||
* public key after converting it to an xonly_pubkey.
|
||||
* pk_parity: Ignored if NULL. Otherwise, pointer to an integer that will be set to the
|
||||
* pk_parity argument of secp256k1_xonly_pubkey_from_pubkey.
|
||||
* In: keypair: pointer to a keypair.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_keypair_xonly_pub(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_xonly_pubkey *pubkey,
|
||||
int *pk_parity,
|
||||
const secp256k1_keypair *keypair
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Tweak a keypair by adding tweak32 to the secret key and updating the public
|
||||
* key accordingly.
|
||||
*
|
||||
* Calling this function and then secp256k1_keypair_pub results in the same
|
||||
* public key as calling secp256k1_keypair_xonly_pub and then
|
||||
* secp256k1_xonly_pubkey_tweak_add.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid or the resulting keypair would be
|
||||
* invalid (only when the tweak is the negation of the keypair's
|
||||
* secret key). 1 otherwise.
|
||||
*
|
||||
* Args: ctx: pointer to a context object.
|
||||
* In/Out: keypair: pointer to a keypair to apply the tweak to. Will be set to
|
||||
* an invalid value if this function returns 0.
|
||||
* In: tweak32: pointer to a 32-byte tweak, which must be valid according to
|
||||
* secp256k1_ec_seckey_verify or 32 zero bytes. For uniformly
|
||||
* random 32-byte tweaks, the chance of being invalid is
|
||||
* negligible (around 1 in 2^128).
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_tweak_add(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_keypair *keypair,
|
||||
const unsigned char *tweak32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SECP256K1_EXTRAKEYS_H */
|
||||
@@ -0,0 +1,588 @@
|
||||
#ifndef SECP256K1_MUSIG_H
|
||||
#define SECP256K1_MUSIG_H
|
||||
|
||||
#include "secp256k1_extrakeys.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/** This module implements BIP 327 "MuSig2 for BIP340-compatible
|
||||
* Multi-Signatures"
|
||||
* (https://github.com/bitcoin/bips/blob/master/bip-0327.mediawiki)
|
||||
* v1.0.0. You can find an example demonstrating the musig module in
|
||||
* examples/musig.c.
|
||||
*
|
||||
* The module also supports BIP 341 ("Taproot") public key tweaking.
|
||||
*
|
||||
* It is recommended to read the documentation in this include file carefully.
|
||||
* Further notes on API usage can be found in doc/musig.md
|
||||
*
|
||||
* Since the first version of MuSig is essentially replaced by MuSig2, we use
|
||||
* MuSig, musig and MuSig2 synonymously unless noted otherwise.
|
||||
*/
|
||||
|
||||
/** Opaque data structures
|
||||
*
|
||||
* The exact representation of data inside the opaque data structures is
|
||||
* implementation defined and not guaranteed to be portable between different
|
||||
* platforms or versions. With the exception of `secp256k1_musig_secnonce`, the
|
||||
* data structures can be safely copied/moved. If you need to convert to a
|
||||
* format suitable for storage, transmission, or comparison, use the
|
||||
* corresponding serialization and parsing functions.
|
||||
*/
|
||||
|
||||
/** Opaque data structure that caches information about public key aggregation.
|
||||
*
|
||||
* Guaranteed to be 197 bytes in size. No serialization and parsing functions
|
||||
* (yet).
|
||||
*/
|
||||
typedef struct secp256k1_musig_keyagg_cache {
|
||||
unsigned char data[197];
|
||||
} secp256k1_musig_keyagg_cache;
|
||||
|
||||
/** Opaque data structure that holds a signer's _secret_ nonce.
|
||||
*
|
||||
* Guaranteed to be 132 bytes in size.
|
||||
*
|
||||
* WARNING: This structure MUST NOT be copied or read or written to directly. A
|
||||
* signer who is online throughout the whole process and can keep this
|
||||
* structure in memory can use the provided API functions for a safe standard
|
||||
* workflow.
|
||||
*
|
||||
* Copying this data structure can result in nonce reuse which will leak the
|
||||
* secret signing key.
|
||||
*/
|
||||
typedef struct secp256k1_musig_secnonce {
|
||||
unsigned char data[132];
|
||||
} secp256k1_musig_secnonce;
|
||||
|
||||
/** Opaque data structure that holds a signer's public nonce.
|
||||
*
|
||||
* Guaranteed to be 132 bytes in size. Serialized and parsed with
|
||||
* `musig_pubnonce_serialize` and `musig_pubnonce_parse`.
|
||||
*/
|
||||
typedef struct secp256k1_musig_pubnonce {
|
||||
unsigned char data[132];
|
||||
} secp256k1_musig_pubnonce;
|
||||
|
||||
/** Opaque data structure that holds an aggregate public nonce.
|
||||
*
|
||||
* Guaranteed to be 132 bytes in size. Serialized and parsed with
|
||||
* `musig_aggnonce_serialize` and `musig_aggnonce_parse`.
|
||||
*/
|
||||
typedef struct secp256k1_musig_aggnonce {
|
||||
unsigned char data[132];
|
||||
} secp256k1_musig_aggnonce;
|
||||
|
||||
/** Opaque data structure that holds a MuSig session.
|
||||
*
|
||||
* This structure is not required to be kept secret for the signing protocol to
|
||||
* be secure. Guaranteed to be 133 bytes in size. No serialization and parsing
|
||||
* functions (yet).
|
||||
*/
|
||||
typedef struct secp256k1_musig_session {
|
||||
unsigned char data[133];
|
||||
} secp256k1_musig_session;
|
||||
|
||||
/** Opaque data structure that holds a partial MuSig signature.
|
||||
*
|
||||
* Guaranteed to be 36 bytes in size. Serialized and parsed with
|
||||
* `musig_partial_sig_serialize` and `musig_partial_sig_parse`.
|
||||
*/
|
||||
typedef struct secp256k1_musig_partial_sig {
|
||||
unsigned char data[36];
|
||||
} secp256k1_musig_partial_sig;
|
||||
|
||||
/** Parse a signer's public nonce.
|
||||
*
|
||||
* Returns: 1 when the nonce could be parsed, 0 otherwise.
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: nonce: pointer to a nonce object
|
||||
* In: in66: pointer to the 66-byte nonce to be parsed
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubnonce_parse(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_musig_pubnonce *nonce,
|
||||
const unsigned char *in66
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Serialize a signer's public nonce
|
||||
*
|
||||
* Returns: 1 always
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: out66: pointer to a 66-byte array to store the serialized nonce
|
||||
* In: nonce: pointer to the nonce
|
||||
*/
|
||||
SECP256K1_API int secp256k1_musig_pubnonce_serialize(
|
||||
const secp256k1_context *ctx,
|
||||
unsigned char *out66,
|
||||
const secp256k1_musig_pubnonce *nonce
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Parse an aggregate public nonce.
|
||||
*
|
||||
* Returns: 1 when the nonce could be parsed, 0 otherwise.
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: nonce: pointer to a nonce object
|
||||
* In: in66: pointer to the 66-byte nonce to be parsed
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_aggnonce_parse(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_musig_aggnonce *nonce,
|
||||
const unsigned char *in66
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Serialize an aggregate public nonce
|
||||
*
|
||||
* Returns: 1 always
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: out66: pointer to a 66-byte array to store the serialized nonce
|
||||
* In: nonce: pointer to the nonce
|
||||
*/
|
||||
SECP256K1_API int secp256k1_musig_aggnonce_serialize(
|
||||
const secp256k1_context *ctx,
|
||||
unsigned char *out66,
|
||||
const secp256k1_musig_aggnonce *nonce
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Parse a MuSig partial signature.
|
||||
*
|
||||
* Returns: 1 when the signature could be parsed, 0 otherwise.
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: sig: pointer to a signature object
|
||||
* In: in32: pointer to the 32-byte signature to be parsed
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_parse(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_musig_partial_sig *sig,
|
||||
const unsigned char *in32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Serialize a MuSig partial signature
|
||||
*
|
||||
* Returns: 1 always
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: out32: pointer to a 32-byte array to store the serialized signature
|
||||
* In: sig: pointer to the signature
|
||||
*/
|
||||
SECP256K1_API int secp256k1_musig_partial_sig_serialize(
|
||||
const secp256k1_context *ctx,
|
||||
unsigned char *out32,
|
||||
const secp256k1_musig_partial_sig *sig
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Computes an aggregate public key and uses it to initialize a keyagg_cache
|
||||
*
|
||||
* Different orders of `pubkeys` result in different `agg_pk`s.
|
||||
*
|
||||
* Before aggregating, the pubkeys can be sorted with `secp256k1_ec_pubkey_sort`
|
||||
* which ensures the same `agg_pk` result for the same multiset of pubkeys.
|
||||
* This is useful to do before `pubkey_agg`, such that the order of pubkeys
|
||||
* does not affect the aggregate public key.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid, 1 otherwise
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: agg_pk: the MuSig-aggregated x-only public key. If you do not need it,
|
||||
* this arg can be NULL.
|
||||
* keyagg_cache: if non-NULL, pointer to a musig_keyagg_cache struct that
|
||||
* is required for signing (or observing the signing session
|
||||
* and verifying partial signatures).
|
||||
* In: pubkeys: input array of pointers to public keys to aggregate. The order
|
||||
* is important; a different order will result in a different
|
||||
* aggregate public key.
|
||||
* n_pubkeys: length of pubkeys array. Must be greater than 0.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_agg(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_xonly_pubkey *agg_pk,
|
||||
secp256k1_musig_keyagg_cache *keyagg_cache,
|
||||
const secp256k1_pubkey * const *pubkeys,
|
||||
size_t n_pubkeys
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Obtain the aggregate public key from a keyagg_cache.
|
||||
*
|
||||
* This is only useful if you need the non-xonly public key, in particular for
|
||||
* plain (non-xonly) tweaking or batch-verifying multiple key aggregations
|
||||
* (not implemented).
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid, 1 otherwise
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: agg_pk: the MuSig-aggregated public key.
|
||||
* In: keyagg_cache: pointer to a `musig_keyagg_cache` struct initialized by
|
||||
* `musig_pubkey_agg`
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_get(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_pubkey *agg_pk,
|
||||
const secp256k1_musig_keyagg_cache *keyagg_cache
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Apply plain "EC" tweaking to a public key in a given keyagg_cache by adding
|
||||
* the generator multiplied with `tweak32` to it. This is useful for deriving
|
||||
* child keys from an aggregate public key via BIP 32 where `tweak32` is set to
|
||||
* a hash as defined in BIP 32.
|
||||
*
|
||||
* Callers are responsible for deriving `tweak32` in a way that does not reduce
|
||||
* the security of MuSig (for example, by following BIP 32).
|
||||
*
|
||||
* The tweaking method is the same as `secp256k1_ec_pubkey_tweak_add`. So after
|
||||
* the following pseudocode buf and buf2 have identical contents (absent
|
||||
* earlier failures).
|
||||
*
|
||||
* secp256k1_musig_pubkey_agg(..., keyagg_cache, pubkeys, ...)
|
||||
* secp256k1_musig_pubkey_get(..., agg_pk, keyagg_cache)
|
||||
* secp256k1_musig_pubkey_ec_tweak_add(..., output_pk, tweak32, keyagg_cache)
|
||||
* secp256k1_ec_pubkey_serialize(..., buf, ..., output_pk, ...)
|
||||
* secp256k1_ec_pubkey_tweak_add(..., agg_pk, tweak32)
|
||||
* secp256k1_ec_pubkey_serialize(..., buf2, ..., agg_pk, ...)
|
||||
*
|
||||
* This function is required if you want to _sign_ for a tweaked aggregate key.
|
||||
* If you are only computing a public key but not intending to create a
|
||||
* signature for it, use `secp256k1_ec_pubkey_tweak_add` instead.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid, 1 otherwise
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: output_pubkey: pointer to a public key to store the result. Will be set
|
||||
* to an invalid value if this function returns 0. If you
|
||||
* do not need it, this arg can be NULL.
|
||||
* In/Out: keyagg_cache: pointer to a `musig_keyagg_cache` struct initialized by
|
||||
* `musig_pubkey_agg`
|
||||
* In: tweak32: pointer to a 32-byte tweak. The tweak is valid if it passes
|
||||
* `secp256k1_ec_seckey_verify` and is not equal to the
|
||||
* secret key corresponding to the public key represented
|
||||
* by keyagg_cache or its negation. For uniformly random
|
||||
* 32-byte arrays the chance of being invalid is
|
||||
* negligible (around 1 in 2^128).
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_ec_tweak_add(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_pubkey *output_pubkey,
|
||||
secp256k1_musig_keyagg_cache *keyagg_cache,
|
||||
const unsigned char *tweak32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Apply x-only tweaking to a public key in a given keyagg_cache by adding the
|
||||
* generator multiplied with `tweak32` to it. This is useful for creating
|
||||
* Taproot outputs where `tweak32` is set to a TapTweak hash as defined in BIP
|
||||
* 341.
|
||||
*
|
||||
* Callers are responsible for deriving `tweak32` in a way that does not reduce
|
||||
* the security of MuSig (for example, by following Taproot BIP 341).
|
||||
*
|
||||
* The tweaking method is the same as `secp256k1_xonly_pubkey_tweak_add`. So in
|
||||
* the following pseudocode xonly_pubkey_tweak_add_check (absent earlier
|
||||
* failures) returns 1.
|
||||
*
|
||||
* secp256k1_musig_pubkey_agg(..., agg_pk, keyagg_cache, pubkeys, ...)
|
||||
* secp256k1_musig_pubkey_xonly_tweak_add(..., output_pk, keyagg_cache, tweak32)
|
||||
* secp256k1_xonly_pubkey_serialize(..., buf, output_pk)
|
||||
* secp256k1_xonly_pubkey_tweak_add_check(..., buf, ..., agg_pk, tweak32)
|
||||
*
|
||||
* This function is required if you want to _sign_ for a tweaked aggregate key.
|
||||
* If you are only computing a public key but not intending to create a
|
||||
* signature for it, use `secp256k1_xonly_pubkey_tweak_add` instead.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid, 1 otherwise
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: output_pubkey: pointer to a public key to store the result. Will be set
|
||||
* to an invalid value if this function returns 0. If you
|
||||
* do not need it, this arg can be NULL.
|
||||
* In/Out: keyagg_cache: pointer to a `musig_keyagg_cache` struct initialized by
|
||||
* `musig_pubkey_agg`
|
||||
* In: tweak32: pointer to a 32-byte tweak. The tweak is valid if it passes
|
||||
* `secp256k1_ec_seckey_verify` and is not equal to the
|
||||
* secret key corresponding to the public key represented
|
||||
* by keyagg_cache or its negation. For uniformly random
|
||||
* 32-byte arrays the chance of being invalid is
|
||||
* negligible (around 1 in 2^128).
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_xonly_tweak_add(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_pubkey *output_pubkey,
|
||||
secp256k1_musig_keyagg_cache *keyagg_cache,
|
||||
const unsigned char *tweak32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Starts a signing session by generating a nonce
|
||||
*
|
||||
* This function outputs a secret nonce that will be required for signing and a
|
||||
* corresponding public nonce that is intended to be sent to other signers.
|
||||
*
|
||||
* MuSig differs from regular Schnorr signing in that implementers _must_ take
|
||||
* special care to not reuse a nonce. This can be ensured by following these rules:
|
||||
*
|
||||
* 1. Each call to this function must have a UNIQUE session_secrand32 that must
|
||||
* NOT BE REUSED in subsequent calls to this function and must be KEPT
|
||||
* SECRET (even from other signers).
|
||||
* 2. If you already know the seckey, message or aggregate public key
|
||||
* cache, they can be optionally provided to derive the nonce and increase
|
||||
* misuse-resistance. The extra_input32 argument can be used to provide
|
||||
* additional data that does not repeat in normal scenarios, such as the
|
||||
* current time.
|
||||
* 3. Avoid copying (or serializing) the secnonce. This reduces the possibility
|
||||
* that it is used more than once for signing.
|
||||
*
|
||||
* If you don't have access to good randomness for session_secrand32, but you
|
||||
* have access to a non-repeating counter, then see
|
||||
* secp256k1_musig_nonce_gen_counter.
|
||||
*
|
||||
* Remember that nonce reuse will leak the secret key!
|
||||
* Note that using the same seckey for multiple MuSig sessions is fine.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid and 1 otherwise
|
||||
* Args: ctx: pointer to a context object (not secp256k1_context_static)
|
||||
* Out: secnonce: pointer to a structure to store the secret nonce
|
||||
* pubnonce: pointer to a structure to store the public nonce
|
||||
* In/Out:
|
||||
* session_secrand32: a 32-byte session_secrand32 as explained above. Must be unique to this
|
||||
* call to secp256k1_musig_nonce_gen and must be uniformly
|
||||
* random. If the function call is successful, the
|
||||
* session_secrand32 buffer is invalidated to prevent reuse.
|
||||
* In:
|
||||
* seckey: the 32-byte secret key that will later be used for signing, if
|
||||
* already known (can be NULL)
|
||||
* pubkey: public key of the signer creating the nonce. The secnonce
|
||||
* output of this function cannot be used to sign for any
|
||||
* other public key. While the public key should correspond
|
||||
* to the provided seckey, a mismatch will not cause the
|
||||
* function to return 0.
|
||||
* msg32: the 32-byte message that will later be signed, if already known
|
||||
* (can be NULL)
|
||||
* keyagg_cache: pointer to the keyagg_cache that was used to create the aggregate
|
||||
* (and potentially tweaked) public key if already known
|
||||
* (can be NULL)
|
||||
* extra_input32: an optional 32-byte array that is input to the nonce
|
||||
* derivation function (can be NULL)
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_nonce_gen(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_musig_secnonce *secnonce,
|
||||
secp256k1_musig_pubnonce *pubnonce,
|
||||
unsigned char *session_secrand32,
|
||||
const unsigned char *seckey,
|
||||
const secp256k1_pubkey *pubkey,
|
||||
const unsigned char *msg32,
|
||||
const secp256k1_musig_keyagg_cache *keyagg_cache,
|
||||
const unsigned char *extra_input32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(6);
|
||||
|
||||
|
||||
/** Alternative way to generate a nonce and start a signing session
|
||||
*
|
||||
* This function outputs a secret nonce that will be required for signing and a
|
||||
* corresponding public nonce that is intended to be sent to other signers.
|
||||
*
|
||||
* This function differs from `secp256k1_musig_nonce_gen` by accepting a
|
||||
* non-repeating counter value instead of a secret random value. This requires
|
||||
* that a secret key is provided to `secp256k1_musig_nonce_gen_counter`
|
||||
* (through the keypair argument), as opposed to `secp256k1_musig_nonce_gen`
|
||||
* where the seckey argument is optional.
|
||||
*
|
||||
* MuSig differs from regular Schnorr signing in that implementers _must_ take
|
||||
* special care to not reuse a nonce. This can be ensured by following these rules:
|
||||
*
|
||||
* 1. The nonrepeating_cnt argument must be a counter value that never repeats,
|
||||
* i.e., you must never call `secp256k1_musig_nonce_gen_counter` twice with
|
||||
* the same keypair and nonrepeating_cnt value. For example, this implies
|
||||
* that if the same keypair is used with `secp256k1_musig_nonce_gen_counter`
|
||||
* on multiple devices, none of the devices should have the same counter
|
||||
* value as any other device.
|
||||
* 2. If the seckey, message or aggregate public key cache is already available
|
||||
* at this stage, any of these can be optionally provided, in which case
|
||||
* they will be used in the derivation of the nonce and increase
|
||||
* misuse-resistance. The extra_input32 argument can be used to provide
|
||||
* additional data that does not repeat in normal scenarios, such as the
|
||||
* current time.
|
||||
* 3. Avoid copying (or serializing) the secnonce. This reduces the possibility
|
||||
* that it is used more than once for signing.
|
||||
*
|
||||
* Remember that nonce reuse will leak the secret key!
|
||||
* Note that using the same keypair for multiple MuSig sessions is fine.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid and 1 otherwise
|
||||
* Args: ctx: pointer to a context object (not secp256k1_context_static)
|
||||
* Out: secnonce: pointer to a structure to store the secret nonce
|
||||
* pubnonce: pointer to a structure to store the public nonce
|
||||
* In:
|
||||
* nonrepeating_cnt: the value of a counter as explained above. Must be
|
||||
* unique to this call to secp256k1_musig_nonce_gen.
|
||||
* keypair: keypair of the signer creating the nonce. The secnonce
|
||||
* output of this function cannot be used to sign for any
|
||||
* other keypair.
|
||||
* msg32: the 32-byte message that will later be signed, if already known
|
||||
* (can be NULL)
|
||||
* keyagg_cache: pointer to the keyagg_cache that was used to create the aggregate
|
||||
* (and potentially tweaked) public key if already known
|
||||
* (can be NULL)
|
||||
* extra_input32: an optional 32-byte array that is input to the nonce
|
||||
* derivation function (can be NULL)
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_nonce_gen_counter(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_musig_secnonce *secnonce,
|
||||
secp256k1_musig_pubnonce *pubnonce,
|
||||
uint64_t nonrepeating_cnt,
|
||||
const secp256k1_keypair *keypair,
|
||||
const unsigned char *msg32,
|
||||
const secp256k1_musig_keyagg_cache *keyagg_cache,
|
||||
const unsigned char *extra_input32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
|
||||
|
||||
/** Aggregates the nonces of all signers into a single nonce
|
||||
*
|
||||
* This can be done by an untrusted party to reduce the communication
|
||||
* between signers. Instead of everyone sending nonces to everyone else, there
|
||||
* can be one party receiving all nonces, aggregating the nonces with this
|
||||
* function and then sending only the aggregate nonce back to the signers.
|
||||
*
|
||||
* If the aggregator does not compute the aggregate nonce correctly, the final
|
||||
* signature will be invalid.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid, 1 otherwise
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: aggnonce: pointer to an aggregate public nonce object for
|
||||
* musig_nonce_process
|
||||
* In: pubnonces: array of pointers to public nonces sent by the
|
||||
* signers
|
||||
* n_pubnonces: number of elements in the pubnonces array. Must be
|
||||
* greater than 0.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_musig_nonce_agg(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_musig_aggnonce *aggnonce,
|
||||
const secp256k1_musig_pubnonce * const *pubnonces,
|
||||
size_t n_pubnonces
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Takes the aggregate nonce and creates a session that is required for signing
|
||||
* and verification of partial signatures.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid, 1 otherwise
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: session: pointer to a struct to store the session
|
||||
* In: aggnonce: pointer to an aggregate public nonce object that is the
|
||||
* output of musig_nonce_agg
|
||||
* msg32: the 32-byte message to sign
|
||||
* keyagg_cache: pointer to the keyagg_cache that was used to create the
|
||||
* aggregate (and potentially tweaked) pubkey
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_nonce_process(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_musig_session *session,
|
||||
const secp256k1_musig_aggnonce *aggnonce,
|
||||
const unsigned char *msg32,
|
||||
const secp256k1_musig_keyagg_cache *keyagg_cache
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
|
||||
|
||||
/** Produces a partial signature
|
||||
*
|
||||
* This function overwrites the given secnonce with zeros and will abort if given a
|
||||
* secnonce that is all zeros. This is a best effort attempt to protect against nonce
|
||||
* reuse. However, this is of course easily defeated if the secnonce has been
|
||||
* copied (or serialized). Remember that nonce reuse will leak the secret key!
|
||||
*
|
||||
* For signing to succeed, the secnonce provided to this function must have
|
||||
* been generated for the provided keypair. This means that when signing for a
|
||||
* keypair consisting of a seckey and pubkey, the secnonce must have been
|
||||
* created by calling musig_nonce_gen with that pubkey. Otherwise, the
|
||||
* illegal_callback is called.
|
||||
*
|
||||
* This function does not verify the output partial signature, deviating from
|
||||
* the BIP 327 specification. It is recommended to verify the output partial
|
||||
* signature with `secp256k1_musig_partial_sig_verify` to prevent random or
|
||||
* adversarially provoked computation errors.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid or the provided secnonce has already
|
||||
* been used for signing, 1 otherwise
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: partial_sig: pointer to struct to store the partial signature
|
||||
* In/Out: secnonce: pointer to the secnonce struct created in
|
||||
* musig_nonce_gen that has been never used in a
|
||||
* partial_sign call before and has been created for the
|
||||
* keypair
|
||||
* In: keypair: pointer to keypair to sign the message with
|
||||
* keyagg_cache: pointer to the keyagg_cache that was output when the
|
||||
* aggregate public key for this session
|
||||
* session: pointer to the session that was created with
|
||||
* musig_nonce_process
|
||||
*/
|
||||
SECP256K1_API int secp256k1_musig_partial_sign(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_musig_partial_sig *partial_sig,
|
||||
secp256k1_musig_secnonce *secnonce,
|
||||
const secp256k1_keypair *keypair,
|
||||
const secp256k1_musig_keyagg_cache *keyagg_cache,
|
||||
const secp256k1_musig_session *session
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6);
|
||||
|
||||
/** Verifies an individual signer's partial signature
|
||||
*
|
||||
* The signature is verified for a specific signing session. In order to avoid
|
||||
* accidentally verifying a signature from a different or non-existing signing
|
||||
* session, you must ensure the following:
|
||||
* 1. The `keyagg_cache` argument is identical to the one used to create the
|
||||
* `session` with `musig_nonce_process`.
|
||||
* 2. The `pubkey` argument must be identical to the one sent by the signer
|
||||
* before aggregating it with `musig_pubkey_agg` to create the
|
||||
* `keyagg_cache`.
|
||||
* 3. The `pubnonce` argument must be identical to the one sent by the signer
|
||||
* before aggregating it with `musig_nonce_agg` and using the result to
|
||||
* create the `session` with `musig_nonce_process`.
|
||||
*
|
||||
* It is not required to call this function in regular MuSig sessions, because
|
||||
* if any partial signature does not verify, the final signature will not
|
||||
* verify either, so the problem will be caught. However, this function
|
||||
* provides the ability to identify which specific partial signature fails
|
||||
* verification.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid or the partial signature does not
|
||||
* verify, 1 otherwise
|
||||
* Args ctx: pointer to a context object
|
||||
* In: partial_sig: pointer to partial signature to verify, sent by
|
||||
* the signer associated with `pubnonce` and `pubkey`
|
||||
* pubnonce: public nonce of the signer in the signing session
|
||||
* pubkey: public key of the signer in the signing session
|
||||
* keyagg_cache: pointer to the keyagg_cache that was output when the
|
||||
* aggregate public key for this signing session
|
||||
* session: pointer to the session that was created with
|
||||
* `musig_nonce_process`
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_verify(
|
||||
const secp256k1_context *ctx,
|
||||
const secp256k1_musig_partial_sig *partial_sig,
|
||||
const secp256k1_musig_pubnonce *pubnonce,
|
||||
const secp256k1_pubkey *pubkey,
|
||||
const secp256k1_musig_keyagg_cache *keyagg_cache,
|
||||
const secp256k1_musig_session *session
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6);
|
||||
|
||||
/** Aggregates partial signatures
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid, 1 otherwise (which does NOT mean
|
||||
* the resulting signature verifies).
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: sig64: complete (but possibly invalid) Schnorr signature
|
||||
* In: session: pointer to the session that was created with
|
||||
* musig_nonce_process
|
||||
* partial_sigs: array of pointers to partial signatures to aggregate
|
||||
* n_sigs: number of elements in the partial_sigs array. Must be
|
||||
* greater than 0.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_musig_partial_sig_agg(
|
||||
const secp256k1_context *ctx,
|
||||
unsigned char *sig64,
|
||||
const secp256k1_musig_session *session,
|
||||
const secp256k1_musig_partial_sig * const *partial_sigs,
|
||||
size_t n_sigs
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,134 @@
|
||||
#ifndef SECP256K1_PREALLOCATED_H
|
||||
#define SECP256K1_PREALLOCATED_H
|
||||
|
||||
#include "secp256k1.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* The module provided by this header file is intended for settings in which it
|
||||
* is not possible or desirable to rely on dynamic memory allocation. It provides
|
||||
* functions for creating, cloning, and destroying secp256k1 context objects in a
|
||||
* contiguous fixed-size block of memory provided by the caller.
|
||||
*
|
||||
* Context objects created by functions in this module can be used like contexts
|
||||
* objects created by functions in secp256k1.h, i.e., they can be passed to any
|
||||
* API function that expects a context object (see secp256k1.h for details). The
|
||||
* only exception is that context objects created by functions in this module
|
||||
* must be destroyed using secp256k1_context_preallocated_destroy (in this
|
||||
* module) instead of secp256k1_context_destroy (in secp256k1.h).
|
||||
*
|
||||
* It is guaranteed that functions in this module will not call malloc or its
|
||||
* friends realloc, calloc, and free.
|
||||
*/
|
||||
|
||||
/** Determine the memory size of a secp256k1 context object to be created in
|
||||
* caller-provided memory.
|
||||
*
|
||||
* The purpose of this function is to determine how much memory must be provided
|
||||
* to secp256k1_context_preallocated_create.
|
||||
*
|
||||
* Returns: the required size of the caller-provided memory block
|
||||
* In: flags: which parts of the context to initialize.
|
||||
*/
|
||||
SECP256K1_API size_t secp256k1_context_preallocated_size(
|
||||
unsigned int flags
|
||||
) SECP256K1_WARN_UNUSED_RESULT;
|
||||
|
||||
/** Create a secp256k1 context object in caller-provided memory.
|
||||
*
|
||||
* The caller must provide a pointer to a rewritable contiguous block of memory
|
||||
* of size at least secp256k1_context_preallocated_size(flags) bytes, suitably
|
||||
* aligned to hold an object of any type.
|
||||
*
|
||||
* The block of memory is exclusively owned by the created context object during
|
||||
* the lifetime of this context object, which begins with the call to this
|
||||
* function and ends when a call to secp256k1_context_preallocated_destroy
|
||||
* (which destroys the context object again) returns. During the lifetime of the
|
||||
* context object, the caller is obligated not to access this block of memory,
|
||||
* i.e., the caller may not read or write the memory, e.g., by copying the memory
|
||||
* contents to a different location or trying to create a second context object
|
||||
* in the memory. In simpler words, the prealloc pointer (or any pointer derived
|
||||
* from it) should not be used during the lifetime of the context object.
|
||||
*
|
||||
* Returns: pointer to newly created context object.
|
||||
* In: prealloc: pointer to a rewritable contiguous block of memory of
|
||||
* size at least secp256k1_context_preallocated_size(flags)
|
||||
* bytes, as detailed above.
|
||||
* flags: which parts of the context to initialize.
|
||||
*
|
||||
* See secp256k1_context_create (in secp256k1.h) for further details.
|
||||
*
|
||||
* See also secp256k1_context_randomize (in secp256k1.h)
|
||||
* and secp256k1_context_preallocated_destroy.
|
||||
*/
|
||||
SECP256K1_API secp256k1_context *secp256k1_context_preallocated_create(
|
||||
void *prealloc,
|
||||
unsigned int flags
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT;
|
||||
|
||||
/** Determine the memory size of a secp256k1 context object to be copied into
|
||||
* caller-provided memory.
|
||||
*
|
||||
* Returns: the required size of the caller-provided memory block.
|
||||
* In: ctx: pointer to a context to copy.
|
||||
*/
|
||||
SECP256K1_API size_t secp256k1_context_preallocated_clone_size(
|
||||
const secp256k1_context *ctx
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT;
|
||||
|
||||
/** Copy a secp256k1 context object into caller-provided memory.
|
||||
*
|
||||
* The caller must provide a pointer to a rewritable contiguous block of memory
|
||||
* of size at least secp256k1_context_preallocated_size(flags) bytes, suitably
|
||||
* aligned to hold an object of any type.
|
||||
*
|
||||
* The block of memory is exclusively owned by the created context object during
|
||||
* the lifetime of this context object, see the description of
|
||||
* secp256k1_context_preallocated_create for details.
|
||||
*
|
||||
* Cloning secp256k1_context_static is not possible, and should not be emulated by
|
||||
* the caller (e.g., using memcpy). Create a new context instead.
|
||||
*
|
||||
* Returns: pointer to a newly created context object.
|
||||
* Args: ctx: pointer to a context to copy (not secp256k1_context_static).
|
||||
* In: prealloc: pointer to a rewritable contiguous block of memory of
|
||||
* size at least secp256k1_context_preallocated_size(flags)
|
||||
* bytes, as detailed above.
|
||||
*/
|
||||
SECP256K1_API secp256k1_context *secp256k1_context_preallocated_clone(
|
||||
const secp256k1_context *ctx,
|
||||
void *prealloc
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_WARN_UNUSED_RESULT;
|
||||
|
||||
/** Destroy a secp256k1 context object that has been created in
|
||||
* caller-provided memory.
|
||||
*
|
||||
* The context pointer may not be used afterwards.
|
||||
*
|
||||
* The context to destroy must have been created using
|
||||
* secp256k1_context_preallocated_create or secp256k1_context_preallocated_clone.
|
||||
* If the context has instead been created using secp256k1_context_create or
|
||||
* secp256k1_context_clone, the behaviour is undefined. In that case,
|
||||
* secp256k1_context_destroy must be used instead.
|
||||
*
|
||||
* If required, it is the responsibility of the caller to deallocate the block
|
||||
* of memory properly after this function returns, e.g., by calling free on the
|
||||
* preallocated pointer given to secp256k1_context_preallocated_create or
|
||||
* secp256k1_context_preallocated_clone.
|
||||
*
|
||||
* Args: ctx: pointer to a context to destroy, constructed using
|
||||
* secp256k1_context_preallocated_create or
|
||||
* secp256k1_context_preallocated_clone
|
||||
* (i.e., not secp256k1_context_static).
|
||||
*/
|
||||
SECP256K1_API void secp256k1_context_preallocated_destroy(
|
||||
secp256k1_context *ctx
|
||||
) SECP256K1_ARG_NONNULL(1);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SECP256K1_PREALLOCATED_H */
|
||||
@@ -0,0 +1,123 @@
|
||||
#ifndef SECP256K1_RECOVERY_H
|
||||
#define SECP256K1_RECOVERY_H
|
||||
|
||||
#include "secp256k1.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Opaque data structure that holds a parsed ECDSA signature,
|
||||
* supporting pubkey recovery.
|
||||
*
|
||||
* The exact representation of data inside is implementation defined and not
|
||||
* guaranteed to be portable between different platforms or versions. It is
|
||||
* however guaranteed to be 65 bytes in size, and can be safely copied/moved.
|
||||
* If you need to convert to a format suitable for storage or transmission, use
|
||||
* the secp256k1_ecdsa_signature_serialize_* and
|
||||
* secp256k1_ecdsa_signature_parse_* functions.
|
||||
*
|
||||
* Furthermore, it is guaranteed that identical signatures (including their
|
||||
* recoverability) will have identical representation, so they can be
|
||||
* memcmp'ed.
|
||||
*/
|
||||
typedef struct secp256k1_ecdsa_recoverable_signature {
|
||||
unsigned char data[65];
|
||||
} secp256k1_ecdsa_recoverable_signature;
|
||||
|
||||
/** Parse a compact ECDSA signature (64 bytes + recovery id).
|
||||
*
|
||||
* Returns: 1 when the signature could be parsed, 0 otherwise
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: sig: pointer to a signature object
|
||||
* In: input64: pointer to a 64-byte compact signature
|
||||
* recid: the recovery id (0, 1, 2 or 3)
|
||||
*/
|
||||
SECP256K1_API int secp256k1_ecdsa_recoverable_signature_parse_compact(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_ecdsa_recoverable_signature *sig,
|
||||
const unsigned char *input64,
|
||||
int recid
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Convert a recoverable signature into a normal signature.
|
||||
*
|
||||
* Returns: 1
|
||||
* Args: ctx: pointer to a context object.
|
||||
* Out: sig: pointer to a normal signature.
|
||||
* In: sigin: pointer to a recoverable signature.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_ecdsa_recoverable_signature_convert(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_ecdsa_signature *sig,
|
||||
const secp256k1_ecdsa_recoverable_signature *sigin
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Serialize an ECDSA signature in compact format (64 bytes + recovery id).
|
||||
*
|
||||
* Returns: 1
|
||||
* Args: ctx: pointer to a context object.
|
||||
* Out: output64: pointer to a 64-byte array of the compact signature.
|
||||
* recid: pointer to an integer to hold the recovery id.
|
||||
* In: sig: pointer to an initialized signature object.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_ecdsa_recoverable_signature_serialize_compact(
|
||||
const secp256k1_context *ctx,
|
||||
unsigned char *output64,
|
||||
int *recid,
|
||||
const secp256k1_ecdsa_recoverable_signature *sig
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Create a recoverable ECDSA signature.
|
||||
*
|
||||
* Returns: 1: signature created
|
||||
* 0: the nonce generation function failed, or the secret key was invalid.
|
||||
* Args: ctx: pointer to a context object (not secp256k1_context_static).
|
||||
* Out: sig: pointer to an array where the signature will be placed.
|
||||
* In: msghash32: the 32-byte message hash being signed.
|
||||
* seckey: pointer to a 32-byte secret key.
|
||||
* noncefp: pointer to a nonce generation function. If NULL,
|
||||
* secp256k1_nonce_function_default is used.
|
||||
* ndata: pointer to arbitrary data used by the nonce generation function
|
||||
* (can be NULL for secp256k1_nonce_function_default).
|
||||
*/
|
||||
SECP256K1_API int secp256k1_ecdsa_sign_recoverable(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_ecdsa_recoverable_signature *sig,
|
||||
const unsigned char *msghash32,
|
||||
const unsigned char *seckey,
|
||||
secp256k1_nonce_function noncefp,
|
||||
const void *ndata
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Recover an ECDSA public key from a signature.
|
||||
*
|
||||
* Successful public key recovery guarantees that the signature, after normalization,
|
||||
* passes `secp256k1_ecdsa_verify`. Thus, explicit verification is not necessary.
|
||||
*
|
||||
* However, a recoverable signature that successfully passes `secp256k1_ecdsa_recover`,
|
||||
* when converted to a non-recoverable signature (using
|
||||
* `secp256k1_ecdsa_recoverable_signature_convert`), is not guaranteed to be
|
||||
* normalized and thus not guaranteed to pass `secp256k1_ecdsa_verify`. If a
|
||||
* normalized signature is required, call `secp256k1_ecdsa_signature_normalize`
|
||||
* after `secp256k1_ecdsa_recoverable_signature_convert`.
|
||||
*
|
||||
* Returns: 1: public key successfully recovered
|
||||
* 0: otherwise.
|
||||
* Args: ctx: pointer to a context object.
|
||||
* Out: pubkey: pointer to the recovered public key.
|
||||
* In: sig: pointer to initialized signature that supports pubkey recovery.
|
||||
* msghash32: the 32-byte message hash assumed to be signed.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_recover(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_pubkey *pubkey,
|
||||
const secp256k1_ecdsa_recoverable_signature *sig,
|
||||
const unsigned char *msghash32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SECP256K1_RECOVERY_H */
|
||||
@@ -0,0 +1,190 @@
|
||||
#ifndef SECP256K1_SCHNORRSIG_H
|
||||
#define SECP256K1_SCHNORRSIG_H
|
||||
|
||||
#include "secp256k1.h"
|
||||
#include "secp256k1_extrakeys.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** This module implements a variant of Schnorr signatures compliant with
|
||||
* Bitcoin Improvement Proposal 340 "Schnorr Signatures for secp256k1"
|
||||
* (https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki).
|
||||
*/
|
||||
|
||||
/** A pointer to a function to deterministically generate a nonce.
|
||||
*
|
||||
* Same as secp256k1_nonce function with the exception of accepting an
|
||||
* additional pubkey argument and not requiring an attempt argument. The pubkey
|
||||
* argument can protect signature schemes with key-prefixed challenge hash
|
||||
* inputs against reusing the nonce when signing with the wrong precomputed
|
||||
* pubkey.
|
||||
*
|
||||
* Returns: 1 if a nonce was successfully generated. 0 will cause signing to
|
||||
* return an error.
|
||||
* Out: nonce32: pointer to a 32-byte array to be filled by the function
|
||||
* In: msg: the message being verified. Is NULL if and only if msglen
|
||||
* is 0.
|
||||
* msglen: the length of the message
|
||||
* key32: pointer to a 32-byte secret key (will not be NULL)
|
||||
* xonly_pk32: the 32-byte serialized xonly pubkey corresponding to key32
|
||||
* (will not be NULL)
|
||||
* algo: pointer to an array describing the signature
|
||||
* algorithm (will not be NULL)
|
||||
* algolen: the length of the algo array
|
||||
* data: arbitrary data pointer that is passed through
|
||||
*
|
||||
* Except for test cases, this function should compute some cryptographic hash of
|
||||
* the message, the key, the pubkey, the algorithm description, and data.
|
||||
*/
|
||||
typedef int (*secp256k1_nonce_function_hardened)(
|
||||
unsigned char *nonce32,
|
||||
const unsigned char *msg,
|
||||
size_t msglen,
|
||||
const unsigned char *key32,
|
||||
const unsigned char *xonly_pk32,
|
||||
const unsigned char *algo,
|
||||
size_t algolen,
|
||||
void *data
|
||||
);
|
||||
|
||||
/** An implementation of the nonce generation function as defined in Bitcoin
|
||||
* Improvement Proposal 340 "Schnorr Signatures for secp256k1"
|
||||
* (https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki).
|
||||
*
|
||||
* If a data pointer is passed, it is assumed to be a pointer to 32 bytes of
|
||||
* auxiliary random data as defined in BIP-340. If the data pointer is NULL,
|
||||
* the nonce derivation procedure follows BIP-340 by setting the auxiliary
|
||||
* random data to zero. The algo argument must be non-NULL, otherwise the
|
||||
* function will fail and return 0. The hash will be tagged with algo.
|
||||
* Therefore, to create BIP-340 compliant signatures, algo must be set to
|
||||
* "BIP0340/nonce" and algolen to 13.
|
||||
*/
|
||||
SECP256K1_API const secp256k1_nonce_function_hardened secp256k1_nonce_function_bip340;
|
||||
|
||||
/** Data structure that contains additional arguments for schnorrsig_sign_custom.
|
||||
*
|
||||
* A schnorrsig_extraparams structure object can be initialized correctly by
|
||||
* setting it to SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT.
|
||||
*
|
||||
* Members:
|
||||
* magic: set to SECP256K1_SCHNORRSIG_EXTRAPARAMS_MAGIC at initialization
|
||||
* and has no other function than making sure the object is
|
||||
* initialized.
|
||||
* noncefp: pointer to a nonce generation function. If NULL,
|
||||
* secp256k1_nonce_function_bip340 is used
|
||||
* ndata: pointer to arbitrary data used by the nonce generation function
|
||||
* (can be NULL). If it is non-NULL and
|
||||
* secp256k1_nonce_function_bip340 is used, then ndata must be a
|
||||
* pointer to 32-byte auxiliary randomness as per BIP-340.
|
||||
*/
|
||||
typedef struct secp256k1_schnorrsig_extraparams {
|
||||
unsigned char magic[4];
|
||||
secp256k1_nonce_function_hardened noncefp;
|
||||
void *ndata;
|
||||
} secp256k1_schnorrsig_extraparams;
|
||||
|
||||
#define SECP256K1_SCHNORRSIG_EXTRAPARAMS_MAGIC { 0xda, 0x6f, 0xb3, 0x8c }
|
||||
#define SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT {\
|
||||
SECP256K1_SCHNORRSIG_EXTRAPARAMS_MAGIC,\
|
||||
NULL,\
|
||||
NULL\
|
||||
}
|
||||
|
||||
/** Create a Schnorr signature.
|
||||
*
|
||||
* Does _not_ strictly follow BIP-340 because it does not verify the resulting
|
||||
* signature. Instead, you can manually use secp256k1_schnorrsig_verify and
|
||||
* abort if it fails.
|
||||
*
|
||||
* This function only signs 32-byte messages. If you have messages of a
|
||||
* different size (or the same size but without a context-specific tag
|
||||
* prefix), it is recommended to create a 32-byte message hash with
|
||||
* secp256k1_tagged_sha256 and then sign the hash. Tagged hashing allows
|
||||
* providing an context-specific tag for domain separation. This prevents
|
||||
* signatures from being valid in multiple contexts by accident.
|
||||
*
|
||||
* Returns 1 on success, 0 on failure.
|
||||
* Args: ctx: pointer to a context object (not secp256k1_context_static).
|
||||
* Out: sig64: pointer to a 64-byte array to store the serialized signature.
|
||||
* In: msg32: the 32-byte message being signed.
|
||||
* keypair: pointer to an initialized keypair.
|
||||
* aux_rand32: 32 bytes of fresh randomness. While recommended to provide
|
||||
* this, it is only supplemental to security and can be NULL. A
|
||||
* NULL argument is treated the same as an all-zero one. See
|
||||
* BIP-340 "Default Signing" for a full explanation of this
|
||||
* argument and for guidance if randomness is expensive.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_schnorrsig_sign32(
|
||||
const secp256k1_context *ctx,
|
||||
unsigned char *sig64,
|
||||
const unsigned char *msg32,
|
||||
const secp256k1_keypair *keypair,
|
||||
const unsigned char *aux_rand32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Same as secp256k1_schnorrsig_sign32, but DEPRECATED. Will be removed in
|
||||
* future versions. */
|
||||
SECP256K1_API int secp256k1_schnorrsig_sign(
|
||||
const secp256k1_context *ctx,
|
||||
unsigned char *sig64,
|
||||
const unsigned char *msg32,
|
||||
const secp256k1_keypair *keypair,
|
||||
const unsigned char *aux_rand32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4)
|
||||
SECP256K1_DEPRECATED("Use secp256k1_schnorrsig_sign32 instead");
|
||||
|
||||
/** Create a Schnorr signature with a more flexible API.
|
||||
*
|
||||
* Same arguments as secp256k1_schnorrsig_sign except that it allows signing
|
||||
* variable length messages and accepts a pointer to an extraparams object that
|
||||
* allows customizing signing by passing additional arguments.
|
||||
*
|
||||
* Equivalent to secp256k1_schnorrsig_sign32(..., aux_rand32) if msglen is 32
|
||||
* and extraparams is initialized as follows:
|
||||
* ```
|
||||
* secp256k1_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT;
|
||||
* extraparams.ndata = (unsigned char*)aux_rand32;
|
||||
* ```
|
||||
*
|
||||
* Returns 1 on success, 0 on failure.
|
||||
* Args: ctx: pointer to a context object (not secp256k1_context_static).
|
||||
* Out: sig64: pointer to a 64-byte array to store the serialized signature.
|
||||
* In: msg: the message being signed. Can only be NULL if msglen is 0.
|
||||
* msglen: length of the message.
|
||||
* keypair: pointer to an initialized keypair.
|
||||
* extraparams: pointer to an extraparams object (can be NULL).
|
||||
*/
|
||||
SECP256K1_API int secp256k1_schnorrsig_sign_custom(
|
||||
const secp256k1_context *ctx,
|
||||
unsigned char *sig64,
|
||||
const unsigned char *msg,
|
||||
size_t msglen,
|
||||
const secp256k1_keypair *keypair,
|
||||
secp256k1_schnorrsig_extraparams *extraparams
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(5);
|
||||
|
||||
/** Verify a Schnorr signature.
|
||||
*
|
||||
* Returns: 1: correct signature
|
||||
* 0: incorrect signature
|
||||
* Args: ctx: pointer to a context object.
|
||||
* In: sig64: pointer to the 64-byte signature to verify.
|
||||
* msg: the message being verified. Can only be NULL if msglen is 0.
|
||||
* msglen: length of the message
|
||||
* pubkey: pointer to an x-only public key to verify with
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorrsig_verify(
|
||||
const secp256k1_context *ctx,
|
||||
const unsigned char *sig64,
|
||||
const unsigned char *msg,
|
||||
size_t msglen,
|
||||
const secp256k1_xonly_pubkey *pubkey
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(5);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SECP256K1_SCHNORRSIG_H */
|
||||
229
firmware/kb2040_hidden_signer/src/secp256k1/src/CMakeLists.txt
Normal file
229
firmware/kb2040_hidden_signer/src/secp256k1/src/CMakeLists.txt
Normal file
@@ -0,0 +1,229 @@
|
||||
add_library(secp256k1)
|
||||
|
||||
set_property(TARGET secp256k1 PROPERTY PUBLIC_HEADER
|
||||
${PROJECT_SOURCE_DIR}/include/secp256k1.h
|
||||
${PROJECT_SOURCE_DIR}/include/secp256k1_preallocated.h
|
||||
)
|
||||
|
||||
# Processing must be done in a topological sorting of the dependency graph
|
||||
# (dependent module first).
|
||||
if(SECP256K1_ENABLE_MODULE_ELLSWIFT)
|
||||
add_compile_definitions(ENABLE_MODULE_ELLSWIFT=1)
|
||||
set_property(TARGET secp256k1 APPEND PROPERTY PUBLIC_HEADER ${PROJECT_SOURCE_DIR}/include/secp256k1_ellswift.h)
|
||||
endif()
|
||||
|
||||
if(SECP256K1_ENABLE_MODULE_MUSIG)
|
||||
if(DEFINED SECP256K1_ENABLE_MODULE_SCHNORRSIG AND NOT SECP256K1_ENABLE_MODULE_SCHNORRSIG)
|
||||
message(FATAL_ERROR "Module dependency error: You have disabled the schnorrsig module explicitly, but it is required by the musig module.")
|
||||
endif()
|
||||
set(SECP256K1_ENABLE_MODULE_SCHNORRSIG ON)
|
||||
add_compile_definitions(ENABLE_MODULE_MUSIG=1)
|
||||
set_property(TARGET secp256k1 APPEND PROPERTY PUBLIC_HEADER ${PROJECT_SOURCE_DIR}/include/secp256k1_musig.h)
|
||||
endif()
|
||||
|
||||
if(SECP256K1_ENABLE_MODULE_SCHNORRSIG)
|
||||
if(DEFINED SECP256K1_ENABLE_MODULE_EXTRAKEYS AND NOT SECP256K1_ENABLE_MODULE_EXTRAKEYS)
|
||||
message(FATAL_ERROR "Module dependency error: You have disabled the extrakeys module explicitly, but it is required by the schnorrsig module.")
|
||||
endif()
|
||||
set(SECP256K1_ENABLE_MODULE_EXTRAKEYS ON)
|
||||
add_compile_definitions(ENABLE_MODULE_SCHNORRSIG=1)
|
||||
set_property(TARGET secp256k1 APPEND PROPERTY PUBLIC_HEADER ${PROJECT_SOURCE_DIR}/include/secp256k1_schnorrsig.h)
|
||||
endif()
|
||||
|
||||
if(SECP256K1_ENABLE_MODULE_EXTRAKEYS)
|
||||
add_compile_definitions(ENABLE_MODULE_EXTRAKEYS=1)
|
||||
set_property(TARGET secp256k1 APPEND PROPERTY PUBLIC_HEADER ${PROJECT_SOURCE_DIR}/include/secp256k1_extrakeys.h)
|
||||
endif()
|
||||
|
||||
if(SECP256K1_ENABLE_MODULE_RECOVERY)
|
||||
add_compile_definitions(ENABLE_MODULE_RECOVERY=1)
|
||||
set_property(TARGET secp256k1 APPEND PROPERTY PUBLIC_HEADER ${PROJECT_SOURCE_DIR}/include/secp256k1_recovery.h)
|
||||
endif()
|
||||
|
||||
if(SECP256K1_ENABLE_MODULE_ECDH)
|
||||
add_compile_definitions(ENABLE_MODULE_ECDH=1)
|
||||
set_property(TARGET secp256k1 APPEND PROPERTY PUBLIC_HEADER ${PROJECT_SOURCE_DIR}/include/secp256k1_ecdh.h)
|
||||
endif()
|
||||
|
||||
add_library(secp256k1_precomputed OBJECT EXCLUDE_FROM_ALL
|
||||
precomputed_ecmult.c
|
||||
precomputed_ecmult_gen.c
|
||||
)
|
||||
|
||||
# Add objects explicitly rather than linking to the object libs to keep them
|
||||
# from being exported.
|
||||
target_sources(secp256k1 PRIVATE secp256k1.c $<TARGET_OBJECTS:secp256k1_precomputed>)
|
||||
|
||||
if(NOT SECP256K1_ENABLE_API_VISIBILITY_ATTRIBUTES)
|
||||
target_compile_definitions(secp256k1 PRIVATE SECP256K1_NO_API_VISIBILITY_ATTRIBUTES)
|
||||
endif()
|
||||
|
||||
# Create a helper lib that parent projects can use to link secp256k1 into a
|
||||
# static lib.
|
||||
add_library(secp256k1_objs INTERFACE)
|
||||
target_sources(secp256k1_objs INTERFACE $<TARGET_OBJECTS:secp256k1> $<TARGET_OBJECTS:secp256k1_precomputed>)
|
||||
|
||||
add_library(secp256k1_asm INTERFACE)
|
||||
if(SECP256K1_ASM STREQUAL "arm32")
|
||||
add_library(secp256k1_asm_arm OBJECT EXCLUDE_FROM_ALL)
|
||||
target_sources(secp256k1_asm_arm PUBLIC
|
||||
asm/field_10x26_arm.s
|
||||
)
|
||||
target_sources(secp256k1 PRIVATE $<TARGET_OBJECTS:secp256k1_asm_arm>)
|
||||
target_sources(secp256k1_objs INTERFACE $<TARGET_OBJECTS:secp256k1_asm_arm>)
|
||||
target_link_libraries(secp256k1_asm INTERFACE secp256k1_asm_arm)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
# Define our export symbol only for shared libs.
|
||||
set_target_properties(secp256k1 PROPERTIES DEFINE_SYMBOL SECP256K1_DLL_EXPORT)
|
||||
target_compile_definitions(secp256k1 INTERFACE $<$<NOT:$<BOOL:${BUILD_SHARED_LIBS}>>:SECP256K1_STATIC>)
|
||||
endif()
|
||||
|
||||
# Object libs don't know if they're being built for a shared or static lib.
|
||||
# Grab the PIC property from secp256k1 which knows.
|
||||
get_target_property(use_pic secp256k1 POSITION_INDEPENDENT_CODE)
|
||||
set_target_properties(secp256k1_precomputed PROPERTIES POSITION_INDEPENDENT_CODE ${use_pic})
|
||||
|
||||
# Add the include path for parent projects so that they don't have to manually add it.
|
||||
target_include_directories(secp256k1 INTERFACE
|
||||
$<BUILD_INTERFACE:$<$<NOT:$<BOOL:${PROJECT_IS_TOP_LEVEL}>>:${PROJECT_SOURCE_DIR}/include>>
|
||||
)
|
||||
set_target_properties(secp256k1_objs PROPERTIES
|
||||
INTERFACE_COMPILE_DEFINITIONS "$<TARGET_PROPERTY:secp256k1,INTERFACE_COMPILE_DEFINITIONS>"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "$<TARGET_PROPERTY:secp256k1,INTERFACE_INCLUDE_DIRECTORIES>"
|
||||
)
|
||||
|
||||
# This emulates Libtool to make sure Libtool and CMake agree on the ABI version,
|
||||
# see below "Calculate the version variables" in autotools-aux/ltmain.sh.
|
||||
math(EXPR ${PROJECT_NAME}_soversion "${${PROJECT_NAME}_LIB_VERSION_CURRENT} - ${${PROJECT_NAME}_LIB_VERSION_AGE}")
|
||||
set_target_properties(secp256k1 PROPERTIES
|
||||
SOVERSION ${${PROJECT_NAME}_soversion}
|
||||
)
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "^(Linux|FreeBSD)$")
|
||||
set_target_properties(secp256k1 PROPERTIES
|
||||
VERSION ${${PROJECT_NAME}_soversion}.${${PROJECT_NAME}_LIB_VERSION_AGE}.${${PROJECT_NAME}_LIB_VERSION_REVISION}
|
||||
)
|
||||
elseif(APPLE)
|
||||
math(EXPR ${PROJECT_NAME}_compatibility_version "${${PROJECT_NAME}_LIB_VERSION_CURRENT} + 1")
|
||||
set_target_properties(secp256k1 PROPERTIES
|
||||
MACHO_COMPATIBILITY_VERSION ${${PROJECT_NAME}_compatibility_version}
|
||||
MACHO_CURRENT_VERSION ${${PROJECT_NAME}_compatibility_version}.${${PROJECT_NAME}_LIB_VERSION_REVISION}
|
||||
)
|
||||
unset(${PROJECT_NAME}_compatibility_version)
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
||||
set(${PROJECT_NAME}_windows "secp256k1")
|
||||
if(MSVC)
|
||||
set(${PROJECT_NAME}_windows "${PROJECT_NAME}")
|
||||
endif()
|
||||
set_target_properties(secp256k1 PROPERTIES
|
||||
ARCHIVE_OUTPUT_NAME "${${PROJECT_NAME}_windows}"
|
||||
RUNTIME_OUTPUT_NAME "${${PROJECT_NAME}_windows}-${${PROJECT_NAME}_soversion}"
|
||||
)
|
||||
unset(${PROJECT_NAME}_windows)
|
||||
endif()
|
||||
unset(${PROJECT_NAME}_soversion)
|
||||
|
||||
if(SECP256K1_BUILD_BENCHMARK)
|
||||
add_executable(bench bench.c)
|
||||
target_link_libraries(bench secp256k1)
|
||||
add_executable(bench_internal bench_internal.c)
|
||||
target_link_libraries(bench_internal secp256k1_precomputed secp256k1_asm)
|
||||
add_executable(bench_ecmult bench_ecmult.c)
|
||||
target_link_libraries(bench_ecmult secp256k1_precomputed secp256k1_asm)
|
||||
endif()
|
||||
|
||||
if(SECP256K1_BUILD_TESTS)
|
||||
include(CheckIncludeFile)
|
||||
check_include_file(sys/types.h HAVE_SYS_TYPES_H)
|
||||
check_include_file(sys/wait.h HAVE_SYS_WAIT_H)
|
||||
check_include_file(unistd.h HAVE_UNISTD_H)
|
||||
|
||||
set(TEST_DEFINITIONS "")
|
||||
if(HAVE_SYS_TYPES_H AND HAVE_SYS_WAIT_H AND HAVE_UNISTD_H)
|
||||
list(APPEND TEST_DEFINITIONS SUPPORTS_CONCURRENCY=1)
|
||||
endif()
|
||||
|
||||
function(add_executable_and_tests exe_name verify_definition)
|
||||
add_executable(${exe_name} tests.c)
|
||||
target_link_libraries(${exe_name} secp256k1_precomputed secp256k1_asm)
|
||||
target_compile_definitions(${exe_name} PRIVATE ${verify_definition} ${TEST_DEFINITIONS})
|
||||
include(DiscoverTests)
|
||||
discover_tests(${exe_name}
|
||||
DISCOVERY_ARGS "--list_tests"
|
||||
DISCOVERY_MATCH "^\\t\\\\[ *[0-9]+\\\\] ([^ ].*)$"
|
||||
TEST_NAME_REPLACEMENT "secp256k1.${exe_name}.\\\\1"
|
||||
TEST_ARGS_REPLACEMENT "--target=\\\\1 --log=1"
|
||||
PROPERTIES
|
||||
LABELS "secp256k1_${exe_name}"
|
||||
)
|
||||
endfunction()
|
||||
|
||||
add_executable_and_tests(noverify_tests "")
|
||||
if(NOT CMAKE_BUILD_TYPE STREQUAL "Coverage")
|
||||
add_executable_and_tests(tests VERIFY)
|
||||
endif()
|
||||
unset(TEST_DEFINITIONS)
|
||||
endif()
|
||||
|
||||
if(SECP256K1_BUILD_EXHAUSTIVE_TESTS)
|
||||
# Note: do not include secp256k1_precomputed in exhaustive_tests (it uses runtime-generated tables).
|
||||
add_executable(exhaustive_tests tests_exhaustive.c)
|
||||
target_link_libraries(exhaustive_tests secp256k1_asm)
|
||||
target_compile_definitions(exhaustive_tests PRIVATE $<$<NOT:$<CONFIG:Coverage>>:VERIFY>)
|
||||
add_test(NAME secp256k1.exhaustive_tests COMMAND exhaustive_tests)
|
||||
set_tests_properties(secp256k1.exhaustive_tests PROPERTIES
|
||||
LABELS secp256k1_exhaustive
|
||||
)
|
||||
endif()
|
||||
|
||||
if(SECP256K1_BUILD_CTIME_TESTS)
|
||||
add_executable(ctime_tests ctime_tests.c)
|
||||
target_link_libraries(ctime_tests secp256k1)
|
||||
endif()
|
||||
|
||||
if(SECP256K1_INSTALL)
|
||||
include(GNUInstallDirs)
|
||||
target_include_directories(secp256k1 INTERFACE
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
)
|
||||
install(TARGETS secp256k1
|
||||
EXPORT ${PROJECT_NAME}-targets
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
|
||||
)
|
||||
|
||||
install(EXPORT ${PROJECT_NAME}-targets
|
||||
FILE ${PROJECT_NAME}-targets.cmake
|
||||
NAMESPACE ${PROJECT_NAME}::
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
|
||||
)
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
configure_package_config_file(
|
||||
${PROJECT_SOURCE_DIR}/cmake/config.cmake.in
|
||||
${PROJECT_NAME}-config.cmake
|
||||
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
|
||||
NO_SET_AND_CHECK_MACRO
|
||||
)
|
||||
write_basic_package_version_file(${PROJECT_NAME}-config-version.cmake
|
||||
COMPATIBILITY SameMinorVersion
|
||||
)
|
||||
|
||||
install(
|
||||
FILES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
|
||||
)
|
||||
|
||||
include(GeneratePkgConfigFile)
|
||||
generate_pkg_config_file(${PROJECT_SOURCE_DIR}/libsecp256k1.pc.in)
|
||||
install(
|
||||
FILES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig
|
||||
)
|
||||
endif()
|
||||
@@ -0,0 +1,916 @@
|
||||
@ vim: set tabstop=8 softtabstop=8 shiftwidth=8 noexpandtab syntax=armasm:
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2014 Wladimir J. van der Laan *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
/*
|
||||
ARM implementation of field_10x26 inner loops.
|
||||
|
||||
Note:
|
||||
|
||||
- To avoid unnecessary loads and make use of available registers, two
|
||||
'passes' have every time been interleaved, with the odd passes accumulating c' and d'
|
||||
which will be added to c and d respectively in the even passes
|
||||
|
||||
*/
|
||||
|
||||
.syntax unified
|
||||
@ eabi attributes - see readelf -A
|
||||
.eabi_attribute 24, 1 @ Tag_ABI_align_needed = 8-byte
|
||||
.eabi_attribute 25, 1 @ Tag_ABI_align_preserved = 8-byte, except leaf SP
|
||||
.text
|
||||
|
||||
@ Field constants
|
||||
.set field_R0, 0x3d10
|
||||
.set field_R1, 0x400
|
||||
.set field_not_M, 0xfc000000 @ ~M = ~0x3ffffff
|
||||
|
||||
.align 2
|
||||
.global secp256k1_fe_mul_inner
|
||||
.type secp256k1_fe_mul_inner, %function
|
||||
.hidden secp256k1_fe_mul_inner
|
||||
@ Arguments:
|
||||
@ r0 r Restrict: can overlap with a, not with b
|
||||
@ r1 a
|
||||
@ r2 b
|
||||
@ Stack (total 4+10*4 = 44)
|
||||
@ sp + #0 saved 'r' pointer
|
||||
@ sp + #4 + 4*X t0,t1,t2,t3,t4,t5,t6,t7,u8,t9
|
||||
secp256k1_fe_mul_inner:
|
||||
stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r14}
|
||||
sub sp, sp, #48 @ frame=44 + alignment
|
||||
str r0, [sp, #0] @ save result address, we need it only at the end
|
||||
|
||||
/******************************************
|
||||
* Main computation code.
|
||||
******************************************
|
||||
|
||||
Allocation:
|
||||
r0,r14,r7,r8 scratch
|
||||
r1 a (pointer)
|
||||
r2 b (pointer)
|
||||
r3:r4 c
|
||||
r5:r6 d
|
||||
r11:r12 c'
|
||||
r9:r10 d'
|
||||
|
||||
Note: do not write to r[] here, it may overlap with a[]
|
||||
*/
|
||||
|
||||
/* A - interleaved with B */
|
||||
ldr r7, [r1, #0*4] @ a[0]
|
||||
ldr r8, [r2, #9*4] @ b[9]
|
||||
ldr r0, [r1, #1*4] @ a[1]
|
||||
umull r5, r6, r7, r8 @ d = a[0] * b[9]
|
||||
ldr r14, [r2, #8*4] @ b[8]
|
||||
umull r9, r10, r0, r8 @ d' = a[1] * b[9]
|
||||
ldr r7, [r1, #2*4] @ a[2]
|
||||
umlal r5, r6, r0, r14 @ d += a[1] * b[8]
|
||||
ldr r8, [r2, #7*4] @ b[7]
|
||||
umlal r9, r10, r7, r14 @ d' += a[2] * b[8]
|
||||
ldr r0, [r1, #3*4] @ a[3]
|
||||
umlal r5, r6, r7, r8 @ d += a[2] * b[7]
|
||||
ldr r14, [r2, #6*4] @ b[6]
|
||||
umlal r9, r10, r0, r8 @ d' += a[3] * b[7]
|
||||
ldr r7, [r1, #4*4] @ a[4]
|
||||
umlal r5, r6, r0, r14 @ d += a[3] * b[6]
|
||||
ldr r8, [r2, #5*4] @ b[5]
|
||||
umlal r9, r10, r7, r14 @ d' += a[4] * b[6]
|
||||
ldr r0, [r1, #5*4] @ a[5]
|
||||
umlal r5, r6, r7, r8 @ d += a[4] * b[5]
|
||||
ldr r14, [r2, #4*4] @ b[4]
|
||||
umlal r9, r10, r0, r8 @ d' += a[5] * b[5]
|
||||
ldr r7, [r1, #6*4] @ a[6]
|
||||
umlal r5, r6, r0, r14 @ d += a[5] * b[4]
|
||||
ldr r8, [r2, #3*4] @ b[3]
|
||||
umlal r9, r10, r7, r14 @ d' += a[6] * b[4]
|
||||
ldr r0, [r1, #7*4] @ a[7]
|
||||
umlal r5, r6, r7, r8 @ d += a[6] * b[3]
|
||||
ldr r14, [r2, #2*4] @ b[2]
|
||||
umlal r9, r10, r0, r8 @ d' += a[7] * b[3]
|
||||
ldr r7, [r1, #8*4] @ a[8]
|
||||
umlal r5, r6, r0, r14 @ d += a[7] * b[2]
|
||||
ldr r8, [r2, #1*4] @ b[1]
|
||||
umlal r9, r10, r7, r14 @ d' += a[8] * b[2]
|
||||
ldr r0, [r1, #9*4] @ a[9]
|
||||
umlal r5, r6, r7, r8 @ d += a[8] * b[1]
|
||||
ldr r14, [r2, #0*4] @ b[0]
|
||||
umlal r9, r10, r0, r8 @ d' += a[9] * b[1]
|
||||
ldr r7, [r1, #0*4] @ a[0]
|
||||
umlal r5, r6, r0, r14 @ d += a[9] * b[0]
|
||||
@ r7,r14 used in B
|
||||
|
||||
bic r0, r5, field_not_M @ t9 = d & M
|
||||
str r0, [sp, #4 + 4*9]
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
|
||||
/* B */
|
||||
umull r3, r4, r7, r14 @ c = a[0] * b[0]
|
||||
adds r5, r5, r9 @ d += d'
|
||||
adc r6, r6, r10
|
||||
|
||||
bic r0, r5, field_not_M @ u0 = d & M
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
movw r14, field_R0 @ c += u0 * R0
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
bic r14, r3, field_not_M @ t0 = c & M
|
||||
str r14, [sp, #4 + 0*4]
|
||||
mov r3, r3, lsr #26 @ c >>= 26
|
||||
orr r3, r3, r4, asl #6
|
||||
mov r4, r4, lsr #26
|
||||
mov r14, field_R1 @ c += u0 * R1
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
/* C - interleaved with D */
|
||||
ldr r7, [r1, #0*4] @ a[0]
|
||||
ldr r8, [r2, #2*4] @ b[2]
|
||||
ldr r14, [r2, #1*4] @ b[1]
|
||||
umull r11, r12, r7, r8 @ c' = a[0] * b[2]
|
||||
ldr r0, [r1, #1*4] @ a[1]
|
||||
umlal r3, r4, r7, r14 @ c += a[0] * b[1]
|
||||
ldr r8, [r2, #0*4] @ b[0]
|
||||
umlal r11, r12, r0, r14 @ c' += a[1] * b[1]
|
||||
ldr r7, [r1, #2*4] @ a[2]
|
||||
umlal r3, r4, r0, r8 @ c += a[1] * b[0]
|
||||
ldr r14, [r2, #9*4] @ b[9]
|
||||
umlal r11, r12, r7, r8 @ c' += a[2] * b[0]
|
||||
ldr r0, [r1, #3*4] @ a[3]
|
||||
umlal r5, r6, r7, r14 @ d += a[2] * b[9]
|
||||
ldr r8, [r2, #8*4] @ b[8]
|
||||
umull r9, r10, r0, r14 @ d' = a[3] * b[9]
|
||||
ldr r7, [r1, #4*4] @ a[4]
|
||||
umlal r5, r6, r0, r8 @ d += a[3] * b[8]
|
||||
ldr r14, [r2, #7*4] @ b[7]
|
||||
umlal r9, r10, r7, r8 @ d' += a[4] * b[8]
|
||||
ldr r0, [r1, #5*4] @ a[5]
|
||||
umlal r5, r6, r7, r14 @ d += a[4] * b[7]
|
||||
ldr r8, [r2, #6*4] @ b[6]
|
||||
umlal r9, r10, r0, r14 @ d' += a[5] * b[7]
|
||||
ldr r7, [r1, #6*4] @ a[6]
|
||||
umlal r5, r6, r0, r8 @ d += a[5] * b[6]
|
||||
ldr r14, [r2, #5*4] @ b[5]
|
||||
umlal r9, r10, r7, r8 @ d' += a[6] * b[6]
|
||||
ldr r0, [r1, #7*4] @ a[7]
|
||||
umlal r5, r6, r7, r14 @ d += a[6] * b[5]
|
||||
ldr r8, [r2, #4*4] @ b[4]
|
||||
umlal r9, r10, r0, r14 @ d' += a[7] * b[5]
|
||||
ldr r7, [r1, #8*4] @ a[8]
|
||||
umlal r5, r6, r0, r8 @ d += a[7] * b[4]
|
||||
ldr r14, [r2, #3*4] @ b[3]
|
||||
umlal r9, r10, r7, r8 @ d' += a[8] * b[4]
|
||||
ldr r0, [r1, #9*4] @ a[9]
|
||||
umlal r5, r6, r7, r14 @ d += a[8] * b[3]
|
||||
ldr r8, [r2, #2*4] @ b[2]
|
||||
umlal r9, r10, r0, r14 @ d' += a[9] * b[3]
|
||||
umlal r5, r6, r0, r8 @ d += a[9] * b[2]
|
||||
|
||||
bic r0, r5, field_not_M @ u1 = d & M
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
movw r14, field_R0 @ c += u1 * R0
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
bic r14, r3, field_not_M @ t1 = c & M
|
||||
str r14, [sp, #4 + 1*4]
|
||||
mov r3, r3, lsr #26 @ c >>= 26
|
||||
orr r3, r3, r4, asl #6
|
||||
mov r4, r4, lsr #26
|
||||
mov r14, field_R1 @ c += u1 * R1
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
/* D */
|
||||
adds r3, r3, r11 @ c += c'
|
||||
adc r4, r4, r12
|
||||
adds r5, r5, r9 @ d += d'
|
||||
adc r6, r6, r10
|
||||
|
||||
bic r0, r5, field_not_M @ u2 = d & M
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
movw r14, field_R0 @ c += u2 * R0
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
bic r14, r3, field_not_M @ t2 = c & M
|
||||
str r14, [sp, #4 + 2*4]
|
||||
mov r3, r3, lsr #26 @ c >>= 26
|
||||
orr r3, r3, r4, asl #6
|
||||
mov r4, r4, lsr #26
|
||||
mov r14, field_R1 @ c += u2 * R1
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
/* E - interleaved with F */
|
||||
ldr r7, [r1, #0*4] @ a[0]
|
||||
ldr r8, [r2, #4*4] @ b[4]
|
||||
umull r11, r12, r7, r8 @ c' = a[0] * b[4]
|
||||
ldr r8, [r2, #3*4] @ b[3]
|
||||
umlal r3, r4, r7, r8 @ c += a[0] * b[3]
|
||||
ldr r7, [r1, #1*4] @ a[1]
|
||||
umlal r11, r12, r7, r8 @ c' += a[1] * b[3]
|
||||
ldr r8, [r2, #2*4] @ b[2]
|
||||
umlal r3, r4, r7, r8 @ c += a[1] * b[2]
|
||||
ldr r7, [r1, #2*4] @ a[2]
|
||||
umlal r11, r12, r7, r8 @ c' += a[2] * b[2]
|
||||
ldr r8, [r2, #1*4] @ b[1]
|
||||
umlal r3, r4, r7, r8 @ c += a[2] * b[1]
|
||||
ldr r7, [r1, #3*4] @ a[3]
|
||||
umlal r11, r12, r7, r8 @ c' += a[3] * b[1]
|
||||
ldr r8, [r2, #0*4] @ b[0]
|
||||
umlal r3, r4, r7, r8 @ c += a[3] * b[0]
|
||||
ldr r7, [r1, #4*4] @ a[4]
|
||||
umlal r11, r12, r7, r8 @ c' += a[4] * b[0]
|
||||
ldr r8, [r2, #9*4] @ b[9]
|
||||
umlal r5, r6, r7, r8 @ d += a[4] * b[9]
|
||||
ldr r7, [r1, #5*4] @ a[5]
|
||||
umull r9, r10, r7, r8 @ d' = a[5] * b[9]
|
||||
ldr r8, [r2, #8*4] @ b[8]
|
||||
umlal r5, r6, r7, r8 @ d += a[5] * b[8]
|
||||
ldr r7, [r1, #6*4] @ a[6]
|
||||
umlal r9, r10, r7, r8 @ d' += a[6] * b[8]
|
||||
ldr r8, [r2, #7*4] @ b[7]
|
||||
umlal r5, r6, r7, r8 @ d += a[6] * b[7]
|
||||
ldr r7, [r1, #7*4] @ a[7]
|
||||
umlal r9, r10, r7, r8 @ d' += a[7] * b[7]
|
||||
ldr r8, [r2, #6*4] @ b[6]
|
||||
umlal r5, r6, r7, r8 @ d += a[7] * b[6]
|
||||
ldr r7, [r1, #8*4] @ a[8]
|
||||
umlal r9, r10, r7, r8 @ d' += a[8] * b[6]
|
||||
ldr r8, [r2, #5*4] @ b[5]
|
||||
umlal r5, r6, r7, r8 @ d += a[8] * b[5]
|
||||
ldr r7, [r1, #9*4] @ a[9]
|
||||
umlal r9, r10, r7, r8 @ d' += a[9] * b[5]
|
||||
ldr r8, [r2, #4*4] @ b[4]
|
||||
umlal r5, r6, r7, r8 @ d += a[9] * b[4]
|
||||
|
||||
bic r0, r5, field_not_M @ u3 = d & M
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
movw r14, field_R0 @ c += u3 * R0
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
bic r14, r3, field_not_M @ t3 = c & M
|
||||
str r14, [sp, #4 + 3*4]
|
||||
mov r3, r3, lsr #26 @ c >>= 26
|
||||
orr r3, r3, r4, asl #6
|
||||
mov r4, r4, lsr #26
|
||||
mov r14, field_R1 @ c += u3 * R1
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
/* F */
|
||||
adds r3, r3, r11 @ c += c'
|
||||
adc r4, r4, r12
|
||||
adds r5, r5, r9 @ d += d'
|
||||
adc r6, r6, r10
|
||||
|
||||
bic r0, r5, field_not_M @ u4 = d & M
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
movw r14, field_R0 @ c += u4 * R0
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
bic r14, r3, field_not_M @ t4 = c & M
|
||||
str r14, [sp, #4 + 4*4]
|
||||
mov r3, r3, lsr #26 @ c >>= 26
|
||||
orr r3, r3, r4, asl #6
|
||||
mov r4, r4, lsr #26
|
||||
mov r14, field_R1 @ c += u4 * R1
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
/* G - interleaved with H */
|
||||
ldr r7, [r1, #0*4] @ a[0]
|
||||
ldr r8, [r2, #6*4] @ b[6]
|
||||
ldr r14, [r2, #5*4] @ b[5]
|
||||
umull r11, r12, r7, r8 @ c' = a[0] * b[6]
|
||||
ldr r0, [r1, #1*4] @ a[1]
|
||||
umlal r3, r4, r7, r14 @ c += a[0] * b[5]
|
||||
ldr r8, [r2, #4*4] @ b[4]
|
||||
umlal r11, r12, r0, r14 @ c' += a[1] * b[5]
|
||||
ldr r7, [r1, #2*4] @ a[2]
|
||||
umlal r3, r4, r0, r8 @ c += a[1] * b[4]
|
||||
ldr r14, [r2, #3*4] @ b[3]
|
||||
umlal r11, r12, r7, r8 @ c' += a[2] * b[4]
|
||||
ldr r0, [r1, #3*4] @ a[3]
|
||||
umlal r3, r4, r7, r14 @ c += a[2] * b[3]
|
||||
ldr r8, [r2, #2*4] @ b[2]
|
||||
umlal r11, r12, r0, r14 @ c' += a[3] * b[3]
|
||||
ldr r7, [r1, #4*4] @ a[4]
|
||||
umlal r3, r4, r0, r8 @ c += a[3] * b[2]
|
||||
ldr r14, [r2, #1*4] @ b[1]
|
||||
umlal r11, r12, r7, r8 @ c' += a[4] * b[2]
|
||||
ldr r0, [r1, #5*4] @ a[5]
|
||||
umlal r3, r4, r7, r14 @ c += a[4] * b[1]
|
||||
ldr r8, [r2, #0*4] @ b[0]
|
||||
umlal r11, r12, r0, r14 @ c' += a[5] * b[1]
|
||||
ldr r7, [r1, #6*4] @ a[6]
|
||||
umlal r3, r4, r0, r8 @ c += a[5] * b[0]
|
||||
ldr r14, [r2, #9*4] @ b[9]
|
||||
umlal r11, r12, r7, r8 @ c' += a[6] * b[0]
|
||||
ldr r0, [r1, #7*4] @ a[7]
|
||||
umlal r5, r6, r7, r14 @ d += a[6] * b[9]
|
||||
ldr r8, [r2, #8*4] @ b[8]
|
||||
umull r9, r10, r0, r14 @ d' = a[7] * b[9]
|
||||
ldr r7, [r1, #8*4] @ a[8]
|
||||
umlal r5, r6, r0, r8 @ d += a[7] * b[8]
|
||||
ldr r14, [r2, #7*4] @ b[7]
|
||||
umlal r9, r10, r7, r8 @ d' += a[8] * b[8]
|
||||
ldr r0, [r1, #9*4] @ a[9]
|
||||
umlal r5, r6, r7, r14 @ d += a[8] * b[7]
|
||||
ldr r8, [r2, #6*4] @ b[6]
|
||||
umlal r9, r10, r0, r14 @ d' += a[9] * b[7]
|
||||
umlal r5, r6, r0, r8 @ d += a[9] * b[6]
|
||||
|
||||
bic r0, r5, field_not_M @ u5 = d & M
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
movw r14, field_R0 @ c += u5 * R0
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
bic r14, r3, field_not_M @ t5 = c & M
|
||||
str r14, [sp, #4 + 5*4]
|
||||
mov r3, r3, lsr #26 @ c >>= 26
|
||||
orr r3, r3, r4, asl #6
|
||||
mov r4, r4, lsr #26
|
||||
mov r14, field_R1 @ c += u5 * R1
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
/* H */
|
||||
adds r3, r3, r11 @ c += c'
|
||||
adc r4, r4, r12
|
||||
adds r5, r5, r9 @ d += d'
|
||||
adc r6, r6, r10
|
||||
|
||||
bic r0, r5, field_not_M @ u6 = d & M
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
movw r14, field_R0 @ c += u6 * R0
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
bic r14, r3, field_not_M @ t6 = c & M
|
||||
str r14, [sp, #4 + 6*4]
|
||||
mov r3, r3, lsr #26 @ c >>= 26
|
||||
orr r3, r3, r4, asl #6
|
||||
mov r4, r4, lsr #26
|
||||
mov r14, field_R1 @ c += u6 * R1
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
/* I - interleaved with J */
|
||||
ldr r8, [r2, #8*4] @ b[8]
|
||||
ldr r7, [r1, #0*4] @ a[0]
|
||||
ldr r14, [r2, #7*4] @ b[7]
|
||||
umull r11, r12, r7, r8 @ c' = a[0] * b[8]
|
||||
ldr r0, [r1, #1*4] @ a[1]
|
||||
umlal r3, r4, r7, r14 @ c += a[0] * b[7]
|
||||
ldr r8, [r2, #6*4] @ b[6]
|
||||
umlal r11, r12, r0, r14 @ c' += a[1] * b[7]
|
||||
ldr r7, [r1, #2*4] @ a[2]
|
||||
umlal r3, r4, r0, r8 @ c += a[1] * b[6]
|
||||
ldr r14, [r2, #5*4] @ b[5]
|
||||
umlal r11, r12, r7, r8 @ c' += a[2] * b[6]
|
||||
ldr r0, [r1, #3*4] @ a[3]
|
||||
umlal r3, r4, r7, r14 @ c += a[2] * b[5]
|
||||
ldr r8, [r2, #4*4] @ b[4]
|
||||
umlal r11, r12, r0, r14 @ c' += a[3] * b[5]
|
||||
ldr r7, [r1, #4*4] @ a[4]
|
||||
umlal r3, r4, r0, r8 @ c += a[3] * b[4]
|
||||
ldr r14, [r2, #3*4] @ b[3]
|
||||
umlal r11, r12, r7, r8 @ c' += a[4] * b[4]
|
||||
ldr r0, [r1, #5*4] @ a[5]
|
||||
umlal r3, r4, r7, r14 @ c += a[4] * b[3]
|
||||
ldr r8, [r2, #2*4] @ b[2]
|
||||
umlal r11, r12, r0, r14 @ c' += a[5] * b[3]
|
||||
ldr r7, [r1, #6*4] @ a[6]
|
||||
umlal r3, r4, r0, r8 @ c += a[5] * b[2]
|
||||
ldr r14, [r2, #1*4] @ b[1]
|
||||
umlal r11, r12, r7, r8 @ c' += a[6] * b[2]
|
||||
ldr r0, [r1, #7*4] @ a[7]
|
||||
umlal r3, r4, r7, r14 @ c += a[6] * b[1]
|
||||
ldr r8, [r2, #0*4] @ b[0]
|
||||
umlal r11, r12, r0, r14 @ c' += a[7] * b[1]
|
||||
ldr r7, [r1, #8*4] @ a[8]
|
||||
umlal r3, r4, r0, r8 @ c += a[7] * b[0]
|
||||
ldr r14, [r2, #9*4] @ b[9]
|
||||
umlal r11, r12, r7, r8 @ c' += a[8] * b[0]
|
||||
ldr r0, [r1, #9*4] @ a[9]
|
||||
umlal r5, r6, r7, r14 @ d += a[8] * b[9]
|
||||
ldr r8, [r2, #8*4] @ b[8]
|
||||
umull r9, r10, r0, r14 @ d' = a[9] * b[9]
|
||||
umlal r5, r6, r0, r8 @ d += a[9] * b[8]
|
||||
|
||||
bic r0, r5, field_not_M @ u7 = d & M
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
movw r14, field_R0 @ c += u7 * R0
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
bic r14, r3, field_not_M @ t7 = c & M
|
||||
str r14, [sp, #4 + 7*4]
|
||||
mov r3, r3, lsr #26 @ c >>= 26
|
||||
orr r3, r3, r4, asl #6
|
||||
mov r4, r4, lsr #26
|
||||
mov r14, field_R1 @ c += u7 * R1
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
/* J */
|
||||
adds r3, r3, r11 @ c += c'
|
||||
adc r4, r4, r12
|
||||
adds r5, r5, r9 @ d += d'
|
||||
adc r6, r6, r10
|
||||
|
||||
bic r0, r5, field_not_M @ u8 = d & M
|
||||
str r0, [sp, #4 + 8*4]
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
movw r14, field_R0 @ c += u8 * R0
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
/******************************************
|
||||
* compute and write back result
|
||||
******************************************
|
||||
Allocation:
|
||||
r0 r
|
||||
r3:r4 c
|
||||
r5:r6 d
|
||||
r7 t0
|
||||
r8 t1
|
||||
r9 t2
|
||||
r11 u8
|
||||
r12 t9
|
||||
r1,r2,r10,r14 scratch
|
||||
|
||||
Note: do not read from a[] after here, it may overlap with r[]
|
||||
*/
|
||||
ldr r0, [sp, #0]
|
||||
add r1, sp, #4 + 3*4 @ r[3..7] = t3..7, r11=u8, r12=t9
|
||||
ldmia r1, {r2,r7,r8,r9,r10,r11,r12}
|
||||
add r1, r0, #3*4
|
||||
stmia r1, {r2,r7,r8,r9,r10}
|
||||
|
||||
bic r2, r3, field_not_M @ r[8] = c & M
|
||||
str r2, [r0, #8*4]
|
||||
mov r3, r3, lsr #26 @ c >>= 26
|
||||
orr r3, r3, r4, asl #6
|
||||
mov r4, r4, lsr #26
|
||||
mov r14, field_R1 @ c += u8 * R1
|
||||
umlal r3, r4, r11, r14
|
||||
movw r14, field_R0 @ c += d * R0
|
||||
umlal r3, r4, r5, r14
|
||||
adds r3, r3, r12 @ c += t9
|
||||
adc r4, r4, #0
|
||||
|
||||
add r1, sp, #4 + 0*4 @ r7,r8,r9 = t0,t1,t2
|
||||
ldmia r1, {r7,r8,r9}
|
||||
|
||||
ubfx r2, r3, #0, #22 @ r[9] = c & (M >> 4)
|
||||
str r2, [r0, #9*4]
|
||||
mov r3, r3, lsr #22 @ c >>= 22
|
||||
orr r3, r3, r4, asl #10
|
||||
mov r4, r4, lsr #22
|
||||
movw r14, field_R1 << 4 @ c += d * (R1 << 4)
|
||||
umlal r3, r4, r5, r14
|
||||
|
||||
movw r14, field_R0 >> 4 @ d = c * (R0 >> 4) + t0 (64x64 multiply+add)
|
||||
umull r5, r6, r3, r14 @ d = c.lo * (R0 >> 4)
|
||||
adds r5, r5, r7 @ d.lo += t0
|
||||
mla r6, r14, r4, r6 @ d.hi += c.hi * (R0 >> 4)
|
||||
adc r6, r6, 0 @ d.hi += carry
|
||||
|
||||
bic r2, r5, field_not_M @ r[0] = d & M
|
||||
str r2, [r0, #0*4]
|
||||
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
|
||||
movw r14, field_R1 >> 4 @ d += c * (R1 >> 4) + t1 (64x64 multiply+add)
|
||||
umull r1, r2, r3, r14 @ tmp = c.lo * (R1 >> 4)
|
||||
adds r5, r5, r8 @ d.lo += t1
|
||||
adc r6, r6, #0 @ d.hi += carry
|
||||
adds r5, r5, r1 @ d.lo += tmp.lo
|
||||
mla r2, r14, r4, r2 @ tmp.hi += c.hi * (R1 >> 4)
|
||||
adc r6, r6, r2 @ d.hi += carry + tmp.hi
|
||||
|
||||
bic r2, r5, field_not_M @ r[1] = d & M
|
||||
str r2, [r0, #1*4]
|
||||
mov r5, r5, lsr #26 @ d >>= 26 (ignore hi)
|
||||
orr r5, r5, r6, asl #6
|
||||
|
||||
add r5, r5, r9 @ d += t2
|
||||
str r5, [r0, #2*4] @ r[2] = d
|
||||
|
||||
add sp, sp, #48
|
||||
ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}
|
||||
.size secp256k1_fe_mul_inner, .-secp256k1_fe_mul_inner
|
||||
|
||||
.align 2
|
||||
.global secp256k1_fe_sqr_inner
|
||||
.type secp256k1_fe_sqr_inner, %function
|
||||
.hidden secp256k1_fe_sqr_inner
|
||||
@ Arguments:
|
||||
@ r0 r Can overlap with a
|
||||
@ r1 a
|
||||
@ Stack (total 4+10*4 = 44)
|
||||
@ sp + #0 saved 'r' pointer
|
||||
@ sp + #4 + 4*X t0,t1,t2,t3,t4,t5,t6,t7,u8,t9
|
||||
secp256k1_fe_sqr_inner:
|
||||
stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r14}
|
||||
sub sp, sp, #48 @ frame=44 + alignment
|
||||
str r0, [sp, #0] @ save result address, we need it only at the end
|
||||
/******************************************
|
||||
* Main computation code.
|
||||
******************************************
|
||||
|
||||
Allocation:
|
||||
r0,r14,r2,r7,r8 scratch
|
||||
r1 a (pointer)
|
||||
r3:r4 c
|
||||
r5:r6 d
|
||||
r11:r12 c'
|
||||
r9:r10 d'
|
||||
|
||||
Note: do not write to r[] here, it may overlap with a[]
|
||||
*/
|
||||
/* A interleaved with B */
|
||||
ldr r0, [r1, #1*4] @ a[1]*2
|
||||
ldr r7, [r1, #0*4] @ a[0]
|
||||
mov r0, r0, asl #1
|
||||
ldr r14, [r1, #9*4] @ a[9]
|
||||
umull r3, r4, r7, r7 @ c = a[0] * a[0]
|
||||
ldr r8, [r1, #8*4] @ a[8]
|
||||
mov r7, r7, asl #1
|
||||
umull r5, r6, r7, r14 @ d = a[0]*2 * a[9]
|
||||
ldr r7, [r1, #2*4] @ a[2]*2
|
||||
umull r9, r10, r0, r14 @ d' = a[1]*2 * a[9]
|
||||
ldr r14, [r1, #7*4] @ a[7]
|
||||
umlal r5, r6, r0, r8 @ d += a[1]*2 * a[8]
|
||||
mov r7, r7, asl #1
|
||||
ldr r0, [r1, #3*4] @ a[3]*2
|
||||
umlal r9, r10, r7, r8 @ d' += a[2]*2 * a[8]
|
||||
ldr r8, [r1, #6*4] @ a[6]
|
||||
umlal r5, r6, r7, r14 @ d += a[2]*2 * a[7]
|
||||
mov r0, r0, asl #1
|
||||
ldr r7, [r1, #4*4] @ a[4]*2
|
||||
umlal r9, r10, r0, r14 @ d' += a[3]*2 * a[7]
|
||||
ldr r14, [r1, #5*4] @ a[5]
|
||||
mov r7, r7, asl #1
|
||||
umlal r5, r6, r0, r8 @ d += a[3]*2 * a[6]
|
||||
umlal r9, r10, r7, r8 @ d' += a[4]*2 * a[6]
|
||||
umlal r5, r6, r7, r14 @ d += a[4]*2 * a[5]
|
||||
umlal r9, r10, r14, r14 @ d' += a[5] * a[5]
|
||||
|
||||
bic r0, r5, field_not_M @ t9 = d & M
|
||||
str r0, [sp, #4 + 9*4]
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
|
||||
/* B */
|
||||
adds r5, r5, r9 @ d += d'
|
||||
adc r6, r6, r10
|
||||
|
||||
bic r0, r5, field_not_M @ u0 = d & M
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
movw r14, field_R0 @ c += u0 * R0
|
||||
umlal r3, r4, r0, r14
|
||||
bic r14, r3, field_not_M @ t0 = c & M
|
||||
str r14, [sp, #4 + 0*4]
|
||||
mov r3, r3, lsr #26 @ c >>= 26
|
||||
orr r3, r3, r4, asl #6
|
||||
mov r4, r4, lsr #26
|
||||
mov r14, field_R1 @ c += u0 * R1
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
/* C interleaved with D */
|
||||
ldr r0, [r1, #0*4] @ a[0]*2
|
||||
ldr r14, [r1, #1*4] @ a[1]
|
||||
mov r0, r0, asl #1
|
||||
ldr r8, [r1, #2*4] @ a[2]
|
||||
umlal r3, r4, r0, r14 @ c += a[0]*2 * a[1]
|
||||
mov r7, r8, asl #1 @ a[2]*2
|
||||
umull r11, r12, r14, r14 @ c' = a[1] * a[1]
|
||||
ldr r14, [r1, #9*4] @ a[9]
|
||||
umlal r11, r12, r0, r8 @ c' += a[0]*2 * a[2]
|
||||
ldr r0, [r1, #3*4] @ a[3]*2
|
||||
ldr r8, [r1, #8*4] @ a[8]
|
||||
umlal r5, r6, r7, r14 @ d += a[2]*2 * a[9]
|
||||
mov r0, r0, asl #1
|
||||
ldr r7, [r1, #4*4] @ a[4]*2
|
||||
umull r9, r10, r0, r14 @ d' = a[3]*2 * a[9]
|
||||
ldr r14, [r1, #7*4] @ a[7]
|
||||
umlal r5, r6, r0, r8 @ d += a[3]*2 * a[8]
|
||||
mov r7, r7, asl #1
|
||||
ldr r0, [r1, #5*4] @ a[5]*2
|
||||
umlal r9, r10, r7, r8 @ d' += a[4]*2 * a[8]
|
||||
ldr r8, [r1, #6*4] @ a[6]
|
||||
mov r0, r0, asl #1
|
||||
umlal r5, r6, r7, r14 @ d += a[4]*2 * a[7]
|
||||
umlal r9, r10, r0, r14 @ d' += a[5]*2 * a[7]
|
||||
umlal r5, r6, r0, r8 @ d += a[5]*2 * a[6]
|
||||
umlal r9, r10, r8, r8 @ d' += a[6] * a[6]
|
||||
|
||||
bic r0, r5, field_not_M @ u1 = d & M
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
movw r14, field_R0 @ c += u1 * R0
|
||||
umlal r3, r4, r0, r14
|
||||
bic r14, r3, field_not_M @ t1 = c & M
|
||||
str r14, [sp, #4 + 1*4]
|
||||
mov r3, r3, lsr #26 @ c >>= 26
|
||||
orr r3, r3, r4, asl #6
|
||||
mov r4, r4, lsr #26
|
||||
mov r14, field_R1 @ c += u1 * R1
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
/* D */
|
||||
adds r3, r3, r11 @ c += c'
|
||||
adc r4, r4, r12
|
||||
adds r5, r5, r9 @ d += d'
|
||||
adc r6, r6, r10
|
||||
|
||||
bic r0, r5, field_not_M @ u2 = d & M
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
movw r14, field_R0 @ c += u2 * R0
|
||||
umlal r3, r4, r0, r14
|
||||
bic r14, r3, field_not_M @ t2 = c & M
|
||||
str r14, [sp, #4 + 2*4]
|
||||
mov r3, r3, lsr #26 @ c >>= 26
|
||||
orr r3, r3, r4, asl #6
|
||||
mov r4, r4, lsr #26
|
||||
mov r14, field_R1 @ c += u2 * R1
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
/* E interleaved with F */
|
||||
ldr r7, [r1, #0*4] @ a[0]*2
|
||||
ldr r0, [r1, #1*4] @ a[1]*2
|
||||
ldr r14, [r1, #2*4] @ a[2]
|
||||
mov r7, r7, asl #1
|
||||
ldr r8, [r1, #3*4] @ a[3]
|
||||
ldr r2, [r1, #4*4]
|
||||
umlal r3, r4, r7, r8 @ c += a[0]*2 * a[3]
|
||||
mov r0, r0, asl #1
|
||||
umull r11, r12, r7, r2 @ c' = a[0]*2 * a[4]
|
||||
mov r2, r2, asl #1 @ a[4]*2
|
||||
umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[3]
|
||||
ldr r8, [r1, #9*4] @ a[9]
|
||||
umlal r3, r4, r0, r14 @ c += a[1]*2 * a[2]
|
||||
ldr r0, [r1, #5*4] @ a[5]*2
|
||||
umlal r11, r12, r14, r14 @ c' += a[2] * a[2]
|
||||
ldr r14, [r1, #8*4] @ a[8]
|
||||
mov r0, r0, asl #1
|
||||
umlal r5, r6, r2, r8 @ d += a[4]*2 * a[9]
|
||||
ldr r7, [r1, #6*4] @ a[6]*2
|
||||
umull r9, r10, r0, r8 @ d' = a[5]*2 * a[9]
|
||||
mov r7, r7, asl #1
|
||||
ldr r8, [r1, #7*4] @ a[7]
|
||||
umlal r5, r6, r0, r14 @ d += a[5]*2 * a[8]
|
||||
umlal r9, r10, r7, r14 @ d' += a[6]*2 * a[8]
|
||||
umlal r5, r6, r7, r8 @ d += a[6]*2 * a[7]
|
||||
umlal r9, r10, r8, r8 @ d' += a[7] * a[7]
|
||||
|
||||
bic r0, r5, field_not_M @ u3 = d & M
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
movw r14, field_R0 @ c += u3 * R0
|
||||
umlal r3, r4, r0, r14
|
||||
bic r14, r3, field_not_M @ t3 = c & M
|
||||
str r14, [sp, #4 + 3*4]
|
||||
mov r3, r3, lsr #26 @ c >>= 26
|
||||
orr r3, r3, r4, asl #6
|
||||
mov r4, r4, lsr #26
|
||||
mov r14, field_R1 @ c += u3 * R1
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
/* F */
|
||||
adds r3, r3, r11 @ c += c'
|
||||
adc r4, r4, r12
|
||||
adds r5, r5, r9 @ d += d'
|
||||
adc r6, r6, r10
|
||||
|
||||
bic r0, r5, field_not_M @ u4 = d & M
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
movw r14, field_R0 @ c += u4 * R0
|
||||
umlal r3, r4, r0, r14
|
||||
bic r14, r3, field_not_M @ t4 = c & M
|
||||
str r14, [sp, #4 + 4*4]
|
||||
mov r3, r3, lsr #26 @ c >>= 26
|
||||
orr r3, r3, r4, asl #6
|
||||
mov r4, r4, lsr #26
|
||||
mov r14, field_R1 @ c += u4 * R1
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
/* G interleaved with H */
|
||||
ldr r7, [r1, #0*4] @ a[0]*2
|
||||
ldr r0, [r1, #1*4] @ a[1]*2
|
||||
mov r7, r7, asl #1
|
||||
ldr r8, [r1, #5*4] @ a[5]
|
||||
ldr r2, [r1, #6*4] @ a[6]
|
||||
umlal r3, r4, r7, r8 @ c += a[0]*2 * a[5]
|
||||
ldr r14, [r1, #4*4] @ a[4]
|
||||
mov r0, r0, asl #1
|
||||
umull r11, r12, r7, r2 @ c' = a[0]*2 * a[6]
|
||||
ldr r7, [r1, #2*4] @ a[2]*2
|
||||
umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[5]
|
||||
mov r7, r7, asl #1
|
||||
ldr r8, [r1, #3*4] @ a[3]
|
||||
umlal r3, r4, r0, r14 @ c += a[1]*2 * a[4]
|
||||
mov r0, r2, asl #1 @ a[6]*2
|
||||
umlal r11, r12, r7, r14 @ c' += a[2]*2 * a[4]
|
||||
ldr r14, [r1, #9*4] @ a[9]
|
||||
umlal r3, r4, r7, r8 @ c += a[2]*2 * a[3]
|
||||
ldr r7, [r1, #7*4] @ a[7]*2
|
||||
umlal r11, r12, r8, r8 @ c' += a[3] * a[3]
|
||||
mov r7, r7, asl #1
|
||||
ldr r8, [r1, #8*4] @ a[8]
|
||||
umlal r5, r6, r0, r14 @ d += a[6]*2 * a[9]
|
||||
umull r9, r10, r7, r14 @ d' = a[7]*2 * a[9]
|
||||
umlal r5, r6, r7, r8 @ d += a[7]*2 * a[8]
|
||||
umlal r9, r10, r8, r8 @ d' += a[8] * a[8]
|
||||
|
||||
bic r0, r5, field_not_M @ u5 = d & M
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
movw r14, field_R0 @ c += u5 * R0
|
||||
umlal r3, r4, r0, r14
|
||||
bic r14, r3, field_not_M @ t5 = c & M
|
||||
str r14, [sp, #4 + 5*4]
|
||||
mov r3, r3, lsr #26 @ c >>= 26
|
||||
orr r3, r3, r4, asl #6
|
||||
mov r4, r4, lsr #26
|
||||
mov r14, field_R1 @ c += u5 * R1
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
/* H */
|
||||
adds r3, r3, r11 @ c += c'
|
||||
adc r4, r4, r12
|
||||
adds r5, r5, r9 @ d += d'
|
||||
adc r6, r6, r10
|
||||
|
||||
bic r0, r5, field_not_M @ u6 = d & M
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
movw r14, field_R0 @ c += u6 * R0
|
||||
umlal r3, r4, r0, r14
|
||||
bic r14, r3, field_not_M @ t6 = c & M
|
||||
str r14, [sp, #4 + 6*4]
|
||||
mov r3, r3, lsr #26 @ c >>= 26
|
||||
orr r3, r3, r4, asl #6
|
||||
mov r4, r4, lsr #26
|
||||
mov r14, field_R1 @ c += u6 * R1
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
/* I interleaved with J */
|
||||
ldr r7, [r1, #0*4] @ a[0]*2
|
||||
ldr r0, [r1, #1*4] @ a[1]*2
|
||||
mov r7, r7, asl #1
|
||||
ldr r8, [r1, #7*4] @ a[7]
|
||||
ldr r2, [r1, #8*4] @ a[8]
|
||||
umlal r3, r4, r7, r8 @ c += a[0]*2 * a[7]
|
||||
ldr r14, [r1, #6*4] @ a[6]
|
||||
mov r0, r0, asl #1
|
||||
umull r11, r12, r7, r2 @ c' = a[0]*2 * a[8]
|
||||
ldr r7, [r1, #2*4] @ a[2]*2
|
||||
umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[7]
|
||||
ldr r8, [r1, #5*4] @ a[5]
|
||||
umlal r3, r4, r0, r14 @ c += a[1]*2 * a[6]
|
||||
ldr r0, [r1, #3*4] @ a[3]*2
|
||||
mov r7, r7, asl #1
|
||||
umlal r11, r12, r7, r14 @ c' += a[2]*2 * a[6]
|
||||
ldr r14, [r1, #4*4] @ a[4]
|
||||
mov r0, r0, asl #1
|
||||
umlal r3, r4, r7, r8 @ c += a[2]*2 * a[5]
|
||||
mov r2, r2, asl #1 @ a[8]*2
|
||||
umlal r11, r12, r0, r8 @ c' += a[3]*2 * a[5]
|
||||
umlal r3, r4, r0, r14 @ c += a[3]*2 * a[4]
|
||||
umlal r11, r12, r14, r14 @ c' += a[4] * a[4]
|
||||
ldr r8, [r1, #9*4] @ a[9]
|
||||
umlal r5, r6, r2, r8 @ d += a[8]*2 * a[9]
|
||||
@ r8 will be used in J
|
||||
|
||||
bic r0, r5, field_not_M @ u7 = d & M
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
movw r14, field_R0 @ c += u7 * R0
|
||||
umlal r3, r4, r0, r14
|
||||
bic r14, r3, field_not_M @ t7 = c & M
|
||||
str r14, [sp, #4 + 7*4]
|
||||
mov r3, r3, lsr #26 @ c >>= 26
|
||||
orr r3, r3, r4, asl #6
|
||||
mov r4, r4, lsr #26
|
||||
mov r14, field_R1 @ c += u7 * R1
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
/* J */
|
||||
adds r3, r3, r11 @ c += c'
|
||||
adc r4, r4, r12
|
||||
umlal r5, r6, r8, r8 @ d += a[9] * a[9]
|
||||
|
||||
bic r0, r5, field_not_M @ u8 = d & M
|
||||
str r0, [sp, #4 + 8*4]
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
movw r14, field_R0 @ c += u8 * R0
|
||||
umlal r3, r4, r0, r14
|
||||
|
||||
/******************************************
|
||||
* compute and write back result
|
||||
******************************************
|
||||
Allocation:
|
||||
r0 r
|
||||
r3:r4 c
|
||||
r5:r6 d
|
||||
r7 t0
|
||||
r8 t1
|
||||
r9 t2
|
||||
r11 u8
|
||||
r12 t9
|
||||
r1,r2,r10,r14 scratch
|
||||
|
||||
Note: do not read from a[] after here, it may overlap with r[]
|
||||
*/
|
||||
ldr r0, [sp, #0]
|
||||
add r1, sp, #4 + 3*4 @ r[3..7] = t3..7, r11=u8, r12=t9
|
||||
ldmia r1, {r2,r7,r8,r9,r10,r11,r12}
|
||||
add r1, r0, #3*4
|
||||
stmia r1, {r2,r7,r8,r9,r10}
|
||||
|
||||
bic r2, r3, field_not_M @ r[8] = c & M
|
||||
str r2, [r0, #8*4]
|
||||
mov r3, r3, lsr #26 @ c >>= 26
|
||||
orr r3, r3, r4, asl #6
|
||||
mov r4, r4, lsr #26
|
||||
mov r14, field_R1 @ c += u8 * R1
|
||||
umlal r3, r4, r11, r14
|
||||
movw r14, field_R0 @ c += d * R0
|
||||
umlal r3, r4, r5, r14
|
||||
adds r3, r3, r12 @ c += t9
|
||||
adc r4, r4, #0
|
||||
|
||||
add r1, sp, #4 + 0*4 @ r7,r8,r9 = t0,t1,t2
|
||||
ldmia r1, {r7,r8,r9}
|
||||
|
||||
ubfx r2, r3, #0, #22 @ r[9] = c & (M >> 4)
|
||||
str r2, [r0, #9*4]
|
||||
mov r3, r3, lsr #22 @ c >>= 22
|
||||
orr r3, r3, r4, asl #10
|
||||
mov r4, r4, lsr #22
|
||||
movw r14, field_R1 << 4 @ c += d * (R1 << 4)
|
||||
umlal r3, r4, r5, r14
|
||||
|
||||
movw r14, field_R0 >> 4 @ d = c * (R0 >> 4) + t0 (64x64 multiply+add)
|
||||
umull r5, r6, r3, r14 @ d = c.lo * (R0 >> 4)
|
||||
adds r5, r5, r7 @ d.lo += t0
|
||||
mla r6, r14, r4, r6 @ d.hi += c.hi * (R0 >> 4)
|
||||
adc r6, r6, 0 @ d.hi += carry
|
||||
|
||||
bic r2, r5, field_not_M @ r[0] = d & M
|
||||
str r2, [r0, #0*4]
|
||||
|
||||
mov r5, r5, lsr #26 @ d >>= 26
|
||||
orr r5, r5, r6, asl #6
|
||||
mov r6, r6, lsr #26
|
||||
|
||||
movw r14, field_R1 >> 4 @ d += c * (R1 >> 4) + t1 (64x64 multiply+add)
|
||||
umull r1, r2, r3, r14 @ tmp = c.lo * (R1 >> 4)
|
||||
adds r5, r5, r8 @ d.lo += t1
|
||||
adc r6, r6, #0 @ d.hi += carry
|
||||
adds r5, r5, r1 @ d.lo += tmp.lo
|
||||
mla r2, r14, r4, r2 @ tmp.hi += c.hi * (R1 >> 4)
|
||||
adc r6, r6, r2 @ d.hi += carry + tmp.hi
|
||||
|
||||
bic r2, r5, field_not_M @ r[1] = d & M
|
||||
str r2, [r0, #1*4]
|
||||
mov r5, r5, lsr #26 @ d >>= 26 (ignore hi)
|
||||
orr r5, r5, r6, asl #6
|
||||
|
||||
add r5, r5, r9 @ d += t2
|
||||
str r5, [r0, #2*4] @ r[2] = d
|
||||
|
||||
add sp, sp, #48
|
||||
ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}
|
||||
.size secp256k1_fe_sqr_inner, .-secp256k1_fe_sqr_inner
|
||||
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
@@ -0,0 +1,87 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2020 Pieter Wuille *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_ASSUMPTIONS_H
|
||||
#define SECP256K1_ASSUMPTIONS_H
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "util.h"
|
||||
#if defined(SECP256K1_INT128_NATIVE)
|
||||
#include "int128_native.h"
|
||||
#endif
|
||||
|
||||
/* This library, like most software, relies on a number of compiler implementation defined (but not undefined)
|
||||
behaviours. Although the behaviours we require are essentially universal we test them specifically here to
|
||||
reduce the odds of experiencing an unwelcome surprise.
|
||||
*/
|
||||
|
||||
#if defined(__has_attribute)
|
||||
# if __has_attribute(__unavailable__)
|
||||
__attribute__((__unavailable__("Don't call this function. It only exists because STATIC_ASSERT cannot be used outside a function.")))
|
||||
# endif
|
||||
#endif
|
||||
static void secp256k1_assumption_checker(void) {
|
||||
/* Bytes are 8 bits. */
|
||||
STATIC_ASSERT(CHAR_BIT == 8);
|
||||
|
||||
/* No integer promotion for uint32_t. This ensures that we can multiply uintXX_t values where XX >= 32
|
||||
without signed overflow, which would be undefined behaviour. */
|
||||
STATIC_ASSERT(UINT_MAX <= UINT32_MAX);
|
||||
|
||||
/* Conversions from unsigned to signed outside of the bounds of the signed type are
|
||||
implementation-defined. Verify that they function as reinterpreting the lower
|
||||
bits of the input in two's complement notation. Do this for conversions:
|
||||
- from uint(N)_t to int(N)_t with negative result
|
||||
- from uint(2N)_t to int(N)_t with negative result
|
||||
- from int(2N)_t to int(N)_t with negative result
|
||||
- from int(2N)_t to int(N)_t with positive result */
|
||||
|
||||
/* To int8_t. */
|
||||
STATIC_ASSERT(((int8_t)(uint8_t)0xAB == (int8_t)-(int8_t)0x55));
|
||||
STATIC_ASSERT((int8_t)(uint16_t)0xABCD == (int8_t)-(int8_t)0x33);
|
||||
STATIC_ASSERT((int8_t)(int16_t)(uint16_t)0xCDEF == (int8_t)(uint8_t)0xEF);
|
||||
STATIC_ASSERT((int8_t)(int16_t)(uint16_t)0x9234 == (int8_t)(uint8_t)0x34);
|
||||
|
||||
/* To int16_t. */
|
||||
STATIC_ASSERT((int16_t)(uint16_t)0xBCDE == (int16_t)-(int16_t)0x4322);
|
||||
STATIC_ASSERT((int16_t)(uint32_t)0xA1B2C3D4 == (int16_t)-(int16_t)0x3C2C);
|
||||
STATIC_ASSERT((int16_t)(int32_t)(uint32_t)0xC1D2E3F4 == (int16_t)(uint16_t)0xE3F4);
|
||||
STATIC_ASSERT((int16_t)(int32_t)(uint32_t)0x92345678 == (int16_t)(uint16_t)0x5678);
|
||||
|
||||
/* To int32_t. */
|
||||
STATIC_ASSERT((int32_t)(uint32_t)0xB2C3D4E5 == (int32_t)-(int32_t)0x4D3C2B1B);
|
||||
STATIC_ASSERT((int32_t)(uint64_t)0xA123B456C789D012ULL == (int32_t)-(int32_t)0x38762FEE);
|
||||
STATIC_ASSERT((int32_t)(int64_t)(uint64_t)0xC1D2E3F4A5B6C7D8ULL == (int32_t)(uint32_t)0xA5B6C7D8);
|
||||
STATIC_ASSERT((int32_t)(int64_t)(uint64_t)0xABCDEF0123456789ULL == (int32_t)(uint32_t)0x23456789);
|
||||
|
||||
/* To int64_t. */
|
||||
STATIC_ASSERT((int64_t)(uint64_t)0xB123C456D789E012ULL == (int64_t)-(int64_t)0x4EDC3BA928761FEEULL);
|
||||
#if defined(SECP256K1_INT128_NATIVE)
|
||||
STATIC_ASSERT((int64_t)(((uint128_t)0xA1234567B8901234ULL << 64) + 0xC5678901D2345678ULL) == (int64_t)-(int64_t)0x3A9876FE2DCBA988ULL);
|
||||
STATIC_ASSERT(((int64_t)(int128_t)(((uint128_t)0xB1C2D3E4F5A6B7C8ULL << 64) + 0xD9E0F1A2B3C4D5E6ULL)) == (int64_t)(uint64_t)0xD9E0F1A2B3C4D5E6ULL);
|
||||
STATIC_ASSERT(((int64_t)(int128_t)(((uint128_t)0xABCDEF0123456789ULL << 64) + 0x0123456789ABCDEFULL)) == (int64_t)(uint64_t)0x0123456789ABCDEFULL);
|
||||
|
||||
/* To int128_t. */
|
||||
STATIC_ASSERT((int128_t)(((uint128_t)0xB1234567C8901234ULL << 64) + 0xD5678901E2345678ULL) == (int128_t)(-(int128_t)0x8E1648B3F50E80DCULL * 0x8E1648B3F50E80DDULL + 0x5EA688D5482F9464ULL));
|
||||
#endif
|
||||
|
||||
/* Right shift on negative signed values is implementation defined. Verify that it
|
||||
acts as a right shift in two's complement with sign extension (i.e duplicating
|
||||
the top bit into newly added bits). */
|
||||
STATIC_ASSERT((((int8_t)0xE8) >> 2) == (int8_t)(uint8_t)0xFA);
|
||||
STATIC_ASSERT((((int16_t)0xE9AC) >> 4) == (int16_t)(uint16_t)0xFE9A);
|
||||
STATIC_ASSERT((((int32_t)0x937C918A) >> 9) == (int32_t)(uint32_t)0xFFC9BE48);
|
||||
STATIC_ASSERT((((int64_t)0xA8B72231DF9CF4B9ULL) >> 19) == (int64_t)(uint64_t)0xFFFFF516E4463BF3ULL);
|
||||
#if defined(SECP256K1_INT128_NATIVE)
|
||||
STATIC_ASSERT((((int128_t)(((uint128_t)0xCD833A65684A0DBCULL << 64) + 0xB349312F71EA7637ULL)) >> 39) == (int128_t)(((uint128_t)0xFFFFFFFFFF9B0674ULL << 64) + 0xCAD0941B79669262ULL));
|
||||
#endif
|
||||
|
||||
/* This function is not supposed to be called. */
|
||||
VERIFY_CHECK(0);
|
||||
}
|
||||
|
||||
#endif /* SECP256K1_ASSUMPTIONS_H */
|
||||
174
firmware/kb2040_hidden_signer/src/secp256k1/src/bench.h
Normal file
174
firmware/kb2040_hidden_signer/src/secp256k1/src/bench.h
Normal file
@@ -0,0 +1,174 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2014 Pieter Wuille *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_BENCH_H
|
||||
#define SECP256K1_BENCH_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tests_common.h"
|
||||
|
||||
#define FP_EXP (6)
|
||||
#define FP_MULT (1000000LL)
|
||||
|
||||
/* Format fixed point number. */
|
||||
static void print_number(const int64_t x) {
|
||||
int64_t x_abs, y;
|
||||
int c, i, rounding, g; /* g = integer part size, c = fractional part size */
|
||||
size_t ptr;
|
||||
char buffer[30];
|
||||
|
||||
if (x == INT64_MIN) {
|
||||
/* Prevent UB. */
|
||||
printf("ERR");
|
||||
return;
|
||||
}
|
||||
x_abs = x < 0 ? -x : x;
|
||||
|
||||
/* Determine how many decimals we want to show (more than FP_EXP makes no
|
||||
* sense). */
|
||||
y = x_abs;
|
||||
c = 0;
|
||||
while (y > 0LL && y < 100LL * FP_MULT && c < FP_EXP) {
|
||||
y *= 10LL;
|
||||
c++;
|
||||
}
|
||||
|
||||
/* Round to 'c' decimals. */
|
||||
y = x_abs;
|
||||
rounding = 0;
|
||||
for (i = c; i < FP_EXP; ++i) {
|
||||
rounding = (y % 10) >= 5;
|
||||
y /= 10;
|
||||
}
|
||||
y += rounding;
|
||||
|
||||
/* Format and print the number. */
|
||||
ptr = sizeof(buffer) - 1;
|
||||
buffer[ptr] = 0;
|
||||
g = 0;
|
||||
if (c != 0) { /* non zero fractional part */
|
||||
for (i = 0; i < c; ++i) {
|
||||
buffer[--ptr] = '0' + (y % 10);
|
||||
y /= 10;
|
||||
}
|
||||
} else if (c == 0) { /* fractional part is 0 */
|
||||
buffer[--ptr] = '0';
|
||||
}
|
||||
buffer[--ptr] = '.';
|
||||
do {
|
||||
buffer[--ptr] = '0' + (y % 10);
|
||||
y /= 10;
|
||||
g++;
|
||||
} while (y != 0);
|
||||
if (x < 0) {
|
||||
buffer[--ptr] = '-';
|
||||
g++;
|
||||
}
|
||||
printf("%5.*s", g, &buffer[ptr]); /* Prints integer part */
|
||||
printf("%-*s", FP_EXP, &buffer[ptr + g]); /* Prints fractional part */
|
||||
}
|
||||
|
||||
static void run_benchmark(char *name, void (*benchmark)(void*, int), void (*setup)(void*), void (*teardown)(void*, int), void* data, int count, int iter) {
|
||||
int i;
|
||||
int64_t min = INT64_MAX;
|
||||
int64_t sum = 0;
|
||||
int64_t max = 0;
|
||||
for (i = 0; i < count; i++) {
|
||||
int64_t begin, total;
|
||||
if (setup != NULL) {
|
||||
setup(data);
|
||||
}
|
||||
begin = gettime_i64();
|
||||
benchmark(data, iter);
|
||||
total = gettime_i64() - begin;
|
||||
if (teardown != NULL) {
|
||||
teardown(data, iter);
|
||||
}
|
||||
if (total < min) {
|
||||
min = total;
|
||||
}
|
||||
if (total > max) {
|
||||
max = total;
|
||||
}
|
||||
sum += total;
|
||||
}
|
||||
/* ',' is used as a column delimiter */
|
||||
printf("%-30s, ", name);
|
||||
print_number(min * FP_MULT / iter);
|
||||
printf(" , ");
|
||||
print_number(((sum * FP_MULT) / count) / iter);
|
||||
printf(" , ");
|
||||
print_number(max * FP_MULT / iter);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static int have_flag(int argc, char** argv, char *flag) {
|
||||
char** argm = argv + argc;
|
||||
argv++;
|
||||
while (argv != argm) {
|
||||
if (strcmp(*argv, flag) == 0) {
|
||||
return 1;
|
||||
}
|
||||
argv++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* takes an array containing the arguments that the user is allowed to enter on the command-line
|
||||
returns:
|
||||
- 1 if the user entered an invalid argument
|
||||
- 0 if all the user entered arguments are valid */
|
||||
static int have_invalid_args(int argc, char** argv, char** valid_args, size_t n) {
|
||||
size_t i;
|
||||
int found_valid;
|
||||
char** argm = argv + argc;
|
||||
argv++;
|
||||
|
||||
while (argv != argm) {
|
||||
found_valid = 0;
|
||||
for (i = 0; i < n; i++) {
|
||||
if (strcmp(*argv, valid_args[i]) == 0) {
|
||||
found_valid = 1; /* user entered a valid arg from the list */
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found_valid == 0) {
|
||||
return 1; /* invalid arg found */
|
||||
}
|
||||
argv++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_iters(int default_iters) {
|
||||
char* env = getenv("SECP256K1_BENCH_ITERS");
|
||||
if (env) {
|
||||
char* endptr;
|
||||
long int iters = strtol(env, &endptr, 0);
|
||||
if (*endptr != '\0' || iters <= 0) {
|
||||
printf("Error: Value of SECP256K1_BENCH_ITERS is not a positive integer: %s\n\n", env);
|
||||
return 0;
|
||||
}
|
||||
return iters;
|
||||
} else {
|
||||
return default_iters;
|
||||
}
|
||||
}
|
||||
|
||||
static void print_output_table_header_row(void) {
|
||||
char* bench_str = "Benchmark"; /* left justified */
|
||||
char* min_str = " Min(us) "; /* center alignment */
|
||||
char* avg_str = " Avg(us) ";
|
||||
char* max_str = " Max(us) ";
|
||||
printf("%-30s,%-15s,%-15s,%-15s\n", bench_str, min_str, avg_str, max_str);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
#endif /* SECP256K1_BENCH_H */
|
||||
117
firmware/kb2040_hidden_signer/src/secp256k1/src/checkmem.h
Normal file
117
firmware/kb2040_hidden_signer/src/secp256k1/src/checkmem.h
Normal file
@@ -0,0 +1,117 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2022 Pieter Wuille *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
/* The code here is inspired by Kris Kwiatkowski's approach in
|
||||
* https://github.com/kriskwiatkowski/pqc/blob/main/src/common/ct_check.h
|
||||
* to provide a general interface for memory-checking mechanisms, primarily
|
||||
* for constant-time checking.
|
||||
*/
|
||||
|
||||
/* These macros are defined by this header file:
|
||||
*
|
||||
* - SECP256K1_CHECKMEM_ENABLED:
|
||||
* - 1 if memory-checking integration is available, 0 otherwise.
|
||||
* This is just a compile-time macro. Use the next macro to check it is actually
|
||||
* available at runtime.
|
||||
* - SECP256K1_CHECKMEM_RUNNING():
|
||||
* - Acts like a function call, returning 1 if memory checking is available
|
||||
* at runtime.
|
||||
* - SECP256K1_CHECKMEM_CHECK(p, len):
|
||||
* - Assert or otherwise fail in case the len-byte memory block pointed to by p is
|
||||
* not considered entirely defined.
|
||||
* - SECP256K1_CHECKMEM_CHECK_VERIFY(p, len):
|
||||
* - Like SECP256K1_CHECKMEM_CHECK, but only works in VERIFY mode.
|
||||
* - SECP256K1_CHECKMEM_UNDEFINE(p, len):
|
||||
* - marks the len-byte memory block pointed to by p as undefined data (secret data,
|
||||
* in the context of constant-time checking).
|
||||
* - SECP256K1_CHECKMEM_DEFINE(p, len):
|
||||
* - marks the len-byte memory pointed to by p as defined data (public data, in the
|
||||
* context of constant-time checking).
|
||||
* - SECP256K1_CHECKMEM_MSAN_DEFINE(p, len):
|
||||
* - Like SECP256K1_CHECKMEM_DEFINE, but applies only to memory_sanitizer.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SECP256K1_CHECKMEM_H
|
||||
#define SECP256K1_CHECKMEM_H
|
||||
|
||||
/* Define a statement-like macro that ignores the arguments. */
|
||||
#define SECP256K1_CHECKMEM_NOOP(p, len) do { (void)(p); (void)(len); } while(0)
|
||||
|
||||
/* If compiling under msan, map the SECP256K1_CHECKMEM_* functionality to msan.
|
||||
* Choose this preferentially, even when VALGRIND is defined, as msan-compiled
|
||||
* binaries can't be run under valgrind anyway. */
|
||||
#if defined(__has_feature)
|
||||
# if __has_feature(memory_sanitizer)
|
||||
# include <sanitizer/msan_interface.h>
|
||||
# define SECP256K1_CHECKMEM_ENABLED 1
|
||||
# if defined(__clang__) && ((__clang_major__ == 21 && __clang_minor__ >= 1) || __clang_major__ >= 22)
|
||||
# define SECP256K1_CHECKMEM_UNDEFINE(p, len) do { \
|
||||
/* Work around https://github.com/llvm/llvm-project/issues/160094 */ \
|
||||
_Pragma("clang diagnostic push") \
|
||||
_Pragma("clang diagnostic ignored \"-Wuninitialized-const-pointer\"") \
|
||||
__msan_allocated_memory((p), (len)); \
|
||||
_Pragma("clang diagnostic pop") \
|
||||
} while(0)
|
||||
# else
|
||||
# define SECP256K1_CHECKMEM_UNDEFINE(p, len) __msan_allocated_memory((p), (len))
|
||||
# endif
|
||||
# define SECP256K1_CHECKMEM_DEFINE(p, len) __msan_unpoison((p), (len))
|
||||
# define SECP256K1_CHECKMEM_MSAN_DEFINE(p, len) __msan_unpoison((p), (len))
|
||||
# define SECP256K1_CHECKMEM_CHECK(p, len) __msan_check_mem_is_initialized((p), (len))
|
||||
# define SECP256K1_CHECKMEM_RUNNING() (1)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined SECP256K1_CHECKMEM_MSAN_DEFINE
|
||||
# define SECP256K1_CHECKMEM_MSAN_DEFINE(p, len) SECP256K1_CHECKMEM_NOOP((p), (len))
|
||||
#endif
|
||||
|
||||
/* If valgrind integration is desired (through the VALGRIND define), implement the
|
||||
* SECP256K1_CHECKMEM_* macros using valgrind. */
|
||||
#if !defined SECP256K1_CHECKMEM_ENABLED
|
||||
# if defined VALGRIND
|
||||
# include <stddef.h>
|
||||
# if defined(__clang__) && defined(__APPLE__)
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wreserved-identifier"
|
||||
# elif defined(__GNUC__) && (__GNUC__ >= 15)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wtrailing-whitespace"
|
||||
# endif
|
||||
# include <valgrind/memcheck.h>
|
||||
# if defined(__clang__) && defined(__APPLE__)
|
||||
# pragma clang diagnostic pop
|
||||
# elif defined(__GNUC__) && (__GNUC__ >= 15)
|
||||
# pragma GCC diagnostic pop
|
||||
# endif
|
||||
# define SECP256K1_CHECKMEM_ENABLED 1
|
||||
# define SECP256K1_CHECKMEM_UNDEFINE(p, len) VALGRIND_MAKE_MEM_UNDEFINED((p), (len))
|
||||
# define SECP256K1_CHECKMEM_DEFINE(p, len) VALGRIND_MAKE_MEM_DEFINED((p), (len))
|
||||
# define SECP256K1_CHECKMEM_CHECK(p, len) VALGRIND_CHECK_MEM_IS_DEFINED((p), (len))
|
||||
/* VALGRIND_MAKE_MEM_DEFINED returns 0 iff not running on memcheck.
|
||||
* This is more precise than the RUNNING_ON_VALGRIND macro, which
|
||||
* checks for valgrind in general instead of memcheck specifically. */
|
||||
# define SECP256K1_CHECKMEM_RUNNING() (VALGRIND_MAKE_MEM_DEFINED(NULL, 0) != 0)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* As a fall-back, map these macros to dummy statements. */
|
||||
#if !defined SECP256K1_CHECKMEM_ENABLED
|
||||
# define SECP256K1_CHECKMEM_ENABLED 0
|
||||
# define SECP256K1_CHECKMEM_UNDEFINE(p, len) SECP256K1_CHECKMEM_NOOP((p), (len))
|
||||
# define SECP256K1_CHECKMEM_DEFINE(p, len) SECP256K1_CHECKMEM_NOOP((p), (len))
|
||||
# define SECP256K1_CHECKMEM_CHECK(p, len) SECP256K1_CHECKMEM_NOOP((p), (len))
|
||||
# define SECP256K1_CHECKMEM_RUNNING() (0)
|
||||
#endif
|
||||
|
||||
#if defined VERIFY
|
||||
#define SECP256K1_CHECKMEM_CHECK_VERIFY(p, len) SECP256K1_CHECKMEM_CHECK((p), (len))
|
||||
#else
|
||||
#define SECP256K1_CHECKMEM_CHECK_VERIFY(p, len) SECP256K1_CHECKMEM_NOOP((p), (len))
|
||||
#endif
|
||||
|
||||
#endif /* SECP256K1_CHECKMEM_H */
|
||||
21
firmware/kb2040_hidden_signer/src/secp256k1/src/ecdsa.h
Normal file
21
firmware/kb2040_hidden_signer/src/secp256k1/src/ecdsa.h
Normal file
@@ -0,0 +1,21 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2013, 2014 Pieter Wuille *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_ECDSA_H
|
||||
#define SECP256K1_ECDSA_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "scalar.h"
|
||||
#include "group.h"
|
||||
#include "ecmult.h"
|
||||
|
||||
static int secp256k1_ecdsa_sig_parse(secp256k1_scalar *r, secp256k1_scalar *s, const unsigned char *sig, size_t size);
|
||||
static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, size_t *size, const secp256k1_scalar *r, const secp256k1_scalar *s);
|
||||
static int secp256k1_ecdsa_sig_verify(const secp256k1_scalar* r, const secp256k1_scalar* s, const secp256k1_ge *pubkey, const secp256k1_scalar *message);
|
||||
static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, secp256k1_scalar* r, secp256k1_scalar* s, const secp256k1_scalar *seckey, const secp256k1_scalar *message, const secp256k1_scalar *nonce, int *recid);
|
||||
|
||||
#endif /* SECP256K1_ECDSA_H */
|
||||
312
firmware/kb2040_hidden_signer/src/secp256k1/src/ecdsa_impl.h
Normal file
312
firmware/kb2040_hidden_signer/src/secp256k1/src/ecdsa_impl.h
Normal file
@@ -0,0 +1,312 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2013-2015 Pieter Wuille *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
|
||||
#ifndef SECP256K1_ECDSA_IMPL_H
|
||||
#define SECP256K1_ECDSA_IMPL_H
|
||||
|
||||
#include "scalar.h"
|
||||
#include "field.h"
|
||||
#include "group.h"
|
||||
#include "ecmult.h"
|
||||
#include "ecmult_gen.h"
|
||||
#include "ecdsa.h"
|
||||
|
||||
/** Group order for secp256k1 defined as 'n' in "Standards for Efficient Cryptography" (SEC2) 2.7.1
|
||||
* $ sage -c 'load("secp256k1_params.sage"); print(hex(N))'
|
||||
* 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141
|
||||
*/
|
||||
static const secp256k1_fe secp256k1_ecdsa_const_order_as_fe = SECP256K1_FE_CONST(
|
||||
0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL,
|
||||
0xBAAEDCE6UL, 0xAF48A03BUL, 0xBFD25E8CUL, 0xD0364141UL
|
||||
);
|
||||
|
||||
/** Difference between field and order, values 'p' and 'n' values defined in
|
||||
* "Standards for Efficient Cryptography" (SEC2) 2.7.1.
|
||||
* $ sage -c 'load("secp256k1_params.sage"); print(hex(P-N))'
|
||||
* 0x14551231950b75fc4402da1722fc9baee
|
||||
*/
|
||||
static const secp256k1_fe secp256k1_ecdsa_const_p_minus_order = SECP256K1_FE_CONST(
|
||||
0, 0, 0, 1, 0x45512319UL, 0x50B75FC4UL, 0x402DA172UL, 0x2FC9BAEEUL
|
||||
);
|
||||
|
||||
static int secp256k1_der_read_len(size_t *len, const unsigned char **sigp, const unsigned char *sigend) {
|
||||
size_t lenleft;
|
||||
unsigned char b1;
|
||||
VERIFY_CHECK(len != NULL);
|
||||
*len = 0;
|
||||
if (*sigp >= sigend) {
|
||||
return 0;
|
||||
}
|
||||
b1 = *((*sigp)++);
|
||||
if (b1 == 0xFF) {
|
||||
/* X.690-0207 8.1.3.5.c the value 0xFF shall not be used. */
|
||||
return 0;
|
||||
}
|
||||
if ((b1 & 0x80) == 0) {
|
||||
/* X.690-0207 8.1.3.4 short form length octets */
|
||||
*len = b1;
|
||||
return 1;
|
||||
}
|
||||
if (b1 == 0x80) {
|
||||
/* Indefinite length is not allowed in DER. */
|
||||
return 0;
|
||||
}
|
||||
/* X.690-207 8.1.3.5 long form length octets */
|
||||
lenleft = b1 & 0x7F; /* lenleft is at least 1 */
|
||||
if (lenleft > (size_t)(sigend - *sigp)) {
|
||||
return 0;
|
||||
}
|
||||
if (**sigp == 0) {
|
||||
/* Not the shortest possible length encoding. */
|
||||
return 0;
|
||||
}
|
||||
if (lenleft > sizeof(size_t)) {
|
||||
/* The resulting length would exceed the range of a size_t, so
|
||||
* it is certainly longer than the passed array size. */
|
||||
return 0;
|
||||
}
|
||||
while (lenleft > 0) {
|
||||
*len = (*len << 8) | **sigp;
|
||||
(*sigp)++;
|
||||
lenleft--;
|
||||
}
|
||||
if (*len > (size_t)(sigend - *sigp)) {
|
||||
/* Result exceeds the length of the passed array.
|
||||
(Checking this is the responsibility of the caller but it
|
||||
can't hurt do it here, too.) */
|
||||
return 0;
|
||||
}
|
||||
if (*len < 128) {
|
||||
/* Not the shortest possible length encoding. */
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int secp256k1_der_parse_integer(secp256k1_scalar *r, const unsigned char **sig, const unsigned char *sigend) {
|
||||
int overflow = 0;
|
||||
unsigned char ra[32] = {0};
|
||||
size_t rlen;
|
||||
|
||||
if (*sig == sigend || **sig != 0x02) {
|
||||
/* Not a primitive integer (X.690-0207 8.3.1). */
|
||||
return 0;
|
||||
}
|
||||
(*sig)++;
|
||||
if (secp256k1_der_read_len(&rlen, sig, sigend) == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (rlen == 0 || rlen > (size_t)(sigend - *sig)) {
|
||||
/* Exceeds bounds or not at least length 1 (X.690-0207 8.3.1). */
|
||||
return 0;
|
||||
}
|
||||
if (**sig == 0x00 && rlen > 1 && (((*sig)[1]) & 0x80) == 0x00) {
|
||||
/* Excessive 0x00 padding. */
|
||||
return 0;
|
||||
}
|
||||
if (**sig == 0xFF && rlen > 1 && (((*sig)[1]) & 0x80) == 0x80) {
|
||||
/* Excessive 0xFF padding. */
|
||||
return 0;
|
||||
}
|
||||
if ((**sig & 0x80) == 0x80) {
|
||||
/* Negative. */
|
||||
overflow = 1;
|
||||
}
|
||||
/* There is at most one leading zero byte:
|
||||
* if there were two leading zero bytes, we would have failed and returned 0
|
||||
* because of excessive 0x00 padding already. */
|
||||
if (rlen > 0 && **sig == 0) {
|
||||
/* Skip leading zero byte */
|
||||
rlen--;
|
||||
(*sig)++;
|
||||
}
|
||||
if (rlen > 32) {
|
||||
overflow = 1;
|
||||
}
|
||||
if (!overflow) {
|
||||
if (rlen) memcpy(ra + 32 - rlen, *sig, rlen);
|
||||
secp256k1_scalar_set_b32(r, ra, &overflow);
|
||||
}
|
||||
if (overflow) {
|
||||
secp256k1_scalar_set_int(r, 0);
|
||||
}
|
||||
(*sig) += rlen;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int secp256k1_ecdsa_sig_parse(secp256k1_scalar *rr, secp256k1_scalar *rs, const unsigned char *sig, size_t size) {
|
||||
const unsigned char *sigend = sig + size;
|
||||
size_t rlen;
|
||||
if (sig == sigend || *(sig++) != 0x30) {
|
||||
/* The encoding doesn't start with a constructed sequence (X.690-0207 8.9.1). */
|
||||
return 0;
|
||||
}
|
||||
if (secp256k1_der_read_len(&rlen, &sig, sigend) == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (rlen != (size_t)(sigend - sig)) {
|
||||
/* Tuple exceeds bounds or garage after tuple. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!secp256k1_der_parse_integer(rr, &sig, sigend)) {
|
||||
return 0;
|
||||
}
|
||||
if (!secp256k1_der_parse_integer(rs, &sig, sigend)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sig != sigend) {
|
||||
/* Trailing garbage inside tuple. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, size_t *size, const secp256k1_scalar* ar, const secp256k1_scalar* as) {
|
||||
unsigned char r[33] = {0}, s[33] = {0};
|
||||
unsigned char *rp = r, *sp = s;
|
||||
size_t lenR = 33, lenS = 33;
|
||||
secp256k1_scalar_get_b32(&r[1], ar);
|
||||
secp256k1_scalar_get_b32(&s[1], as);
|
||||
while (lenR > 1 && rp[0] == 0 && rp[1] < 0x80) { lenR--; rp++; }
|
||||
while (lenS > 1 && sp[0] == 0 && sp[1] < 0x80) { lenS--; sp++; }
|
||||
if (*size < 6+lenS+lenR) {
|
||||
*size = 6 + lenS + lenR;
|
||||
return 0;
|
||||
}
|
||||
*size = 6 + lenS + lenR;
|
||||
sig[0] = 0x30;
|
||||
sig[1] = 4 + lenS + lenR;
|
||||
sig[2] = 0x02;
|
||||
sig[3] = lenR;
|
||||
memcpy(sig+4, rp, lenR);
|
||||
sig[4+lenR] = 0x02;
|
||||
sig[5+lenR] = lenS;
|
||||
memcpy(sig+lenR+6, sp, lenS);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int secp256k1_ecdsa_sig_verify(const secp256k1_scalar *sigr, const secp256k1_scalar *sigs, const secp256k1_ge *pubkey, const secp256k1_scalar *message) {
|
||||
unsigned char c[32];
|
||||
secp256k1_scalar sn, u1, u2;
|
||||
#if !defined(EXHAUSTIVE_TEST_ORDER)
|
||||
int range;
|
||||
secp256k1_fe xr;
|
||||
#endif
|
||||
secp256k1_gej pubkeyj;
|
||||
secp256k1_gej pr;
|
||||
|
||||
if (secp256k1_scalar_is_zero(sigr) || secp256k1_scalar_is_zero(sigs)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_scalar_inverse_var(&sn, sigs);
|
||||
secp256k1_scalar_mul(&u1, &sn, message);
|
||||
secp256k1_scalar_mul(&u2, &sn, sigr);
|
||||
secp256k1_gej_set_ge(&pubkeyj, pubkey);
|
||||
secp256k1_ecmult(&pr, &pubkeyj, &u2, &u1);
|
||||
if (secp256k1_gej_is_infinity(&pr)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(EXHAUSTIVE_TEST_ORDER)
|
||||
{
|
||||
secp256k1_scalar computed_r;
|
||||
secp256k1_ge pr_ge;
|
||||
secp256k1_ge_set_gej(&pr_ge, &pr);
|
||||
secp256k1_fe_normalize(&pr_ge.x);
|
||||
|
||||
secp256k1_fe_get_b32(c, &pr_ge.x);
|
||||
secp256k1_scalar_set_b32(&computed_r, c, NULL);
|
||||
return secp256k1_scalar_eq(sigr, &computed_r);
|
||||
}
|
||||
#else
|
||||
|
||||
/* Interpret sigr as a field element xr */
|
||||
secp256k1_scalar_get_b32(c, sigr);
|
||||
range = secp256k1_fe_set_b32_limit(&xr, c);
|
||||
#ifdef VERIFY
|
||||
/* We know that c is in range; it comes from a scalar. */
|
||||
VERIFY_CHECK(range);
|
||||
#else
|
||||
(void)range;
|
||||
#endif
|
||||
|
||||
/** We now have the recomputed R point in pr, and its claimed x coordinate (modulo n)
|
||||
* in xr. Naively, we would extract the x coordinate from pr (requiring a inversion modulo p),
|
||||
* compute the remainder modulo n, and compare it to xr. However:
|
||||
*
|
||||
* xr == X(pr) mod n
|
||||
* <=> exists h. (xr + h * n < p && xr + h * n == X(pr))
|
||||
* [Since 2 * n > p, h can only be 0 or 1]
|
||||
* <=> (xr == X(pr)) || (xr + n < p && xr + n == X(pr))
|
||||
* [In Jacobian coordinates, X(pr) is pr.x / pr.z^2 mod p]
|
||||
* <=> (xr == pr.x / pr.z^2 mod p) || (xr + n < p && xr + n == pr.x / pr.z^2 mod p)
|
||||
* [Multiplying both sides of the equations by pr.z^2 mod p]
|
||||
* <=> (xr * pr.z^2 mod p == pr.x) || (xr + n < p && (xr + n) * pr.z^2 mod p == pr.x)
|
||||
*
|
||||
* Thus, we can avoid the inversion, but we have to check both cases separately.
|
||||
* secp256k1_gej_eq_x implements the (xr * pr.z^2 mod p == pr.x) test.
|
||||
*/
|
||||
if (secp256k1_gej_eq_x_var(&xr, &pr)) {
|
||||
/* xr * pr.z^2 mod p == pr.x, so the signature is valid. */
|
||||
return 1;
|
||||
}
|
||||
if (secp256k1_fe_cmp_var(&xr, &secp256k1_ecdsa_const_p_minus_order) >= 0) {
|
||||
/* xr + n >= p, so we can skip testing the second case. */
|
||||
return 0;
|
||||
}
|
||||
secp256k1_fe_add(&xr, &secp256k1_ecdsa_const_order_as_fe);
|
||||
if (secp256k1_gej_eq_x_var(&xr, &pr)) {
|
||||
/* (xr + n) * pr.z^2 mod p == pr.x, so the signature is valid. */
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *seckey, const secp256k1_scalar *message, const secp256k1_scalar *nonce, int *recid) {
|
||||
unsigned char b[32];
|
||||
secp256k1_gej rp;
|
||||
secp256k1_ge r;
|
||||
secp256k1_scalar n;
|
||||
int overflow = 0;
|
||||
int high;
|
||||
|
||||
secp256k1_ecmult_gen(ctx, &rp, nonce);
|
||||
secp256k1_ge_set_gej(&r, &rp);
|
||||
secp256k1_fe_normalize(&r.x);
|
||||
secp256k1_fe_normalize(&r.y);
|
||||
secp256k1_fe_get_b32(b, &r.x);
|
||||
secp256k1_scalar_set_b32(sigr, b, &overflow);
|
||||
if (recid) {
|
||||
/* The overflow condition is cryptographically unreachable as hitting it requires finding the discrete log
|
||||
* of some P where P.x >= order, and only 1 in about 2^127 points meet this criteria.
|
||||
*/
|
||||
*recid = (overflow << 1) | secp256k1_fe_is_odd(&r.y);
|
||||
}
|
||||
secp256k1_scalar_mul(&n, sigr, seckey);
|
||||
secp256k1_scalar_add(&n, &n, message);
|
||||
secp256k1_scalar_inverse(sigs, nonce);
|
||||
secp256k1_scalar_mul(sigs, sigs, &n);
|
||||
secp256k1_scalar_clear(&n);
|
||||
secp256k1_gej_clear(&rp);
|
||||
secp256k1_ge_clear(&r);
|
||||
high = secp256k1_scalar_is_high(sigs);
|
||||
secp256k1_scalar_cond_negate(sigs, high);
|
||||
if (recid) {
|
||||
*recid ^= high;
|
||||
}
|
||||
/* P.x = order is on the curve, so technically sig->r could end up being zero, which would be an invalid signature.
|
||||
* This is cryptographically unreachable as hitting it requires finding the discrete log of P.x = N.
|
||||
*/
|
||||
return (int)(!secp256k1_scalar_is_zero(sigr)) & (int)(!secp256k1_scalar_is_zero(sigs));
|
||||
}
|
||||
|
||||
#endif /* SECP256K1_ECDSA_IMPL_H */
|
||||
28
firmware/kb2040_hidden_signer/src/secp256k1/src/eckey.h
Normal file
28
firmware/kb2040_hidden_signer/src/secp256k1/src/eckey.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2013, 2014 Pieter Wuille *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_ECKEY_H
|
||||
#define SECP256K1_ECKEY_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "group.h"
|
||||
#include "scalar.h"
|
||||
#include "ecmult.h"
|
||||
#include "ecmult_gen.h"
|
||||
|
||||
static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size);
|
||||
/** Serialize a group element (that is not allowed to be infinity) to a compressed public key (33 bytes). */
|
||||
static void secp256k1_eckey_pubkey_serialize33(secp256k1_ge *elem, unsigned char *pub33);
|
||||
/** Serialize a group element (that is not allowed to be infinity) to an uncompressed public key (65 bytes). */
|
||||
static void secp256k1_eckey_pubkey_serialize65(secp256k1_ge *elem, unsigned char *pub65);
|
||||
|
||||
static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp256k1_scalar *tweak);
|
||||
static int secp256k1_eckey_pubkey_tweak_add(secp256k1_ge *key, const secp256k1_scalar *tweak);
|
||||
static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar *key, const secp256k1_scalar *tweak);
|
||||
static int secp256k1_eckey_pubkey_tweak_mul(secp256k1_ge *key, const secp256k1_scalar *tweak);
|
||||
|
||||
#endif /* SECP256K1_ECKEY_H */
|
||||
94
firmware/kb2040_hidden_signer/src/secp256k1/src/eckey_impl.h
Normal file
94
firmware/kb2040_hidden_signer/src/secp256k1/src/eckey_impl.h
Normal file
@@ -0,0 +1,94 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2013, 2014 Pieter Wuille *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_ECKEY_IMPL_H
|
||||
#define SECP256K1_ECKEY_IMPL_H
|
||||
|
||||
#include "eckey.h"
|
||||
|
||||
#include "util.h"
|
||||
#include "scalar.h"
|
||||
#include "field.h"
|
||||
#include "group.h"
|
||||
#include "ecmult_gen.h"
|
||||
|
||||
static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size) {
|
||||
if (size == 33 && (pub[0] == SECP256K1_TAG_PUBKEY_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_ODD)) {
|
||||
secp256k1_fe x;
|
||||
return secp256k1_fe_set_b32_limit(&x, pub+1) && secp256k1_ge_set_xo_var(elem, &x, pub[0] == SECP256K1_TAG_PUBKEY_ODD);
|
||||
} else if (size == 65 && (pub[0] == SECP256K1_TAG_PUBKEY_UNCOMPRESSED || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD)) {
|
||||
secp256k1_fe x, y;
|
||||
if (!secp256k1_fe_set_b32_limit(&x, pub+1) || !secp256k1_fe_set_b32_limit(&y, pub+33)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_ge_set_xy(elem, &x, &y);
|
||||
if ((pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD) &&
|
||||
secp256k1_fe_is_odd(&y) != (pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD)) {
|
||||
return 0;
|
||||
}
|
||||
return secp256k1_ge_is_valid_var(elem);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void secp256k1_eckey_pubkey_serialize33(secp256k1_ge *elem, unsigned char *pub33) {
|
||||
VERIFY_CHECK(!secp256k1_ge_is_infinity(elem));
|
||||
|
||||
secp256k1_fe_normalize_var(&elem->x);
|
||||
secp256k1_fe_normalize_var(&elem->y);
|
||||
pub33[0] = secp256k1_fe_is_odd(&elem->y) ? SECP256K1_TAG_PUBKEY_ODD : SECP256K1_TAG_PUBKEY_EVEN;
|
||||
secp256k1_fe_get_b32(&pub33[1], &elem->x);
|
||||
}
|
||||
|
||||
static void secp256k1_eckey_pubkey_serialize65(secp256k1_ge *elem, unsigned char *pub65) {
|
||||
VERIFY_CHECK(!secp256k1_ge_is_infinity(elem));
|
||||
|
||||
secp256k1_fe_normalize_var(&elem->x);
|
||||
secp256k1_fe_normalize_var(&elem->y);
|
||||
pub65[0] = SECP256K1_TAG_PUBKEY_UNCOMPRESSED;
|
||||
secp256k1_fe_get_b32(&pub65[1], &elem->x);
|
||||
secp256k1_fe_get_b32(&pub65[33], &elem->y);
|
||||
}
|
||||
|
||||
static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp256k1_scalar *tweak) {
|
||||
secp256k1_scalar_add(key, key, tweak);
|
||||
return !secp256k1_scalar_is_zero(key);
|
||||
}
|
||||
|
||||
static int secp256k1_eckey_pubkey_tweak_add(secp256k1_ge *key, const secp256k1_scalar *tweak) {
|
||||
secp256k1_gej pt;
|
||||
secp256k1_gej_set_ge(&pt, key);
|
||||
secp256k1_ecmult(&pt, &pt, &secp256k1_scalar_one, tweak);
|
||||
|
||||
if (secp256k1_gej_is_infinity(&pt)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_ge_set_gej(key, &pt);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar *key, const secp256k1_scalar *tweak) {
|
||||
int ret;
|
||||
ret = !secp256k1_scalar_is_zero(tweak);
|
||||
|
||||
secp256k1_scalar_mul(key, key, tweak);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int secp256k1_eckey_pubkey_tweak_mul(secp256k1_ge *key, const secp256k1_scalar *tweak) {
|
||||
secp256k1_gej pt;
|
||||
if (secp256k1_scalar_is_zero(tweak)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_gej_set_ge(&pt, key);
|
||||
secp256k1_ecmult(&pt, &pt, tweak, NULL);
|
||||
secp256k1_ge_set_gej(key, &pt);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* SECP256K1_ECKEY_IMPL_H */
|
||||
64
firmware/kb2040_hidden_signer/src/secp256k1/src/ecmult.h
Normal file
64
firmware/kb2040_hidden_signer/src/secp256k1/src/ecmult.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2013, 2014, 2017 Pieter Wuille, Andrew Poelstra *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_ECMULT_H
|
||||
#define SECP256K1_ECMULT_H
|
||||
|
||||
#include "group.h"
|
||||
#include "scalar.h"
|
||||
#include "scratch.h"
|
||||
|
||||
#ifndef ECMULT_WINDOW_SIZE
|
||||
# define ECMULT_WINDOW_SIZE 15
|
||||
# ifdef DEBUG_CONFIG
|
||||
# pragma message DEBUG_CONFIG_MSG("ECMULT_WINDOW_SIZE undefined, assuming default value")
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_CONFIG
|
||||
# pragma message DEBUG_CONFIG_DEF(ECMULT_WINDOW_SIZE)
|
||||
#endif
|
||||
|
||||
/* No one will ever need more than a window size of 24. The code might
|
||||
* be correct for larger values of ECMULT_WINDOW_SIZE but this is not
|
||||
* tested.
|
||||
*
|
||||
* The following limitations are known, and there are probably more:
|
||||
* If WINDOW_G > 27 and size_t has 32 bits, then the code is incorrect
|
||||
* because the size of the memory object that we allocate (in bytes)
|
||||
* will not fit in a size_t.
|
||||
* If WINDOW_G > 31 and int has 32 bits, then the code is incorrect
|
||||
* because certain expressions will overflow.
|
||||
*/
|
||||
#if ECMULT_WINDOW_SIZE < 2 || ECMULT_WINDOW_SIZE > 24
|
||||
# error Set ECMULT_WINDOW_SIZE to an integer in range [2..24].
|
||||
#endif
|
||||
|
||||
/** The number of entries a table with precomputed multiples needs to have. */
|
||||
#define ECMULT_TABLE_SIZE(w) ((size_t)1 << ((w)-2))
|
||||
|
||||
/** Double multiply: R = na*A + ng*G
|
||||
*
|
||||
* Passing NULL as ng is equivalent to the zero scalar but a tiny bit faster.
|
||||
*/
|
||||
static void secp256k1_ecmult(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng);
|
||||
|
||||
typedef int (secp256k1_ecmult_multi_callback)(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data);
|
||||
|
||||
/**
|
||||
* Multi-multiply: R = inp_g_sc * G + sum_i ni * Ai.
|
||||
* Chooses the right algorithm for a given number of points and scratch space
|
||||
* size. Resets and overwrites the given scratch space. If the points do not
|
||||
* fit in the scratch space the algorithm is repeatedly run with batches of
|
||||
* points. If no scratch space is given then a simple algorithm is used that
|
||||
* simply multiplies the points with the corresponding scalars and adds them up.
|
||||
* Returns: 1 on success (including when inp_g_sc is NULL and n is 0)
|
||||
* 0 if there is not enough scratch space for a single point or
|
||||
* callback returns 0
|
||||
*/
|
||||
static int secp256k1_ecmult_multi_var(const secp256k1_callback* error_callback, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n);
|
||||
|
||||
#endif /* SECP256K1_ECMULT_H */
|
||||
@@ -0,0 +1,16 @@
|
||||
/*****************************************************************************************************
|
||||
* Copyright (c) 2013, 2014, 2017, 2021 Pieter Wuille, Andrew Poelstra, Jonas Nick, Russell O'Connor *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php. *
|
||||
*****************************************************************************************************/
|
||||
|
||||
#ifndef SECP256K1_ECMULT_COMPUTE_TABLE_H
|
||||
#define SECP256K1_ECMULT_COMPUTE_TABLE_H
|
||||
|
||||
/* Construct table of all odd multiples of gen in range 1..(2**(window_g-1)-1). */
|
||||
static void secp256k1_ecmult_compute_table(secp256k1_ge_storage* table, int window_g, const secp256k1_gej* gen);
|
||||
|
||||
/* Like secp256k1_ecmult_compute_table, but one for both gen and gen*2^128. */
|
||||
static void secp256k1_ecmult_compute_two_tables(secp256k1_ge_storage* table, secp256k1_ge_storage* table_128, int window_g, const secp256k1_ge* gen);
|
||||
|
||||
#endif /* SECP256K1_ECMULT_COMPUTE_TABLE_H */
|
||||
@@ -0,0 +1,49 @@
|
||||
/*****************************************************************************************************
|
||||
* Copyright (c) 2013, 2014, 2017, 2021 Pieter Wuille, Andrew Poelstra, Jonas Nick, Russell O'Connor *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php. *
|
||||
*****************************************************************************************************/
|
||||
|
||||
#ifndef SECP256K1_ECMULT_COMPUTE_TABLE_IMPL_H
|
||||
#define SECP256K1_ECMULT_COMPUTE_TABLE_IMPL_H
|
||||
|
||||
#include "ecmult_compute_table.h"
|
||||
#include "group_impl.h"
|
||||
#include "field_impl.h"
|
||||
#include "ecmult.h"
|
||||
#include "util.h"
|
||||
|
||||
static void secp256k1_ecmult_compute_table(secp256k1_ge_storage* table, int window_g, const secp256k1_gej* gen) {
|
||||
secp256k1_gej gj;
|
||||
secp256k1_ge ge, dgen;
|
||||
size_t j;
|
||||
|
||||
gj = *gen;
|
||||
secp256k1_ge_set_gej_var(&ge, &gj);
|
||||
secp256k1_ge_to_storage(&table[0], &ge);
|
||||
|
||||
secp256k1_gej_double_var(&gj, gen, NULL);
|
||||
secp256k1_ge_set_gej_var(&dgen, &gj);
|
||||
|
||||
for (j = 1; j < ECMULT_TABLE_SIZE(window_g); ++j) {
|
||||
secp256k1_gej_set_ge(&gj, &ge);
|
||||
secp256k1_gej_add_ge_var(&gj, &gj, &dgen, NULL);
|
||||
secp256k1_ge_set_gej_var(&ge, &gj);
|
||||
secp256k1_ge_to_storage(&table[j], &ge);
|
||||
}
|
||||
}
|
||||
|
||||
/* Like secp256k1_ecmult_compute_table, but one for both gen and gen*2^128. */
|
||||
static void secp256k1_ecmult_compute_two_tables(secp256k1_ge_storage* table, secp256k1_ge_storage* table_128, int window_g, const secp256k1_ge* gen) {
|
||||
secp256k1_gej gj;
|
||||
int i;
|
||||
|
||||
secp256k1_gej_set_ge(&gj, gen);
|
||||
secp256k1_ecmult_compute_table(table, window_g, &gj);
|
||||
for (i = 0; i < 128; ++i) {
|
||||
secp256k1_gej_double_var(&gj, &gj, NULL);
|
||||
}
|
||||
secp256k1_ecmult_compute_table(table_128, window_g, &gj);
|
||||
}
|
||||
|
||||
#endif /* SECP256K1_ECMULT_COMPUTE_TABLE_IMPL_H */
|
||||
@@ -0,0 +1,38 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2015 Andrew Poelstra *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_ECMULT_CONST_H
|
||||
#define SECP256K1_ECMULT_CONST_H
|
||||
|
||||
#include "scalar.h"
|
||||
#include "group.h"
|
||||
|
||||
/**
|
||||
* Multiply: R = q*A (in constant-time for q)
|
||||
*/
|
||||
static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q);
|
||||
|
||||
/**
|
||||
* Same as secp256k1_ecmult_const, but takes in an x coordinate of the base point
|
||||
* only, specified as fraction n/d (numerator/denominator). Only the x coordinate of the result is
|
||||
* returned.
|
||||
*
|
||||
* If known_on_curve is 0, a verification is performed that n/d is a valid X
|
||||
* coordinate, and 0 is returned if not. Otherwise, 1 is returned.
|
||||
*
|
||||
* d being NULL is interpreted as d=1. If non-NULL, d must not be zero. q must not be zero.
|
||||
*
|
||||
* Constant time in the value of q, but not any other inputs.
|
||||
*/
|
||||
static int secp256k1_ecmult_const_xonly(
|
||||
secp256k1_fe *r,
|
||||
const secp256k1_fe *n,
|
||||
const secp256k1_fe *d,
|
||||
const secp256k1_scalar *q,
|
||||
int known_on_curve
|
||||
);
|
||||
|
||||
#endif /* SECP256K1_ECMULT_CONST_H */
|
||||
@@ -0,0 +1,402 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2015, 2022 Pieter Wuille, Andrew Poelstra *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_ECMULT_CONST_IMPL_H
|
||||
#define SECP256K1_ECMULT_CONST_IMPL_H
|
||||
|
||||
#include "scalar.h"
|
||||
#include "group.h"
|
||||
#include "ecmult_const.h"
|
||||
#include "ecmult_impl.h"
|
||||
|
||||
#if defined(EXHAUSTIVE_TEST_ORDER)
|
||||
/* We need 2^ECMULT_CONST_GROUP_SIZE - 1 to be less than EXHAUSTIVE_TEST_ORDER, because
|
||||
* the tables cannot have infinities in them (this breaks the effective-affine technique's
|
||||
* z-ratio tracking) */
|
||||
# if EXHAUSTIVE_TEST_ORDER == 199
|
||||
# define ECMULT_CONST_GROUP_SIZE 4
|
||||
# elif EXHAUSTIVE_TEST_ORDER == 13
|
||||
# define ECMULT_CONST_GROUP_SIZE 3
|
||||
# elif EXHAUSTIVE_TEST_ORDER == 7
|
||||
# define ECMULT_CONST_GROUP_SIZE 2
|
||||
# else
|
||||
# error "Unknown EXHAUSTIVE_TEST_ORDER"
|
||||
# endif
|
||||
#else
|
||||
/* Group size 4 or 5 appears optimal. */
|
||||
# define ECMULT_CONST_GROUP_SIZE 5
|
||||
#endif
|
||||
|
||||
#define ECMULT_CONST_TABLE_SIZE (1L << (ECMULT_CONST_GROUP_SIZE - 1))
|
||||
#define ECMULT_CONST_GROUPS ((129 + ECMULT_CONST_GROUP_SIZE - 1) / ECMULT_CONST_GROUP_SIZE)
|
||||
#define ECMULT_CONST_BITS (ECMULT_CONST_GROUPS * ECMULT_CONST_GROUP_SIZE)
|
||||
|
||||
/** Fill a table 'pre' with precomputed odd multiples of a.
|
||||
*
|
||||
* The resulting point set is brought to a single constant Z denominator, stores the X and Y
|
||||
* coordinates as ge points in pre, and stores the global Z in globalz.
|
||||
*
|
||||
* 'pre' must be an array of size ECMULT_CONST_TABLE_SIZE.
|
||||
*/
|
||||
static void secp256k1_ecmult_const_odd_multiples_table_globalz(secp256k1_ge *pre, secp256k1_fe *globalz, const secp256k1_gej *a) {
|
||||
secp256k1_fe zr[ECMULT_CONST_TABLE_SIZE];
|
||||
|
||||
secp256k1_ecmult_odd_multiples_table(ECMULT_CONST_TABLE_SIZE, pre, zr, globalz, a);
|
||||
secp256k1_ge_table_set_globalz(ECMULT_CONST_TABLE_SIZE, pre, zr);
|
||||
}
|
||||
|
||||
/* Given a table 'pre' with odd multiples of a point, put in r the signed-bit multiplication of n with that point.
|
||||
*
|
||||
* For example, if ECMULT_CONST_GROUP_SIZE is 4, then pre is expected to contain 8 entries:
|
||||
* [1*P, 3*P, 5*P, 7*P, 9*P, 11*P, 13*P, 15*P]. n is then expected to be a 4-bit integer (range 0-15), and its
|
||||
* bits are interpreted as signs of powers of two to look up.
|
||||
*
|
||||
* For example, if n=4, which is 0100 in binary, which is interpreted as [- + - -], so the looked up value is
|
||||
* [ -(2^3) + (2^2) - (2^1) - (2^0) ]*P = -7*P. Every valid n translates to an odd number in range [-15,15],
|
||||
* which means we just need to look up one of the precomputed values, and optionally negate it.
|
||||
*/
|
||||
#define ECMULT_CONST_TABLE_GET_GE(r,pre,n) do { \
|
||||
unsigned int m = 0; \
|
||||
/* If the top bit of n is 0, we want the negation. */ \
|
||||
volatile unsigned int negative = ((n) >> (ECMULT_CONST_GROUP_SIZE - 1)) ^ 1; \
|
||||
/* Let n[i] be the i-th bit of n, then the index is
|
||||
* sum(cnot(n[i]) * 2^i, i=0..l-2)
|
||||
* where cnot(b) = b if n[l-1] = 1 and 1 - b otherwise.
|
||||
* For example, if n = 4, in binary 0100, the index is 3, in binary 011.
|
||||
*
|
||||
* Proof:
|
||||
* Let
|
||||
* x = sum((2*n[i] - 1)*2^i, i=0..l-1)
|
||||
* = 2*sum(n[i] * 2^i, i=0..l-1) - 2^l + 1
|
||||
* be the value represented by n.
|
||||
* The index is (x - 1)/2 if x > 0 and -(x + 1)/2 otherwise.
|
||||
* Case x > 0:
|
||||
* n[l-1] = 1
|
||||
* index = sum(n[i] * 2^i, i=0..l-1) - 2^(l-1)
|
||||
* = sum(n[i] * 2^i, i=0..l-2)
|
||||
* Case x <= 0:
|
||||
* n[l-1] = 0
|
||||
* index = -(2*sum(n[i] * 2^i, i=0..l-1) - 2^l + 2)/2
|
||||
* = 2^(l-1) - 1 - sum(n[i] * 2^i, i=0..l-1)
|
||||
* = sum((1 - n[i]) * 2^i, i=0..l-2)
|
||||
*/ \
|
||||
unsigned int index = ((unsigned int)(-negative) ^ n) & ((1U << (ECMULT_CONST_GROUP_SIZE - 1)) - 1U); \
|
||||
secp256k1_fe neg_y; \
|
||||
VERIFY_CHECK((n) < (1U << ECMULT_CONST_GROUP_SIZE)); \
|
||||
VERIFY_CHECK(index < (1U << (ECMULT_CONST_GROUP_SIZE - 1))); \
|
||||
/* Unconditionally set r->x = (pre)[m].x and r->y = (pre)[m].y because it's either the correct one
|
||||
* or will get replaced in the later iterations, this is needed to make sure `r` is initialized. */ \
|
||||
secp256k1_ge_set_xy((r), &(pre)[m].x, &(pre)[m].y); \
|
||||
for (m = 1; m < ECMULT_CONST_TABLE_SIZE; m++) { \
|
||||
/* This loop is used to avoid secret data in array indices. See
|
||||
* the comment in ecmult_gen_impl.h for rationale. */ \
|
||||
secp256k1_fe_cmov(&(r)->x, &(pre)[m].x, m == index); \
|
||||
secp256k1_fe_cmov(&(r)->y, &(pre)[m].y, m == index); \
|
||||
} \
|
||||
secp256k1_fe_negate(&neg_y, &(r)->y, 1); \
|
||||
secp256k1_fe_cmov(&(r)->y, &neg_y, negative); \
|
||||
} while(0)
|
||||
|
||||
/* For K as defined in the comment of secp256k1_ecmult_const, we have several precomputed
|
||||
* formulas/constants.
|
||||
* - in exhaustive test mode, we give an explicit expression to compute it at compile time: */
|
||||
#ifdef EXHAUSTIVE_TEST_ORDER
|
||||
static const secp256k1_scalar secp256k1_ecmult_const_K = ((SECP256K1_SCALAR_CONST(0, 0, 0, (1U << (ECMULT_CONST_BITS - 128)) - 2U, 0, 0, 0, 0) + EXHAUSTIVE_TEST_ORDER - 1U) * (1U + EXHAUSTIVE_TEST_LAMBDA)) % EXHAUSTIVE_TEST_ORDER;
|
||||
/* - for the real secp256k1 group we have constants for various ECMULT_CONST_BITS values. */
|
||||
#elif ECMULT_CONST_BITS == 129
|
||||
/* For GROUP_SIZE = 1,3. */
|
||||
static const secp256k1_scalar secp256k1_ecmult_const_K = SECP256K1_SCALAR_CONST(0xac9c52b3ul, 0x3fa3cf1ful, 0x5ad9e3fdul, 0x77ed9ba4ul, 0xa880b9fcul, 0x8ec739c2ul, 0xe0cfc810ul, 0xb51283ceul);
|
||||
#elif ECMULT_CONST_BITS == 130
|
||||
/* For GROUP_SIZE = 2,5. */
|
||||
static const secp256k1_scalar secp256k1_ecmult_const_K = SECP256K1_SCALAR_CONST(0xa4e88a7dul, 0xcb13034eul, 0xc2bdd6bful, 0x7c118d6bul, 0x589ae848ul, 0x26ba29e4ul, 0xb5c2c1dcul, 0xde9798d9ul);
|
||||
#elif ECMULT_CONST_BITS == 132
|
||||
/* For GROUP_SIZE = 4,6 */
|
||||
static const secp256k1_scalar secp256k1_ecmult_const_K = SECP256K1_SCALAR_CONST(0x76b1d93dul, 0x0fae3c6bul, 0x3215874bul, 0x94e93813ul, 0x7937fe0dul, 0xb66bcaaful, 0xb3749ca5ul, 0xd7b6171bul);
|
||||
#else
|
||||
# error "Unknown ECMULT_CONST_BITS"
|
||||
#endif
|
||||
|
||||
static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q) {
|
||||
/* The approach below combines the signed-digit logic from Mike Hamburg's
|
||||
* "Fast and compact elliptic-curve cryptography" (https://eprint.iacr.org/2012/309)
|
||||
* Section 3.3, with the GLV endomorphism.
|
||||
*
|
||||
* The idea there is to interpret the bits of a scalar as signs (1 = +, 0 = -), and compute a
|
||||
* point multiplication in that fashion. Let v be an n-bit non-negative integer (0 <= v < 2^n),
|
||||
* and v[i] its i'th bit (so v = sum(v[i] * 2^i, i=0..n-1)). Then define:
|
||||
*
|
||||
* C_l(v, A) = sum((2*v[i] - 1) * 2^i*A, i=0..l-1)
|
||||
*
|
||||
* Then it holds that C_l(v, A) = sum((2*v[i] - 1) * 2^i*A, i=0..l-1)
|
||||
* = (2*sum(v[i] * 2^i, i=0..l-1) + 1 - 2^l) * A
|
||||
* = (2*v + 1 - 2^l) * A
|
||||
*
|
||||
* Thus, one can compute q*A as C_256((q + 2^256 - 1) / 2, A). This is the basis for the
|
||||
* paper's signed-digit multi-comb algorithm for multiplication using a precomputed table.
|
||||
*
|
||||
* It is appealing to try to combine this with the GLV optimization: the idea that a scalar
|
||||
* s can be written as s1 + lambda*s2, where lambda is a curve-specific constant such that
|
||||
* lambda*A is easy to compute, and where s1 and s2 are small. In particular we have the
|
||||
* secp256k1_scalar_split_lambda function which performs such a split with the resulting s1
|
||||
* and s2 in range (-2^128, 2^128) mod n. This does work, but is uninteresting:
|
||||
*
|
||||
* To compute q*A:
|
||||
* - Let s1, s2 = split_lambda(q)
|
||||
* - Let R1 = C_256((s1 + 2^256 - 1) / 2, A)
|
||||
* - Let R2 = C_256((s2 + 2^256 - 1) / 2, lambda*A)
|
||||
* - Return R1 + R2
|
||||
*
|
||||
* The issue is that while s1 and s2 are small-range numbers, (s1 + 2^256 - 1) / 2 (mod n)
|
||||
* and (s2 + 2^256 - 1) / 2 (mod n) are not, undoing the benefit of the splitting.
|
||||
*
|
||||
* To make it work, we want to modify the input scalar q first, before splitting, and then only
|
||||
* add a 2^128 offset of the split results (so that they end up in the single 129-bit range
|
||||
* [0,2^129]). A slightly smaller offset would work due to the bounds on the split, but we pick
|
||||
* 2^128 for simplicity. Let s be the scalar fed to split_lambda, and f(q) the function to
|
||||
* compute it from q:
|
||||
*
|
||||
* To compute q*A:
|
||||
* - Compute s = f(q)
|
||||
* - Let s1, s2 = split_lambda(s)
|
||||
* - Let v1 = s1 + 2^128 (mod n)
|
||||
* - Let v2 = s2 + 2^128 (mod n)
|
||||
* - Let R1 = C_l(v1, A)
|
||||
* - Let R2 = C_l(v2, lambda*A)
|
||||
* - Return R1 + R2
|
||||
*
|
||||
* l will thus need to be at least 129, but we may overshoot by a few bits (see
|
||||
* further), so keep it as a variable.
|
||||
*
|
||||
* To solve for s, we reason:
|
||||
* q*A = R1 + R2
|
||||
* <=> q*A = C_l(s1 + 2^128, A) + C_l(s2 + 2^128, lambda*A)
|
||||
* <=> q*A = (2*(s1 + 2^128) + 1 - 2^l) * A + (2*(s2 + 2^128) + 1 - 2^l) * lambda*A
|
||||
* <=> q*A = (2*(s1 + s2*lambda) + (2^129 + 1 - 2^l) * (1 + lambda)) * A
|
||||
* <=> q = 2*(s1 + s2*lambda) + (2^129 + 1 - 2^l) * (1 + lambda) (mod n)
|
||||
* <=> q = 2*s + (2^129 + 1 - 2^l) * (1 + lambda) (mod n)
|
||||
* <=> s = (q + (2^l - 2^129 - 1) * (1 + lambda)) / 2 (mod n)
|
||||
* <=> f(q) = (q + K) / 2 (mod n)
|
||||
* where K = (2^l - 2^129 - 1)*(1 + lambda) (mod n)
|
||||
*
|
||||
* We will process the computation of C_l(v1, A) and C_l(v2, lambda*A) in groups of
|
||||
* ECMULT_CONST_GROUP_SIZE, so we set l to the smallest multiple of ECMULT_CONST_GROUP_SIZE
|
||||
* that is not less than 129; this equals ECMULT_CONST_BITS.
|
||||
*/
|
||||
|
||||
/* The offset to add to s1 and s2 to make them non-negative. Equal to 2^128. */
|
||||
static const secp256k1_scalar S_OFFSET = SECP256K1_SCALAR_CONST(0, 0, 0, 1, 0, 0, 0, 0);
|
||||
secp256k1_scalar s, v1, v2;
|
||||
secp256k1_ge pre_a[ECMULT_CONST_TABLE_SIZE];
|
||||
secp256k1_ge pre_a_lam[ECMULT_CONST_TABLE_SIZE];
|
||||
secp256k1_fe global_z;
|
||||
int group, i;
|
||||
|
||||
/* We're allowed to be non-constant time in the point, and the code below (in particular,
|
||||
* secp256k1_ecmult_const_odd_multiples_table_globalz) cannot deal with infinity in a
|
||||
* constant-time manner anyway. */
|
||||
if (secp256k1_ge_is_infinity(a)) {
|
||||
secp256k1_gej_set_infinity(r);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Compute v1 and v2. */
|
||||
secp256k1_scalar_add(&s, q, &secp256k1_ecmult_const_K);
|
||||
secp256k1_scalar_half(&s, &s);
|
||||
secp256k1_scalar_split_lambda(&v1, &v2, &s);
|
||||
secp256k1_scalar_add(&v1, &v1, &S_OFFSET);
|
||||
secp256k1_scalar_add(&v2, &v2, &S_OFFSET);
|
||||
|
||||
#ifdef VERIFY
|
||||
/* Verify that v1 and v2 are in range [0, 2^129-1]. */
|
||||
for (i = 129; i < 256; ++i) {
|
||||
VERIFY_CHECK(secp256k1_scalar_get_bits_limb32(&v1, i, 1) == 0);
|
||||
VERIFY_CHECK(secp256k1_scalar_get_bits_limb32(&v2, i, 1) == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Calculate odd multiples of A and A*lambda.
|
||||
* All multiples are brought to the same Z 'denominator', which is stored
|
||||
* in global_z. Due to secp256k1' isomorphism we can do all operations pretending
|
||||
* that the Z coordinate was 1, use affine addition formulae, and correct
|
||||
* the Z coordinate of the result once at the end.
|
||||
*/
|
||||
secp256k1_gej_set_ge(r, a);
|
||||
secp256k1_ecmult_const_odd_multiples_table_globalz(pre_a, &global_z, r);
|
||||
for (i = 0; i < ECMULT_CONST_TABLE_SIZE; i++) {
|
||||
secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]);
|
||||
}
|
||||
|
||||
/* Next, we compute r = C_l(v1, A) + C_l(v2, lambda*A).
|
||||
*
|
||||
* We proceed in groups of ECMULT_CONST_GROUP_SIZE bits, operating on that many bits
|
||||
* at a time, from high in v1, v2 to low. Call these bits1 (from v1) and bits2 (from v2).
|
||||
*
|
||||
* Now note that ECMULT_CONST_TABLE_GET_GE(&t, pre_a, bits1) loads into t a point equal
|
||||
* to C_{ECMULT_CONST_GROUP_SIZE}(bits1, A), and analogously for pre_lam_a / bits2.
|
||||
* This means that all we need to do is add these looked up values together, multiplied
|
||||
* by 2^(ECMULT_GROUP_SIZE * group).
|
||||
*/
|
||||
for (group = ECMULT_CONST_GROUPS - 1; group >= 0; --group) {
|
||||
/* Using the _var get_bits function is ok here, since it's only variable in offset and count, not in the scalar. */
|
||||
unsigned int bits1 = secp256k1_scalar_get_bits_var(&v1, group * ECMULT_CONST_GROUP_SIZE, ECMULT_CONST_GROUP_SIZE);
|
||||
unsigned int bits2 = secp256k1_scalar_get_bits_var(&v2, group * ECMULT_CONST_GROUP_SIZE, ECMULT_CONST_GROUP_SIZE);
|
||||
secp256k1_ge t;
|
||||
int j;
|
||||
|
||||
ECMULT_CONST_TABLE_GET_GE(&t, pre_a, bits1);
|
||||
if (group == ECMULT_CONST_GROUPS - 1) {
|
||||
/* Directly set r in the first iteration. */
|
||||
secp256k1_gej_set_ge(r, &t);
|
||||
} else {
|
||||
/* Shift the result so far up. */
|
||||
for (j = 0; j < ECMULT_CONST_GROUP_SIZE; ++j) {
|
||||
secp256k1_gej_double(r, r);
|
||||
}
|
||||
secp256k1_gej_add_ge(r, r, &t);
|
||||
}
|
||||
ECMULT_CONST_TABLE_GET_GE(&t, pre_a_lam, bits2);
|
||||
secp256k1_gej_add_ge(r, r, &t);
|
||||
}
|
||||
|
||||
/* Map the result back to the secp256k1 curve from the isomorphic curve. */
|
||||
secp256k1_fe_mul(&r->z, &r->z, &global_z);
|
||||
}
|
||||
|
||||
static int secp256k1_ecmult_const_xonly(secp256k1_fe* r, const secp256k1_fe *n, const secp256k1_fe *d, const secp256k1_scalar *q, int known_on_curve) {
|
||||
|
||||
/* This algorithm is a generalization of Peter Dettman's technique for
|
||||
* avoiding the square root in a random-basepoint x-only multiplication
|
||||
* on a Weierstrass curve:
|
||||
* https://mailarchive.ietf.org/arch/msg/cfrg/7DyYY6gg32wDgHAhgSb6XxMDlJA/
|
||||
*
|
||||
*
|
||||
* === Background: the effective affine technique ===
|
||||
*
|
||||
* Let phi_u be the isomorphism that maps (x, y) on secp256k1 curve y^2 = x^3 + 7 to
|
||||
* x' = u^2*x, y' = u^3*y on curve y'^2 = x'^3 + u^6*7. This new curve has the same order as
|
||||
* the original (it is isomorphic), but moreover, has the same addition/doubling formulas, as
|
||||
* the curve b=7 coefficient does not appear in those formulas (or at least does not appear in
|
||||
* the formulas implemented in this codebase, both affine and Jacobian). See also Example 9.5.2
|
||||
* in https://www.math.auckland.ac.nz/~sgal018/crypto-book/ch9.pdf.
|
||||
*
|
||||
* This means any linear combination of secp256k1 points can be computed by applying phi_u
|
||||
* (with non-zero u) on all input points (including the generator, if used), computing the
|
||||
* linear combination on the isomorphic curve (using the same group laws), and then applying
|
||||
* phi_u^{-1} to get back to secp256k1.
|
||||
*
|
||||
* Switching to Jacobian coordinates, note that phi_u applied to (X, Y, Z) is simply
|
||||
* (X, Y, Z/u). Thus, if we want to compute (X1, Y1, Z) + (X2, Y2, Z), with identical Z
|
||||
* coordinates, we can use phi_Z to transform it to (X1, Y1, 1) + (X2, Y2, 1) on an isomorphic
|
||||
* curve where the affine addition formula can be used instead.
|
||||
* If (X3, Y3, Z3) = (X1, Y1) + (X2, Y2) on that curve, then our answer on secp256k1 is
|
||||
* (X3, Y3, Z3*Z).
|
||||
*
|
||||
* This is the effective affine technique: if we have a linear combination of group elements
|
||||
* to compute, and all those group elements have the same Z coordinate, we can simply pretend
|
||||
* that all those Z coordinates are 1, perform the computation that way, and then multiply the
|
||||
* original Z coordinate back in.
|
||||
*
|
||||
* The technique works on any a=0 short Weierstrass curve. It is possible to generalize it to
|
||||
* other curves too, but there the isomorphic curves will have different 'a' coefficients,
|
||||
* which typically does affect the group laws.
|
||||
*
|
||||
*
|
||||
* === Avoiding the square root for x-only point multiplication ===
|
||||
*
|
||||
* In this function, we want to compute the X coordinate of q*(n/d, y), for
|
||||
* y = sqrt((n/d)^3 + 7). Its negation would also be a valid Y coordinate, but by convention
|
||||
* we pick whatever sqrt returns (which we assume to be a deterministic function).
|
||||
*
|
||||
* Let g = y^2*d^3 = n^3 + 7*d^3. This also means y = sqrt(g/d^3).
|
||||
* Further let v = sqrt(d*g), which must exist as d*g = y^2*d^4 = (y*d^2)^2.
|
||||
*
|
||||
* The input point (n/d, y) also has Jacobian coordinates:
|
||||
*
|
||||
* (n/d, y, 1)
|
||||
* = (n/d * v^2, y * v^3, v)
|
||||
* = (n/d * d*g, y * sqrt(d^3*g^3), v)
|
||||
* = (n/d * d*g, sqrt(y^2 * d^3*g^3), v)
|
||||
* = (n*g, sqrt(g/d^3 * d^3*g^3), v)
|
||||
* = (n*g, sqrt(g^4), v)
|
||||
* = (n*g, g^2, v)
|
||||
*
|
||||
* It is easy to verify that both (n*g, g^2, v) and its negation (n*g, -g^2, v) have affine X
|
||||
* coordinate n/d, and this holds even when the square root function doesn't have a
|
||||
* deterministic sign. We choose the (n*g, g^2, v) version.
|
||||
*
|
||||
* Now switch to the effective affine curve using phi_v, where the input point has coordinates
|
||||
* (n*g, g^2). Compute (X, Y, Z) = q * (n*g, g^2) there.
|
||||
*
|
||||
* Back on secp256k1, that means q * (n*g, g^2, v) = (X, Y, v*Z). This last point has affine X
|
||||
* coordinate X / (v^2*Z^2) = X / (d*g*Z^2). Determining the affine Y coordinate would involve
|
||||
* a square root, but as long as we only care about the resulting X coordinate, no square root
|
||||
* is needed anywhere in this computation.
|
||||
*/
|
||||
|
||||
secp256k1_fe g, i;
|
||||
secp256k1_ge p;
|
||||
secp256k1_gej rj;
|
||||
|
||||
/* Compute g = (n^3 + B*d^3). */
|
||||
secp256k1_fe_sqr(&g, n);
|
||||
secp256k1_fe_mul(&g, &g, n);
|
||||
if (d) {
|
||||
secp256k1_fe b;
|
||||
VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero(d));
|
||||
secp256k1_fe_sqr(&b, d);
|
||||
VERIFY_CHECK(SECP256K1_B <= 8); /* magnitude of b will be <= 8 after the next call */
|
||||
secp256k1_fe_mul_int(&b, SECP256K1_B);
|
||||
secp256k1_fe_mul(&b, &b, d);
|
||||
secp256k1_fe_add(&g, &b);
|
||||
if (!known_on_curve) {
|
||||
/* We need to determine whether (n/d)^3 + 7 is square.
|
||||
*
|
||||
* is_square((n/d)^3 + 7)
|
||||
* <=> is_square(((n/d)^3 + 7) * d^4)
|
||||
* <=> is_square((n^3 + 7*d^3) * d)
|
||||
* <=> is_square(g * d)
|
||||
*/
|
||||
secp256k1_fe c;
|
||||
secp256k1_fe_mul(&c, &g, d);
|
||||
if (!secp256k1_fe_is_square_var(&c)) return 0;
|
||||
}
|
||||
} else {
|
||||
secp256k1_fe_add_int(&g, SECP256K1_B);
|
||||
if (!known_on_curve) {
|
||||
/* g at this point equals x^3 + 7. Test if it is square. */
|
||||
if (!secp256k1_fe_is_square_var(&g)) return 0;
|
||||
}
|
||||
}
|
||||
|
||||
SECP256K1_FE_VERIFY_MAGNITUDE(&g, 2);
|
||||
|
||||
/* Compute base point P = (n*g, g^2), the effective affine version of
|
||||
* (n*g, g^2, v), which has corresponding affine X coordinate n/d. */
|
||||
{
|
||||
secp256k1_fe x, y;
|
||||
secp256k1_fe_mul(&x, &g, n);
|
||||
secp256k1_fe_sqr(&y, &g);
|
||||
secp256k1_ge_set_xy(&p, &x, &y);
|
||||
}
|
||||
|
||||
/* Perform x-only EC multiplication of P with q. */
|
||||
VERIFY_CHECK(!secp256k1_scalar_is_zero(q));
|
||||
secp256k1_ecmult_const(&rj, &p, q);
|
||||
VERIFY_CHECK(!secp256k1_gej_is_infinity(&rj));
|
||||
|
||||
/* The resulting (X, Y, Z) point on the effective-affine isomorphic curve corresponds to
|
||||
* (X, Y, Z*v) on the secp256k1 curve. The affine version of that has X coordinate
|
||||
* (X / (Z^2*d*g)). */
|
||||
secp256k1_fe_sqr(&i, &rj.z);
|
||||
secp256k1_fe_mul(&i, &i, &g);
|
||||
if (d) secp256k1_fe_mul(&i, &i, d);
|
||||
secp256k1_fe_inv(&i, &i);
|
||||
secp256k1_fe_mul(r, &rj.x, &i);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* SECP256K1_ECMULT_CONST_IMPL_H */
|
||||
144
firmware/kb2040_hidden_signer/src/secp256k1/src/ecmult_gen.h
Normal file
144
firmware/kb2040_hidden_signer/src/secp256k1/src/ecmult_gen.h
Normal file
@@ -0,0 +1,144 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) Pieter Wuille, Peter Dettman *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_ECMULT_GEN_H
|
||||
#define SECP256K1_ECMULT_GEN_H
|
||||
|
||||
#include "hash.h"
|
||||
#include "scalar.h"
|
||||
#include "group.h"
|
||||
|
||||
|
||||
/* Configuration parameters for the signed-digit multi-comb algorithm:
|
||||
*
|
||||
* - COMB_BLOCKS is the number of blocks the input is split into. Each
|
||||
* has a corresponding table.
|
||||
* - COMB_TEETH is the number of bits simultaneously covered by one table.
|
||||
* - COMB_RANGE is the number of bits in supported scalars. For production
|
||||
* purposes, only 256 is reasonable, but smaller numbers are supported for
|
||||
* exhaustive test mode.
|
||||
*
|
||||
* The comb's spacing (COMB_SPACING), or the distance between the teeth,
|
||||
* is defined as ceil(COMB_RANGE / (COMB_BLOCKS * COMB_TEETH)). Each block covers
|
||||
* COMB_SPACING * COMB_TEETH consecutive bits in the input.
|
||||
*
|
||||
* The size of the precomputed table is COMB_BLOCKS * (1 << (COMB_TEETH - 1))
|
||||
* secp256k1_ge_storages.
|
||||
*
|
||||
* The number of point additions equals COMB_BLOCKS * COMB_SPACING. Each point
|
||||
* addition involves a cmov from (1 << (COMB_TEETH - 1)) table entries and a
|
||||
* conditional negation.
|
||||
*
|
||||
* The number of point doublings is COMB_SPACING - 1. */
|
||||
|
||||
#if defined(EXHAUSTIVE_TEST_ORDER)
|
||||
/* We need to control these values for exhaustive tests because
|
||||
* the table cannot have infinities in them (secp256k1_ge_storage
|
||||
* doesn't support infinities) */
|
||||
# undef COMB_BLOCKS
|
||||
# undef COMB_TEETH
|
||||
# if EXHAUSTIVE_TEST_ORDER == 7
|
||||
# define COMB_RANGE 3
|
||||
# define COMB_BLOCKS 1
|
||||
# define COMB_TEETH 2
|
||||
# elif EXHAUSTIVE_TEST_ORDER == 13
|
||||
# define COMB_RANGE 4
|
||||
# define COMB_BLOCKS 1
|
||||
# define COMB_TEETH 2
|
||||
# elif EXHAUSTIVE_TEST_ORDER == 199
|
||||
# define COMB_RANGE 8
|
||||
# define COMB_BLOCKS 2
|
||||
# define COMB_TEETH 3
|
||||
# else
|
||||
# error "Unknown exhaustive test order"
|
||||
# endif
|
||||
# if (COMB_RANGE >= 32) || ((EXHAUSTIVE_TEST_ORDER >> (COMB_RANGE - 1)) != 1)
|
||||
# error "COMB_RANGE != ceil(log2(EXHAUSTIVE_TEST_ORDER+1))"
|
||||
# endif
|
||||
#else /* !defined(EXHAUSTIVE_TEST_ORDER) */
|
||||
# define COMB_RANGE 256
|
||||
#endif /* defined(EXHAUSTIVE_TEST_ORDER) */
|
||||
|
||||
/* Use (11, 6) as default configuration, which results in a 22 kB table. */
|
||||
#ifndef COMB_BLOCKS
|
||||
# define COMB_BLOCKS 11
|
||||
# ifdef DEBUG_CONFIG
|
||||
# pragma message DEBUG_CONFIG_MSG("COMB_BLOCKS undefined, assuming default value")
|
||||
# endif
|
||||
#endif
|
||||
#ifndef COMB_TEETH
|
||||
# define COMB_TEETH 6
|
||||
# ifdef DEBUG_CONFIG
|
||||
# pragma message DEBUG_CONFIG_MSG("COMB_TEETH undefined, assuming default value")
|
||||
# endif
|
||||
#endif
|
||||
/* Use ceil(COMB_RANGE / (COMB_BLOCKS * COMB_TEETH)) as COMB_SPACING. */
|
||||
#define COMB_SPACING CEIL_DIV(COMB_RANGE, COMB_BLOCKS * COMB_TEETH)
|
||||
|
||||
/* Range checks on the parameters. */
|
||||
|
||||
/* The remaining COMB_* parameters are derived values, don't modify these. */
|
||||
/* - The number of bits covered by all the blocks; must be at least COMB_RANGE. */
|
||||
#define COMB_BITS (COMB_BLOCKS * COMB_TEETH * COMB_SPACING)
|
||||
/* - The number of entries per table. */
|
||||
#define COMB_POINTS (1 << (COMB_TEETH - 1))
|
||||
|
||||
/* Sanity checks. */
|
||||
#if !(1 <= COMB_BLOCKS && COMB_BLOCKS <= 256)
|
||||
# error "COMB_BLOCKS must be in the range [1, 256]"
|
||||
#endif
|
||||
#if !(1 <= COMB_TEETH && COMB_TEETH <= 8)
|
||||
# error "COMB_TEETH must be in the range [1, 8]"
|
||||
#endif
|
||||
#if COMB_BITS < COMB_RANGE
|
||||
# error "COMB_BLOCKS * COMB_TEETH * COMB_SPACING is too low"
|
||||
#endif
|
||||
|
||||
/* These last 2 checks are not strictly required, but prevent gratuitously inefficient
|
||||
* configurations. Note that they compare with 256 rather than COMB_RANGE, so they do
|
||||
* permit somewhat excessive values for the exhaustive test case, where testing with
|
||||
* suboptimal parameters may be desirable. */
|
||||
#if (COMB_BLOCKS - 1) * COMB_TEETH * COMB_SPACING >= 256
|
||||
# error "COMB_BLOCKS can be reduced"
|
||||
#endif
|
||||
#if COMB_BLOCKS * (COMB_TEETH - 1) * COMB_SPACING >= 256
|
||||
# error "COMB_TEETH can be reduced"
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_CONFIG
|
||||
# pragma message DEBUG_CONFIG_DEF(COMB_RANGE)
|
||||
# pragma message DEBUG_CONFIG_DEF(COMB_BLOCKS)
|
||||
# pragma message DEBUG_CONFIG_DEF(COMB_TEETH)
|
||||
# pragma message DEBUG_CONFIG_DEF(COMB_SPACING)
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
/* Whether the context has been built. */
|
||||
int built;
|
||||
|
||||
/* Values chosen such that
|
||||
*
|
||||
* n*G == comb(n + scalar_offset, G/2) + ge_offset.
|
||||
*
|
||||
* This expression lets us use scalar blinding and optimize the comb precomputation. See
|
||||
* ecmult_gen_impl.h for more details. */
|
||||
secp256k1_scalar scalar_offset;
|
||||
secp256k1_ge ge_offset;
|
||||
|
||||
/* Factor used for projective blinding. This value is used to rescale the Z
|
||||
* coordinate of the first table lookup. */
|
||||
secp256k1_fe proj_blind;
|
||||
} secp256k1_ecmult_gen_context;
|
||||
|
||||
static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context* ctx, const secp256k1_hash_ctx *hash_ctx);
|
||||
static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context* ctx);
|
||||
|
||||
/** Multiply with the generator: R = a*G */
|
||||
static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context* ctx, secp256k1_gej *r, const secp256k1_scalar *a);
|
||||
|
||||
static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const secp256k1_hash_ctx *hash_ctx, const unsigned char *seed32);
|
||||
|
||||
#endif /* SECP256K1_ECMULT_GEN_H */
|
||||
@@ -0,0 +1,14 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) Pieter Wuille, Gregory Maxwell *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_ECMULT_GEN_COMPUTE_TABLE_H
|
||||
#define SECP256K1_ECMULT_GEN_COMPUTE_TABLE_H
|
||||
|
||||
#include "ecmult_gen.h"
|
||||
|
||||
static void secp256k1_ecmult_gen_compute_table(secp256k1_ge_storage* table, const secp256k1_ge* gen, int blocks, int teeth, int spacing);
|
||||
|
||||
#endif /* SECP256K1_ECMULT_GEN_COMPUTE_TABLE_H */
|
||||
@@ -0,0 +1,108 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) Pieter Wuille, Gregory Maxwell, Peter Dettman *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_ECMULT_GEN_COMPUTE_TABLE_IMPL_H
|
||||
#define SECP256K1_ECMULT_GEN_COMPUTE_TABLE_IMPL_H
|
||||
|
||||
#include "ecmult_gen_compute_table.h"
|
||||
#include "group_impl.h"
|
||||
#include "field_impl.h"
|
||||
#include "scalar_impl.h"
|
||||
#include "ecmult_gen.h"
|
||||
#include "util.h"
|
||||
|
||||
static void secp256k1_ecmult_gen_compute_table(secp256k1_ge_storage* table, const secp256k1_ge* gen, int blocks, int teeth, int spacing) {
|
||||
size_t points = ((size_t)1) << (teeth - 1);
|
||||
size_t points_total = points * blocks;
|
||||
secp256k1_ge* prec = checked_malloc(&default_error_callback, points_total * sizeof(*prec));
|
||||
secp256k1_gej* ds = checked_malloc(&default_error_callback, teeth * sizeof(*ds));
|
||||
secp256k1_gej* vs = checked_malloc(&default_error_callback, points_total * sizeof(*vs));
|
||||
secp256k1_gej u;
|
||||
size_t vs_pos = 0;
|
||||
secp256k1_scalar half;
|
||||
int block, i;
|
||||
|
||||
VERIFY_CHECK(points_total > 0);
|
||||
|
||||
/* u is the running power of two times gen we're working with, initially gen/2. */
|
||||
secp256k1_scalar_half(&half, &secp256k1_scalar_one);
|
||||
secp256k1_gej_set_infinity(&u);
|
||||
for (i = 255; i >= 0; --i) {
|
||||
/* Use a very simple multiplication ladder to avoid dependency on ecmult. */
|
||||
secp256k1_gej_double_var(&u, &u, NULL);
|
||||
if (secp256k1_scalar_get_bits_limb32(&half, i, 1)) {
|
||||
secp256k1_gej_add_ge_var(&u, &u, gen, NULL);
|
||||
}
|
||||
}
|
||||
#ifdef VERIFY
|
||||
{
|
||||
/* Verify that u*2 = gen. */
|
||||
secp256k1_gej double_u;
|
||||
secp256k1_gej_double_var(&double_u, &u, NULL);
|
||||
VERIFY_CHECK(secp256k1_gej_eq_ge_var(&double_u, gen));
|
||||
}
|
||||
#endif
|
||||
|
||||
for (block = 0; block < blocks; ++block) {
|
||||
int tooth;
|
||||
/* Here u = 2^(block*teeth*spacing) * gen/2. */
|
||||
secp256k1_gej sum;
|
||||
secp256k1_gej_set_infinity(&sum);
|
||||
for (tooth = 0; tooth < teeth; ++tooth) {
|
||||
/* Here u = 2^((block*teeth + tooth)*spacing) * gen/2. */
|
||||
/* Make sum = sum(2^((block*teeth + t)*spacing), t=0..tooth) * gen/2. */
|
||||
secp256k1_gej_add_var(&sum, &sum, &u, NULL);
|
||||
/* Make u = 2^((block*teeth + tooth)*spacing + 1) * gen/2. */
|
||||
secp256k1_gej_double_var(&u, &u, NULL);
|
||||
/* Make ds[tooth] = u = 2^((block*teeth + tooth)*spacing + 1) * gen/2. */
|
||||
ds[tooth] = u;
|
||||
/* Make u = 2^((block*teeth + tooth + 1)*spacing) * gen/2, unless at the end. */
|
||||
if (block + tooth != blocks + teeth - 2) {
|
||||
int bit_off;
|
||||
for (bit_off = 1; bit_off < spacing; ++bit_off) {
|
||||
secp256k1_gej_double_var(&u, &u, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Now u = 2^((block*teeth + teeth)*spacing) * gen/2
|
||||
* = 2^((block+1)*teeth*spacing) * gen/2 */
|
||||
|
||||
/* Next, compute the table entries for block number block in Jacobian coordinates.
|
||||
* The entries will occupy vs[block*points + i] for i=0..points-1.
|
||||
* We start by computing the first (i=0) value corresponding to all summed
|
||||
* powers of two times G being negative. */
|
||||
secp256k1_gej_neg(&vs[vs_pos++], &sum);
|
||||
/* And then teeth-1 times "double" the range of i values for which the table
|
||||
* is computed: in each iteration, double the table by taking an existing
|
||||
* table entry and adding ds[tooth]. */
|
||||
for (tooth = 0; tooth < teeth - 1; ++tooth) {
|
||||
size_t stride = ((size_t)1) << tooth;
|
||||
size_t index;
|
||||
for (index = 0; index < stride; ++index, ++vs_pos) {
|
||||
secp256k1_gej_add_var(&vs[vs_pos], &vs[vs_pos - stride], &ds[tooth], NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
VERIFY_CHECK(vs_pos == points_total);
|
||||
|
||||
/* Convert all points simultaneously from secp256k1_gej to secp256k1_ge. */
|
||||
secp256k1_ge_set_all_gej_var(prec, vs, points_total);
|
||||
/* Convert all points from secp256k1_ge to secp256k1_ge_storage output. */
|
||||
for (block = 0; block < blocks; ++block) {
|
||||
size_t index;
|
||||
for (index = 0; index < points; ++index) {
|
||||
VERIFY_CHECK(!secp256k1_ge_is_infinity(&prec[block * points + index]));
|
||||
secp256k1_ge_to_storage(&table[block * points + index], &prec[block * points + index]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Free memory. */
|
||||
free(vs);
|
||||
free(ds);
|
||||
free(prec);
|
||||
}
|
||||
|
||||
#endif /* SECP256K1_ECMULT_GEN_COMPUTE_TABLE_IMPL_H */
|
||||
@@ -0,0 +1,341 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) Pieter Wuille, Gregory Maxwell, Peter Dettman *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_ECMULT_GEN_IMPL_H
|
||||
#define SECP256K1_ECMULT_GEN_IMPL_H
|
||||
|
||||
#include "util.h"
|
||||
#include "scalar.h"
|
||||
#include "group.h"
|
||||
#include "ecmult_gen.h"
|
||||
#include "hash_impl.h"
|
||||
#include "precomputed_ecmult_gen.h"
|
||||
|
||||
static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx, const secp256k1_hash_ctx *hash_ctx) {
|
||||
secp256k1_ecmult_gen_blind(ctx, hash_ctx, NULL);
|
||||
ctx->built = 1;
|
||||
}
|
||||
|
||||
static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context* ctx) {
|
||||
return ctx->built;
|
||||
}
|
||||
|
||||
static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context *ctx) {
|
||||
ctx->built = 0;
|
||||
secp256k1_scalar_clear(&ctx->scalar_offset);
|
||||
secp256k1_ge_clear(&ctx->ge_offset);
|
||||
secp256k1_fe_clear(&ctx->proj_blind);
|
||||
}
|
||||
|
||||
/* Compute the scalar (2^COMB_BITS - 1) / 2, the difference between the gn argument to
|
||||
* secp256k1_ecmult_gen, and the scalar whose encoding the table lookup bits are drawn
|
||||
* from (before applying blinding). */
|
||||
static void secp256k1_ecmult_gen_scalar_diff(secp256k1_scalar* diff) {
|
||||
int i;
|
||||
|
||||
/* Compute scalar -1/2. */
|
||||
secp256k1_scalar neghalf;
|
||||
secp256k1_scalar_half(&neghalf, &secp256k1_scalar_one);
|
||||
secp256k1_scalar_negate(&neghalf, &neghalf);
|
||||
|
||||
/* Compute offset = 2^(COMB_BITS - 1). */
|
||||
*diff = secp256k1_scalar_one;
|
||||
for (i = 0; i < COMB_BITS - 1; ++i) {
|
||||
secp256k1_scalar_add(diff, diff, diff);
|
||||
}
|
||||
|
||||
/* The result is the sum 2^(COMB_BITS - 1) + (-1/2). */
|
||||
secp256k1_scalar_add(diff, diff, &neghalf);
|
||||
}
|
||||
|
||||
static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context *ctx, secp256k1_gej *r, const secp256k1_scalar *gn) {
|
||||
uint32_t comb_off;
|
||||
secp256k1_ge add;
|
||||
secp256k1_fe neg;
|
||||
secp256k1_ge_storage adds;
|
||||
secp256k1_scalar d;
|
||||
/* Array of uint32_t values large enough to store COMB_BITS bits. Only the bottom
|
||||
* 8 are ever nonzero, but having the zero padding at the end if COMB_BITS>256
|
||||
* avoids the need to deal with out-of-bounds reads from a scalar. */
|
||||
uint32_t recoded[(COMB_BITS + 31) >> 5] = {0};
|
||||
int first = 1, i;
|
||||
|
||||
memset(&adds, 0, sizeof(adds));
|
||||
|
||||
/* We want to compute R = gn*G.
|
||||
*
|
||||
* To blind the scalar used in the computation, we rewrite this to be
|
||||
* R = (gn - b)*G + b*G, with a blinding value b determined by the context.
|
||||
*
|
||||
* The multiplication (gn-b)*G will be performed using a signed-digit multi-comb (see Section
|
||||
* 3.3 of "Fast and compact elliptic-curve cryptography" by Mike Hamburg,
|
||||
* https://eprint.iacr.org/2012/309).
|
||||
*
|
||||
* Let comb(s, P) = sum((2*s[i]-1)*2^i*P for i=0..COMB_BITS-1), where s[i] is the i'th bit of
|
||||
* the binary representation of scalar s. So the s[i] values determine whether -2^i*P (s[i]=0)
|
||||
* or +2^i*P (s[i]=1) are added together. COMB_BITS is at least 256, so all bits of s are
|
||||
* covered. By manipulating:
|
||||
*
|
||||
* comb(s, P) = sum((2*s[i]-1)*2^i*P for i=0..COMB_BITS-1)
|
||||
* <=> comb(s, P) = sum((2*s[i]-1)*2^i for i=0..COMB_BITS-1) * P
|
||||
* <=> comb(s, P) = (2*sum(s[i]*2^i for i=0..COMB_BITS-1) - sum(2^i for i=0..COMB_BITS-1)) * P
|
||||
* <=> comb(s, P) = (2*s - (2^COMB_BITS - 1)) * P
|
||||
*
|
||||
* If we wanted to compute (gn-b)*G as comb(s, G), it would need to hold that
|
||||
*
|
||||
* (gn - b) * G = (2*s - (2^COMB_BITS - 1)) * G
|
||||
* <=> s = (gn - b + (2^COMB_BITS - 1))/2 (mod order)
|
||||
*
|
||||
* We use an alternative here that avoids the modular division by two: instead we compute
|
||||
* (gn-b)*G as comb(d, G/2). For that to hold it must be the case that
|
||||
*
|
||||
* (gn - b) * G = (2*d - (2^COMB_BITS - 1)) * (G/2)
|
||||
* <=> d = gn - b + (2^COMB_BITS - 1)/2 (mod order)
|
||||
*
|
||||
* Adding precomputation, our final equations become:
|
||||
*
|
||||
* ctx->scalar_offset = (2^COMB_BITS - 1)/2 - b (mod order)
|
||||
* ctx->ge_offset = b*G
|
||||
* d = gn + ctx->scalar_offset (mod order)
|
||||
* R = comb(d, G/2) + ctx->ge_offset
|
||||
*
|
||||
* comb(d, G/2) function is then computed by summing + or - 2^(i-1)*G, for i=0..COMB_BITS-1,
|
||||
* depending on the value of the bits d[i] of the binary representation of scalar d.
|
||||
*/
|
||||
|
||||
/* Compute the scalar d = (gn + ctx->scalar_offset). */
|
||||
secp256k1_scalar_add(&d, &ctx->scalar_offset, gn);
|
||||
/* Convert to recoded array. */
|
||||
for (i = 0; i < 8 && i < ((COMB_BITS + 31) >> 5); ++i) {
|
||||
recoded[i] = secp256k1_scalar_get_bits_limb32(&d, 32 * i, 32);
|
||||
}
|
||||
secp256k1_scalar_clear(&d);
|
||||
|
||||
/* In secp256k1_ecmult_gen_prec_table we have precomputed sums of the
|
||||
* (2*d[i]-1) * 2^(i-1) * G points, for various combinations of i positions.
|
||||
* We rewrite our equation in terms of these table entries.
|
||||
*
|
||||
* Let mask(b) = sum(2^((b*COMB_TEETH + t)*COMB_SPACING) for t=0..COMB_TEETH-1),
|
||||
* with b ranging from 0 to COMB_BLOCKS-1. So for example with COMB_BLOCKS=11,
|
||||
* COMB_TEETH=6, COMB_SPACING=4, we would have:
|
||||
* mask(0) = 2^0 + 2^4 + 2^8 + 2^12 + 2^16 + 2^20,
|
||||
* mask(1) = 2^24 + 2^28 + 2^32 + 2^36 + 2^40 + 2^44,
|
||||
* mask(2) = 2^48 + 2^52 + 2^56 + 2^60 + 2^64 + 2^68,
|
||||
* ...
|
||||
* mask(10) = 2^240 + 2^244 + 2^248 + 2^252 + 2^256 + 2^260
|
||||
*
|
||||
* We will split up the bits d[i] using these masks. Specifically, each mask is
|
||||
* used COMB_SPACING times, with different shifts:
|
||||
*
|
||||
* d = (d & mask(0)<<0) + (d & mask(1)<<0) + ... + (d & mask(COMB_BLOCKS-1)<<0) +
|
||||
* (d & mask(0)<<1) + (d & mask(1)<<1) + ... + (d & mask(COMB_BLOCKS-1)<<1) +
|
||||
* ...
|
||||
* (d & mask(0)<<(COMB_SPACING-1)) + ...
|
||||
*
|
||||
* Now define table(b, m) = (m - mask(b)/2) * G, and we will precompute these values for
|
||||
* b=0..COMB_BLOCKS-1, and for all values m which (d & mask(b)) can take (so m can take on
|
||||
* 2^COMB_TEETH distinct values).
|
||||
*
|
||||
* If m=(d & mask(b)), then table(b, m) is the sum of 2^i * (2*d[i]-1) * G/2, with i
|
||||
* iterating over the set bits in mask(b). In our example, table(2, 2^48 + 2^56 + 2^68)
|
||||
* would equal (2^48 - 2^52 + 2^56 - 2^60 - 2^64 + 2^68) * G/2.
|
||||
*
|
||||
* With that, we can rewrite comb(d, G/2) as:
|
||||
*
|
||||
* 2^0 * (table(0, d>>0 & mask(0)) + ... + table(COMB_BLOCKS-1, d>>0 & mask(COMP_BLOCKS-1)))
|
||||
* + 2^1 * (table(0, d>>1 & mask(0)) + ... + table(COMB_BLOCKS-1, d>>1 & mask(COMP_BLOCKS-1)))
|
||||
* + 2^2 * (table(0, d>>2 & mask(0)) + ... + table(COMB_BLOCKS-1, d>>2 & mask(COMP_BLOCKS-1)))
|
||||
* + ...
|
||||
* + 2^(COMB_SPACING-1) * (table(0, d>>(COMB_SPACING-1) & mask(0)) + ...)
|
||||
*
|
||||
* Or more generically as
|
||||
*
|
||||
* sum(2^i * sum(table(b, d>>i & mask(b)), b=0..COMB_BLOCKS-1), i=0..COMB_SPACING-1)
|
||||
*
|
||||
* This is implemented using an outer loop that runs in reverse order over the lines of this
|
||||
* equation, which in each iteration runs an inner loop that adds the terms of that line and
|
||||
* then doubles the result before proceeding to the next line.
|
||||
*
|
||||
* In pseudocode:
|
||||
* c = infinity
|
||||
* for comb_off in range(COMB_SPACING - 1, -1, -1):
|
||||
* for block in range(COMB_BLOCKS):
|
||||
* c += table(block, (d >> comb_off) & mask(block))
|
||||
* if comb_off > 0:
|
||||
* c = 2*c
|
||||
* return c
|
||||
*
|
||||
* This computes c = comb(d, G/2), and thus finally R = c + ctx->ge_offset. Note that it would
|
||||
* be possible to apply an initial offset instead of a final offset (moving ge_offset to take
|
||||
* the place of infinity above), but the chosen approach allows using (in a future improvement)
|
||||
* an incomplete addition formula for most of the multiplication.
|
||||
*
|
||||
* The last question is how to implement the table(b, m) function. For any value of b,
|
||||
* m=(d & mask(b)) can only take on at most 2^COMB_TEETH possible values (the last one may have
|
||||
* fewer as there mask(b) may exceed the curve order). So we could create COMB_BLOCK tables
|
||||
* which contain a value for each such m value.
|
||||
*
|
||||
* Now note that if m=(d & mask(b)), then flipping the relevant bits of m results in negating
|
||||
* the result of table(b, m). This is because table(b,m XOR mask(b)) = table(b, mask(b) - m) =
|
||||
* (mask(b) - m - mask(b)/2)*G = (-m + mask(b)/2)*G = -(m - mask(b)/2)*G = -table(b, m).
|
||||
* Because of this it suffices to only store the first half of the m values for every b. If an
|
||||
* entry from the second half is needed, we look up its bit-flipped version instead, and negate
|
||||
* it.
|
||||
*
|
||||
* secp256k1_ecmult_gen_prec_table[b][index] stores the table(b, m) entries. Index
|
||||
* is the relevant mask(b) bits of m packed together without gaps. */
|
||||
|
||||
/* Outer loop: iterate over comb_off from COMB_SPACING - 1 down to 0. */
|
||||
comb_off = COMB_SPACING - 1;
|
||||
while (1) {
|
||||
uint32_t block;
|
||||
uint32_t bit_pos = comb_off;
|
||||
/* Inner loop: for each block, add table entries to the result. */
|
||||
for (block = 0; block < COMB_BLOCKS; ++block) {
|
||||
/* Gather the mask(block)-selected bits of d into bits. They're packed:
|
||||
* bits[tooth] = d[(block*COMB_TEETH + tooth)*COMB_SPACING + comb_off]. */
|
||||
uint32_t bits = 0, sign, abs, index, tooth;
|
||||
/* Instead of reading individual bits here to construct the bits variable,
|
||||
* build up the result by xoring rotated reads together. In every iteration,
|
||||
* one additional bit is made correct, starting at the bottom. The bits
|
||||
* above that contain junk. This reduces leakage by avoiding computations
|
||||
* on variables that can have only a low number of possible values (e.g.,
|
||||
* just two values when reading a single bit into a variable.) See:
|
||||
* https://www.usenix.org/system/files/conference/usenixsecurity18/sec18-alam.pdf
|
||||
*/
|
||||
for (tooth = 0; tooth < COMB_TEETH; ++tooth) {
|
||||
/* Construct bitdata s.t. the bottom bit is the bit we'd like to read.
|
||||
*
|
||||
* We could just set bitdata = recoded[bit_pos >> 5] >> (bit_pos & 0x1f)
|
||||
* but this would simply discard the bits that fall off at the bottom,
|
||||
* and thus, for example, bitdata could still have only two values if we
|
||||
* happen to shift by exactly 31 positions. We use a rotation instead,
|
||||
* which ensures that bitdata doesn't lose entropy. This relies on the
|
||||
* rotation being atomic, i.e., the compiler emitting an actual rot
|
||||
* instruction. */
|
||||
uint32_t bitdata = secp256k1_rotr32(recoded[bit_pos >> 5], bit_pos & 0x1f);
|
||||
|
||||
/* Clear the bit at position tooth, but sssh, don't tell clang. */
|
||||
uint32_t volatile vmask = ~(1 << tooth);
|
||||
bits &= vmask;
|
||||
|
||||
/* Write the bit into position tooth (and junk into higher bits). */
|
||||
bits ^= bitdata << tooth;
|
||||
bit_pos += COMB_SPACING;
|
||||
}
|
||||
|
||||
/* If the top bit of bits is 1, flip them all (corresponding to looking up
|
||||
* the negated table value), and remember to negate the result in sign. */
|
||||
sign = (bits >> (COMB_TEETH - 1)) & 1;
|
||||
abs = (bits ^ -sign) & (COMB_POINTS - 1);
|
||||
VERIFY_CHECK(sign == 0 || sign == 1);
|
||||
VERIFY_CHECK(abs < COMB_POINTS);
|
||||
|
||||
/** This uses a conditional move to avoid any secret data in array indexes.
|
||||
* _Any_ use of secret indexes has been demonstrated to result in timing
|
||||
* sidechannels, even when the cache-line access patterns are uniform.
|
||||
* See also:
|
||||
* "A word of warning", CHES 2013 Rump Session, by Daniel J. Bernstein and Peter Schwabe
|
||||
* (https://cryptojedi.org/peter/data/chesrump-20130822.pdf) and
|
||||
* "Cache Attacks and Countermeasures: the Case of AES", RSA 2006,
|
||||
* by Dag Arne Osvik, Adi Shamir, and Eran Tromer
|
||||
* (https://eprint.iacr.org/2005/271.pdf)
|
||||
*/
|
||||
for (index = 0; index < COMB_POINTS; ++index) {
|
||||
secp256k1_ge_storage_cmov(&adds, &secp256k1_ecmult_gen_prec_table[block][index], index == abs);
|
||||
}
|
||||
|
||||
/* Set add=adds or add=-adds, in constant time, based on sign. */
|
||||
secp256k1_ge_from_storage(&add, &adds);
|
||||
secp256k1_fe_negate(&neg, &add.y, 1);
|
||||
secp256k1_fe_cmov(&add.y, &neg, sign);
|
||||
|
||||
/* Add the looked up and conditionally negated value to r. */
|
||||
if (EXPECT(first, 0)) {
|
||||
/* If this is the first table lookup, we can skip addition. */
|
||||
secp256k1_gej_set_ge(r, &add);
|
||||
/* Give the entry a random Z coordinate to blind intermediary results. */
|
||||
secp256k1_gej_rescale(r, &ctx->proj_blind);
|
||||
first = 0;
|
||||
} else {
|
||||
secp256k1_gej_add_ge(r, r, &add);
|
||||
}
|
||||
}
|
||||
|
||||
/* Double the result, except in the last iteration. */
|
||||
if (comb_off-- == 0) break;
|
||||
secp256k1_gej_double(r, r);
|
||||
}
|
||||
|
||||
/* Correct for the scalar_offset added at the start (ge_offset = b*G, while b was
|
||||
* subtracted from the input scalar gn). */
|
||||
secp256k1_gej_add_ge(r, r, &ctx->ge_offset);
|
||||
|
||||
/* Cleanup. */
|
||||
secp256k1_fe_clear(&neg);
|
||||
secp256k1_ge_clear(&add);
|
||||
secp256k1_memclear_explicit(&adds, sizeof(adds));
|
||||
secp256k1_memclear_explicit(&recoded, sizeof(recoded));
|
||||
}
|
||||
|
||||
/* Setup blinding values for secp256k1_ecmult_gen. */
|
||||
static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const secp256k1_hash_ctx *hash_ctx, const unsigned char *seed32) {
|
||||
secp256k1_scalar b;
|
||||
secp256k1_scalar diff;
|
||||
secp256k1_gej gb;
|
||||
secp256k1_fe f;
|
||||
unsigned char nonce32[32];
|
||||
secp256k1_rfc6979_hmac_sha256 rng;
|
||||
unsigned char keydata[64];
|
||||
|
||||
/* Compute the (2^COMB_BITS - 1)/2 term once. */
|
||||
secp256k1_ecmult_gen_scalar_diff(&diff);
|
||||
|
||||
if (seed32 == NULL) {
|
||||
/* When seed is NULL, reset the final point and blinding value. */
|
||||
secp256k1_ge_neg(&ctx->ge_offset, &secp256k1_ge_const_g);
|
||||
secp256k1_scalar_add(&ctx->scalar_offset, &secp256k1_scalar_one, &diff);
|
||||
ctx->proj_blind = secp256k1_fe_one;
|
||||
return;
|
||||
}
|
||||
/* The prior blinding value (if not reset) is chained forward by including it in the hash. */
|
||||
secp256k1_scalar_get_b32(keydata, &ctx->scalar_offset);
|
||||
/** Using a CSPRNG allows a failure free interface, avoids needing large amounts of random data,
|
||||
* and guards against weak or adversarial seeds. This is a simpler and safer interface than
|
||||
* asking the caller for blinding values directly and expecting them to retry on failure.
|
||||
*/
|
||||
VERIFY_CHECK(seed32 != NULL);
|
||||
memcpy(keydata + 32, seed32, 32);
|
||||
secp256k1_rfc6979_hmac_sha256_initialize(hash_ctx, &rng, keydata, 64);
|
||||
secp256k1_memclear_explicit(keydata, sizeof(keydata));
|
||||
|
||||
/* Compute projective blinding factor (cannot be 0). */
|
||||
secp256k1_rfc6979_hmac_sha256_generate(hash_ctx, &rng, nonce32, 32);
|
||||
secp256k1_fe_set_b32_mod(&f, nonce32);
|
||||
secp256k1_fe_cmov(&f, &secp256k1_fe_one, secp256k1_fe_normalizes_to_zero(&f));
|
||||
ctx->proj_blind = f;
|
||||
|
||||
/* For a random blinding value b, set scalar_offset=diff-b, ge_offset=bG */
|
||||
secp256k1_rfc6979_hmac_sha256_generate(hash_ctx, &rng, nonce32, 32);
|
||||
secp256k1_scalar_set_b32(&b, nonce32, NULL);
|
||||
/* The blinding value cannot be zero, as that would mean ge_offset = infinity,
|
||||
* which secp256k1_gej_add_ge cannot handle. */
|
||||
secp256k1_scalar_cmov(&b, &secp256k1_scalar_one, secp256k1_scalar_is_zero(&b));
|
||||
secp256k1_rfc6979_hmac_sha256_finalize(&rng);
|
||||
secp256k1_ecmult_gen(ctx, &gb, &b);
|
||||
secp256k1_scalar_negate(&b, &b);
|
||||
secp256k1_scalar_add(&ctx->scalar_offset, &b, &diff);
|
||||
secp256k1_ge_set_gej(&ctx->ge_offset, &gb);
|
||||
|
||||
/* Clean up. */
|
||||
secp256k1_memclear_explicit(nonce32, sizeof(nonce32));
|
||||
secp256k1_scalar_clear(&b);
|
||||
secp256k1_gej_clear(&gb);
|
||||
secp256k1_fe_clear(&f);
|
||||
secp256k1_rfc6979_hmac_sha256_clear(&rng);
|
||||
}
|
||||
|
||||
#endif /* SECP256K1_ECMULT_GEN_IMPL_H */
|
||||
869
firmware/kb2040_hidden_signer/src/secp256k1/src/ecmult_impl.h
Normal file
869
firmware/kb2040_hidden_signer/src/secp256k1/src/ecmult_impl.h
Normal file
@@ -0,0 +1,869 @@
|
||||
/******************************************************************************
|
||||
* Copyright (c) 2013, 2014, 2017 Pieter Wuille, Andrew Poelstra, Jonas Nick *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php. *
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef SECP256K1_ECMULT_IMPL_H
|
||||
#define SECP256K1_ECMULT_IMPL_H
|
||||
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "group.h"
|
||||
#include "scalar.h"
|
||||
#include "ecmult.h"
|
||||
#include "precomputed_ecmult.h"
|
||||
|
||||
#if defined(EXHAUSTIVE_TEST_ORDER)
|
||||
/* We need to lower these values for exhaustive tests because
|
||||
* the tables cannot have infinities in them (this breaks the
|
||||
* affine-isomorphism stuff which tracks z-ratios) */
|
||||
# if EXHAUSTIVE_TEST_ORDER > 128
|
||||
# define WINDOW_A 5
|
||||
# elif EXHAUSTIVE_TEST_ORDER > 8
|
||||
# define WINDOW_A 4
|
||||
# else
|
||||
# define WINDOW_A 2
|
||||
# endif
|
||||
#else
|
||||
/* optimal for 128-bit and 256-bit exponents. */
|
||||
# define WINDOW_A 5
|
||||
/** Larger values for ECMULT_WINDOW_SIZE result in possibly better
|
||||
* performance at the cost of an exponentially larger precomputed
|
||||
* table. The exact table size is
|
||||
* (1 << (WINDOW_G - 2)) * sizeof(secp256k1_ge_storage) bytes,
|
||||
* where sizeof(secp256k1_ge_storage) is typically 64 bytes but can
|
||||
* be larger due to platform-specific padding and alignment.
|
||||
* Two tables of this size are used (due to the endomorphism
|
||||
* optimization).
|
||||
*/
|
||||
#endif
|
||||
|
||||
#define WNAF_BITS 128
|
||||
#define WNAF_SIZE_BITS(bits, w) CEIL_DIV(bits, w)
|
||||
#define WNAF_SIZE(w) WNAF_SIZE_BITS(WNAF_BITS, w)
|
||||
|
||||
/* The number of objects allocated on the scratch space for ecmult_multi algorithms */
|
||||
#define PIPPENGER_SCRATCH_OBJECTS 6
|
||||
#define STRAUSS_SCRATCH_OBJECTS 5
|
||||
|
||||
#define PIPPENGER_MAX_BUCKET_WINDOW 12
|
||||
|
||||
/* Minimum number of points for which pippenger_wnaf is faster than strauss wnaf */
|
||||
#define ECMULT_PIPPENGER_THRESHOLD 88
|
||||
|
||||
#define ECMULT_MAX_POINTS_PER_BATCH 5000000
|
||||
|
||||
/** Fill a table 'pre_a' with precomputed odd multiples of a.
|
||||
* pre_a will contain [1*a,3*a,...,(2*n-1)*a], so it needs space for n group elements.
|
||||
* zr needs space for n field elements.
|
||||
*
|
||||
* Although pre_a is an array of _ge rather than _gej, it actually represents elements
|
||||
* in Jacobian coordinates with their z coordinates omitted. The omitted z-coordinates
|
||||
* can be recovered using z and zr. Using the notation z(b) to represent the omitted
|
||||
* z coordinate of b:
|
||||
* - z(pre_a[n-1]) = 'z'
|
||||
* - z(pre_a[i-1]) = z(pre_a[i]) / zr[i] for n > i > 0
|
||||
*
|
||||
* Lastly the zr[0] value, which isn't used above, is set so that:
|
||||
* - a.z = z(pre_a[0]) / zr[0]
|
||||
*/
|
||||
static void secp256k1_ecmult_odd_multiples_table(size_t n, secp256k1_ge *pre_a, secp256k1_fe *zr, secp256k1_fe *z, const secp256k1_gej *a) {
|
||||
secp256k1_gej d, ai;
|
||||
secp256k1_ge d_ge;
|
||||
size_t i;
|
||||
|
||||
VERIFY_CHECK(!secp256k1_gej_is_infinity(a));
|
||||
|
||||
secp256k1_gej_double_var(&d, a, NULL);
|
||||
|
||||
/*
|
||||
* Perform the additions using an isomorphic curve Y^2 = X^3 + 7*C^6 where C := d.z.
|
||||
* The isomorphism, phi, maps a secp256k1 point (x, y) to the point (x*C^2, y*C^3) on the other curve.
|
||||
* In Jacobian coordinates phi maps (x, y, z) to (x*C^2, y*C^3, z) or, equivalently to (x, y, z/C).
|
||||
*
|
||||
* phi(x, y, z) = (x*C^2, y*C^3, z) = (x, y, z/C)
|
||||
* d_ge := phi(d) = (d.x, d.y, 1)
|
||||
* ai := phi(a) = (a.x*C^2, a.y*C^3, a.z)
|
||||
*
|
||||
* The group addition functions work correctly on these isomorphic curves.
|
||||
* In particular phi(d) is easy to represent in affine coordinates under this isomorphism.
|
||||
* This lets us use the faster secp256k1_gej_add_ge_var group addition function that we wouldn't be able to use otherwise.
|
||||
*/
|
||||
secp256k1_ge_set_xy(&d_ge, &d.x, &d.y);
|
||||
secp256k1_ge_set_gej_zinv(&pre_a[0], a, &d.z);
|
||||
secp256k1_gej_set_ge(&ai, &pre_a[0]);
|
||||
ai.z = a->z;
|
||||
|
||||
/* pre_a[0] is the point (a.x*C^2, a.y*C^3, a.z*C) which is equivalent to a.
|
||||
* Set zr[0] to C, which is the ratio between the omitted z(pre_a[0]) value and a.z.
|
||||
*/
|
||||
zr[0] = d.z;
|
||||
|
||||
for (i = 1; i < n; i++) {
|
||||
secp256k1_gej_add_ge_var(&ai, &ai, &d_ge, &zr[i]);
|
||||
secp256k1_ge_set_xy(&pre_a[i], &ai.x, &ai.y);
|
||||
}
|
||||
|
||||
/* Multiply the last z-coordinate by C to undo the isomorphism.
|
||||
* Since the z-coordinates of the pre_a values are implied by the zr array of z-coordinate ratios,
|
||||
* undoing the isomorphism here undoes the isomorphism for all pre_a values.
|
||||
*/
|
||||
secp256k1_fe_mul(z, &ai.z, &d.z);
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_ecmult_table_verify(int n, int w) {
|
||||
(void)n;
|
||||
(void)w;
|
||||
VERIFY_CHECK(((n) & 1) == 1);
|
||||
VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1));
|
||||
VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1));
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_ecmult_table_get_ge(secp256k1_ge *r, const secp256k1_ge *pre, int n, int w) {
|
||||
secp256k1_ecmult_table_verify(n,w);
|
||||
if (n > 0) {
|
||||
*r = pre[(n-1)/2];
|
||||
} else {
|
||||
*r = pre[(-n-1)/2];
|
||||
secp256k1_fe_negate(&(r->y), &(r->y), 1);
|
||||
}
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_ecmult_table_get_ge_lambda(secp256k1_ge *r, const secp256k1_ge *pre, const secp256k1_fe *x, int n, int w) {
|
||||
secp256k1_ecmult_table_verify(n,w);
|
||||
if (n > 0) {
|
||||
secp256k1_ge_set_xy(r, &x[(n-1)/2], &pre[(n-1)/2].y);
|
||||
} else {
|
||||
secp256k1_ge_set_xy(r, &x[(-n-1)/2], &pre[(-n-1)/2].y);
|
||||
secp256k1_fe_negate(&(r->y), &(r->y), 1);
|
||||
}
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_ecmult_table_get_ge_storage(secp256k1_ge *r, const secp256k1_ge_storage *pre, int n, int w) {
|
||||
secp256k1_ecmult_table_verify(n,w);
|
||||
if (n > 0) {
|
||||
secp256k1_ge_from_storage(r, &pre[(n-1)/2]);
|
||||
} else {
|
||||
secp256k1_ge_from_storage(r, &pre[(-n-1)/2]);
|
||||
secp256k1_fe_negate(&(r->y), &(r->y), 1);
|
||||
}
|
||||
}
|
||||
|
||||
/** Convert a number to WNAF notation. The number becomes represented by sum(2^i * wnaf[i], i=0..bits),
|
||||
* with the following guarantees:
|
||||
* - each wnaf[i] is either 0, or an odd integer between -(1<<(w-1) - 1) and (1<<(w-1) - 1)
|
||||
* - two non-zero entries in wnaf are separated by at least w-1 zeroes.
|
||||
* - the number of set values in wnaf is returned. This number is at most 256, and at most one more
|
||||
* than the number of bits in the (absolute value) of the input.
|
||||
*/
|
||||
static int secp256k1_ecmult_wnaf(int *wnaf, int len, const secp256k1_scalar *a, int w) {
|
||||
secp256k1_scalar s;
|
||||
int last_set_bit = -1;
|
||||
int bit = 0;
|
||||
int sign = 1;
|
||||
int carry = 0;
|
||||
|
||||
VERIFY_CHECK(wnaf != NULL);
|
||||
VERIFY_CHECK(0 <= len && len <= 256);
|
||||
VERIFY_CHECK(a != NULL);
|
||||
VERIFY_CHECK(2 <= w && w <= 31);
|
||||
|
||||
for (bit = 0; bit < len; bit++) {
|
||||
wnaf[bit] = 0;
|
||||
}
|
||||
|
||||
s = *a;
|
||||
if (secp256k1_scalar_get_bits_limb32(&s, 255, 1)) {
|
||||
secp256k1_scalar_negate(&s, &s);
|
||||
sign = -1;
|
||||
}
|
||||
|
||||
bit = 0;
|
||||
while (bit < len) {
|
||||
int now;
|
||||
int word;
|
||||
if (secp256k1_scalar_get_bits_limb32(&s, bit, 1) == (unsigned int)carry) {
|
||||
bit++;
|
||||
continue;
|
||||
}
|
||||
|
||||
now = w;
|
||||
if (now > len - bit) {
|
||||
now = len - bit;
|
||||
}
|
||||
|
||||
word = secp256k1_scalar_get_bits_var(&s, bit, now) + carry;
|
||||
|
||||
carry = (word >> (w-1)) & 1;
|
||||
word -= carry << w;
|
||||
|
||||
wnaf[bit] = sign * word;
|
||||
last_set_bit = bit;
|
||||
|
||||
bit += now;
|
||||
}
|
||||
#ifdef VERIFY
|
||||
{
|
||||
int verify_bit = bit;
|
||||
|
||||
VERIFY_CHECK(carry == 0);
|
||||
|
||||
while (verify_bit < 256) {
|
||||
VERIFY_CHECK(secp256k1_scalar_get_bits_limb32(&s, verify_bit, 1) == 0);
|
||||
verify_bit++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return last_set_bit + 1;
|
||||
}
|
||||
|
||||
/* Same as secp256k1_ecmult_wnaf, but stores to int8_t array. Requires w <= 8. */
|
||||
static int secp256k1_ecmult_wnaf_small(int8_t *wnaf, int len, const secp256k1_scalar *a, int w) {
|
||||
int wnaf_tmp[256];
|
||||
int ret, i;
|
||||
|
||||
VERIFY_CHECK(2 <= w && w <= 8);
|
||||
ret = secp256k1_ecmult_wnaf(wnaf_tmp, len, a, w);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
wnaf[i] = (int8_t)wnaf_tmp[i];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct secp256k1_strauss_point_state {
|
||||
int8_t wnaf_na_1[129];
|
||||
int8_t wnaf_na_lam[129];
|
||||
int bits_na_1;
|
||||
int bits_na_lam;
|
||||
};
|
||||
|
||||
struct secp256k1_strauss_state {
|
||||
/* aux is used to hold z-ratios, and then used to hold pre_a[i].x * BETA values. */
|
||||
secp256k1_fe* aux;
|
||||
secp256k1_ge* pre_a;
|
||||
struct secp256k1_strauss_point_state* ps;
|
||||
};
|
||||
|
||||
static void secp256k1_ecmult_strauss_wnaf(const struct secp256k1_strauss_state *state, secp256k1_gej *r, size_t num, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng) {
|
||||
secp256k1_ge tmpa;
|
||||
secp256k1_fe Z;
|
||||
/* Split G factors. */
|
||||
secp256k1_scalar ng_1, ng_128;
|
||||
int wnaf_ng_1[129];
|
||||
int bits_ng_1 = 0;
|
||||
int wnaf_ng_128[129];
|
||||
int bits_ng_128 = 0;
|
||||
int i;
|
||||
int bits = 0;
|
||||
size_t np;
|
||||
size_t no = 0;
|
||||
|
||||
secp256k1_fe_set_int(&Z, 1);
|
||||
for (np = 0; np < num; ++np) {
|
||||
secp256k1_gej tmp;
|
||||
secp256k1_scalar na_1, na_lam;
|
||||
if (secp256k1_scalar_is_zero(&na[np]) || secp256k1_gej_is_infinity(&a[np])) {
|
||||
continue;
|
||||
}
|
||||
/* split na into na_1 and na_lam (where na = na_1 + na_lam*lambda, and na_1 and na_lam are ~128 bit) */
|
||||
secp256k1_scalar_split_lambda(&na_1, &na_lam, &na[np]);
|
||||
|
||||
/* build wnaf representation for na_1 and na_lam. */
|
||||
state->ps[no].bits_na_1 = secp256k1_ecmult_wnaf_small(state->ps[no].wnaf_na_1, 129, &na_1, WINDOW_A);
|
||||
state->ps[no].bits_na_lam = secp256k1_ecmult_wnaf_small(state->ps[no].wnaf_na_lam, 129, &na_lam, WINDOW_A);
|
||||
VERIFY_CHECK(state->ps[no].bits_na_1 <= 129);
|
||||
VERIFY_CHECK(state->ps[no].bits_na_lam <= 129);
|
||||
if (state->ps[no].bits_na_1 > bits) {
|
||||
bits = state->ps[no].bits_na_1;
|
||||
}
|
||||
if (state->ps[no].bits_na_lam > bits) {
|
||||
bits = state->ps[no].bits_na_lam;
|
||||
}
|
||||
|
||||
/* Calculate odd multiples of a.
|
||||
* All multiples are brought to the same Z 'denominator', which is stored
|
||||
* in Z. Due to secp256k1' isomorphism we can do all operations pretending
|
||||
* that the Z coordinate was 1, use affine addition formulae, and correct
|
||||
* the Z coordinate of the result once at the end.
|
||||
* The exception is the precomputed G table points, which are actually
|
||||
* affine. Compared to the base used for other points, they have a Z ratio
|
||||
* of 1/Z, so we can use secp256k1_gej_add_zinv_var, which uses the same
|
||||
* isomorphism to efficiently add with a known Z inverse.
|
||||
*/
|
||||
tmp = a[np];
|
||||
if (no) {
|
||||
secp256k1_gej_rescale(&tmp, &Z);
|
||||
}
|
||||
secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), state->pre_a + no * ECMULT_TABLE_SIZE(WINDOW_A), state->aux + no * ECMULT_TABLE_SIZE(WINDOW_A), &Z, &tmp);
|
||||
if (no) secp256k1_fe_mul(state->aux + no * ECMULT_TABLE_SIZE(WINDOW_A), state->aux + no * ECMULT_TABLE_SIZE(WINDOW_A), &(a[np].z));
|
||||
|
||||
++no;
|
||||
}
|
||||
|
||||
/* Bring them to the same Z denominator. */
|
||||
if (no) {
|
||||
secp256k1_ge_table_set_globalz(ECMULT_TABLE_SIZE(WINDOW_A) * no, state->pre_a, state->aux);
|
||||
}
|
||||
|
||||
for (np = 0; np < no; ++np) {
|
||||
size_t j;
|
||||
for (j = 0; j < ECMULT_TABLE_SIZE(WINDOW_A); j++) {
|
||||
secp256k1_fe_mul(&state->aux[np * ECMULT_TABLE_SIZE(WINDOW_A) + j], &state->pre_a[np * ECMULT_TABLE_SIZE(WINDOW_A) + j].x, &secp256k1_const_beta);
|
||||
}
|
||||
}
|
||||
|
||||
if (ng) {
|
||||
/* split ng into ng_1 and ng_128 (where gn = gn_1 + gn_128*2^128, and gn_1 and gn_128 are ~128 bit) */
|
||||
secp256k1_scalar_split_128(&ng_1, &ng_128, ng);
|
||||
|
||||
/* Build wnaf representation for ng_1 and ng_128 */
|
||||
bits_ng_1 = secp256k1_ecmult_wnaf(wnaf_ng_1, 129, &ng_1, WINDOW_G);
|
||||
bits_ng_128 = secp256k1_ecmult_wnaf(wnaf_ng_128, 129, &ng_128, WINDOW_G);
|
||||
if (bits_ng_1 > bits) {
|
||||
bits = bits_ng_1;
|
||||
}
|
||||
if (bits_ng_128 > bits) {
|
||||
bits = bits_ng_128;
|
||||
}
|
||||
}
|
||||
|
||||
secp256k1_gej_set_infinity(r);
|
||||
|
||||
for (i = bits - 1; i >= 0; i--) {
|
||||
int n;
|
||||
secp256k1_gej_double_var(r, r, NULL);
|
||||
for (np = 0; np < no; ++np) {
|
||||
if (i < state->ps[np].bits_na_1 && (n = state->ps[np].wnaf_na_1[i])) {
|
||||
secp256k1_ecmult_table_get_ge(&tmpa, state->pre_a + np * ECMULT_TABLE_SIZE(WINDOW_A), n, WINDOW_A);
|
||||
secp256k1_gej_add_ge_var(r, r, &tmpa, NULL);
|
||||
}
|
||||
if (i < state->ps[np].bits_na_lam && (n = state->ps[np].wnaf_na_lam[i])) {
|
||||
secp256k1_ecmult_table_get_ge_lambda(&tmpa, state->pre_a + np * ECMULT_TABLE_SIZE(WINDOW_A), state->aux + np * ECMULT_TABLE_SIZE(WINDOW_A), n, WINDOW_A);
|
||||
secp256k1_gej_add_ge_var(r, r, &tmpa, NULL);
|
||||
}
|
||||
}
|
||||
if (i < bits_ng_1 && (n = wnaf_ng_1[i])) {
|
||||
secp256k1_ecmult_table_get_ge_storage(&tmpa, secp256k1_pre_g, n, WINDOW_G);
|
||||
secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z);
|
||||
}
|
||||
if (i < bits_ng_128 && (n = wnaf_ng_128[i])) {
|
||||
secp256k1_ecmult_table_get_ge_storage(&tmpa, secp256k1_pre_g_128, n, WINDOW_G);
|
||||
secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z);
|
||||
}
|
||||
}
|
||||
|
||||
if (!secp256k1_gej_is_infinity(r)) {
|
||||
secp256k1_fe_mul(&r->z, &r->z, &Z);
|
||||
}
|
||||
}
|
||||
|
||||
static void secp256k1_ecmult(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng) {
|
||||
secp256k1_fe aux[ECMULT_TABLE_SIZE(WINDOW_A)];
|
||||
secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)];
|
||||
struct secp256k1_strauss_point_state ps[1];
|
||||
struct secp256k1_strauss_state state;
|
||||
|
||||
state.aux = aux;
|
||||
state.pre_a = pre_a;
|
||||
state.ps = ps;
|
||||
secp256k1_ecmult_strauss_wnaf(&state, r, 1, a, na, ng);
|
||||
}
|
||||
|
||||
static size_t secp256k1_strauss_scratch_size(size_t n_points) {
|
||||
static const size_t point_size = (sizeof(secp256k1_ge) + sizeof(secp256k1_fe)) * ECMULT_TABLE_SIZE(WINDOW_A) + sizeof(struct secp256k1_strauss_point_state) + sizeof(secp256k1_gej) + sizeof(secp256k1_scalar);
|
||||
return n_points*point_size;
|
||||
}
|
||||
|
||||
static int secp256k1_ecmult_strauss_batch(const secp256k1_callback* error_callback, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n_points, size_t cb_offset) {
|
||||
secp256k1_gej* points;
|
||||
secp256k1_scalar* scalars;
|
||||
struct secp256k1_strauss_state state;
|
||||
size_t i;
|
||||
const size_t scratch_checkpoint = secp256k1_scratch_checkpoint(error_callback, scratch);
|
||||
|
||||
secp256k1_gej_set_infinity(r);
|
||||
if (inp_g_sc == NULL && n_points == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* We allocate STRAUSS_SCRATCH_OBJECTS objects on the scratch space. If these
|
||||
* allocations change, make sure to update the STRAUSS_SCRATCH_OBJECTS
|
||||
* constant and strauss_scratch_size accordingly. */
|
||||
points = (secp256k1_gej*)secp256k1_scratch_alloc(error_callback, scratch, n_points * sizeof(secp256k1_gej));
|
||||
scalars = (secp256k1_scalar*)secp256k1_scratch_alloc(error_callback, scratch, n_points * sizeof(secp256k1_scalar));
|
||||
state.aux = (secp256k1_fe*)secp256k1_scratch_alloc(error_callback, scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_fe));
|
||||
state.pre_a = (secp256k1_ge*)secp256k1_scratch_alloc(error_callback, scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_ge));
|
||||
state.ps = (struct secp256k1_strauss_point_state*)secp256k1_scratch_alloc(error_callback, scratch, n_points * sizeof(struct secp256k1_strauss_point_state));
|
||||
|
||||
if (points == NULL || scalars == NULL || state.aux == NULL || state.pre_a == NULL || state.ps == NULL) {
|
||||
secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < n_points; i++) {
|
||||
secp256k1_ge point;
|
||||
if (!cb(&scalars[i], &point, i+cb_offset, cbdata)) {
|
||||
secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint);
|
||||
return 0;
|
||||
}
|
||||
secp256k1_gej_set_ge(&points[i], &point);
|
||||
}
|
||||
secp256k1_ecmult_strauss_wnaf(&state, r, n_points, points, scalars, inp_g_sc);
|
||||
secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Wrapper for secp256k1_ecmult_multi_func interface */
|
||||
static int secp256k1_ecmult_strauss_batch_single(const secp256k1_callback* error_callback, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n) {
|
||||
return secp256k1_ecmult_strauss_batch(error_callback, scratch, r, inp_g_sc, cb, cbdata, n, 0);
|
||||
}
|
||||
|
||||
static size_t secp256k1_strauss_max_points(const secp256k1_callback* error_callback, secp256k1_scratch *scratch) {
|
||||
return secp256k1_scratch_max_allocation(error_callback, scratch, STRAUSS_SCRATCH_OBJECTS) / secp256k1_strauss_scratch_size(1);
|
||||
}
|
||||
|
||||
/** Convert a number to WNAF notation.
|
||||
* The number becomes represented by sum(2^{wi} * wnaf[i], i=0..WNAF_SIZE(w)+1) - return_val.
|
||||
* It has the following guarantees:
|
||||
* - each wnaf[i] is either 0 or an odd integer between -(1 << w) and (1 << w)
|
||||
* - the number of words set is always WNAF_SIZE(w)
|
||||
* - the returned skew is 0 or 1
|
||||
*/
|
||||
static int secp256k1_wnaf_fixed(int *wnaf, const secp256k1_scalar *s, int w) {
|
||||
int skew = 0;
|
||||
int pos;
|
||||
int max_pos;
|
||||
int last_w;
|
||||
const secp256k1_scalar *work = s;
|
||||
|
||||
if (secp256k1_scalar_is_zero(s)) {
|
||||
for (pos = 0; pos < WNAF_SIZE(w); pos++) {
|
||||
wnaf[pos] = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (secp256k1_scalar_is_even(s)) {
|
||||
skew = 1;
|
||||
}
|
||||
|
||||
wnaf[0] = secp256k1_scalar_get_bits_var(work, 0, w) + skew;
|
||||
/* Compute last window size. Relevant when window size doesn't divide the
|
||||
* number of bits in the scalar */
|
||||
last_w = WNAF_BITS - (WNAF_SIZE(w) - 1) * w;
|
||||
|
||||
/* Store the position of the first nonzero word in max_pos to allow
|
||||
* skipping leading zeros when calculating the wnaf. */
|
||||
for (pos = WNAF_SIZE(w) - 1; pos > 0; pos--) {
|
||||
int val = secp256k1_scalar_get_bits_var(work, pos * w, pos == WNAF_SIZE(w)-1 ? last_w : w);
|
||||
if(val != 0) {
|
||||
break;
|
||||
}
|
||||
wnaf[pos] = 0;
|
||||
}
|
||||
max_pos = pos;
|
||||
pos = 1;
|
||||
|
||||
while (pos <= max_pos) {
|
||||
int val = secp256k1_scalar_get_bits_var(work, pos * w, pos == WNAF_SIZE(w)-1 ? last_w : w);
|
||||
if ((val & 1) == 0) {
|
||||
wnaf[pos - 1] -= (1 << w);
|
||||
wnaf[pos] = (val + 1);
|
||||
} else {
|
||||
wnaf[pos] = val;
|
||||
}
|
||||
/* Set a coefficient to zero if it is 1 or -1 and the proceeding digit
|
||||
* is strictly negative or strictly positive respectively. Only change
|
||||
* coefficients at previous positions because above code assumes that
|
||||
* wnaf[pos - 1] is odd.
|
||||
*/
|
||||
if (pos >= 2 && ((wnaf[pos - 1] == 1 && wnaf[pos - 2] < 0) || (wnaf[pos - 1] == -1 && wnaf[pos - 2] > 0))) {
|
||||
if (wnaf[pos - 1] == 1) {
|
||||
wnaf[pos - 2] += 1 << w;
|
||||
} else {
|
||||
wnaf[pos - 2] -= 1 << w;
|
||||
}
|
||||
wnaf[pos - 1] = 0;
|
||||
}
|
||||
++pos;
|
||||
}
|
||||
|
||||
return skew;
|
||||
}
|
||||
|
||||
struct secp256k1_pippenger_point_state {
|
||||
int skew_na;
|
||||
size_t input_pos;
|
||||
};
|
||||
|
||||
struct secp256k1_pippenger_state {
|
||||
int *wnaf_na;
|
||||
struct secp256k1_pippenger_point_state* ps;
|
||||
};
|
||||
|
||||
/*
|
||||
* pippenger_wnaf computes the result of a multi-point multiplication as
|
||||
* follows: The scalars are brought into wnaf with n_wnaf elements each. Then
|
||||
* for every i < n_wnaf, first each point is added to a "bucket" corresponding
|
||||
* to the point's wnaf[i]. Second, the buckets are added together such that
|
||||
* r += 1*bucket[0] + 3*bucket[1] + 5*bucket[2] + ...
|
||||
*/
|
||||
static int secp256k1_ecmult_pippenger_wnaf(secp256k1_gej *buckets, int bucket_window, struct secp256k1_pippenger_state *state, secp256k1_gej *r, const secp256k1_scalar *sc, const secp256k1_ge *pt, size_t num) {
|
||||
size_t n_wnaf = WNAF_SIZE(bucket_window+1);
|
||||
size_t np;
|
||||
size_t no = 0;
|
||||
int i;
|
||||
|
||||
for (np = 0; np < num; ++np) {
|
||||
if (secp256k1_scalar_is_zero(&sc[np]) || secp256k1_ge_is_infinity(&pt[np])) {
|
||||
continue;
|
||||
}
|
||||
state->ps[no].input_pos = np;
|
||||
state->ps[no].skew_na = secp256k1_wnaf_fixed(&state->wnaf_na[no*n_wnaf], &sc[np], bucket_window+1);
|
||||
no++;
|
||||
}
|
||||
secp256k1_gej_set_infinity(r);
|
||||
|
||||
if (no == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = n_wnaf - 1; i >= 0; i--) {
|
||||
secp256k1_gej running_sum;
|
||||
int j;
|
||||
size_t buc;
|
||||
|
||||
for (buc = 0; buc < ECMULT_TABLE_SIZE(bucket_window+2); buc++) {
|
||||
secp256k1_gej_set_infinity(&buckets[buc]);
|
||||
}
|
||||
|
||||
for (np = 0; np < no; ++np) {
|
||||
int n = state->wnaf_na[np*n_wnaf + i];
|
||||
struct secp256k1_pippenger_point_state point_state = state->ps[np];
|
||||
secp256k1_ge tmp;
|
||||
|
||||
if (i == 0) {
|
||||
/* correct for wnaf skew */
|
||||
int skew = point_state.skew_na;
|
||||
if (skew) {
|
||||
secp256k1_ge_neg(&tmp, &pt[point_state.input_pos]);
|
||||
secp256k1_gej_add_ge_var(&buckets[0], &buckets[0], &tmp, NULL);
|
||||
}
|
||||
}
|
||||
if (n > 0) {
|
||||
buc = (n - 1)/2;
|
||||
secp256k1_gej_add_ge_var(&buckets[buc], &buckets[buc], &pt[point_state.input_pos], NULL);
|
||||
} else if (n < 0) {
|
||||
buc = -(n + 1)/2;
|
||||
secp256k1_ge_neg(&tmp, &pt[point_state.input_pos]);
|
||||
secp256k1_gej_add_ge_var(&buckets[buc], &buckets[buc], &tmp, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
for (j = 0; j < bucket_window; j++) {
|
||||
secp256k1_gej_double_var(r, r, NULL);
|
||||
}
|
||||
|
||||
secp256k1_gej_set_infinity(&running_sum);
|
||||
/* Accumulate the sum: bucket[0] + 3*bucket[1] + 5*bucket[2] + 7*bucket[3] + ...
|
||||
* = bucket[0] + bucket[1] + bucket[2] + bucket[3] + ...
|
||||
* + 2 * (bucket[1] + 2*bucket[2] + 3*bucket[3] + ...)
|
||||
* using an intermediate running sum:
|
||||
* running_sum = bucket[0] + bucket[1] + bucket[2] + ...
|
||||
*
|
||||
* The doubling is done implicitly by deferring the final window doubling (of 'r').
|
||||
*/
|
||||
for (buc = ECMULT_TABLE_SIZE(bucket_window+2) - 1; buc > 0; buc--) {
|
||||
secp256k1_gej_add_var(&running_sum, &running_sum, &buckets[buc], NULL);
|
||||
secp256k1_gej_add_var(r, r, &running_sum, NULL);
|
||||
}
|
||||
|
||||
secp256k1_gej_add_var(&running_sum, &running_sum, &buckets[0], NULL);
|
||||
secp256k1_gej_double_var(r, r, NULL);
|
||||
secp256k1_gej_add_var(r, r, &running_sum, NULL);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns optimal bucket_window (number of bits of a scalar represented by a
|
||||
* set of buckets) for a given number of points.
|
||||
*/
|
||||
static int secp256k1_pippenger_bucket_window(size_t n) {
|
||||
if (n <= 1) {
|
||||
return 1;
|
||||
} else if (n <= 4) {
|
||||
return 2;
|
||||
} else if (n <= 20) {
|
||||
return 3;
|
||||
} else if (n <= 57) {
|
||||
return 4;
|
||||
} else if (n <= 136) {
|
||||
return 5;
|
||||
} else if (n <= 235) {
|
||||
return 6;
|
||||
} else if (n <= 1260) {
|
||||
return 7;
|
||||
} else if (n <= 4420) {
|
||||
return 9;
|
||||
} else if (n <= 7880) {
|
||||
return 10;
|
||||
} else if (n <= 16050) {
|
||||
return 11;
|
||||
} else {
|
||||
return PIPPENGER_MAX_BUCKET_WINDOW;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum optimal number of points for a bucket_window.
|
||||
*/
|
||||
static size_t secp256k1_pippenger_bucket_window_inv(int bucket_window) {
|
||||
switch(bucket_window) {
|
||||
case 1: return 1;
|
||||
case 2: return 4;
|
||||
case 3: return 20;
|
||||
case 4: return 57;
|
||||
case 5: return 136;
|
||||
case 6: return 235;
|
||||
case 7: return 1260;
|
||||
case 8: return 1260;
|
||||
case 9: return 4420;
|
||||
case 10: return 7880;
|
||||
case 11: return 16050;
|
||||
case PIPPENGER_MAX_BUCKET_WINDOW: return SIZE_MAX;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_ecmult_endo_split(secp256k1_scalar *s1, secp256k1_scalar *s2, secp256k1_ge *p1, secp256k1_ge *p2) {
|
||||
secp256k1_scalar tmp = *s1;
|
||||
secp256k1_scalar_split_lambda(s1, s2, &tmp);
|
||||
secp256k1_ge_mul_lambda(p2, p1);
|
||||
|
||||
if (secp256k1_scalar_is_high(s1)) {
|
||||
secp256k1_scalar_negate(s1, s1);
|
||||
secp256k1_ge_neg(p1, p1);
|
||||
}
|
||||
if (secp256k1_scalar_is_high(s2)) {
|
||||
secp256k1_scalar_negate(s2, s2);
|
||||
secp256k1_ge_neg(p2, p2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the scratch size required for a given number of points (excluding
|
||||
* base point G) without considering alignment.
|
||||
*/
|
||||
static size_t secp256k1_pippenger_scratch_size(size_t n_points, int bucket_window) {
|
||||
size_t entries = 2*n_points + 2;
|
||||
size_t entry_size = sizeof(secp256k1_ge) + sizeof(secp256k1_scalar) + sizeof(struct secp256k1_pippenger_point_state) + (WNAF_SIZE(bucket_window+1)+1)*sizeof(int);
|
||||
return (sizeof(secp256k1_gej) << bucket_window) + sizeof(struct secp256k1_pippenger_state) + entries * entry_size;
|
||||
}
|
||||
|
||||
static int secp256k1_ecmult_pippenger_batch(const secp256k1_callback* error_callback, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n_points, size_t cb_offset) {
|
||||
const size_t scratch_checkpoint = secp256k1_scratch_checkpoint(error_callback, scratch);
|
||||
/* Use 2(n+1) with the endomorphism, when calculating batch
|
||||
* sizes. The reason for +1 is that we add the G scalar to the list of
|
||||
* other scalars. */
|
||||
size_t entries = 2*n_points + 2;
|
||||
secp256k1_ge *points;
|
||||
secp256k1_scalar *scalars;
|
||||
secp256k1_gej *buckets;
|
||||
struct secp256k1_pippenger_state *state_space;
|
||||
size_t idx = 0;
|
||||
size_t point_idx = 0;
|
||||
int bucket_window;
|
||||
|
||||
secp256k1_gej_set_infinity(r);
|
||||
if (inp_g_sc == NULL && n_points == 0) {
|
||||
return 1;
|
||||
}
|
||||
bucket_window = secp256k1_pippenger_bucket_window(n_points);
|
||||
|
||||
/* We allocate PIPPENGER_SCRATCH_OBJECTS objects on the scratch space. If
|
||||
* these allocations change, make sure to update the
|
||||
* PIPPENGER_SCRATCH_OBJECTS constant and pippenger_scratch_size
|
||||
* accordingly. */
|
||||
points = (secp256k1_ge *) secp256k1_scratch_alloc(error_callback, scratch, entries * sizeof(*points));
|
||||
scalars = (secp256k1_scalar *) secp256k1_scratch_alloc(error_callback, scratch, entries * sizeof(*scalars));
|
||||
state_space = (struct secp256k1_pippenger_state *) secp256k1_scratch_alloc(error_callback, scratch, sizeof(*state_space));
|
||||
if (points == NULL || scalars == NULL || state_space == NULL) {
|
||||
secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint);
|
||||
return 0;
|
||||
}
|
||||
state_space->ps = (struct secp256k1_pippenger_point_state *) secp256k1_scratch_alloc(error_callback, scratch, entries * sizeof(*state_space->ps));
|
||||
state_space->wnaf_na = (int *) secp256k1_scratch_alloc(error_callback, scratch, entries*(WNAF_SIZE(bucket_window+1)) * sizeof(int));
|
||||
buckets = (secp256k1_gej *) secp256k1_scratch_alloc(error_callback, scratch, ((size_t)1 << bucket_window) * sizeof(*buckets));
|
||||
if (state_space->ps == NULL || state_space->wnaf_na == NULL || buckets == NULL) {
|
||||
secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (inp_g_sc != NULL) {
|
||||
scalars[0] = *inp_g_sc;
|
||||
points[0] = secp256k1_ge_const_g;
|
||||
idx++;
|
||||
secp256k1_ecmult_endo_split(&scalars[0], &scalars[1], &points[0], &points[1]);
|
||||
idx++;
|
||||
}
|
||||
|
||||
while (point_idx < n_points) {
|
||||
if (!cb(&scalars[idx], &points[idx], point_idx + cb_offset, cbdata)) {
|
||||
secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint);
|
||||
return 0;
|
||||
}
|
||||
idx++;
|
||||
secp256k1_ecmult_endo_split(&scalars[idx - 1], &scalars[idx], &points[idx - 1], &points[idx]);
|
||||
idx++;
|
||||
point_idx++;
|
||||
}
|
||||
|
||||
secp256k1_ecmult_pippenger_wnaf(buckets, bucket_window, state_space, r, scalars, points, idx);
|
||||
secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Wrapper for secp256k1_ecmult_multi_func interface */
|
||||
static int secp256k1_ecmult_pippenger_batch_single(const secp256k1_callback* error_callback, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n) {
|
||||
return secp256k1_ecmult_pippenger_batch(error_callback, scratch, r, inp_g_sc, cb, cbdata, n, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum number of points in addition to G that can be used with
|
||||
* a given scratch space. The function ensures that fewer points may also be
|
||||
* used.
|
||||
*/
|
||||
static size_t secp256k1_pippenger_max_points(const secp256k1_callback* error_callback, secp256k1_scratch *scratch) {
|
||||
size_t max_alloc = secp256k1_scratch_max_allocation(error_callback, scratch, PIPPENGER_SCRATCH_OBJECTS);
|
||||
int bucket_window;
|
||||
size_t res = 0;
|
||||
|
||||
for (bucket_window = 1; bucket_window <= PIPPENGER_MAX_BUCKET_WINDOW; bucket_window++) {
|
||||
size_t n_points;
|
||||
size_t max_points = secp256k1_pippenger_bucket_window_inv(bucket_window);
|
||||
size_t space_for_points;
|
||||
size_t space_overhead;
|
||||
size_t entry_size = sizeof(secp256k1_ge) + sizeof(secp256k1_scalar) + sizeof(struct secp256k1_pippenger_point_state) + (WNAF_SIZE(bucket_window+1)+1)*sizeof(int);
|
||||
|
||||
entry_size = 2*entry_size;
|
||||
space_overhead = (sizeof(secp256k1_gej) << bucket_window) + entry_size + sizeof(struct secp256k1_pippenger_state);
|
||||
if (space_overhead > max_alloc) {
|
||||
break;
|
||||
}
|
||||
space_for_points = max_alloc - space_overhead;
|
||||
|
||||
n_points = space_for_points/entry_size;
|
||||
n_points = n_points > max_points ? max_points : n_points;
|
||||
if (n_points > res) {
|
||||
res = n_points;
|
||||
}
|
||||
if (n_points < max_points) {
|
||||
/* A larger bucket_window may support even more points. But if we
|
||||
* would choose that then the caller couldn't safely use any number
|
||||
* smaller than what this function returns */
|
||||
break;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Computes ecmult_multi by simply multiplying and adding each point. Does not
|
||||
* require a scratch space */
|
||||
static int secp256k1_ecmult_multi_simple_var(secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n_points) {
|
||||
size_t point_idx;
|
||||
secp256k1_gej tmpj;
|
||||
|
||||
secp256k1_gej_set_infinity(r);
|
||||
secp256k1_gej_set_infinity(&tmpj);
|
||||
/* r = inp_g_sc*G */
|
||||
secp256k1_ecmult(r, &tmpj, &secp256k1_scalar_zero, inp_g_sc);
|
||||
for (point_idx = 0; point_idx < n_points; point_idx++) {
|
||||
secp256k1_ge point;
|
||||
secp256k1_gej pointj;
|
||||
secp256k1_scalar scalar;
|
||||
if (!cb(&scalar, &point, point_idx, cbdata)) {
|
||||
return 0;
|
||||
}
|
||||
/* r += scalar*point */
|
||||
secp256k1_gej_set_ge(&pointj, &point);
|
||||
secp256k1_ecmult(&tmpj, &pointj, &scalar, NULL);
|
||||
secp256k1_gej_add_var(r, r, &tmpj, NULL);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Compute the number of batches and the batch size given the maximum batch size and the
|
||||
* total number of points */
|
||||
static int secp256k1_ecmult_multi_batch_size_helper(size_t *n_batches, size_t *n_batch_points, size_t max_n_batch_points, size_t n) {
|
||||
if (max_n_batch_points == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (max_n_batch_points > ECMULT_MAX_POINTS_PER_BATCH) {
|
||||
max_n_batch_points = ECMULT_MAX_POINTS_PER_BATCH;
|
||||
}
|
||||
if (n == 0) {
|
||||
*n_batches = 0;
|
||||
*n_batch_points = 0;
|
||||
return 1;
|
||||
}
|
||||
/* Compute ceil(n/max_n_batch_points) and ceil(n/n_batches) */
|
||||
*n_batches = CEIL_DIV(n, max_n_batch_points);
|
||||
*n_batch_points = CEIL_DIV(n, *n_batches);
|
||||
return 1;
|
||||
}
|
||||
|
||||
typedef int (*secp256k1_ecmult_multi_func)(const secp256k1_callback* error_callback, secp256k1_scratch*, secp256k1_gej*, const secp256k1_scalar*, secp256k1_ecmult_multi_callback cb, void*, size_t);
|
||||
static int secp256k1_ecmult_multi_var(const secp256k1_callback* error_callback, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n) {
|
||||
size_t i;
|
||||
|
||||
int (*f)(const secp256k1_callback* error_callback, secp256k1_scratch*, secp256k1_gej*, const secp256k1_scalar*, secp256k1_ecmult_multi_callback cb, void*, size_t, size_t);
|
||||
size_t n_batches;
|
||||
size_t n_batch_points;
|
||||
|
||||
secp256k1_gej_set_infinity(r);
|
||||
if (inp_g_sc == NULL && n == 0) {
|
||||
return 1;
|
||||
} else if (n == 0) {
|
||||
secp256k1_ecmult(r, r, &secp256k1_scalar_zero, inp_g_sc);
|
||||
return 1;
|
||||
}
|
||||
if (scratch == NULL) {
|
||||
return secp256k1_ecmult_multi_simple_var(r, inp_g_sc, cb, cbdata, n);
|
||||
}
|
||||
|
||||
/* Compute the batch sizes for Pippenger's algorithm given a scratch space. If it's greater than
|
||||
* a threshold use Pippenger's algorithm. Otherwise use Strauss' algorithm.
|
||||
* As a first step check if there's enough space for Pippenger's algo (which requires less space
|
||||
* than Strauss' algo) and if not, use the simple algorithm. */
|
||||
if (!secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, secp256k1_pippenger_max_points(error_callback, scratch), n)) {
|
||||
return secp256k1_ecmult_multi_simple_var(r, inp_g_sc, cb, cbdata, n);
|
||||
}
|
||||
if (n_batch_points >= ECMULT_PIPPENGER_THRESHOLD) {
|
||||
f = secp256k1_ecmult_pippenger_batch;
|
||||
} else {
|
||||
if (!secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, secp256k1_strauss_max_points(error_callback, scratch), n)) {
|
||||
return secp256k1_ecmult_multi_simple_var(r, inp_g_sc, cb, cbdata, n);
|
||||
}
|
||||
f = secp256k1_ecmult_strauss_batch;
|
||||
}
|
||||
for(i = 0; i < n_batches; i++) {
|
||||
size_t nbp = n < n_batch_points ? n : n_batch_points;
|
||||
size_t offset = n_batch_points*i;
|
||||
secp256k1_gej tmp;
|
||||
if (!f(error_callback, scratch, &tmp, i == 0 ? inp_g_sc : NULL, cb, cbdata, nbp, offset)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_gej_add_var(r, r, &tmp, NULL);
|
||||
n -= nbp;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* SECP256K1_ECMULT_IMPL_H */
|
||||
351
firmware/kb2040_hidden_signer/src/secp256k1/src/field.h
Normal file
351
firmware/kb2040_hidden_signer/src/secp256k1/src/field.h
Normal file
@@ -0,0 +1,351 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2013, 2014 Pieter Wuille *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_FIELD_H
|
||||
#define SECP256K1_FIELD_H
|
||||
|
||||
#include "util.h"
|
||||
|
||||
/* This file defines the generic interface for working with secp256k1_fe
|
||||
* objects, which represent field elements (integers modulo 2^256 - 2^32 - 977).
|
||||
*
|
||||
* The actual definition of the secp256k1_fe type depends on the chosen field
|
||||
* implementation; see the field_5x52.h and field_10x26.h files for details.
|
||||
*
|
||||
* All secp256k1_fe objects have implicit properties that determine what
|
||||
* operations are permitted on it. These are purely a function of what
|
||||
* secp256k1_fe_ operations are applied on it, generally (implicitly) fixed at
|
||||
* compile time, and do not depend on the chosen field implementation. Despite
|
||||
* that, what these properties actually entail for the field representation
|
||||
* values depends on the chosen field implementation. These properties are:
|
||||
* - magnitude: an integer in [0,32]
|
||||
* - normalized: 0 or 1; normalized=1 implies magnitude <= 1.
|
||||
*
|
||||
* In VERIFY mode, they are materialized explicitly as fields in the struct,
|
||||
* allowing run-time verification of these properties. In that case, the field
|
||||
* implementation also provides a secp256k1_fe_verify routine to verify that
|
||||
* these fields match the run-time value and perform internal consistency
|
||||
* checks. */
|
||||
#ifdef VERIFY
|
||||
# define SECP256K1_FE_VERIFY_FIELDS \
|
||||
int magnitude; \
|
||||
int normalized;
|
||||
#else
|
||||
# define SECP256K1_FE_VERIFY_FIELDS
|
||||
#endif
|
||||
|
||||
#if defined(SECP256K1_WIDEMUL_INT128)
|
||||
#include "field_5x52.h"
|
||||
#elif defined(SECP256K1_WIDEMUL_INT64)
|
||||
#include "field_10x26.h"
|
||||
#else
|
||||
#error "Please select wide multiplication implementation"
|
||||
#endif
|
||||
|
||||
#ifdef VERIFY
|
||||
/* Magnitude and normalized value for constants. */
|
||||
#define SECP256K1_FE_VERIFY_CONST(d7, d6, d5, d4, d3, d2, d1, d0) \
|
||||
/* Magnitude is 0 for constant 0; 1 otherwise. */ \
|
||||
, (((d7) | (d6) | (d5) | (d4) | (d3) | (d2) | (d1) | (d0)) != 0) \
|
||||
/* Normalized is 1 unless sum(d_i<<(32*i) for i=0..7) exceeds field modulus. */ \
|
||||
, (!(((d7) & (d6) & (d5) & (d4) & (d3) & (d2)) == 0xfffffffful && ((d1) == 0xfffffffful || ((d1) == 0xfffffffe && (d0 >= 0xfffffc2f)))))
|
||||
#else
|
||||
#define SECP256K1_FE_VERIFY_CONST(d7, d6, d5, d4, d3, d2, d1, d0)
|
||||
#endif
|
||||
|
||||
/** This expands to an initializer for a secp256k1_fe valued sum((i*32) * d_i, i=0..7) mod p.
|
||||
*
|
||||
* It has magnitude 1, unless d_i are all 0, in which case the magnitude is 0.
|
||||
* It is normalized, unless sum(2^(i*32) * d_i, i=0..7) >= p.
|
||||
*
|
||||
* SECP256K1_FE_CONST_INNER is provided by the implementation.
|
||||
*/
|
||||
#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)) SECP256K1_FE_VERIFY_CONST((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)) }
|
||||
|
||||
static const secp256k1_fe secp256k1_fe_one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1);
|
||||
static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST(
|
||||
0x7ae96a2bul, 0x657c0710ul, 0x6e64479eul, 0xac3434e9ul,
|
||||
0x9cf04975ul, 0x12f58995ul, 0xc1396c28ul, 0x719501eeul
|
||||
);
|
||||
|
||||
#ifndef VERIFY
|
||||
/* In non-VERIFY mode, we #define the fe operations to be identical to their
|
||||
* internal field implementation, to avoid the potential overhead of a
|
||||
* function call (even though presumably inlinable). */
|
||||
# define secp256k1_fe_normalize secp256k1_fe_impl_normalize
|
||||
# define secp256k1_fe_normalize_weak secp256k1_fe_impl_normalize_weak
|
||||
# define secp256k1_fe_normalize_var secp256k1_fe_impl_normalize_var
|
||||
# define secp256k1_fe_normalizes_to_zero secp256k1_fe_impl_normalizes_to_zero
|
||||
# define secp256k1_fe_normalizes_to_zero_var secp256k1_fe_impl_normalizes_to_zero_var
|
||||
# define secp256k1_fe_set_int secp256k1_fe_impl_set_int
|
||||
# define secp256k1_fe_is_zero secp256k1_fe_impl_is_zero
|
||||
# define secp256k1_fe_is_odd secp256k1_fe_impl_is_odd
|
||||
# define secp256k1_fe_cmp_var secp256k1_fe_impl_cmp_var
|
||||
# define secp256k1_fe_set_b32_mod secp256k1_fe_impl_set_b32_mod
|
||||
# define secp256k1_fe_set_b32_limit secp256k1_fe_impl_set_b32_limit
|
||||
# define secp256k1_fe_get_b32 secp256k1_fe_impl_get_b32
|
||||
# define secp256k1_fe_negate_unchecked secp256k1_fe_impl_negate_unchecked
|
||||
# define secp256k1_fe_mul_int_unchecked secp256k1_fe_impl_mul_int_unchecked
|
||||
# define secp256k1_fe_add secp256k1_fe_impl_add
|
||||
# define secp256k1_fe_mul secp256k1_fe_impl_mul
|
||||
# define secp256k1_fe_sqr secp256k1_fe_impl_sqr
|
||||
# define secp256k1_fe_cmov secp256k1_fe_impl_cmov
|
||||
# define secp256k1_fe_to_storage secp256k1_fe_impl_to_storage
|
||||
# define secp256k1_fe_from_storage secp256k1_fe_impl_from_storage
|
||||
# define secp256k1_fe_inv secp256k1_fe_impl_inv
|
||||
# define secp256k1_fe_inv_var secp256k1_fe_impl_inv_var
|
||||
# define secp256k1_fe_get_bounds secp256k1_fe_impl_get_bounds
|
||||
# define secp256k1_fe_half secp256k1_fe_impl_half
|
||||
# define secp256k1_fe_add_int secp256k1_fe_impl_add_int
|
||||
# define secp256k1_fe_is_square_var secp256k1_fe_impl_is_square_var
|
||||
#endif /* !defined(VERIFY) */
|
||||
|
||||
/** Normalize a field element.
|
||||
*
|
||||
* On input, r must be a valid field element.
|
||||
* On output, r represents the same value but has normalized=1 and magnitude=1.
|
||||
*/
|
||||
static void secp256k1_fe_normalize(secp256k1_fe *r);
|
||||
|
||||
/** Give a field element magnitude 1.
|
||||
*
|
||||
* On input, r must be a valid field element.
|
||||
* On output, r represents the same value but has magnitude=1. Normalized is unchanged.
|
||||
*/
|
||||
static void secp256k1_fe_normalize_weak(secp256k1_fe *r);
|
||||
|
||||
/** Normalize a field element, without constant-time guarantee.
|
||||
*
|
||||
* Identical in behavior to secp256k1_fe_normalize, but not constant time in r.
|
||||
*/
|
||||
static void secp256k1_fe_normalize_var(secp256k1_fe *r);
|
||||
|
||||
/** Determine whether r represents field element 0.
|
||||
*
|
||||
* On input, r must be a valid field element.
|
||||
* Returns whether r = 0 (mod p).
|
||||
*/
|
||||
static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r);
|
||||
|
||||
/** Determine whether r represents field element 0, without constant-time guarantee.
|
||||
*
|
||||
* Identical in behavior to secp256k1_normalizes_to_zero, but not constant time in r.
|
||||
*/
|
||||
static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r);
|
||||
|
||||
/** Set a field element to an integer in range [0,0x7FFF].
|
||||
*
|
||||
* On input, r does not need to be initialized, a must be in [0,0x7FFF].
|
||||
* On output, r represents value a, is normalized and has magnitude (a!=0).
|
||||
*/
|
||||
static void secp256k1_fe_set_int(secp256k1_fe *r, int a);
|
||||
|
||||
/** Clear a field element to prevent leaking sensitive information. */
|
||||
static void secp256k1_fe_clear(secp256k1_fe *a);
|
||||
|
||||
/** Determine whether a represents field element 0.
|
||||
*
|
||||
* On input, a must be a valid normalized field element.
|
||||
* Returns whether a = 0 (mod p).
|
||||
*
|
||||
* This behaves identical to secp256k1_normalizes_to_zero{,_var}, but requires
|
||||
* normalized input (and is much faster).
|
||||
*/
|
||||
static int secp256k1_fe_is_zero(const secp256k1_fe *a);
|
||||
|
||||
/** Determine whether a (mod p) is odd.
|
||||
*
|
||||
* On input, a must be a valid normalized field element.
|
||||
* Returns (int(a) mod p) & 1.
|
||||
*/
|
||||
static int secp256k1_fe_is_odd(const secp256k1_fe *a);
|
||||
|
||||
/** Determine whether two field elements are equal.
|
||||
*
|
||||
* On input, a and b must be valid field elements with magnitudes not exceeding
|
||||
* 1 and 31, respectively.
|
||||
* Returns a = b (mod p).
|
||||
*/
|
||||
static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b);
|
||||
|
||||
/** Compare the values represented by 2 field elements, without constant-time guarantee.
|
||||
*
|
||||
* On input, a and b must be valid normalized field elements.
|
||||
* Returns 1 if a > b, -1 if a < b, and 0 if a = b (comparisons are done as integers
|
||||
* in range 0..p-1).
|
||||
*/
|
||||
static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b);
|
||||
|
||||
/** Set a field element equal to the element represented by a provided 32-byte big endian value
|
||||
* interpreted modulo p.
|
||||
*
|
||||
* On input, r does not need to be initialized. a must be a pointer to an initialized 32-byte array.
|
||||
* On output, r = a (mod p). It will have magnitude 1, and not be normalized.
|
||||
*/
|
||||
static void secp256k1_fe_set_b32_mod(secp256k1_fe *r, const unsigned char *a);
|
||||
|
||||
/** Set a field element equal to a provided 32-byte big endian value, checking for overflow.
|
||||
*
|
||||
* On input, r does not need to be initialized. a must be a pointer to an initialized 32-byte array.
|
||||
* On output, r = a if (a < p), it will be normalized with magnitude 1, and 1 is returned.
|
||||
* If a >= p, 0 is returned, and r will be made invalid (and must not be used without overwriting).
|
||||
*/
|
||||
static int secp256k1_fe_set_b32_limit(secp256k1_fe *r, const unsigned char *a);
|
||||
|
||||
/** Convert a field element to 32-byte big endian byte array.
|
||||
* On input, a must be a valid normalized field element, and r a pointer to a 32-byte array.
|
||||
* On output, r = a (mod p).
|
||||
*/
|
||||
static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a);
|
||||
|
||||
/** Negate a field element.
|
||||
*
|
||||
* On input, r does not need to be initialized. a must be a valid field element with
|
||||
* magnitude not exceeding m. m must be an integer constant expression in [0,31].
|
||||
* Performs {r = -a}.
|
||||
* On output, r will not be normalized, and will have magnitude m+1.
|
||||
*/
|
||||
#define secp256k1_fe_negate(r, a, m) ASSERT_INT_CONST_AND_DO(m, secp256k1_fe_negate_unchecked(r, a, m))
|
||||
|
||||
/** Like secp256k1_fe_negate_unchecked but m is not checked to be an integer constant expression.
|
||||
*
|
||||
* Should not be called directly outside of tests.
|
||||
*/
|
||||
static void secp256k1_fe_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m);
|
||||
|
||||
/** Add a small integer to a field element.
|
||||
*
|
||||
* Performs {r += a}. The magnitude of r increases by 1, and normalized is cleared.
|
||||
* a must be in range [0,0x7FFF].
|
||||
*/
|
||||
static void secp256k1_fe_add_int(secp256k1_fe *r, int a);
|
||||
|
||||
/** Multiply a field element with a small integer.
|
||||
*
|
||||
* On input, r must be a valid field element. a must be an integer constant expression in [0,32].
|
||||
* The magnitude of r times a must not exceed 32.
|
||||
* Performs {r *= a}.
|
||||
* On output, r's magnitude is multiplied by a, and r will not be normalized.
|
||||
*/
|
||||
#define secp256k1_fe_mul_int(r, a) ASSERT_INT_CONST_AND_DO(a, secp256k1_fe_mul_int_unchecked(r, a))
|
||||
|
||||
/** Like secp256k1_fe_mul_int but a is not checked to be an integer constant expression.
|
||||
*
|
||||
* Should not be called directly outside of tests.
|
||||
*/
|
||||
static void secp256k1_fe_mul_int_unchecked(secp256k1_fe *r, int a);
|
||||
|
||||
/** Increment a field element by another.
|
||||
*
|
||||
* On input, r and a must be valid field elements, not necessarily normalized.
|
||||
* The sum of their magnitudes must not exceed 32.
|
||||
* Performs {r += a}.
|
||||
* On output, r will not be normalized, and will have magnitude incremented by a's.
|
||||
*/
|
||||
static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a);
|
||||
|
||||
/** Multiply two field elements.
|
||||
*
|
||||
* On input, a and b must be valid field elements; r does not need to be initialized.
|
||||
* r and a may point to the same object, but neither may point to the object pointed
|
||||
* to by b. The magnitudes of a and b must not exceed 8.
|
||||
* Performs {r = a * b}
|
||||
* On output, r will have magnitude 1, but won't be normalized.
|
||||
*/
|
||||
static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b);
|
||||
|
||||
/** Square a field element.
|
||||
*
|
||||
* On input, a must be a valid field element; r does not need to be initialized. The magnitude
|
||||
* of a must not exceed 8.
|
||||
* Performs {r = a**2}
|
||||
* On output, r will have magnitude 1, but won't be normalized.
|
||||
*/
|
||||
static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a);
|
||||
|
||||
/** Compute a square root of a field element.
|
||||
*
|
||||
* On input, a must be a valid field element with magnitude<=8; r need not be initialized.
|
||||
* If sqrt(a) exists, performs {r = sqrt(a)} and returns 1.
|
||||
* Otherwise, sqrt(-a) exists. The function performs {r = sqrt(-a)} and returns 0.
|
||||
* The resulting value represented by r will be a square itself.
|
||||
* Variables r and a must not point to the same object.
|
||||
* On output, r will have magnitude 1 but will not be normalized.
|
||||
*/
|
||||
static int secp256k1_fe_sqrt(secp256k1_fe * SECP256K1_RESTRICT r, const secp256k1_fe * SECP256K1_RESTRICT a);
|
||||
|
||||
/** Compute the modular inverse of a field element.
|
||||
*
|
||||
* On input, a must be a valid field element; r need not be initialized.
|
||||
* Performs {r = a**(p-2)} (which maps 0 to 0, and every other element to its
|
||||
* inverse).
|
||||
* On output, r will have magnitude (a.magnitude != 0) and be normalized.
|
||||
*/
|
||||
static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *a);
|
||||
|
||||
/** Compute the modular inverse of a field element, without constant-time guarantee.
|
||||
*
|
||||
* Behaves identically to secp256k1_fe_inv, but is not constant-time in a.
|
||||
*/
|
||||
static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a);
|
||||
|
||||
/** Convert a field element to secp256k1_fe_storage.
|
||||
*
|
||||
* On input, a must be a valid normalized field element.
|
||||
* Performs {r = a}.
|
||||
*/
|
||||
static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a);
|
||||
|
||||
/** Convert a field element back from secp256k1_fe_storage.
|
||||
*
|
||||
* On input, r need not be initialized.
|
||||
* Performs {r = a}.
|
||||
* On output, r will be normalized and will have magnitude 1.
|
||||
*/
|
||||
static void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a);
|
||||
|
||||
/** If flag is 1, set *r equal to *a; if flag is 0, leave it. Constant-time.
|
||||
* Both *r and *a must be initialized. Flag must be 0 or 1. */
|
||||
static void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag);
|
||||
|
||||
/** Conditionally move a field element in constant time.
|
||||
*
|
||||
* On input, both r and a must be valid field elements. Flag must be 0 or 1.
|
||||
* Performs {r = flag ? a : r}.
|
||||
*
|
||||
* On output, r's magnitude will be the maximum of both input magnitudes.
|
||||
* It will be normalized if and only if both inputs were normalized.
|
||||
*/
|
||||
static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag);
|
||||
|
||||
/** Halve the value of a field element modulo the field prime in constant-time.
|
||||
*
|
||||
* On input, r must be a valid field element.
|
||||
* On output, r will be normalized and have magnitude floor(m/2) + 1 where m is
|
||||
* the magnitude of r on input.
|
||||
*/
|
||||
static void secp256k1_fe_half(secp256k1_fe *r);
|
||||
|
||||
/** Sets r to a field element with magnitude m, normalized if (and only if) m==0.
|
||||
* The value is chosen so that it is likely to trigger edge cases related to
|
||||
* internal overflows. */
|
||||
static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m);
|
||||
|
||||
/** Determine whether a is a square (modulo p).
|
||||
*
|
||||
* On input, a must be a valid field element.
|
||||
*/
|
||||
static int secp256k1_fe_is_square_var(const secp256k1_fe *a);
|
||||
|
||||
/** Check invariants on a field element (no-op unless VERIFY is enabled). */
|
||||
static void secp256k1_fe_verify(const secp256k1_fe *a);
|
||||
#define SECP256K1_FE_VERIFY(a) secp256k1_fe_verify(a)
|
||||
|
||||
/** Check that magnitude of a is at most m (no-op unless VERIFY is enabled). */
|
||||
static void secp256k1_fe_verify_magnitude(const secp256k1_fe *a, int m);
|
||||
#define SECP256K1_FE_VERIFY_MAGNITUDE(a, m) secp256k1_fe_verify_magnitude(a, m)
|
||||
|
||||
#endif /* SECP256K1_FIELD_H */
|
||||
@@ -0,0 +1,57 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2013, 2014 Pieter Wuille *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_FIELD_REPR_H
|
||||
#define SECP256K1_FIELD_REPR_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/** This field implementation represents the value as 10 uint32_t limbs in base
|
||||
* 2^26. */
|
||||
typedef struct {
|
||||
/* A field element f represents the sum(i=0..9, f.n[i] << (i*26)) mod p,
|
||||
* where p is the field modulus, 2^256 - 2^32 - 977.
|
||||
*
|
||||
* The individual limbs f.n[i] can exceed 2^26; the field's magnitude roughly
|
||||
* corresponds to how much excess is allowed. The value
|
||||
* sum(i=0..9, f.n[i] << (i*26)) may exceed p, unless the field element is
|
||||
* normalized. */
|
||||
uint32_t n[10];
|
||||
/*
|
||||
* Magnitude m requires:
|
||||
* n[i] <= 2 * m * (2^26 - 1) for i=0..8
|
||||
* n[9] <= 2 * m * (2^22 - 1)
|
||||
*
|
||||
* Normalized requires:
|
||||
* n[i] <= (2^26 - 1) for i=0..8
|
||||
* sum(i=0..9, n[i] << (i*26)) < p
|
||||
* (together these imply n[9] <= 2^22 - 1)
|
||||
*/
|
||||
SECP256K1_FE_VERIFY_FIELDS
|
||||
} secp256k1_fe;
|
||||
|
||||
/* Unpacks a constant into a overlapping multi-limbed FE element. */
|
||||
#define SECP256K1_FE_CONST_INNER(d7, d6, d5, d4, d3, d2, d1, d0) { \
|
||||
(d0) & 0x3FFFFFFUL, \
|
||||
(((uint32_t)d0) >> 26) | (((uint32_t)(d1) & 0xFFFFFUL) << 6), \
|
||||
(((uint32_t)d1) >> 20) | (((uint32_t)(d2) & 0x3FFFUL) << 12), \
|
||||
(((uint32_t)d2) >> 14) | (((uint32_t)(d3) & 0xFFUL) << 18), \
|
||||
(((uint32_t)d3) >> 8) | (((uint32_t)(d4) & 0x3UL) << 24), \
|
||||
(((uint32_t)d4) >> 2) & 0x3FFFFFFUL, \
|
||||
(((uint32_t)d4) >> 28) | (((uint32_t)(d5) & 0x3FFFFFUL) << 4), \
|
||||
(((uint32_t)d5) >> 22) | (((uint32_t)(d6) & 0xFFFFUL) << 10), \
|
||||
(((uint32_t)d6) >> 16) | (((uint32_t)(d7) & 0x3FFUL) << 16), \
|
||||
(((uint32_t)d7) >> 10) \
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
uint32_t n[8];
|
||||
} secp256k1_fe_storage;
|
||||
|
||||
#define SECP256K1_FE_STORAGE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{ (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }}
|
||||
#define SECP256K1_FE_STORAGE_CONST_GET(d) d.n[7], d.n[6], d.n[5], d.n[4],d.n[3], d.n[2], d.n[1], d.n[0]
|
||||
|
||||
#endif /* SECP256K1_FIELD_REPR_H */
|
||||
1234
firmware/kb2040_hidden_signer/src/secp256k1/src/field_10x26_impl.h
Normal file
1234
firmware/kb2040_hidden_signer/src/secp256k1/src/field_10x26_impl.h
Normal file
File diff suppressed because it is too large
Load Diff
62
firmware/kb2040_hidden_signer/src/secp256k1/src/field_5x52.h
Normal file
62
firmware/kb2040_hidden_signer/src/secp256k1/src/field_5x52.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2013, 2014 Pieter Wuille *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_FIELD_REPR_H
|
||||
#define SECP256K1_FIELD_REPR_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/** This field implementation represents the value as 5 uint64_t limbs in base
|
||||
* 2^52. */
|
||||
typedef struct {
|
||||
/* A field element f represents the sum(i=0..4, f.n[i] << (i*52)) mod p,
|
||||
* where p is the field modulus, 2^256 - 2^32 - 977.
|
||||
*
|
||||
* The individual limbs f.n[i] can exceed 2^52; the field's magnitude roughly
|
||||
* corresponds to how much excess is allowed. The value
|
||||
* sum(i=0..4, f.n[i] << (i*52)) may exceed p, unless the field element is
|
||||
* normalized. */
|
||||
uint64_t n[5];
|
||||
/*
|
||||
* Magnitude m requires:
|
||||
* n[i] <= 2 * m * (2^52 - 1) for i=0..3
|
||||
* n[4] <= 2 * m * (2^48 - 1)
|
||||
*
|
||||
* Normalized requires:
|
||||
* n[i] <= (2^52 - 1) for i=0..3
|
||||
* sum(i=0..4, n[i] << (i*52)) < p
|
||||
* (together these imply n[4] <= 2^48 - 1)
|
||||
*/
|
||||
SECP256K1_FE_VERIFY_FIELDS
|
||||
} secp256k1_fe;
|
||||
|
||||
/* Unpacks a constant into a overlapping multi-limbed FE element. */
|
||||
#define SECP256K1_FE_CONST_INNER(d7, d6, d5, d4, d3, d2, d1, d0) { \
|
||||
(d0) | (((uint64_t)(d1) & 0xFFFFFUL) << 32), \
|
||||
((uint64_t)(d1) >> 20) | (((uint64_t)(d2)) << 12) | (((uint64_t)(d3) & 0xFFUL) << 44), \
|
||||
((uint64_t)(d3) >> 8) | (((uint64_t)(d4) & 0xFFFFFFFUL) << 24), \
|
||||
((uint64_t)(d4) >> 28) | (((uint64_t)(d5)) << 4) | (((uint64_t)(d6) & 0xFFFFUL) << 36), \
|
||||
((uint64_t)(d6) >> 16) | (((uint64_t)(d7)) << 16) \
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
uint64_t n[4];
|
||||
} secp256k1_fe_storage;
|
||||
|
||||
#define SECP256K1_FE_STORAGE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{ \
|
||||
(d0) | (((uint64_t)(d1)) << 32), \
|
||||
(d2) | (((uint64_t)(d3)) << 32), \
|
||||
(d4) | (((uint64_t)(d5)) << 32), \
|
||||
(d6) | (((uint64_t)(d7)) << 32) \
|
||||
}}
|
||||
|
||||
#define SECP256K1_FE_STORAGE_CONST_GET(d) \
|
||||
(uint32_t)(d.n[3] >> 32), (uint32_t)d.n[3], \
|
||||
(uint32_t)(d.n[2] >> 32), (uint32_t)d.n[2], \
|
||||
(uint32_t)(d.n[1] >> 32), (uint32_t)d.n[1], \
|
||||
(uint32_t)(d.n[0] >> 32), (uint32_t)d.n[0]
|
||||
|
||||
#endif /* SECP256K1_FIELD_REPR_H */
|
||||
@@ -0,0 +1,524 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2013, 2014 Pieter Wuille *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_FIELD_REPR_IMPL_H
|
||||
#define SECP256K1_FIELD_REPR_IMPL_H
|
||||
|
||||
#include "checkmem.h"
|
||||
#include "util.h"
|
||||
#include "field.h"
|
||||
#include "modinv64_impl.h"
|
||||
|
||||
#include "field_5x52_int128_impl.h"
|
||||
|
||||
#ifdef VERIFY
|
||||
static void secp256k1_fe_impl_verify(const secp256k1_fe *a) {
|
||||
const uint64_t *d = a->n;
|
||||
int m = a->normalized ? 1 : 2 * a->magnitude;
|
||||
/* secp256k1 'p' value defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */
|
||||
VERIFY_CHECK(d[0] <= 0xFFFFFFFFFFFFFULL * m);
|
||||
VERIFY_CHECK(d[1] <= 0xFFFFFFFFFFFFFULL * m);
|
||||
VERIFY_CHECK(d[2] <= 0xFFFFFFFFFFFFFULL * m);
|
||||
VERIFY_CHECK(d[3] <= 0xFFFFFFFFFFFFFULL * m);
|
||||
VERIFY_CHECK(d[4] <= 0x0FFFFFFFFFFFFULL * m);
|
||||
if (a->normalized) {
|
||||
if ((d[4] == 0x0FFFFFFFFFFFFULL) && ((d[3] & d[2] & d[1]) == 0xFFFFFFFFFFFFFULL)) {
|
||||
VERIFY_CHECK(d[0] < 0xFFFFEFFFFFC2FULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void secp256k1_fe_impl_get_bounds(secp256k1_fe *r, int m) {
|
||||
r->n[0] = 0xFFFFFFFFFFFFFULL * 2 * m;
|
||||
r->n[1] = 0xFFFFFFFFFFFFFULL * 2 * m;
|
||||
r->n[2] = 0xFFFFFFFFFFFFFULL * 2 * m;
|
||||
r->n[3] = 0xFFFFFFFFFFFFFULL * 2 * m;
|
||||
r->n[4] = 0x0FFFFFFFFFFFFULL * 2 * m;
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_normalize(secp256k1_fe *r) {
|
||||
uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4];
|
||||
|
||||
/* Reduce t4 at the start so there will be at most a single carry from the first pass */
|
||||
uint64_t m;
|
||||
uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL;
|
||||
|
||||
/* The first pass ensures the magnitude is 1, ... */
|
||||
t0 += x * 0x1000003D1ULL;
|
||||
t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL;
|
||||
t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; m = t1;
|
||||
t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; m &= t2;
|
||||
t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; m &= t3;
|
||||
|
||||
/* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */
|
||||
VERIFY_CHECK(t4 >> 49 == 0);
|
||||
|
||||
/* At most a single final reduction is needed; check if the value is >= the field characteristic */
|
||||
x = (t4 >> 48) | ((t4 == 0x0FFFFFFFFFFFFULL) & (m == 0xFFFFFFFFFFFFFULL)
|
||||
& (t0 >= 0xFFFFEFFFFFC2FULL));
|
||||
|
||||
/* Apply the final reduction (for constant-time behaviour, we do it always) */
|
||||
t0 += x * 0x1000003D1ULL;
|
||||
t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL;
|
||||
t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL;
|
||||
t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL;
|
||||
t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL;
|
||||
|
||||
/* If t4 didn't carry to bit 48 already, then it should have after any final reduction */
|
||||
VERIFY_CHECK(t4 >> 48 == x);
|
||||
|
||||
/* Mask off the possible multiple of 2^256 from the final reduction */
|
||||
t4 &= 0x0FFFFFFFFFFFFULL;
|
||||
|
||||
r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_normalize_weak(secp256k1_fe *r) {
|
||||
uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4];
|
||||
|
||||
/* Reduce t4 at the start so there will be at most a single carry from the first pass */
|
||||
uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL;
|
||||
|
||||
/* The first pass ensures the magnitude is 1, ... */
|
||||
t0 += x * 0x1000003D1ULL;
|
||||
t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL;
|
||||
t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL;
|
||||
t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL;
|
||||
t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL;
|
||||
|
||||
/* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */
|
||||
VERIFY_CHECK(t4 >> 49 == 0);
|
||||
|
||||
r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_normalize_var(secp256k1_fe *r) {
|
||||
uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4];
|
||||
|
||||
/* Reduce t4 at the start so there will be at most a single carry from the first pass */
|
||||
uint64_t m;
|
||||
uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL;
|
||||
|
||||
/* The first pass ensures the magnitude is 1, ... */
|
||||
t0 += x * 0x1000003D1ULL;
|
||||
t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL;
|
||||
t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; m = t1;
|
||||
t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; m &= t2;
|
||||
t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; m &= t3;
|
||||
|
||||
/* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */
|
||||
VERIFY_CHECK(t4 >> 49 == 0);
|
||||
|
||||
/* At most a single final reduction is needed; check if the value is >= the field characteristic */
|
||||
x = (t4 >> 48) | ((t4 == 0x0FFFFFFFFFFFFULL) & (m == 0xFFFFFFFFFFFFFULL)
|
||||
& (t0 >= 0xFFFFEFFFFFC2FULL));
|
||||
|
||||
if (x) {
|
||||
t0 += 0x1000003D1ULL;
|
||||
t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL;
|
||||
t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL;
|
||||
t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL;
|
||||
t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL;
|
||||
|
||||
/* If t4 didn't carry to bit 48 already, then it should have after any final reduction */
|
||||
VERIFY_CHECK(t4 >> 48 == x);
|
||||
|
||||
/* Mask off the possible multiple of 2^256 from the final reduction */
|
||||
t4 &= 0x0FFFFFFFFFFFFULL;
|
||||
}
|
||||
|
||||
r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;
|
||||
}
|
||||
|
||||
static int secp256k1_fe_impl_normalizes_to_zero(const secp256k1_fe *r) {
|
||||
uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4];
|
||||
|
||||
/* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */
|
||||
uint64_t z0, z1;
|
||||
|
||||
/* Reduce t4 at the start so there will be at most a single carry from the first pass */
|
||||
uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL;
|
||||
|
||||
/* The first pass ensures the magnitude is 1, ... */
|
||||
t0 += x * 0x1000003D1ULL;
|
||||
t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; z0 = t0; z1 = t0 ^ 0x1000003D0ULL;
|
||||
t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; z0 |= t1; z1 &= t1;
|
||||
t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; z0 |= t2; z1 &= t2;
|
||||
t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; z0 |= t3; z1 &= t3;
|
||||
z0 |= t4; z1 &= t4 ^ 0xF000000000000ULL;
|
||||
|
||||
/* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */
|
||||
VERIFY_CHECK(t4 >> 49 == 0);
|
||||
|
||||
return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL);
|
||||
}
|
||||
|
||||
static int secp256k1_fe_impl_normalizes_to_zero_var(const secp256k1_fe *r) {
|
||||
uint64_t t0, t1, t2, t3, t4;
|
||||
uint64_t z0, z1;
|
||||
uint64_t x;
|
||||
|
||||
t0 = r->n[0];
|
||||
t4 = r->n[4];
|
||||
|
||||
/* Reduce t4 at the start so there will be at most a single carry from the first pass */
|
||||
x = t4 >> 48;
|
||||
|
||||
/* The first pass ensures the magnitude is 1, ... */
|
||||
t0 += x * 0x1000003D1ULL;
|
||||
|
||||
/* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */
|
||||
z0 = t0 & 0xFFFFFFFFFFFFFULL;
|
||||
z1 = z0 ^ 0x1000003D0ULL;
|
||||
|
||||
/* Fast return path should catch the majority of cases */
|
||||
if ((z0 != 0ULL) & (z1 != 0xFFFFFFFFFFFFFULL)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
t1 = r->n[1];
|
||||
t2 = r->n[2];
|
||||
t3 = r->n[3];
|
||||
|
||||
t4 &= 0x0FFFFFFFFFFFFULL;
|
||||
|
||||
t1 += (t0 >> 52);
|
||||
t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; z0 |= t1; z1 &= t1;
|
||||
t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; z0 |= t2; z1 &= t2;
|
||||
t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; z0 |= t3; z1 &= t3;
|
||||
z0 |= t4; z1 &= t4 ^ 0xF000000000000ULL;
|
||||
|
||||
/* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */
|
||||
VERIFY_CHECK(t4 >> 49 == 0);
|
||||
|
||||
return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL);
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_impl_set_int(secp256k1_fe *r, int a) {
|
||||
r->n[0] = a;
|
||||
r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0;
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_fe_impl_is_zero(const secp256k1_fe *a) {
|
||||
const uint64_t *t = a->n;
|
||||
return (t[0] | t[1] | t[2] | t[3] | t[4]) == 0;
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_fe_impl_is_odd(const secp256k1_fe *a) {
|
||||
return a->n[0] & 1;
|
||||
}
|
||||
|
||||
static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
|
||||
int i;
|
||||
for (i = 4; i >= 0; i--) {
|
||||
if (a->n[i] > b->n[i]) {
|
||||
return 1;
|
||||
}
|
||||
if (a->n[i] < b->n[i]) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_set_b32_mod(secp256k1_fe *r, const unsigned char *a) {
|
||||
r->n[0] = (uint64_t)a[31]
|
||||
| ((uint64_t)a[30] << 8)
|
||||
| ((uint64_t)a[29] << 16)
|
||||
| ((uint64_t)a[28] << 24)
|
||||
| ((uint64_t)a[27] << 32)
|
||||
| ((uint64_t)a[26] << 40)
|
||||
| ((uint64_t)(a[25] & 0xF) << 48);
|
||||
r->n[1] = (uint64_t)((a[25] >> 4) & 0xF)
|
||||
| ((uint64_t)a[24] << 4)
|
||||
| ((uint64_t)a[23] << 12)
|
||||
| ((uint64_t)a[22] << 20)
|
||||
| ((uint64_t)a[21] << 28)
|
||||
| ((uint64_t)a[20] << 36)
|
||||
| ((uint64_t)a[19] << 44);
|
||||
r->n[2] = (uint64_t)a[18]
|
||||
| ((uint64_t)a[17] << 8)
|
||||
| ((uint64_t)a[16] << 16)
|
||||
| ((uint64_t)a[15] << 24)
|
||||
| ((uint64_t)a[14] << 32)
|
||||
| ((uint64_t)a[13] << 40)
|
||||
| ((uint64_t)(a[12] & 0xF) << 48);
|
||||
r->n[3] = (uint64_t)((a[12] >> 4) & 0xF)
|
||||
| ((uint64_t)a[11] << 4)
|
||||
| ((uint64_t)a[10] << 12)
|
||||
| ((uint64_t)a[9] << 20)
|
||||
| ((uint64_t)a[8] << 28)
|
||||
| ((uint64_t)a[7] << 36)
|
||||
| ((uint64_t)a[6] << 44);
|
||||
r->n[4] = (uint64_t)a[5]
|
||||
| ((uint64_t)a[4] << 8)
|
||||
| ((uint64_t)a[3] << 16)
|
||||
| ((uint64_t)a[2] << 24)
|
||||
| ((uint64_t)a[1] << 32)
|
||||
| ((uint64_t)a[0] << 40);
|
||||
}
|
||||
|
||||
static int secp256k1_fe_impl_set_b32_limit(secp256k1_fe *r, const unsigned char *a) {
|
||||
secp256k1_fe_impl_set_b32_mod(r, a);
|
||||
return !((r->n[4] == 0x0FFFFFFFFFFFFULL) & ((r->n[3] & r->n[2] & r->n[1]) == 0xFFFFFFFFFFFFFULL) & (r->n[0] >= 0xFFFFEFFFFFC2FULL));
|
||||
}
|
||||
|
||||
/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
|
||||
static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a) {
|
||||
r[0] = (a->n[4] >> 40) & 0xFF;
|
||||
r[1] = (a->n[4] >> 32) & 0xFF;
|
||||
r[2] = (a->n[4] >> 24) & 0xFF;
|
||||
r[3] = (a->n[4] >> 16) & 0xFF;
|
||||
r[4] = (a->n[4] >> 8) & 0xFF;
|
||||
r[5] = a->n[4] & 0xFF;
|
||||
r[6] = (a->n[3] >> 44) & 0xFF;
|
||||
r[7] = (a->n[3] >> 36) & 0xFF;
|
||||
r[8] = (a->n[3] >> 28) & 0xFF;
|
||||
r[9] = (a->n[3] >> 20) & 0xFF;
|
||||
r[10] = (a->n[3] >> 12) & 0xFF;
|
||||
r[11] = (a->n[3] >> 4) & 0xFF;
|
||||
r[12] = ((a->n[2] >> 48) & 0xF) | ((a->n[3] & 0xF) << 4);
|
||||
r[13] = (a->n[2] >> 40) & 0xFF;
|
||||
r[14] = (a->n[2] >> 32) & 0xFF;
|
||||
r[15] = (a->n[2] >> 24) & 0xFF;
|
||||
r[16] = (a->n[2] >> 16) & 0xFF;
|
||||
r[17] = (a->n[2] >> 8) & 0xFF;
|
||||
r[18] = a->n[2] & 0xFF;
|
||||
r[19] = (a->n[1] >> 44) & 0xFF;
|
||||
r[20] = (a->n[1] >> 36) & 0xFF;
|
||||
r[21] = (a->n[1] >> 28) & 0xFF;
|
||||
r[22] = (a->n[1] >> 20) & 0xFF;
|
||||
r[23] = (a->n[1] >> 12) & 0xFF;
|
||||
r[24] = (a->n[1] >> 4) & 0xFF;
|
||||
r[25] = ((a->n[0] >> 48) & 0xF) | ((a->n[1] & 0xF) << 4);
|
||||
r[26] = (a->n[0] >> 40) & 0xFF;
|
||||
r[27] = (a->n[0] >> 32) & 0xFF;
|
||||
r[28] = (a->n[0] >> 24) & 0xFF;
|
||||
r[29] = (a->n[0] >> 16) & 0xFF;
|
||||
r[30] = (a->n[0] >> 8) & 0xFF;
|
||||
r[31] = a->n[0] & 0xFF;
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_impl_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m) {
|
||||
/* For all legal values of m (0..31), the following properties hold: */
|
||||
VERIFY_CHECK(0xFFFFEFFFFFC2FULL * 2 * (m + 1) >= 0xFFFFFFFFFFFFFULL * 2 * m);
|
||||
VERIFY_CHECK(0xFFFFFFFFFFFFFULL * 2 * (m + 1) >= 0xFFFFFFFFFFFFFULL * 2 * m);
|
||||
VERIFY_CHECK(0x0FFFFFFFFFFFFULL * 2 * (m + 1) >= 0x0FFFFFFFFFFFFULL * 2 * m);
|
||||
|
||||
/* Due to the properties above, the left hand in the subtractions below is never less than
|
||||
* the right hand. */
|
||||
r->n[0] = 0xFFFFEFFFFFC2FULL * 2 * (m + 1) - a->n[0];
|
||||
r->n[1] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[1];
|
||||
r->n[2] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[2];
|
||||
r->n[3] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[3];
|
||||
r->n[4] = 0x0FFFFFFFFFFFFULL * 2 * (m + 1) - a->n[4];
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_impl_mul_int_unchecked(secp256k1_fe *r, int a) {
|
||||
r->n[0] *= a;
|
||||
r->n[1] *= a;
|
||||
r->n[2] *= a;
|
||||
r->n[3] *= a;
|
||||
r->n[4] *= a;
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_impl_add_int(secp256k1_fe *r, int a) {
|
||||
r->n[0] += a;
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_impl_add(secp256k1_fe *r, const secp256k1_fe *a) {
|
||||
r->n[0] += a->n[0];
|
||||
r->n[1] += a->n[1];
|
||||
r->n[2] += a->n[2];
|
||||
r->n[3] += a->n[3];
|
||||
r->n[4] += a->n[4];
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_impl_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) {
|
||||
secp256k1_fe_mul_inner(r->n, a->n, b->n);
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp256k1_fe *a) {
|
||||
secp256k1_fe_sqr_inner(r->n, a->n);
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_impl_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {
|
||||
uint64_t mask0, mask1;
|
||||
volatile int vflag = flag;
|
||||
VERIFY_CHECK(flag == 0 || flag == 1);
|
||||
SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n));
|
||||
mask0 = vflag + ~((uint64_t)0);
|
||||
mask1 = ~mask0;
|
||||
r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);
|
||||
r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1);
|
||||
r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1);
|
||||
r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1);
|
||||
r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1);
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_fe_impl_half(secp256k1_fe *r) {
|
||||
uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4];
|
||||
uint64_t one = (uint64_t)1;
|
||||
uint64_t mask = -(t0 & one) >> 12;
|
||||
|
||||
/* Bounds analysis (over the rationals).
|
||||
*
|
||||
* Let m = r->magnitude
|
||||
* C = 0xFFFFFFFFFFFFFULL * 2
|
||||
* D = 0x0FFFFFFFFFFFFULL * 2
|
||||
*
|
||||
* Initial bounds: t0..t3 <= C * m
|
||||
* t4 <= D * m
|
||||
*/
|
||||
|
||||
t0 += 0xFFFFEFFFFFC2FULL & mask;
|
||||
t1 += mask;
|
||||
t2 += mask;
|
||||
t3 += mask;
|
||||
t4 += mask >> 4;
|
||||
|
||||
VERIFY_CHECK((t0 & one) == 0);
|
||||
|
||||
/* t0..t3: added <= C/2
|
||||
* t4: added <= D/2
|
||||
*
|
||||
* Current bounds: t0..t3 <= C * (m + 1/2)
|
||||
* t4 <= D * (m + 1/2)
|
||||
*/
|
||||
|
||||
r->n[0] = (t0 >> 1) + ((t1 & one) << 51);
|
||||
r->n[1] = (t1 >> 1) + ((t2 & one) << 51);
|
||||
r->n[2] = (t2 >> 1) + ((t3 & one) << 51);
|
||||
r->n[3] = (t3 >> 1) + ((t4 & one) << 51);
|
||||
r->n[4] = (t4 >> 1);
|
||||
|
||||
/* t0..t3: shifted right and added <= C/4 + 1/2
|
||||
* t4: shifted right
|
||||
*
|
||||
* Current bounds: t0..t3 <= C * (m/2 + 1/2)
|
||||
* t4 <= D * (m/2 + 1/4)
|
||||
*
|
||||
* Therefore the output magnitude (M) has to be set such that:
|
||||
* t0..t3: C * M >= C * (m/2 + 1/2)
|
||||
* t4: D * M >= D * (m/2 + 1/4)
|
||||
*
|
||||
* It suffices for all limbs that, for any input magnitude m:
|
||||
* M >= m/2 + 1/2
|
||||
*
|
||||
* and since we want the smallest such integer value for M:
|
||||
* M == floor(m/2) + 1
|
||||
*/
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) {
|
||||
uint64_t mask0, mask1;
|
||||
volatile int vflag = flag;
|
||||
VERIFY_CHECK(flag == 0 || flag == 1);
|
||||
SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n));
|
||||
mask0 = vflag + ~((uint64_t)0);
|
||||
mask1 = ~mask0;
|
||||
r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);
|
||||
r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1);
|
||||
r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1);
|
||||
r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) {
|
||||
r->n[0] = a->n[0] | a->n[1] << 52;
|
||||
r->n[1] = a->n[1] >> 12 | a->n[2] << 40;
|
||||
r->n[2] = a->n[2] >> 24 | a->n[3] << 28;
|
||||
r->n[3] = a->n[3] >> 36 | a->n[4] << 16;
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_fe_impl_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) {
|
||||
r->n[0] = a->n[0] & 0xFFFFFFFFFFFFFULL;
|
||||
r->n[1] = a->n[0] >> 52 | ((a->n[1] << 12) & 0xFFFFFFFFFFFFFULL);
|
||||
r->n[2] = a->n[1] >> 40 | ((a->n[2] << 24) & 0xFFFFFFFFFFFFFULL);
|
||||
r->n[3] = a->n[2] >> 28 | ((a->n[3] << 36) & 0xFFFFFFFFFFFFFULL);
|
||||
r->n[4] = a->n[3] >> 16;
|
||||
}
|
||||
|
||||
static void secp256k1_fe_from_signed62(secp256k1_fe *r, const secp256k1_modinv64_signed62 *a) {
|
||||
const uint64_t M52 = UINT64_MAX >> 12;
|
||||
const uint64_t a0 = a->v[0], a1 = a->v[1], a2 = a->v[2], a3 = a->v[3], a4 = a->v[4];
|
||||
|
||||
/* The output from secp256k1_modinv64{_var} should be normalized to range [0,modulus), and
|
||||
* have limbs in [0,2^62). The modulus is < 2^256, so the top limb must be below 2^(256-62*4).
|
||||
*/
|
||||
VERIFY_CHECK(a0 >> 62 == 0);
|
||||
VERIFY_CHECK(a1 >> 62 == 0);
|
||||
VERIFY_CHECK(a2 >> 62 == 0);
|
||||
VERIFY_CHECK(a3 >> 62 == 0);
|
||||
VERIFY_CHECK(a4 >> 8 == 0);
|
||||
|
||||
r->n[0] = a0 & M52;
|
||||
r->n[1] = (a0 >> 52 | a1 << 10) & M52;
|
||||
r->n[2] = (a1 >> 42 | a2 << 20) & M52;
|
||||
r->n[3] = (a2 >> 32 | a3 << 30) & M52;
|
||||
r->n[4] = (a3 >> 22 | a4 << 40);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_to_signed62(secp256k1_modinv64_signed62 *r, const secp256k1_fe *a) {
|
||||
const uint64_t M62 = UINT64_MAX >> 2;
|
||||
const uint64_t a0 = a->n[0], a1 = a->n[1], a2 = a->n[2], a3 = a->n[3], a4 = a->n[4];
|
||||
|
||||
r->v[0] = (a0 | a1 << 52) & M62;
|
||||
r->v[1] = (a1 >> 10 | a2 << 42) & M62;
|
||||
r->v[2] = (a2 >> 20 | a3 << 32) & M62;
|
||||
r->v[3] = (a3 >> 30 | a4 << 22) & M62;
|
||||
r->v[4] = a4 >> 40;
|
||||
}
|
||||
|
||||
static const secp256k1_modinv64_modinfo secp256k1_const_modinfo_fe = {
|
||||
{{-0x1000003D1LL, 0, 0, 0, 256}},
|
||||
0x27C7F6E22DDACACFLL
|
||||
};
|
||||
|
||||
static void secp256k1_fe_impl_inv(secp256k1_fe *r, const secp256k1_fe *x) {
|
||||
secp256k1_fe tmp = *x;
|
||||
secp256k1_modinv64_signed62 s;
|
||||
|
||||
secp256k1_fe_normalize(&tmp);
|
||||
secp256k1_fe_to_signed62(&s, &tmp);
|
||||
secp256k1_modinv64(&s, &secp256k1_const_modinfo_fe);
|
||||
secp256k1_fe_from_signed62(r, &s);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_inv_var(secp256k1_fe *r, const secp256k1_fe *x) {
|
||||
secp256k1_fe tmp = *x;
|
||||
secp256k1_modinv64_signed62 s;
|
||||
|
||||
secp256k1_fe_normalize_var(&tmp);
|
||||
secp256k1_fe_to_signed62(&s, &tmp);
|
||||
secp256k1_modinv64_var(&s, &secp256k1_const_modinfo_fe);
|
||||
secp256k1_fe_from_signed62(r, &s);
|
||||
}
|
||||
|
||||
static int secp256k1_fe_impl_is_square_var(const secp256k1_fe *x) {
|
||||
secp256k1_fe tmp;
|
||||
secp256k1_modinv64_signed62 s;
|
||||
int jac, ret;
|
||||
|
||||
tmp = *x;
|
||||
secp256k1_fe_normalize_var(&tmp);
|
||||
/* secp256k1_jacobi64_maybe_var cannot deal with input 0. */
|
||||
if (secp256k1_fe_is_zero(&tmp)) return 1;
|
||||
secp256k1_fe_to_signed62(&s, &tmp);
|
||||
jac = secp256k1_jacobi64_maybe_var(&s, &secp256k1_const_modinfo_fe);
|
||||
if (jac == 0) {
|
||||
/* secp256k1_jacobi64_maybe_var failed to compute the Jacobi symbol. Fall back
|
||||
* to computing a square root. This should be extremely rare with random
|
||||
* input (except in VERIFY mode, where a lower iteration count is used). */
|
||||
secp256k1_fe dummy;
|
||||
ret = secp256k1_fe_sqrt(&dummy, &tmp);
|
||||
} else {
|
||||
ret = jac >= 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* SECP256K1_FIELD_REPR_IMPL_H */
|
||||
@@ -0,0 +1,274 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2013, 2014 Pieter Wuille *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_FIELD_INNER5X52_IMPL_H
|
||||
#define SECP256K1_FIELD_INNER5X52_IMPL_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "int128.h"
|
||||
#include "util.h"
|
||||
|
||||
#define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0)
|
||||
#define VERIFY_BITS_128(x, n) VERIFY_CHECK(secp256k1_u128_check_bits((x), (n)))
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) {
|
||||
secp256k1_uint128 c, d;
|
||||
uint64_t t3, t4, tx, u0;
|
||||
uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4];
|
||||
const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL;
|
||||
|
||||
VERIFY_BITS(a[0], 56);
|
||||
VERIFY_BITS(a[1], 56);
|
||||
VERIFY_BITS(a[2], 56);
|
||||
VERIFY_BITS(a[3], 56);
|
||||
VERIFY_BITS(a[4], 52);
|
||||
VERIFY_BITS(b[0], 56);
|
||||
VERIFY_BITS(b[1], 56);
|
||||
VERIFY_BITS(b[2], 56);
|
||||
VERIFY_BITS(b[3], 56);
|
||||
VERIFY_BITS(b[4], 52);
|
||||
VERIFY_CHECK(r != b);
|
||||
VERIFY_CHECK(a != b);
|
||||
|
||||
/* [... a b c] is a shorthand for ... + a<<104 + b<<52 + c<<0 mod n.
|
||||
* for 0 <= x <= 4, px is a shorthand for sum(a[i]*b[x-i], i=0..x).
|
||||
* for 4 <= x <= 8, px is a shorthand for sum(a[i]*b[x-i], i=(x-4)..4)
|
||||
* Note that [x 0 0 0 0 0] = [x*R].
|
||||
*/
|
||||
|
||||
secp256k1_u128_mul(&d, a0, b[3]);
|
||||
secp256k1_u128_accum_mul(&d, a1, b[2]);
|
||||
secp256k1_u128_accum_mul(&d, a2, b[1]);
|
||||
secp256k1_u128_accum_mul(&d, a3, b[0]);
|
||||
VERIFY_BITS_128(&d, 114);
|
||||
/* [d 0 0 0] = [p3 0 0 0] */
|
||||
secp256k1_u128_mul(&c, a4, b[4]);
|
||||
VERIFY_BITS_128(&c, 112);
|
||||
/* [c 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */
|
||||
secp256k1_u128_accum_mul(&d, R, secp256k1_u128_to_u64(&c)); secp256k1_u128_rshift(&c, 64);
|
||||
VERIFY_BITS_128(&d, 115);
|
||||
VERIFY_BITS_128(&c, 48);
|
||||
/* [(c<<12) 0 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */
|
||||
t3 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52);
|
||||
VERIFY_BITS(t3, 52);
|
||||
VERIFY_BITS_128(&d, 63);
|
||||
/* [(c<<12) 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */
|
||||
|
||||
secp256k1_u128_accum_mul(&d, a0, b[4]);
|
||||
secp256k1_u128_accum_mul(&d, a1, b[3]);
|
||||
secp256k1_u128_accum_mul(&d, a2, b[2]);
|
||||
secp256k1_u128_accum_mul(&d, a3, b[1]);
|
||||
secp256k1_u128_accum_mul(&d, a4, b[0]);
|
||||
VERIFY_BITS_128(&d, 115);
|
||||
/* [(c<<12) 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
|
||||
secp256k1_u128_accum_mul(&d, R << 12, secp256k1_u128_to_u64(&c));
|
||||
VERIFY_BITS_128(&d, 116);
|
||||
/* [d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
|
||||
t4 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52);
|
||||
VERIFY_BITS(t4, 52);
|
||||
VERIFY_BITS_128(&d, 64);
|
||||
/* [d t4 t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
|
||||
tx = (t4 >> 48); t4 &= (M >> 4);
|
||||
VERIFY_BITS(tx, 4);
|
||||
VERIFY_BITS(t4, 48);
|
||||
/* [d t4+(tx<<48) t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
|
||||
|
||||
secp256k1_u128_mul(&c, a0, b[0]);
|
||||
VERIFY_BITS_128(&c, 112);
|
||||
/* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 0 p4 p3 0 0 p0] */
|
||||
secp256k1_u128_accum_mul(&d, a1, b[4]);
|
||||
secp256k1_u128_accum_mul(&d, a2, b[3]);
|
||||
secp256k1_u128_accum_mul(&d, a3, b[2]);
|
||||
secp256k1_u128_accum_mul(&d, a4, b[1]);
|
||||
VERIFY_BITS_128(&d, 114);
|
||||
/* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
|
||||
u0 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52);
|
||||
VERIFY_BITS(u0, 52);
|
||||
VERIFY_BITS_128(&d, 62);
|
||||
/* [d u0 t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
|
||||
/* [d 0 t4+(tx<<48)+(u0<<52) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
|
||||
u0 = (u0 << 4) | tx;
|
||||
VERIFY_BITS(u0, 56);
|
||||
/* [d 0 t4+(u0<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
|
||||
secp256k1_u128_accum_mul(&c, u0, R >> 4);
|
||||
VERIFY_BITS_128(&c, 113);
|
||||
/* [d 0 t4 t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
|
||||
r[0] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52);
|
||||
VERIFY_BITS(r[0], 52);
|
||||
VERIFY_BITS_128(&c, 61);
|
||||
/* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 0 p0] */
|
||||
|
||||
secp256k1_u128_accum_mul(&c, a0, b[1]);
|
||||
secp256k1_u128_accum_mul(&c, a1, b[0]);
|
||||
VERIFY_BITS_128(&c, 114);
|
||||
/* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 p1 p0] */
|
||||
secp256k1_u128_accum_mul(&d, a2, b[4]);
|
||||
secp256k1_u128_accum_mul(&d, a3, b[3]);
|
||||
secp256k1_u128_accum_mul(&d, a4, b[2]);
|
||||
VERIFY_BITS_128(&d, 114);
|
||||
/* [d 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */
|
||||
secp256k1_u128_accum_mul(&c, secp256k1_u128_to_u64(&d) & M, R); secp256k1_u128_rshift(&d, 52);
|
||||
VERIFY_BITS_128(&c, 115);
|
||||
VERIFY_BITS_128(&d, 62);
|
||||
/* [d 0 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */
|
||||
r[1] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52);
|
||||
VERIFY_BITS(r[1], 52);
|
||||
VERIFY_BITS_128(&c, 63);
|
||||
/* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */
|
||||
|
||||
secp256k1_u128_accum_mul(&c, a0, b[2]);
|
||||
secp256k1_u128_accum_mul(&c, a1, b[1]);
|
||||
secp256k1_u128_accum_mul(&c, a2, b[0]);
|
||||
VERIFY_BITS_128(&c, 114);
|
||||
/* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 p2 p1 p0] */
|
||||
secp256k1_u128_accum_mul(&d, a3, b[4]);
|
||||
secp256k1_u128_accum_mul(&d, a4, b[3]);
|
||||
VERIFY_BITS_128(&d, 114);
|
||||
/* [d 0 0 t4 t3 c t1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
|
||||
secp256k1_u128_accum_mul(&c, R, secp256k1_u128_to_u64(&d)); secp256k1_u128_rshift(&d, 64);
|
||||
VERIFY_BITS_128(&c, 115);
|
||||
VERIFY_BITS_128(&d, 50);
|
||||
/* [(d<<12) 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
|
||||
|
||||
r[2] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52);
|
||||
VERIFY_BITS(r[2], 52);
|
||||
VERIFY_BITS_128(&c, 63);
|
||||
/* [(d<<12) 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
|
||||
secp256k1_u128_accum_mul(&c, R << 12, secp256k1_u128_to_u64(&d));
|
||||
secp256k1_u128_accum_u64(&c, t3);
|
||||
VERIFY_BITS_128(&c, 100);
|
||||
/* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
|
||||
r[3] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52);
|
||||
VERIFY_BITS(r[3], 52);
|
||||
VERIFY_BITS_128(&c, 48);
|
||||
/* [t4+c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
|
||||
r[4] = secp256k1_u128_to_u64(&c) + t4;
|
||||
VERIFY_BITS(r[4], 49);
|
||||
/* [r4 r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t *a) {
|
||||
secp256k1_uint128 c, d;
|
||||
uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4];
|
||||
uint64_t t3, t4, tx, u0;
|
||||
const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL;
|
||||
|
||||
VERIFY_BITS(a[0], 56);
|
||||
VERIFY_BITS(a[1], 56);
|
||||
VERIFY_BITS(a[2], 56);
|
||||
VERIFY_BITS(a[3], 56);
|
||||
VERIFY_BITS(a[4], 52);
|
||||
|
||||
/** [... a b c] is a shorthand for ... + a<<104 + b<<52 + c<<0 mod n.
|
||||
* px is a shorthand for sum(a[i]*a[x-i], i=0..x).
|
||||
* Note that [x 0 0 0 0 0] = [x*R].
|
||||
*/
|
||||
|
||||
secp256k1_u128_mul(&d, a0*2, a3);
|
||||
secp256k1_u128_accum_mul(&d, a1*2, a2);
|
||||
VERIFY_BITS_128(&d, 114);
|
||||
/* [d 0 0 0] = [p3 0 0 0] */
|
||||
secp256k1_u128_mul(&c, a4, a4);
|
||||
VERIFY_BITS_128(&c, 112);
|
||||
/* [c 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */
|
||||
secp256k1_u128_accum_mul(&d, R, secp256k1_u128_to_u64(&c)); secp256k1_u128_rshift(&c, 64);
|
||||
VERIFY_BITS_128(&d, 115);
|
||||
VERIFY_BITS_128(&c, 48);
|
||||
/* [(c<<12) 0 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */
|
||||
t3 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52);
|
||||
VERIFY_BITS(t3, 52);
|
||||
VERIFY_BITS_128(&d, 63);
|
||||
/* [(c<<12) 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */
|
||||
|
||||
a4 *= 2;
|
||||
secp256k1_u128_accum_mul(&d, a0, a4);
|
||||
secp256k1_u128_accum_mul(&d, a1*2, a3);
|
||||
secp256k1_u128_accum_mul(&d, a2, a2);
|
||||
VERIFY_BITS_128(&d, 115);
|
||||
/* [(c<<12) 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
|
||||
secp256k1_u128_accum_mul(&d, R << 12, secp256k1_u128_to_u64(&c));
|
||||
VERIFY_BITS_128(&d, 116);
|
||||
/* [d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
|
||||
t4 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52);
|
||||
VERIFY_BITS(t4, 52);
|
||||
VERIFY_BITS_128(&d, 64);
|
||||
/* [d t4 t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
|
||||
tx = (t4 >> 48); t4 &= (M >> 4);
|
||||
VERIFY_BITS(tx, 4);
|
||||
VERIFY_BITS(t4, 48);
|
||||
/* [d t4+(tx<<48) t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
|
||||
|
||||
secp256k1_u128_mul(&c, a0, a0);
|
||||
VERIFY_BITS_128(&c, 112);
|
||||
/* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 0 p4 p3 0 0 p0] */
|
||||
secp256k1_u128_accum_mul(&d, a1, a4);
|
||||
secp256k1_u128_accum_mul(&d, a2*2, a3);
|
||||
VERIFY_BITS_128(&d, 114);
|
||||
/* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
|
||||
u0 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52);
|
||||
VERIFY_BITS(u0, 52);
|
||||
VERIFY_BITS_128(&d, 62);
|
||||
/* [d u0 t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
|
||||
/* [d 0 t4+(tx<<48)+(u0<<52) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
|
||||
u0 = (u0 << 4) | tx;
|
||||
VERIFY_BITS(u0, 56);
|
||||
/* [d 0 t4+(u0<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
|
||||
secp256k1_u128_accum_mul(&c, u0, R >> 4);
|
||||
VERIFY_BITS_128(&c, 113);
|
||||
/* [d 0 t4 t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
|
||||
r[0] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52);
|
||||
VERIFY_BITS(r[0], 52);
|
||||
VERIFY_BITS_128(&c, 61);
|
||||
/* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 0 p0] */
|
||||
|
||||
a0 *= 2;
|
||||
secp256k1_u128_accum_mul(&c, a0, a1);
|
||||
VERIFY_BITS_128(&c, 114);
|
||||
/* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 p1 p0] */
|
||||
secp256k1_u128_accum_mul(&d, a2, a4);
|
||||
secp256k1_u128_accum_mul(&d, a3, a3);
|
||||
VERIFY_BITS_128(&d, 114);
|
||||
/* [d 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */
|
||||
secp256k1_u128_accum_mul(&c, secp256k1_u128_to_u64(&d) & M, R); secp256k1_u128_rshift(&d, 52);
|
||||
VERIFY_BITS_128(&c, 115);
|
||||
VERIFY_BITS_128(&d, 62);
|
||||
/* [d 0 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */
|
||||
r[1] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52);
|
||||
VERIFY_BITS(r[1], 52);
|
||||
VERIFY_BITS_128(&c, 63);
|
||||
/* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */
|
||||
|
||||
secp256k1_u128_accum_mul(&c, a0, a2);
|
||||
secp256k1_u128_accum_mul(&c, a1, a1);
|
||||
VERIFY_BITS_128(&c, 114);
|
||||
/* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 p2 p1 p0] */
|
||||
secp256k1_u128_accum_mul(&d, a3, a4);
|
||||
VERIFY_BITS_128(&d, 114);
|
||||
/* [d 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
|
||||
secp256k1_u128_accum_mul(&c, R, secp256k1_u128_to_u64(&d)); secp256k1_u128_rshift(&d, 64);
|
||||
VERIFY_BITS_128(&c, 115);
|
||||
VERIFY_BITS_128(&d, 50);
|
||||
/* [(d<<12) 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
|
||||
r[2] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52);
|
||||
VERIFY_BITS(r[2], 52);
|
||||
VERIFY_BITS_128(&c, 63);
|
||||
/* [(d<<12) 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
|
||||
|
||||
secp256k1_u128_accum_mul(&c, R << 12, secp256k1_u128_to_u64(&d));
|
||||
secp256k1_u128_accum_u64(&c, t3);
|
||||
VERIFY_BITS_128(&c, 100);
|
||||
/* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
|
||||
r[3] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52);
|
||||
VERIFY_BITS(r[3], 52);
|
||||
VERIFY_BITS_128(&c, 48);
|
||||
/* [t4+c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
|
||||
r[4] = secp256k1_u128_to_u64(&c) + t4;
|
||||
VERIFY_BITS(r[4], 49);
|
||||
/* [r4 r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
|
||||
}
|
||||
|
||||
#endif /* SECP256K1_FIELD_INNER5X52_IMPL_H */
|
||||
457
firmware/kb2040_hidden_signer/src/secp256k1/src/field_impl.h
Normal file
457
firmware/kb2040_hidden_signer/src/secp256k1/src/field_impl.h
Normal file
@@ -0,0 +1,457 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2013, 2014 Pieter Wuille *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_FIELD_IMPL_H
|
||||
#define SECP256K1_FIELD_IMPL_H
|
||||
|
||||
#include "field.h"
|
||||
#include "util.h"
|
||||
|
||||
#if defined(SECP256K1_WIDEMUL_INT128)
|
||||
#include "field_5x52_impl.h"
|
||||
#elif defined(SECP256K1_WIDEMUL_INT64)
|
||||
#include "field_10x26_impl.h"
|
||||
#else
|
||||
#error "Please select wide multiplication implementation"
|
||||
#endif
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) {
|
||||
secp256k1_memclear_explicit(a, sizeof(secp256k1_fe));
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) {
|
||||
secp256k1_fe na;
|
||||
SECP256K1_FE_VERIFY(a);
|
||||
SECP256K1_FE_VERIFY(b);
|
||||
SECP256K1_FE_VERIFY_MAGNITUDE(a, 1);
|
||||
SECP256K1_FE_VERIFY_MAGNITUDE(b, 31);
|
||||
|
||||
secp256k1_fe_negate(&na, a, 1);
|
||||
secp256k1_fe_add(&na, b);
|
||||
return secp256k1_fe_normalizes_to_zero(&na);
|
||||
}
|
||||
|
||||
static int secp256k1_fe_sqrt(secp256k1_fe * SECP256K1_RESTRICT r, const secp256k1_fe * SECP256K1_RESTRICT a) {
|
||||
/** Given that p is congruent to 3 mod 4, we can compute the square root of
|
||||
* a mod p as the (p+1)/4'th power of a.
|
||||
*
|
||||
* As (p+1)/4 is an even number, it will have the same result for a and for
|
||||
* (-a). Only one of these two numbers actually has a square root however,
|
||||
* so we test at the end by squaring and comparing to the input.
|
||||
* Also because (p+1)/4 is an even number, the computed square root is
|
||||
* itself always a square (a ** ((p+1)/4) is the square of a ** ((p+1)/8)).
|
||||
*/
|
||||
secp256k1_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1;
|
||||
int j, ret;
|
||||
|
||||
VERIFY_CHECK(r != a);
|
||||
SECP256K1_FE_VERIFY(a);
|
||||
SECP256K1_FE_VERIFY_MAGNITUDE(a, 8);
|
||||
|
||||
/** The binary representation of (p + 1)/4 has 3 blocks of 1s, with lengths in
|
||||
* { 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block:
|
||||
* 1, [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223]
|
||||
*/
|
||||
|
||||
secp256k1_fe_sqr(&x2, a);
|
||||
secp256k1_fe_mul(&x2, &x2, a);
|
||||
|
||||
secp256k1_fe_sqr(&x3, &x2);
|
||||
secp256k1_fe_mul(&x3, &x3, a);
|
||||
|
||||
x6 = x3;
|
||||
for (j=0; j<3; j++) {
|
||||
secp256k1_fe_sqr(&x6, &x6);
|
||||
}
|
||||
secp256k1_fe_mul(&x6, &x6, &x3);
|
||||
|
||||
x9 = x6;
|
||||
for (j=0; j<3; j++) {
|
||||
secp256k1_fe_sqr(&x9, &x9);
|
||||
}
|
||||
secp256k1_fe_mul(&x9, &x9, &x3);
|
||||
|
||||
x11 = x9;
|
||||
for (j=0; j<2; j++) {
|
||||
secp256k1_fe_sqr(&x11, &x11);
|
||||
}
|
||||
secp256k1_fe_mul(&x11, &x11, &x2);
|
||||
|
||||
x22 = x11;
|
||||
for (j=0; j<11; j++) {
|
||||
secp256k1_fe_sqr(&x22, &x22);
|
||||
}
|
||||
secp256k1_fe_mul(&x22, &x22, &x11);
|
||||
|
||||
x44 = x22;
|
||||
for (j=0; j<22; j++) {
|
||||
secp256k1_fe_sqr(&x44, &x44);
|
||||
}
|
||||
secp256k1_fe_mul(&x44, &x44, &x22);
|
||||
|
||||
x88 = x44;
|
||||
for (j=0; j<44; j++) {
|
||||
secp256k1_fe_sqr(&x88, &x88);
|
||||
}
|
||||
secp256k1_fe_mul(&x88, &x88, &x44);
|
||||
|
||||
x176 = x88;
|
||||
for (j=0; j<88; j++) {
|
||||
secp256k1_fe_sqr(&x176, &x176);
|
||||
}
|
||||
secp256k1_fe_mul(&x176, &x176, &x88);
|
||||
|
||||
x220 = x176;
|
||||
for (j=0; j<44; j++) {
|
||||
secp256k1_fe_sqr(&x220, &x220);
|
||||
}
|
||||
secp256k1_fe_mul(&x220, &x220, &x44);
|
||||
|
||||
x223 = x220;
|
||||
for (j=0; j<3; j++) {
|
||||
secp256k1_fe_sqr(&x223, &x223);
|
||||
}
|
||||
secp256k1_fe_mul(&x223, &x223, &x3);
|
||||
|
||||
/* The final result is then assembled using a sliding window over the blocks. */
|
||||
|
||||
t1 = x223;
|
||||
for (j=0; j<23; j++) {
|
||||
secp256k1_fe_sqr(&t1, &t1);
|
||||
}
|
||||
secp256k1_fe_mul(&t1, &t1, &x22);
|
||||
for (j=0; j<6; j++) {
|
||||
secp256k1_fe_sqr(&t1, &t1);
|
||||
}
|
||||
secp256k1_fe_mul(&t1, &t1, &x2);
|
||||
secp256k1_fe_sqr(&t1, &t1);
|
||||
secp256k1_fe_sqr(r, &t1);
|
||||
|
||||
/* Check that a square root was actually calculated */
|
||||
|
||||
secp256k1_fe_sqr(&t1, r);
|
||||
ret = secp256k1_fe_equal(&t1, a);
|
||||
|
||||
#ifdef VERIFY
|
||||
if (!ret) {
|
||||
secp256k1_fe_negate(&t1, &t1, 1);
|
||||
secp256k1_fe_normalize_var(&t1);
|
||||
VERIFY_CHECK(secp256k1_fe_equal(&t1, a));
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifndef VERIFY
|
||||
static void secp256k1_fe_verify(const secp256k1_fe *a) { (void)a; }
|
||||
static void secp256k1_fe_verify_magnitude(const secp256k1_fe *a, int m) { (void)a; (void)m; }
|
||||
#else
|
||||
static void secp256k1_fe_impl_verify(const secp256k1_fe *a);
|
||||
static void secp256k1_fe_verify(const secp256k1_fe *a) {
|
||||
/* Magnitude between 0 and 32. */
|
||||
SECP256K1_FE_VERIFY_MAGNITUDE(a, 32);
|
||||
/* Normalized is 0 or 1. */
|
||||
VERIFY_CHECK((a->normalized == 0) || (a->normalized == 1));
|
||||
/* If normalized, magnitude must be 0 or 1. */
|
||||
if (a->normalized) SECP256K1_FE_VERIFY_MAGNITUDE(a, 1);
|
||||
/* Invoke implementation-specific checks. */
|
||||
secp256k1_fe_impl_verify(a);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_verify_magnitude(const secp256k1_fe *a, int m) {
|
||||
VERIFY_CHECK(m >= 0);
|
||||
VERIFY_CHECK(m <= 32);
|
||||
VERIFY_CHECK(a->magnitude <= m);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_normalize(secp256k1_fe *r);
|
||||
SECP256K1_INLINE static void secp256k1_fe_normalize(secp256k1_fe *r) {
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
|
||||
secp256k1_fe_impl_normalize(r);
|
||||
r->magnitude = 1;
|
||||
r->normalized = 1;
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_normalize_weak(secp256k1_fe *r);
|
||||
SECP256K1_INLINE static void secp256k1_fe_normalize_weak(secp256k1_fe *r) {
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
|
||||
secp256k1_fe_impl_normalize_weak(r);
|
||||
r->magnitude = 1;
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_normalize_var(secp256k1_fe *r);
|
||||
SECP256K1_INLINE static void secp256k1_fe_normalize_var(secp256k1_fe *r) {
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
|
||||
secp256k1_fe_impl_normalize_var(r);
|
||||
r->magnitude = 1;
|
||||
r->normalized = 1;
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static int secp256k1_fe_impl_normalizes_to_zero(const secp256k1_fe *r);
|
||||
SECP256K1_INLINE static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) {
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
|
||||
return secp256k1_fe_impl_normalizes_to_zero(r);
|
||||
}
|
||||
|
||||
static int secp256k1_fe_impl_normalizes_to_zero_var(const secp256k1_fe *r);
|
||||
SECP256K1_INLINE static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r) {
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
|
||||
return secp256k1_fe_impl_normalizes_to_zero_var(r);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_set_int(secp256k1_fe *r, int a);
|
||||
SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) {
|
||||
VERIFY_CHECK(0 <= a && a <= 0x7FFF);
|
||||
|
||||
secp256k1_fe_impl_set_int(r, a);
|
||||
r->magnitude = (a != 0);
|
||||
r->normalized = 1;
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_add_int(secp256k1_fe *r, int a);
|
||||
SECP256K1_INLINE static void secp256k1_fe_add_int(secp256k1_fe *r, int a) {
|
||||
VERIFY_CHECK(0 <= a && a <= 0x7FFF);
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
|
||||
secp256k1_fe_impl_add_int(r, a);
|
||||
r->magnitude += 1;
|
||||
r->normalized = 0;
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static int secp256k1_fe_impl_is_zero(const secp256k1_fe *a);
|
||||
SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) {
|
||||
SECP256K1_FE_VERIFY(a);
|
||||
VERIFY_CHECK(a->normalized);
|
||||
|
||||
return secp256k1_fe_impl_is_zero(a);
|
||||
}
|
||||
|
||||
static int secp256k1_fe_impl_is_odd(const secp256k1_fe *a);
|
||||
SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) {
|
||||
SECP256K1_FE_VERIFY(a);
|
||||
VERIFY_CHECK(a->normalized);
|
||||
|
||||
return secp256k1_fe_impl_is_odd(a);
|
||||
}
|
||||
|
||||
static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b);
|
||||
SECP256K1_INLINE static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
|
||||
SECP256K1_FE_VERIFY(a);
|
||||
SECP256K1_FE_VERIFY(b);
|
||||
VERIFY_CHECK(a->normalized);
|
||||
VERIFY_CHECK(b->normalized);
|
||||
|
||||
return secp256k1_fe_impl_cmp_var(a, b);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_set_b32_mod(secp256k1_fe *r, const unsigned char *a);
|
||||
SECP256K1_INLINE static void secp256k1_fe_set_b32_mod(secp256k1_fe *r, const unsigned char *a) {
|
||||
secp256k1_fe_impl_set_b32_mod(r, a);
|
||||
r->magnitude = 1;
|
||||
r->normalized = 0;
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static int secp256k1_fe_impl_set_b32_limit(secp256k1_fe *r, const unsigned char *a);
|
||||
SECP256K1_INLINE static int secp256k1_fe_set_b32_limit(secp256k1_fe *r, const unsigned char *a) {
|
||||
if (secp256k1_fe_impl_set_b32_limit(r, a)) {
|
||||
r->magnitude = 1;
|
||||
r->normalized = 1;
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
return 1;
|
||||
} else {
|
||||
/* Mark the output field element as invalid. */
|
||||
r->magnitude = -1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a);
|
||||
SECP256K1_INLINE static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) {
|
||||
SECP256K1_FE_VERIFY(a);
|
||||
VERIFY_CHECK(a->normalized);
|
||||
|
||||
secp256k1_fe_impl_get_b32(r, a);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m);
|
||||
SECP256K1_INLINE static void secp256k1_fe_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m) {
|
||||
SECP256K1_FE_VERIFY(a);
|
||||
VERIFY_CHECK(m >= 0 && m <= 31);
|
||||
SECP256K1_FE_VERIFY_MAGNITUDE(a, m);
|
||||
|
||||
secp256k1_fe_impl_negate_unchecked(r, a, m);
|
||||
r->magnitude = m + 1;
|
||||
r->normalized = 0;
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_mul_int_unchecked(secp256k1_fe *r, int a);
|
||||
SECP256K1_INLINE static void secp256k1_fe_mul_int_unchecked(secp256k1_fe *r, int a) {
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
|
||||
VERIFY_CHECK(a >= 0 && a <= 32);
|
||||
VERIFY_CHECK(a*r->magnitude <= 32);
|
||||
secp256k1_fe_impl_mul_int_unchecked(r, a);
|
||||
r->magnitude *= a;
|
||||
r->normalized = 0;
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_add(secp256k1_fe *r, const secp256k1_fe *a);
|
||||
SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) {
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
SECP256K1_FE_VERIFY(a);
|
||||
VERIFY_CHECK(r->magnitude + a->magnitude <= 32);
|
||||
|
||||
secp256k1_fe_impl_add(r, a);
|
||||
r->magnitude += a->magnitude;
|
||||
r->normalized = 0;
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b);
|
||||
SECP256K1_INLINE static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) {
|
||||
SECP256K1_FE_VERIFY(a);
|
||||
SECP256K1_FE_VERIFY(b);
|
||||
SECP256K1_FE_VERIFY_MAGNITUDE(a, 8);
|
||||
SECP256K1_FE_VERIFY_MAGNITUDE(b, 8);
|
||||
VERIFY_CHECK(r != b);
|
||||
VERIFY_CHECK(a != b);
|
||||
|
||||
secp256k1_fe_impl_mul(r, a, b);
|
||||
r->magnitude = 1;
|
||||
r->normalized = 0;
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp256k1_fe *a);
|
||||
SECP256K1_INLINE static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) {
|
||||
SECP256K1_FE_VERIFY(a);
|
||||
SECP256K1_FE_VERIFY_MAGNITUDE(a, 8);
|
||||
|
||||
secp256k1_fe_impl_sqr(r, a);
|
||||
r->magnitude = 1;
|
||||
r->normalized = 0;
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag);
|
||||
SECP256K1_INLINE static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {
|
||||
VERIFY_CHECK(flag == 0 || flag == 1);
|
||||
SECP256K1_FE_VERIFY(a);
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
|
||||
secp256k1_fe_impl_cmov(r, a, flag);
|
||||
if (a->magnitude > r->magnitude) r->magnitude = a->magnitude;
|
||||
if (!a->normalized) r->normalized = 0;
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a);
|
||||
SECP256K1_INLINE static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) {
|
||||
SECP256K1_FE_VERIFY(a);
|
||||
VERIFY_CHECK(a->normalized);
|
||||
|
||||
secp256k1_fe_impl_to_storage(r, a);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a);
|
||||
SECP256K1_INLINE static void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) {
|
||||
secp256k1_fe_impl_from_storage(r, a);
|
||||
r->magnitude = 1;
|
||||
r->normalized = 1;
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_inv(secp256k1_fe *r, const secp256k1_fe *x);
|
||||
SECP256K1_INLINE static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *x) {
|
||||
int input_is_zero = secp256k1_fe_normalizes_to_zero(x);
|
||||
SECP256K1_FE_VERIFY(x);
|
||||
|
||||
secp256k1_fe_impl_inv(r, x);
|
||||
r->magnitude = x->magnitude > 0;
|
||||
r->normalized = 1;
|
||||
|
||||
VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == input_is_zero);
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_inv_var(secp256k1_fe *r, const secp256k1_fe *x);
|
||||
SECP256K1_INLINE static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *x) {
|
||||
int input_is_zero = secp256k1_fe_normalizes_to_zero(x);
|
||||
SECP256K1_FE_VERIFY(x);
|
||||
|
||||
secp256k1_fe_impl_inv_var(r, x);
|
||||
r->magnitude = x->magnitude > 0;
|
||||
r->normalized = 1;
|
||||
|
||||
VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == input_is_zero);
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static int secp256k1_fe_impl_is_square_var(const secp256k1_fe *x);
|
||||
SECP256K1_INLINE static int secp256k1_fe_is_square_var(const secp256k1_fe *x) {
|
||||
int ret;
|
||||
secp256k1_fe tmp = *x, sqrt;
|
||||
SECP256K1_FE_VERIFY(x);
|
||||
|
||||
ret = secp256k1_fe_impl_is_square_var(x);
|
||||
secp256k1_fe_normalize_weak(&tmp);
|
||||
VERIFY_CHECK(ret == secp256k1_fe_sqrt(&sqrt, &tmp));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_get_bounds(secp256k1_fe* r, int m);
|
||||
SECP256K1_INLINE static void secp256k1_fe_get_bounds(secp256k1_fe* r, int m) {
|
||||
VERIFY_CHECK(m >= 0);
|
||||
VERIFY_CHECK(m <= 32);
|
||||
|
||||
secp256k1_fe_impl_get_bounds(r, m);
|
||||
r->magnitude = m;
|
||||
r->normalized = (m == 0);
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_half(secp256k1_fe *r);
|
||||
SECP256K1_INLINE static void secp256k1_fe_half(secp256k1_fe *r) {
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
SECP256K1_FE_VERIFY_MAGNITUDE(r, 31);
|
||||
|
||||
secp256k1_fe_impl_half(r);
|
||||
r->magnitude = (r->magnitude >> 1) + 1;
|
||||
r->normalized = 0;
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
#endif /* defined(VERIFY) */
|
||||
|
||||
#endif /* SECP256K1_FIELD_IMPL_H */
|
||||
218
firmware/kb2040_hidden_signer/src/secp256k1/src/group.h
Normal file
218
firmware/kb2040_hidden_signer/src/secp256k1/src/group.h
Normal file
@@ -0,0 +1,218 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2013, 2014 Pieter Wuille *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_GROUP_H
|
||||
#define SECP256K1_GROUP_H
|
||||
|
||||
#include "field.h"
|
||||
|
||||
/** A group element in affine coordinates on the secp256k1 curve,
|
||||
* or occasionally on an isomorphic curve of the form y^2 = x^3 + 7*t^6.
|
||||
* Note: For exhaustive test mode, secp256k1 is replaced by a small subgroup of a different curve.
|
||||
*/
|
||||
typedef struct {
|
||||
secp256k1_fe x;
|
||||
secp256k1_fe y;
|
||||
int infinity; /* whether this represents the point at infinity */
|
||||
} secp256k1_ge;
|
||||
|
||||
#define SECP256K1_GE_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_CONST((i),(j),(k),(l),(m),(n),(o),(p)), 0}
|
||||
#define SECP256K1_GE_CONST_INFINITY {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), 1}
|
||||
|
||||
/** A group element of the secp256k1 curve, in jacobian coordinates.
|
||||
* Note: For exhastive test mode, secp256k1 is replaced by a small subgroup of a different curve.
|
||||
*/
|
||||
typedef struct {
|
||||
secp256k1_fe x; /* actual X: x/z^2 */
|
||||
secp256k1_fe y; /* actual Y: y/z^3 */
|
||||
secp256k1_fe z;
|
||||
int infinity; /* whether this represents the point at infinity */
|
||||
} secp256k1_gej;
|
||||
|
||||
#define SECP256K1_GEJ_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_CONST((i),(j),(k),(l),(m),(n),(o),(p)), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1), 0}
|
||||
#define SECP256K1_GEJ_CONST_INFINITY {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), 1}
|
||||
|
||||
typedef struct {
|
||||
secp256k1_fe_storage x;
|
||||
secp256k1_fe_storage y;
|
||||
} secp256k1_ge_storage;
|
||||
|
||||
#define SECP256K1_GE_STORAGE_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_STORAGE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_STORAGE_CONST((i),(j),(k),(l),(m),(n),(o),(p))}
|
||||
|
||||
#define SECP256K1_GE_STORAGE_CONST_GET(t) SECP256K1_FE_STORAGE_CONST_GET(t.x), SECP256K1_FE_STORAGE_CONST_GET(t.y)
|
||||
|
||||
/** Maximum allowed magnitudes for group element coordinates
|
||||
* in affine (x, y) and jacobian (x, y, z) representation. */
|
||||
#define SECP256K1_GE_X_MAGNITUDE_MAX 4
|
||||
#define SECP256K1_GE_Y_MAGNITUDE_MAX 3
|
||||
#define SECP256K1_GEJ_X_MAGNITUDE_MAX 4
|
||||
#define SECP256K1_GEJ_Y_MAGNITUDE_MAX 4
|
||||
#define SECP256K1_GEJ_Z_MAGNITUDE_MAX 1
|
||||
|
||||
/** Set a group element equal to the point with given X and Y coordinates */
|
||||
static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const secp256k1_fe *y);
|
||||
|
||||
/** Set a group element (affine) equal to the point with the given X coordinate, and given oddness
|
||||
* for Y. Return value indicates whether the result is valid. */
|
||||
static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd);
|
||||
|
||||
/** Determine whether x is a valid X coordinate on the curve. */
|
||||
static int secp256k1_ge_x_on_curve_var(const secp256k1_fe *x);
|
||||
|
||||
/** Determine whether fraction xn/xd is a valid X coordinate on the curve (xd != 0). */
|
||||
static int secp256k1_ge_x_frac_on_curve_var(const secp256k1_fe *xn, const secp256k1_fe *xd);
|
||||
|
||||
/** Check whether a group element is the point at infinity. */
|
||||
static int secp256k1_ge_is_infinity(const secp256k1_ge *a);
|
||||
|
||||
/** Check whether a group element is valid (i.e., on the curve). */
|
||||
static int secp256k1_ge_is_valid_var(const secp256k1_ge *a);
|
||||
|
||||
/** Set r equal to the inverse of a (i.e., mirrored around the X axis) */
|
||||
static void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a);
|
||||
|
||||
/** Set a group element equal to another which is given in jacobian coordinates. Constant time. */
|
||||
static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a);
|
||||
|
||||
/** Set a group element equal to another which is given in jacobian coordinates. */
|
||||
static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a);
|
||||
|
||||
/** Set group elements r[0:len] (affine) equal to group elements a[0:len] (jacobian).
|
||||
* None of the group elements in a[0:len] may be infinity. Constant time. */
|
||||
static void secp256k1_ge_set_all_gej(secp256k1_ge *r, const secp256k1_gej *a, size_t len);
|
||||
|
||||
/** Set group elements r[0:len] (affine) equal to group elements a[0:len] (jacobian). */
|
||||
static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len);
|
||||
|
||||
/** Bring a batch of inputs to the same global z "denominator", based on ratios between
|
||||
* (omitted) z coordinates of adjacent elements.
|
||||
*
|
||||
* Although the elements a[i] are _ge rather than _gej, they actually represent elements
|
||||
* in Jacobian coordinates with their z coordinates omitted.
|
||||
*
|
||||
* Using the notation z(b) to represent the omitted z coordinate of b, the array zr of
|
||||
* z coordinate ratios must satisfy zr[i] == z(a[i]) / z(a[i-1]) for 0 < 'i' < len.
|
||||
* The zr[0] value is unused.
|
||||
*
|
||||
* This function adjusts the coordinates of 'a' in place so that for all 'i', z(a[i]) == z(a[len-1]).
|
||||
* In other words, the initial value of z(a[len-1]) becomes the global z "denominator". Only the
|
||||
* a[i].x and a[i].y coordinates are explicitly modified; the adjustment of the omitted z coordinate is
|
||||
* implicit.
|
||||
*
|
||||
* The coordinates of the final element a[len-1] are not changed.
|
||||
*/
|
||||
static void secp256k1_ge_table_set_globalz(size_t len, secp256k1_ge *a, const secp256k1_fe *zr);
|
||||
|
||||
/** Check two group elements (affine) for equality in variable time. */
|
||||
static int secp256k1_ge_eq_var(const secp256k1_ge *a, const secp256k1_ge *b);
|
||||
|
||||
/** Set a group element (affine) equal to the point at infinity. */
|
||||
static void secp256k1_ge_set_infinity(secp256k1_ge *r);
|
||||
|
||||
/** Set a group element (jacobian) equal to the point at infinity. */
|
||||
static void secp256k1_gej_set_infinity(secp256k1_gej *r);
|
||||
|
||||
/** Set a group element (jacobian) equal to another which is given in affine coordinates. */
|
||||
static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a);
|
||||
|
||||
/** Check two group elements (jacobian) for equality in variable time. */
|
||||
static int secp256k1_gej_eq_var(const secp256k1_gej *a, const secp256k1_gej *b);
|
||||
|
||||
/** Check two group elements (jacobian and affine) for equality in variable time. */
|
||||
static int secp256k1_gej_eq_ge_var(const secp256k1_gej *a, const secp256k1_ge *b);
|
||||
|
||||
/** Compare the X coordinate of a group element (jacobian).
|
||||
* The magnitude of the group element's X coordinate must not exceed 31. */
|
||||
static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a);
|
||||
|
||||
/** Set r equal to the inverse of a (i.e., mirrored around the X axis) */
|
||||
static void secp256k1_gej_neg(secp256k1_gej *r, const secp256k1_gej *a);
|
||||
|
||||
/** Check whether a group element is the point at infinity. */
|
||||
static int secp256k1_gej_is_infinity(const secp256k1_gej *a);
|
||||
|
||||
/** Set r equal to the double of a. Constant time. */
|
||||
static void secp256k1_gej_double(secp256k1_gej *r, const secp256k1_gej *a);
|
||||
|
||||
/** Set r equal to the double of a. If rzr is not-NULL this sets *rzr such that r->z == a->z * *rzr (where infinity means an implicit z = 0). */
|
||||
static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr);
|
||||
|
||||
/** Set r equal to the sum of a and b. If rzr is non-NULL this sets *rzr such that r->z == a->z * *rzr (a cannot be infinity in that case). */
|
||||
static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr);
|
||||
|
||||
/** Set r equal to the sum of a and b (with b given in affine coordinates, and not infinity). */
|
||||
static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b);
|
||||
|
||||
/** Set r equal to the sum of a and b (with b given in affine coordinates). This is more efficient
|
||||
than secp256k1_gej_add_var. It is identical to secp256k1_gej_add_ge but without constant-time
|
||||
guarantee, and b is allowed to be infinity. If rzr is non-NULL this sets *rzr such that r->z == a->z * *rzr (a cannot be infinity in that case). */
|
||||
static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, secp256k1_fe *rzr);
|
||||
|
||||
/** Set r equal to the sum of a and b (with the inverse of b's Z coordinate passed as bzinv). */
|
||||
static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, const secp256k1_fe *bzinv);
|
||||
|
||||
/** Set r to be equal to lambda times a, where lambda is chosen in a way such that this is very fast. */
|
||||
static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a);
|
||||
|
||||
/** Clear a secp256k1_gej to prevent leaking sensitive information. */
|
||||
static void secp256k1_gej_clear(secp256k1_gej *r);
|
||||
|
||||
/** Clear a secp256k1_ge to prevent leaking sensitive information. */
|
||||
static void secp256k1_ge_clear(secp256k1_ge *r);
|
||||
|
||||
/** Convert a group element to the storage type. */
|
||||
static void secp256k1_ge_to_storage(secp256k1_ge_storage *r, const secp256k1_ge *a);
|
||||
|
||||
/** Convert a group element back from the storage type. */
|
||||
static void secp256k1_ge_from_storage(secp256k1_ge *r, const secp256k1_ge_storage *a);
|
||||
|
||||
/** If flag is 1, set *r equal to *a; if flag is 0, leave it. Constant-time.
|
||||
* Both *r and *a must be initialized. Flag must be 0 or 1. */
|
||||
static void secp256k1_gej_cmov(secp256k1_gej *r, const secp256k1_gej *a, int flag);
|
||||
|
||||
/** If flag is 1, set *r equal to *a; if flag is 0, leave it. Constant-time.
|
||||
* Both *r and *a must be initialized. Flag must be 0 or 1. */
|
||||
static void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag);
|
||||
|
||||
/** Rescale a jacobian point by b which must be non-zero. Constant-time. */
|
||||
static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *b);
|
||||
|
||||
/** Convert a group element that is not infinity to a 64-byte array. The output
|
||||
* array is platform-dependent. */
|
||||
static void secp256k1_ge_to_bytes(unsigned char *buf, const secp256k1_ge *a);
|
||||
|
||||
/** Convert a 64-byte array into group element. This function assumes that the
|
||||
* provided buffer correctly encodes a group element. */
|
||||
static void secp256k1_ge_from_bytes(secp256k1_ge *r, const unsigned char *buf);
|
||||
|
||||
/** Convert a group element (that is allowed to be infinity) to a 64-byte
|
||||
* array. The output array is platform-dependent. */
|
||||
static void secp256k1_ge_to_bytes_ext(unsigned char *data, const secp256k1_ge *ge);
|
||||
|
||||
/** Convert a 64-byte array into a group element. This function assumes that the
|
||||
* provided buffer is the output of secp256k1_ge_to_bytes_ext. */
|
||||
static void secp256k1_ge_from_bytes_ext(secp256k1_ge *ge, const unsigned char *data);
|
||||
|
||||
/** Determine if a point (which is assumed to be on the curve) is in the correct (sub)group of the curve.
|
||||
*
|
||||
* In normal mode, the used group is secp256k1, which has cofactor=1 meaning that every point on the curve is in the
|
||||
* group, and this function returns always true.
|
||||
*
|
||||
* When compiling in exhaustive test mode, a slightly different curve equation is used, leading to a group with a
|
||||
* (very) small subgroup, and that subgroup is what is used for all cryptographic operations. In that mode, this
|
||||
* function checks whether a point that is on the curve is in fact also in that subgroup.
|
||||
*/
|
||||
static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge);
|
||||
|
||||
/** Check invariants on an affine group element (no-op unless VERIFY is enabled). */
|
||||
static void secp256k1_ge_verify(const secp256k1_ge *a);
|
||||
#define SECP256K1_GE_VERIFY(a) secp256k1_ge_verify(a)
|
||||
|
||||
/** Check invariants on a Jacobian group element (no-op unless VERIFY is enabled). */
|
||||
static void secp256k1_gej_verify(const secp256k1_gej *a);
|
||||
#define SECP256K1_GEJ_VERIFY(a) secp256k1_gej_verify(a)
|
||||
|
||||
#endif /* SECP256K1_GROUP_H */
|
||||
1014
firmware/kb2040_hidden_signer/src/secp256k1/src/group_impl.h
Normal file
1014
firmware/kb2040_hidden_signer/src/secp256k1/src/group_impl.h
Normal file
File diff suppressed because it is too large
Load Diff
54
firmware/kb2040_hidden_signer/src/secp256k1/src/hash.h
Normal file
54
firmware/kb2040_hidden_signer/src/secp256k1/src/hash.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2014 Pieter Wuille *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_HASH_H
|
||||
#define SECP256K1_HASH_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct {
|
||||
secp256k1_sha256_compression_function fn_sha256_compression;
|
||||
} secp256k1_hash_ctx;
|
||||
|
||||
static void secp256k1_hash_ctx_init(secp256k1_hash_ctx *hash_ctx);
|
||||
|
||||
typedef struct {
|
||||
uint32_t s[8];
|
||||
unsigned char buf[64];
|
||||
uint64_t bytes;
|
||||
} secp256k1_sha256;
|
||||
|
||||
static void secp256k1_sha256_initialize(secp256k1_sha256 *hash);
|
||||
/* Initialize a SHA256 hash state with a precomputed midstate.
|
||||
* The byte counter must be a multiple of 64, i.e., there must be no unwritten
|
||||
* bytes in the buffer. */
|
||||
static void secp256k1_sha256_initialize_midstate(secp256k1_sha256 *hash, uint64_t bytes, const uint32_t state[8]);
|
||||
static void secp256k1_sha256_write(const secp256k1_hash_ctx *hash_ctx, secp256k1_sha256 *hash, const unsigned char *data, size_t size);
|
||||
static void secp256k1_sha256_finalize(const secp256k1_hash_ctx *hash_ctx, secp256k1_sha256 *hash, unsigned char *out32);
|
||||
static void secp256k1_sha256_clear(secp256k1_sha256 *hash);
|
||||
|
||||
typedef struct {
|
||||
secp256k1_sha256 inner, outer;
|
||||
} secp256k1_hmac_sha256;
|
||||
|
||||
static void secp256k1_hmac_sha256_initialize(const secp256k1_hash_ctx *hash_ctx, secp256k1_hmac_sha256 *hash, const unsigned char *key, size_t size);
|
||||
static void secp256k1_hmac_sha256_write(const secp256k1_hash_ctx *hash_ctx, secp256k1_hmac_sha256 *hash, const unsigned char *data, size_t size);
|
||||
static void secp256k1_hmac_sha256_finalize(const secp256k1_hash_ctx *hash_ctx, secp256k1_hmac_sha256 *hash, unsigned char *out32);
|
||||
static void secp256k1_hmac_sha256_clear(secp256k1_hmac_sha256 *hash);
|
||||
|
||||
typedef struct {
|
||||
unsigned char v[32];
|
||||
unsigned char k[32];
|
||||
int retry;
|
||||
} secp256k1_rfc6979_hmac_sha256;
|
||||
|
||||
static void secp256k1_rfc6979_hmac_sha256_initialize(const secp256k1_hash_ctx *hash_ctx, secp256k1_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen);
|
||||
static void secp256k1_rfc6979_hmac_sha256_generate(const secp256k1_hash_ctx *hash_ctx, secp256k1_rfc6979_hmac_sha256 *rng, unsigned char *out, size_t outlen);
|
||||
static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256 *rng);
|
||||
static void secp256k1_rfc6979_hmac_sha256_clear(secp256k1_rfc6979_hmac_sha256 *rng);
|
||||
|
||||
#endif /* SECP256K1_HASH_H */
|
||||
332
firmware/kb2040_hidden_signer/src/secp256k1/src/hash_impl.h
Normal file
332
firmware/kb2040_hidden_signer/src/secp256k1/src/hash_impl.h
Normal file
@@ -0,0 +1,332 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2014 Pieter Wuille *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_HASH_IMPL_H
|
||||
#define SECP256K1_HASH_IMPL_H
|
||||
|
||||
#include "hash.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#define Ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z))))
|
||||
#define Maj(x,y,z) (((x) & (y)) | ((z) & ((x) | (y))))
|
||||
#define Sigma0(x) (((x) >> 2 | (x) << 30) ^ ((x) >> 13 | (x) << 19) ^ ((x) >> 22 | (x) << 10))
|
||||
#define Sigma1(x) (((x) >> 6 | (x) << 26) ^ ((x) >> 11 | (x) << 21) ^ ((x) >> 25 | (x) << 7))
|
||||
#define sigma0(x) (((x) >> 7 | (x) << 25) ^ ((x) >> 18 | (x) << 14) ^ ((x) >> 3))
|
||||
#define sigma1(x) (((x) >> 17 | (x) << 15) ^ ((x) >> 19 | (x) << 13) ^ ((x) >> 10))
|
||||
|
||||
#define Round(a,b,c,d,e,f,g,h,k,w) do { \
|
||||
uint32_t t1 = (h) + Sigma1(e) + Ch((e), (f), (g)) + (k) + (w); \
|
||||
uint32_t t2 = Sigma0(a) + Maj((a), (b), (c)); \
|
||||
(d) += t1; \
|
||||
(h) = t1 + t2; \
|
||||
} while(0)
|
||||
|
||||
static void secp256k1_sha256_initialize(secp256k1_sha256 *hash) {
|
||||
hash->s[0] = 0x6a09e667ul;
|
||||
hash->s[1] = 0xbb67ae85ul;
|
||||
hash->s[2] = 0x3c6ef372ul;
|
||||
hash->s[3] = 0xa54ff53aul;
|
||||
hash->s[4] = 0x510e527ful;
|
||||
hash->s[5] = 0x9b05688cul;
|
||||
hash->s[6] = 0x1f83d9abul;
|
||||
hash->s[7] = 0x5be0cd19ul;
|
||||
hash->bytes = 0;
|
||||
}
|
||||
|
||||
static void secp256k1_sha256_initialize_midstate(secp256k1_sha256 *hash, uint64_t bytes, const uint32_t state[8]) {
|
||||
VERIFY_CHECK((bytes & 0x3F) == 0);
|
||||
VERIFY_CHECK(state != NULL);
|
||||
memcpy(hash->s, state, sizeof(hash->s));
|
||||
hash->bytes = bytes;
|
||||
}
|
||||
|
||||
/** Perform one SHA-256 transformation, processing 16 big endian 32-bit words. */
|
||||
static void secp256k1_sha256_transform_impl(uint32_t* s, const unsigned char* buf) {
|
||||
uint32_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7];
|
||||
uint32_t w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15;
|
||||
|
||||
Round(a, b, c, d, e, f, g, h, 0x428a2f98, w0 = secp256k1_read_be32(&buf[0]));
|
||||
Round(h, a, b, c, d, e, f, g, 0x71374491, w1 = secp256k1_read_be32(&buf[4]));
|
||||
Round(g, h, a, b, c, d, e, f, 0xb5c0fbcf, w2 = secp256k1_read_be32(&buf[8]));
|
||||
Round(f, g, h, a, b, c, d, e, 0xe9b5dba5, w3 = secp256k1_read_be32(&buf[12]));
|
||||
Round(e, f, g, h, a, b, c, d, 0x3956c25b, w4 = secp256k1_read_be32(&buf[16]));
|
||||
Round(d, e, f, g, h, a, b, c, 0x59f111f1, w5 = secp256k1_read_be32(&buf[20]));
|
||||
Round(c, d, e, f, g, h, a, b, 0x923f82a4, w6 = secp256k1_read_be32(&buf[24]));
|
||||
Round(b, c, d, e, f, g, h, a, 0xab1c5ed5, w7 = secp256k1_read_be32(&buf[28]));
|
||||
Round(a, b, c, d, e, f, g, h, 0xd807aa98, w8 = secp256k1_read_be32(&buf[32]));
|
||||
Round(h, a, b, c, d, e, f, g, 0x12835b01, w9 = secp256k1_read_be32(&buf[36]));
|
||||
Round(g, h, a, b, c, d, e, f, 0x243185be, w10 = secp256k1_read_be32(&buf[40]));
|
||||
Round(f, g, h, a, b, c, d, e, 0x550c7dc3, w11 = secp256k1_read_be32(&buf[44]));
|
||||
Round(e, f, g, h, a, b, c, d, 0x72be5d74, w12 = secp256k1_read_be32(&buf[48]));
|
||||
Round(d, e, f, g, h, a, b, c, 0x80deb1fe, w13 = secp256k1_read_be32(&buf[52]));
|
||||
Round(c, d, e, f, g, h, a, b, 0x9bdc06a7, w14 = secp256k1_read_be32(&buf[56]));
|
||||
Round(b, c, d, e, f, g, h, a, 0xc19bf174, w15 = secp256k1_read_be32(&buf[60]));
|
||||
|
||||
Round(a, b, c, d, e, f, g, h, 0xe49b69c1, w0 += sigma1(w14) + w9 + sigma0(w1));
|
||||
Round(h, a, b, c, d, e, f, g, 0xefbe4786, w1 += sigma1(w15) + w10 + sigma0(w2));
|
||||
Round(g, h, a, b, c, d, e, f, 0x0fc19dc6, w2 += sigma1(w0) + w11 + sigma0(w3));
|
||||
Round(f, g, h, a, b, c, d, e, 0x240ca1cc, w3 += sigma1(w1) + w12 + sigma0(w4));
|
||||
Round(e, f, g, h, a, b, c, d, 0x2de92c6f, w4 += sigma1(w2) + w13 + sigma0(w5));
|
||||
Round(d, e, f, g, h, a, b, c, 0x4a7484aa, w5 += sigma1(w3) + w14 + sigma0(w6));
|
||||
Round(c, d, e, f, g, h, a, b, 0x5cb0a9dc, w6 += sigma1(w4) + w15 + sigma0(w7));
|
||||
Round(b, c, d, e, f, g, h, a, 0x76f988da, w7 += sigma1(w5) + w0 + sigma0(w8));
|
||||
Round(a, b, c, d, e, f, g, h, 0x983e5152, w8 += sigma1(w6) + w1 + sigma0(w9));
|
||||
Round(h, a, b, c, d, e, f, g, 0xa831c66d, w9 += sigma1(w7) + w2 + sigma0(w10));
|
||||
Round(g, h, a, b, c, d, e, f, 0xb00327c8, w10 += sigma1(w8) + w3 + sigma0(w11));
|
||||
Round(f, g, h, a, b, c, d, e, 0xbf597fc7, w11 += sigma1(w9) + w4 + sigma0(w12));
|
||||
Round(e, f, g, h, a, b, c, d, 0xc6e00bf3, w12 += sigma1(w10) + w5 + sigma0(w13));
|
||||
Round(d, e, f, g, h, a, b, c, 0xd5a79147, w13 += sigma1(w11) + w6 + sigma0(w14));
|
||||
Round(c, d, e, f, g, h, a, b, 0x06ca6351, w14 += sigma1(w12) + w7 + sigma0(w15));
|
||||
Round(b, c, d, e, f, g, h, a, 0x14292967, w15 += sigma1(w13) + w8 + sigma0(w0));
|
||||
|
||||
Round(a, b, c, d, e, f, g, h, 0x27b70a85, w0 += sigma1(w14) + w9 + sigma0(w1));
|
||||
Round(h, a, b, c, d, e, f, g, 0x2e1b2138, w1 += sigma1(w15) + w10 + sigma0(w2));
|
||||
Round(g, h, a, b, c, d, e, f, 0x4d2c6dfc, w2 += sigma1(w0) + w11 + sigma0(w3));
|
||||
Round(f, g, h, a, b, c, d, e, 0x53380d13, w3 += sigma1(w1) + w12 + sigma0(w4));
|
||||
Round(e, f, g, h, a, b, c, d, 0x650a7354, w4 += sigma1(w2) + w13 + sigma0(w5));
|
||||
Round(d, e, f, g, h, a, b, c, 0x766a0abb, w5 += sigma1(w3) + w14 + sigma0(w6));
|
||||
Round(c, d, e, f, g, h, a, b, 0x81c2c92e, w6 += sigma1(w4) + w15 + sigma0(w7));
|
||||
Round(b, c, d, e, f, g, h, a, 0x92722c85, w7 += sigma1(w5) + w0 + sigma0(w8));
|
||||
Round(a, b, c, d, e, f, g, h, 0xa2bfe8a1, w8 += sigma1(w6) + w1 + sigma0(w9));
|
||||
Round(h, a, b, c, d, e, f, g, 0xa81a664b, w9 += sigma1(w7) + w2 + sigma0(w10));
|
||||
Round(g, h, a, b, c, d, e, f, 0xc24b8b70, w10 += sigma1(w8) + w3 + sigma0(w11));
|
||||
Round(f, g, h, a, b, c, d, e, 0xc76c51a3, w11 += sigma1(w9) + w4 + sigma0(w12));
|
||||
Round(e, f, g, h, a, b, c, d, 0xd192e819, w12 += sigma1(w10) + w5 + sigma0(w13));
|
||||
Round(d, e, f, g, h, a, b, c, 0xd6990624, w13 += sigma1(w11) + w6 + sigma0(w14));
|
||||
Round(c, d, e, f, g, h, a, b, 0xf40e3585, w14 += sigma1(w12) + w7 + sigma0(w15));
|
||||
Round(b, c, d, e, f, g, h, a, 0x106aa070, w15 += sigma1(w13) + w8 + sigma0(w0));
|
||||
|
||||
Round(a, b, c, d, e, f, g, h, 0x19a4c116, w0 += sigma1(w14) + w9 + sigma0(w1));
|
||||
Round(h, a, b, c, d, e, f, g, 0x1e376c08, w1 += sigma1(w15) + w10 + sigma0(w2));
|
||||
Round(g, h, a, b, c, d, e, f, 0x2748774c, w2 += sigma1(w0) + w11 + sigma0(w3));
|
||||
Round(f, g, h, a, b, c, d, e, 0x34b0bcb5, w3 += sigma1(w1) + w12 + sigma0(w4));
|
||||
Round(e, f, g, h, a, b, c, d, 0x391c0cb3, w4 += sigma1(w2) + w13 + sigma0(w5));
|
||||
Round(d, e, f, g, h, a, b, c, 0x4ed8aa4a, w5 += sigma1(w3) + w14 + sigma0(w6));
|
||||
Round(c, d, e, f, g, h, a, b, 0x5b9cca4f, w6 += sigma1(w4) + w15 + sigma0(w7));
|
||||
Round(b, c, d, e, f, g, h, a, 0x682e6ff3, w7 += sigma1(w5) + w0 + sigma0(w8));
|
||||
Round(a, b, c, d, e, f, g, h, 0x748f82ee, w8 += sigma1(w6) + w1 + sigma0(w9));
|
||||
Round(h, a, b, c, d, e, f, g, 0x78a5636f, w9 += sigma1(w7) + w2 + sigma0(w10));
|
||||
Round(g, h, a, b, c, d, e, f, 0x84c87814, w10 += sigma1(w8) + w3 + sigma0(w11));
|
||||
Round(f, g, h, a, b, c, d, e, 0x8cc70208, w11 += sigma1(w9) + w4 + sigma0(w12));
|
||||
Round(e, f, g, h, a, b, c, d, 0x90befffa, w12 += sigma1(w10) + w5 + sigma0(w13));
|
||||
Round(d, e, f, g, h, a, b, c, 0xa4506ceb, w13 += sigma1(w11) + w6 + sigma0(w14));
|
||||
Round(c, d, e, f, g, h, a, b, 0xbef9a3f7, w14 + sigma1(w12) + w7 + sigma0(w15));
|
||||
Round(b, c, d, e, f, g, h, a, 0xc67178f2, w15 + sigma1(w13) + w8 + sigma0(w0));
|
||||
|
||||
s[0] += a;
|
||||
s[1] += b;
|
||||
s[2] += c;
|
||||
s[3] += d;
|
||||
s[4] += e;
|
||||
s[5] += f;
|
||||
s[6] += g;
|
||||
s[7] += h;
|
||||
}
|
||||
|
||||
static void secp256k1_sha256_transform(uint32_t *state, const unsigned char *blocks64, size_t n_blocks) {
|
||||
while (n_blocks--) {
|
||||
secp256k1_sha256_transform_impl(state, blocks64);
|
||||
blocks64 += 64;
|
||||
}
|
||||
}
|
||||
|
||||
static void secp256k1_hash_ctx_init(secp256k1_hash_ctx *hash_ctx) {
|
||||
VERIFY_CHECK(hash_ctx != NULL);
|
||||
hash_ctx->fn_sha256_compression = secp256k1_sha256_transform;
|
||||
}
|
||||
|
||||
static void secp256k1_sha256_write(const secp256k1_hash_ctx *hash_ctx, secp256k1_sha256 *hash, const unsigned char *data, size_t len) {
|
||||
size_t chunk_len;
|
||||
size_t bufsize = hash->bytes & 0x3F;
|
||||
hash->bytes += len;
|
||||
VERIFY_CHECK(hash->bytes >= len);
|
||||
VERIFY_CHECK(hash_ctx != NULL);
|
||||
VERIFY_CHECK(hash_ctx->fn_sha256_compression != NULL);
|
||||
|
||||
/* If we exceed the 64-byte block size with this input, process it and wipe the buffer */
|
||||
chunk_len = 64 - bufsize;
|
||||
if (bufsize && len >= chunk_len) {
|
||||
memcpy(hash->buf + bufsize, data, chunk_len);
|
||||
data += chunk_len;
|
||||
len -= chunk_len;
|
||||
hash_ctx->fn_sha256_compression(hash->s, hash->buf, 1);
|
||||
bufsize = 0;
|
||||
}
|
||||
|
||||
/* If we still have data to process, invoke compression directly on the input */
|
||||
if (len >= 64) {
|
||||
const size_t n_blocks = len / 64;
|
||||
const size_t advance = n_blocks * 64;
|
||||
hash_ctx->fn_sha256_compression(hash->s, data, n_blocks);
|
||||
data += advance;
|
||||
len -= advance;
|
||||
}
|
||||
|
||||
/* Fill the buffer with what remains */
|
||||
if (len) {
|
||||
memcpy(hash->buf + bufsize, data, len);
|
||||
}
|
||||
}
|
||||
|
||||
static void secp256k1_sha256_finalize(const secp256k1_hash_ctx *hash_ctx, secp256k1_sha256 *hash, unsigned char *out32) {
|
||||
static const unsigned char pad[64] = {0x80};
|
||||
unsigned char sizedesc[8];
|
||||
int i;
|
||||
/* The maximum message size of SHA256 is 2^64-1 bits. */
|
||||
VERIFY_CHECK(hash->bytes < ((uint64_t)1 << 61));
|
||||
secp256k1_write_be32(&sizedesc[0], hash->bytes >> 29);
|
||||
secp256k1_write_be32(&sizedesc[4], hash->bytes << 3);
|
||||
secp256k1_sha256_write(hash_ctx, hash, pad, 1 + ((119 - (hash->bytes % 64)) % 64));
|
||||
secp256k1_sha256_write(hash_ctx, hash, sizedesc, 8);
|
||||
for (i = 0; i < 8; i++) {
|
||||
secp256k1_write_be32(&out32[4*i], hash->s[i]);
|
||||
hash->s[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Initializes a sha256 struct and writes the 64 byte string
|
||||
* SHA256(tag)||SHA256(tag) into it. */
|
||||
static void secp256k1_sha256_initialize_tagged(const secp256k1_hash_ctx *hash_ctx, secp256k1_sha256 *hash, const unsigned char *tag, size_t taglen) {
|
||||
unsigned char buf[32];
|
||||
secp256k1_sha256_initialize(hash);
|
||||
secp256k1_sha256_write(hash_ctx, hash, tag, taglen);
|
||||
secp256k1_sha256_finalize(hash_ctx, hash, buf);
|
||||
|
||||
secp256k1_sha256_initialize(hash);
|
||||
secp256k1_sha256_write(hash_ctx, hash, buf, 32);
|
||||
secp256k1_sha256_write(hash_ctx, hash, buf, 32);
|
||||
}
|
||||
|
||||
static void secp256k1_sha256_clear(secp256k1_sha256 *hash) {
|
||||
secp256k1_memclear_explicit(hash, sizeof(*hash));
|
||||
}
|
||||
|
||||
static void secp256k1_hmac_sha256_initialize(const secp256k1_hash_ctx *hash_ctx, secp256k1_hmac_sha256 *hash, const unsigned char *key, size_t keylen) {
|
||||
size_t n;
|
||||
unsigned char rkey[64];
|
||||
if (keylen <= sizeof(rkey)) {
|
||||
memcpy(rkey, key, keylen);
|
||||
memset(rkey + keylen, 0, sizeof(rkey) - keylen);
|
||||
} else {
|
||||
secp256k1_sha256 sha256;
|
||||
secp256k1_sha256_initialize(&sha256);
|
||||
secp256k1_sha256_write(hash_ctx, &sha256, key, keylen);
|
||||
secp256k1_sha256_finalize(hash_ctx, &sha256, rkey);
|
||||
memset(rkey + 32, 0, 32);
|
||||
}
|
||||
|
||||
secp256k1_sha256_initialize(&hash->outer);
|
||||
for (n = 0; n < sizeof(rkey); n++) {
|
||||
rkey[n] ^= 0x5c;
|
||||
}
|
||||
secp256k1_sha256_write(hash_ctx, &hash->outer, rkey, sizeof(rkey));
|
||||
|
||||
secp256k1_sha256_initialize(&hash->inner);
|
||||
for (n = 0; n < sizeof(rkey); n++) {
|
||||
rkey[n] ^= 0x5c ^ 0x36;
|
||||
}
|
||||
secp256k1_sha256_write(hash_ctx, &hash->inner, rkey, sizeof(rkey));
|
||||
secp256k1_memclear_explicit(rkey, sizeof(rkey));
|
||||
}
|
||||
|
||||
static void secp256k1_hmac_sha256_write(const secp256k1_hash_ctx *hash_ctx, secp256k1_hmac_sha256 *hash, const unsigned char *data, size_t size) {
|
||||
secp256k1_sha256_write(hash_ctx, &hash->inner, data, size);
|
||||
}
|
||||
|
||||
static void secp256k1_hmac_sha256_finalize(const secp256k1_hash_ctx *hash_ctx, secp256k1_hmac_sha256 *hash, unsigned char *out32) {
|
||||
unsigned char temp[32];
|
||||
secp256k1_sha256_finalize(hash_ctx, &hash->inner, temp);
|
||||
secp256k1_sha256_write(hash_ctx, &hash->outer, temp, 32);
|
||||
secp256k1_memclear_explicit(temp, sizeof(temp));
|
||||
secp256k1_sha256_finalize(hash_ctx, &hash->outer, out32);
|
||||
}
|
||||
|
||||
static void secp256k1_hmac_sha256_clear(secp256k1_hmac_sha256 *hash) {
|
||||
secp256k1_memclear_explicit(hash, sizeof(*hash));
|
||||
}
|
||||
|
||||
static void secp256k1_rfc6979_hmac_sha256_initialize(const secp256k1_hash_ctx *hash_ctx, secp256k1_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen) {
|
||||
secp256k1_hmac_sha256 hmac;
|
||||
static const unsigned char zero[1] = {0x00};
|
||||
static const unsigned char one[1] = {0x01};
|
||||
|
||||
memset(rng->v, 0x01, 32); /* RFC6979 3.2.b. */
|
||||
memset(rng->k, 0x00, 32); /* RFC6979 3.2.c. */
|
||||
|
||||
/* RFC6979 3.2.d. */
|
||||
secp256k1_hmac_sha256_initialize(hash_ctx, &hmac, rng->k, 32);
|
||||
secp256k1_hmac_sha256_write(hash_ctx, &hmac, rng->v, 32);
|
||||
secp256k1_hmac_sha256_write(hash_ctx, &hmac, zero, 1);
|
||||
secp256k1_hmac_sha256_write(hash_ctx, &hmac, key, keylen);
|
||||
secp256k1_hmac_sha256_finalize(hash_ctx, &hmac, rng->k);
|
||||
secp256k1_hmac_sha256_initialize(hash_ctx, &hmac, rng->k, 32);
|
||||
secp256k1_hmac_sha256_write(hash_ctx, &hmac, rng->v, 32);
|
||||
secp256k1_hmac_sha256_finalize(hash_ctx, &hmac, rng->v);
|
||||
|
||||
/* RFC6979 3.2.f. */
|
||||
secp256k1_hmac_sha256_initialize(hash_ctx, &hmac, rng->k, 32);
|
||||
secp256k1_hmac_sha256_write(hash_ctx, &hmac, rng->v, 32);
|
||||
secp256k1_hmac_sha256_write(hash_ctx, &hmac, one, 1);
|
||||
secp256k1_hmac_sha256_write(hash_ctx, &hmac, key, keylen);
|
||||
secp256k1_hmac_sha256_finalize(hash_ctx, &hmac, rng->k);
|
||||
secp256k1_hmac_sha256_initialize(hash_ctx, &hmac, rng->k, 32);
|
||||
secp256k1_hmac_sha256_write(hash_ctx, &hmac, rng->v, 32);
|
||||
secp256k1_hmac_sha256_finalize(hash_ctx, &hmac, rng->v);
|
||||
rng->retry = 0;
|
||||
}
|
||||
|
||||
static void secp256k1_rfc6979_hmac_sha256_generate(const secp256k1_hash_ctx *hash_ctx, secp256k1_rfc6979_hmac_sha256 *rng, unsigned char *out, size_t outlen) {
|
||||
/* RFC6979 3.2.h. */
|
||||
static const unsigned char zero[1] = {0x00};
|
||||
if (rng->retry) {
|
||||
secp256k1_hmac_sha256 hmac;
|
||||
secp256k1_hmac_sha256_initialize(hash_ctx, &hmac, rng->k, 32);
|
||||
secp256k1_hmac_sha256_write(hash_ctx, &hmac, rng->v, 32);
|
||||
secp256k1_hmac_sha256_write(hash_ctx, &hmac, zero, 1);
|
||||
secp256k1_hmac_sha256_finalize(hash_ctx, &hmac, rng->k);
|
||||
secp256k1_hmac_sha256_initialize(hash_ctx, &hmac, rng->k, 32);
|
||||
secp256k1_hmac_sha256_write(hash_ctx, &hmac, rng->v, 32);
|
||||
secp256k1_hmac_sha256_finalize(hash_ctx, &hmac, rng->v);
|
||||
}
|
||||
|
||||
while (outlen > 0) {
|
||||
secp256k1_hmac_sha256 hmac;
|
||||
size_t now = outlen;
|
||||
secp256k1_hmac_sha256_initialize(hash_ctx, &hmac, rng->k, 32);
|
||||
secp256k1_hmac_sha256_write(hash_ctx, &hmac, rng->v, 32);
|
||||
secp256k1_hmac_sha256_finalize(hash_ctx, &hmac, rng->v);
|
||||
if (now > 32) {
|
||||
now = 32;
|
||||
}
|
||||
memcpy(out, rng->v, now);
|
||||
out += now;
|
||||
outlen -= now;
|
||||
}
|
||||
|
||||
rng->retry = 1;
|
||||
}
|
||||
|
||||
static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256 *rng) {
|
||||
(void) rng;
|
||||
}
|
||||
|
||||
static void secp256k1_rfc6979_hmac_sha256_clear(secp256k1_rfc6979_hmac_sha256 *rng) {
|
||||
secp256k1_memclear_explicit(rng, sizeof(*rng));
|
||||
}
|
||||
|
||||
#undef Round
|
||||
#undef sigma1
|
||||
#undef sigma0
|
||||
#undef Sigma1
|
||||
#undef Sigma0
|
||||
#undef Maj
|
||||
#undef Ch
|
||||
|
||||
#endif /* SECP256K1_HASH_IMPL_H */
|
||||
33
firmware/kb2040_hidden_signer/src/secp256k1/src/hsort.h
Normal file
33
firmware/kb2040_hidden_signer/src/secp256k1/src/hsort.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2021 Russell O'Connor, Jonas Nick *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_HSORT_H
|
||||
#define SECP256K1_HSORT_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
/* In-place, iterative heapsort with an interface matching glibc's qsort_r. This
|
||||
* is preferred over standard library implementations because they generally
|
||||
* make no guarantee about being fast for malicious inputs.
|
||||
* Remember that heapsort is unstable.
|
||||
*
|
||||
* In/Out: ptr: pointer to the array to sort. The contents of the array are
|
||||
* sorted in ascending order according to the comparison function.
|
||||
* In: count: number of elements in the array.
|
||||
* size: size in bytes of each element.
|
||||
* cmp: pointer to a comparison function that is called with two
|
||||
* arguments that point to the objects being compared. The cmp_data
|
||||
* argument of secp256k1_hsort is passed as third argument. The
|
||||
* function must return an integer less than, equal to, or greater
|
||||
* than zero if the first argument is considered to be respectively
|
||||
* less than, equal to, or greater than the second.
|
||||
* cmp_data: pointer passed as third argument to cmp.
|
||||
*/
|
||||
static void secp256k1_hsort(void *ptr, size_t count, size_t size,
|
||||
int (*cmp)(const void *, const void *, void *),
|
||||
void *cmp_data);
|
||||
#endif
|
||||
125
firmware/kb2040_hidden_signer/src/secp256k1/src/hsort_impl.h
Normal file
125
firmware/kb2040_hidden_signer/src/secp256k1/src/hsort_impl.h
Normal file
@@ -0,0 +1,125 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2021 Russell O'Connor, Jonas Nick *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_HSORT_IMPL_H
|
||||
#define SECP256K1_HSORT_IMPL_H
|
||||
|
||||
#include "hsort.h"
|
||||
|
||||
/* An array is a heap when, for all non-zero indexes i, the element at index i
|
||||
* compares as less than or equal to the element at index parent(i) = (i-1)/2.
|
||||
*/
|
||||
|
||||
static SECP256K1_INLINE size_t secp256k1_heap_child1(size_t i) {
|
||||
VERIFY_CHECK(i <= (SIZE_MAX - 1)/2);
|
||||
return 2*i + 1;
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE size_t secp256k1_heap_child2(size_t i) {
|
||||
VERIFY_CHECK(i <= SIZE_MAX/2 - 1);
|
||||
return secp256k1_heap_child1(i)+1;
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_heap_swap64(unsigned char *a, unsigned char *b, size_t len) {
|
||||
unsigned char tmp[64];
|
||||
VERIFY_CHECK(len <= 64);
|
||||
memcpy(tmp, a, len);
|
||||
memmove(a, b, len);
|
||||
memcpy(b, tmp, len);
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_heap_swap(unsigned char *arr, size_t i, size_t j, size_t stride) {
|
||||
unsigned char *a = arr + i*stride;
|
||||
unsigned char *b = arr + j*stride;
|
||||
size_t len = stride;
|
||||
while (64 < len) {
|
||||
secp256k1_heap_swap64(a + (len - 64), b + (len - 64), 64);
|
||||
len -= 64;
|
||||
}
|
||||
secp256k1_heap_swap64(a, b, len);
|
||||
}
|
||||
|
||||
/* This function accepts an array arr containing heap_size elements, each of
|
||||
* size stride. The elements in the array at indices >i satisfy the max-heap
|
||||
* property, i.e., for any element at index j (where j > i), all of its children
|
||||
* are smaller than the element itself. The purpose of the function is to update
|
||||
* the array so that all elements at indices >=i satisfy the max-heap
|
||||
* property. */
|
||||
static SECP256K1_INLINE void secp256k1_heap_down(unsigned char *arr, size_t i, size_t heap_size, size_t stride,
|
||||
int (*cmp)(const void *, const void *, void *), void *cmp_data) {
|
||||
while (i < heap_size/2) {
|
||||
VERIFY_CHECK(i <= SIZE_MAX/2 - 1);
|
||||
/* Proof:
|
||||
* i < heap_size/2
|
||||
* i + 1 <= heap_size/2
|
||||
* 2*i + 2 <= heap_size <= SIZE_MAX
|
||||
* 2*i <= SIZE_MAX - 2
|
||||
*/
|
||||
|
||||
VERIFY_CHECK(secp256k1_heap_child1(i) < heap_size);
|
||||
/* Proof:
|
||||
* i < heap_size/2
|
||||
* i + 1 <= heap_size/2
|
||||
* 2*i + 2 <= heap_size
|
||||
* 2*i + 1 < heap_size
|
||||
* child1(i) < heap_size
|
||||
*/
|
||||
|
||||
/* Let [x] be notation for the contents at arr[x*stride].
|
||||
*
|
||||
* If [child1(i)] > [i] and [child2(i)] > [i],
|
||||
* swap [i] with the larger child to ensure the new parent is larger
|
||||
* than both children. When [child1(i)] == [child2(i)], swap [i] with
|
||||
* [child2(i)].
|
||||
* Else if [child1(i)] > [i], swap [i] with [child1(i)].
|
||||
* Else if [child2(i)] > [i], swap [i] with [child2(i)].
|
||||
*/
|
||||
if (secp256k1_heap_child2(i) < heap_size
|
||||
&& 0 <= cmp(arr + secp256k1_heap_child2(i)*stride, arr + secp256k1_heap_child1(i)*stride, cmp_data)) {
|
||||
if (0 < cmp(arr + secp256k1_heap_child2(i)*stride, arr + i*stride, cmp_data)) {
|
||||
secp256k1_heap_swap(arr, i, secp256k1_heap_child2(i), stride);
|
||||
i = secp256k1_heap_child2(i);
|
||||
} else {
|
||||
/* At this point we have [child2(i)] >= [child1(i)] and we have
|
||||
* [child2(i)] <= [i], and thus [child1(i)] <= [i] which means
|
||||
* that the next comparison can be skipped. */
|
||||
return;
|
||||
}
|
||||
} else if (0 < cmp(arr + secp256k1_heap_child1(i)*stride, arr + i*stride, cmp_data)) {
|
||||
secp256k1_heap_swap(arr, i, secp256k1_heap_child1(i), stride);
|
||||
i = secp256k1_heap_child1(i);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* heap_size/2 <= i
|
||||
* heap_size/2 < i + 1
|
||||
* heap_size < 2*i + 2
|
||||
* heap_size <= 2*i + 1
|
||||
* heap_size <= child1(i)
|
||||
* Thus child1(i) and child2(i) are now out of bounds and we are at a leaf.
|
||||
*/
|
||||
}
|
||||
|
||||
/* In-place heap sort. */
|
||||
static void secp256k1_hsort(void *ptr, size_t count, size_t size,
|
||||
int (*cmp)(const void *, const void *, void *),
|
||||
void *cmp_data) {
|
||||
size_t i;
|
||||
|
||||
for (i = count/2; 0 < i; --i) {
|
||||
secp256k1_heap_down(ptr, i-1, count, size, cmp, cmp_data);
|
||||
}
|
||||
for (i = count; 1 < i; --i) {
|
||||
/* Extract the largest value from the heap */
|
||||
secp256k1_heap_swap(ptr, 0, i-1, size);
|
||||
|
||||
/* Repair the heap condition */
|
||||
secp256k1_heap_down(ptr, 0, i-1, size, cmp, cmp_data);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
90
firmware/kb2040_hidden_signer/src/secp256k1/src/int128.h
Normal file
90
firmware/kb2040_hidden_signer/src/secp256k1/src/int128.h
Normal file
@@ -0,0 +1,90 @@
|
||||
#ifndef SECP256K1_INT128_H
|
||||
#define SECP256K1_INT128_H
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#if defined(SECP256K1_WIDEMUL_INT128)
|
||||
# if defined(SECP256K1_INT128_NATIVE)
|
||||
# include "int128_native.h"
|
||||
# elif defined(SECP256K1_INT128_STRUCT)
|
||||
# include "int128_struct.h"
|
||||
# else
|
||||
# error "Please select int128 implementation"
|
||||
# endif
|
||||
|
||||
/* Construct an unsigned 128-bit value from a high and a low 64-bit value. */
|
||||
static SECP256K1_INLINE void secp256k1_u128_load(secp256k1_uint128 *r, uint64_t hi, uint64_t lo);
|
||||
|
||||
/* Multiply two unsigned 64-bit values a and b and write the result to r. */
|
||||
static SECP256K1_INLINE void secp256k1_u128_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b);
|
||||
|
||||
/* Multiply two unsigned 64-bit values a and b and add the result to r.
|
||||
* The final result is taken modulo 2^128.
|
||||
*/
|
||||
static SECP256K1_INLINE void secp256k1_u128_accum_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b);
|
||||
|
||||
/* Add an unsigned 64-bit value a to r.
|
||||
* The final result is taken modulo 2^128.
|
||||
*/
|
||||
static SECP256K1_INLINE void secp256k1_u128_accum_u64(secp256k1_uint128 *r, uint64_t a);
|
||||
|
||||
/* Unsigned (logical) right shift.
|
||||
* Non-constant time in n.
|
||||
*/
|
||||
static SECP256K1_INLINE void secp256k1_u128_rshift(secp256k1_uint128 *r, unsigned int n);
|
||||
|
||||
/* Return the low 64-bits of a 128-bit value as an unsigned 64-bit value. */
|
||||
static SECP256K1_INLINE uint64_t secp256k1_u128_to_u64(const secp256k1_uint128 *a);
|
||||
|
||||
/* Return the high 64-bits of a 128-bit value as an unsigned 64-bit value. */
|
||||
static SECP256K1_INLINE uint64_t secp256k1_u128_hi_u64(const secp256k1_uint128 *a);
|
||||
|
||||
/* Write an unsigned 64-bit value to r. */
|
||||
static SECP256K1_INLINE void secp256k1_u128_from_u64(secp256k1_uint128 *r, uint64_t a);
|
||||
|
||||
/* Tests if r is strictly less than to 2^n.
|
||||
* n must be strictly less than 128.
|
||||
*/
|
||||
static SECP256K1_INLINE int secp256k1_u128_check_bits(const secp256k1_uint128 *r, unsigned int n);
|
||||
|
||||
/* Construct an signed 128-bit value from a high and a low 64-bit value. */
|
||||
static SECP256K1_INLINE void secp256k1_i128_load(secp256k1_int128 *r, int64_t hi, uint64_t lo);
|
||||
|
||||
/* Multiply two signed 64-bit values a and b and write the result to r. */
|
||||
static SECP256K1_INLINE void secp256k1_i128_mul(secp256k1_int128 *r, int64_t a, int64_t b);
|
||||
|
||||
/* Multiply two signed 64-bit values a and b and add the result to r.
|
||||
* Overflow or underflow from the addition is undefined behaviour.
|
||||
*/
|
||||
static SECP256K1_INLINE void secp256k1_i128_accum_mul(secp256k1_int128 *r, int64_t a, int64_t b);
|
||||
|
||||
/* Compute a*d - b*c from signed 64-bit values and write the result to r. */
|
||||
static SECP256K1_INLINE void secp256k1_i128_det(secp256k1_int128 *r, int64_t a, int64_t b, int64_t c, int64_t d);
|
||||
|
||||
/* Signed (arithmetic) right shift.
|
||||
* Non-constant time in b.
|
||||
*/
|
||||
static SECP256K1_INLINE void secp256k1_i128_rshift(secp256k1_int128 *r, unsigned int b);
|
||||
|
||||
/* Return the input value modulo 2^64. */
|
||||
static SECP256K1_INLINE uint64_t secp256k1_i128_to_u64(const secp256k1_int128 *a);
|
||||
|
||||
/* Return the value as a signed 64-bit value.
|
||||
* Requires the input to be between INT64_MIN and INT64_MAX.
|
||||
*/
|
||||
static SECP256K1_INLINE int64_t secp256k1_i128_to_i64(const secp256k1_int128 *a);
|
||||
|
||||
/* Write a signed 64-bit value to r. */
|
||||
static SECP256K1_INLINE void secp256k1_i128_from_i64(secp256k1_int128 *r, int64_t a);
|
||||
|
||||
/* Compare two 128-bit values for equality. */
|
||||
static SECP256K1_INLINE int secp256k1_i128_eq_var(const secp256k1_int128 *a, const secp256k1_int128 *b);
|
||||
|
||||
/* Tests if r is equal to sign*2^n (sign must be 1 or -1).
|
||||
* n must be strictly less than 127.
|
||||
*/
|
||||
static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n, int sign);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef SECP256K1_INT128_IMPL_H
|
||||
#define SECP256K1_INT128_IMPL_H
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#include "int128.h"
|
||||
|
||||
#if defined(SECP256K1_WIDEMUL_INT128)
|
||||
# if defined(SECP256K1_INT128_NATIVE)
|
||||
# include "int128_native_impl.h"
|
||||
# elif defined(SECP256K1_INT128_STRUCT)
|
||||
# include "int128_struct_impl.h"
|
||||
# else
|
||||
# error "Please select int128 implementation"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,19 @@
|
||||
#ifndef SECP256K1_INT128_NATIVE_H
|
||||
#define SECP256K1_INT128_NATIVE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "util.h"
|
||||
|
||||
#if !defined(UINT128_MAX) && defined(__SIZEOF_INT128__)
|
||||
SECP256K1_GNUC_EXT typedef unsigned __int128 uint128_t;
|
||||
SECP256K1_GNUC_EXT typedef __int128 int128_t;
|
||||
# define UINT128_MAX ((uint128_t)(-1))
|
||||
# define INT128_MAX ((int128_t)(UINT128_MAX >> 1))
|
||||
# define INT128_MIN (-INT128_MAX - 1)
|
||||
/* No (U)INT128_C macros because compilers providing __int128 do not support 128-bit literals. */
|
||||
#endif
|
||||
|
||||
typedef uint128_t secp256k1_uint128;
|
||||
typedef int128_t secp256k1_int128;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,94 @@
|
||||
#ifndef SECP256K1_INT128_NATIVE_IMPL_H
|
||||
#define SECP256K1_INT128_NATIVE_IMPL_H
|
||||
|
||||
#include "int128.h"
|
||||
#include "util.h"
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_u128_load(secp256k1_uint128 *r, uint64_t hi, uint64_t lo) {
|
||||
*r = (((uint128_t)hi) << 64) + lo;
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_u128_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b) {
|
||||
*r = (uint128_t)a * b;
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_u128_accum_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b) {
|
||||
*r += (uint128_t)a * b;
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_u128_accum_u64(secp256k1_uint128 *r, uint64_t a) {
|
||||
*r += a;
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_u128_rshift(secp256k1_uint128 *r, unsigned int n) {
|
||||
VERIFY_CHECK(n < 128);
|
||||
*r >>= n;
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE uint64_t secp256k1_u128_to_u64(const secp256k1_uint128 *a) {
|
||||
return (uint64_t)(*a);
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE uint64_t secp256k1_u128_hi_u64(const secp256k1_uint128 *a) {
|
||||
return (uint64_t)(*a >> 64);
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_u128_from_u64(secp256k1_uint128 *r, uint64_t a) {
|
||||
*r = a;
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE int secp256k1_u128_check_bits(const secp256k1_uint128 *r, unsigned int n) {
|
||||
VERIFY_CHECK(n < 128);
|
||||
return (*r >> n == 0);
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_i128_load(secp256k1_int128 *r, int64_t hi, uint64_t lo) {
|
||||
*r = (((uint128_t)(uint64_t)hi) << 64) + lo;
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_i128_mul(secp256k1_int128 *r, int64_t a, int64_t b) {
|
||||
*r = (int128_t)a * b;
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_i128_accum_mul(secp256k1_int128 *r, int64_t a, int64_t b) {
|
||||
int128_t ab = (int128_t)a * b;
|
||||
VERIFY_CHECK(0 <= ab ? *r <= INT128_MAX - ab : INT128_MIN - ab <= *r);
|
||||
*r += ab;
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_i128_det(secp256k1_int128 *r, int64_t a, int64_t b, int64_t c, int64_t d) {
|
||||
int128_t ad = (int128_t)a * d;
|
||||
int128_t bc = (int128_t)b * c;
|
||||
VERIFY_CHECK(0 <= bc ? INT128_MIN + bc <= ad : ad <= INT128_MAX + bc);
|
||||
*r = ad - bc;
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_i128_rshift(secp256k1_int128 *r, unsigned int n) {
|
||||
VERIFY_CHECK(n < 128);
|
||||
*r >>= n;
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE uint64_t secp256k1_i128_to_u64(const secp256k1_int128 *a) {
|
||||
return (uint64_t)*a;
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE int64_t secp256k1_i128_to_i64(const secp256k1_int128 *a) {
|
||||
VERIFY_CHECK(INT64_MIN <= *a && *a <= INT64_MAX);
|
||||
return *a;
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_i128_from_i64(secp256k1_int128 *r, int64_t a) {
|
||||
*r = a;
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE int secp256k1_i128_eq_var(const secp256k1_int128 *a, const secp256k1_int128 *b) {
|
||||
return *a == *b;
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n, int sign) {
|
||||
VERIFY_CHECK(n < 127);
|
||||
VERIFY_CHECK(sign == 1 || sign == -1);
|
||||
return (*r == (int128_t)((uint128_t)sign << n));
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef SECP256K1_INT128_STRUCT_H
|
||||
#define SECP256K1_INT128_STRUCT_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "util.h"
|
||||
|
||||
typedef struct {
|
||||
uint64_t lo;
|
||||
uint64_t hi;
|
||||
} secp256k1_uint128;
|
||||
|
||||
typedef secp256k1_uint128 secp256k1_int128;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,205 @@
|
||||
#ifndef SECP256K1_INT128_STRUCT_IMPL_H
|
||||
#define SECP256K1_INT128_STRUCT_IMPL_H
|
||||
|
||||
#include "int128.h"
|
||||
#include "util.h"
|
||||
|
||||
#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64)) /* MSVC */
|
||||
# include <intrin.h>
|
||||
# if defined(_M_ARM64) || defined(SECP256K1_MSVC_MULH_TEST_OVERRIDE)
|
||||
/* On ARM64 MSVC, use __(u)mulh for the upper half of 64x64 multiplications.
|
||||
(Define SECP256K1_MSVC_MULH_TEST_OVERRIDE to test this code path on X64,
|
||||
which supports both __(u)mulh and _umul128.) */
|
||||
# if defined(SECP256K1_MSVC_MULH_TEST_OVERRIDE)
|
||||
# pragma message(__FILE__ ": SECP256K1_MSVC_MULH_TEST_OVERRIDE is defined, forcing use of __(u)mulh.")
|
||||
# endif
|
||||
static SECP256K1_INLINE uint64_t secp256k1_umul128(uint64_t a, uint64_t b, uint64_t* hi) {
|
||||
*hi = __umulh(a, b);
|
||||
return a * b;
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE int64_t secp256k1_mul128(int64_t a, int64_t b, int64_t* hi) {
|
||||
*hi = __mulh(a, b);
|
||||
return (uint64_t)a * (uint64_t)b;
|
||||
}
|
||||
# else
|
||||
/* On x84_64 MSVC, use native _(u)mul128 for 64x64->128 multiplications. */
|
||||
# define secp256k1_umul128 _umul128
|
||||
# define secp256k1_mul128 _mul128
|
||||
# endif
|
||||
#else
|
||||
/* On other systems, emulate 64x64->128 multiplications using 32x32->64 multiplications. */
|
||||
static SECP256K1_INLINE uint64_t secp256k1_umul128(uint64_t a, uint64_t b, uint64_t* hi) {
|
||||
uint64_t ll = (uint64_t)(uint32_t)a * (uint32_t)b;
|
||||
uint64_t lh = (uint32_t)a * (b >> 32);
|
||||
uint64_t hl = (a >> 32) * (uint32_t)b;
|
||||
uint64_t hh = (a >> 32) * (b >> 32);
|
||||
uint64_t mid34 = (ll >> 32) + (uint32_t)lh + (uint32_t)hl;
|
||||
*hi = hh + (lh >> 32) + (hl >> 32) + (mid34 >> 32);
|
||||
return (mid34 << 32) + (uint32_t)ll;
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE int64_t secp256k1_mul128(int64_t a, int64_t b, int64_t* hi) {
|
||||
uint64_t ll = (uint64_t)(uint32_t)a * (uint32_t)b;
|
||||
int64_t lh = (uint32_t)a * (b >> 32);
|
||||
int64_t hl = (a >> 32) * (uint32_t)b;
|
||||
int64_t hh = (a >> 32) * (b >> 32);
|
||||
uint64_t mid34 = (ll >> 32) + (uint32_t)lh + (uint32_t)hl;
|
||||
*hi = hh + (lh >> 32) + (hl >> 32) + (mid34 >> 32);
|
||||
return (mid34 << 32) + (uint32_t)ll;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_u128_load(secp256k1_uint128 *r, uint64_t hi, uint64_t lo) {
|
||||
r->hi = hi;
|
||||
r->lo = lo;
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_u128_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b) {
|
||||
r->lo = secp256k1_umul128(a, b, &r->hi);
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_u128_accum_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b) {
|
||||
uint64_t lo, hi;
|
||||
lo = secp256k1_umul128(a, b, &hi);
|
||||
r->lo += lo;
|
||||
r->hi += hi + (r->lo < lo);
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_u128_accum_u64(secp256k1_uint128 *r, uint64_t a) {
|
||||
r->lo += a;
|
||||
r->hi += r->lo < a;
|
||||
}
|
||||
|
||||
/* Unsigned (logical) right shift.
|
||||
* Non-constant time in n.
|
||||
*/
|
||||
static SECP256K1_INLINE void secp256k1_u128_rshift(secp256k1_uint128 *r, unsigned int n) {
|
||||
VERIFY_CHECK(n < 128);
|
||||
if (n >= 64) {
|
||||
r->lo = r->hi >> (n-64);
|
||||
r->hi = 0;
|
||||
} else if (n > 0) {
|
||||
#if defined(_MSC_VER) && defined(_M_X64)
|
||||
VERIFY_CHECK(n < 64);
|
||||
r->lo = __shiftright128(r->lo, r->hi, n);
|
||||
#else
|
||||
r->lo = ((1U * r->hi) << (64-n)) | r->lo >> n;
|
||||
#endif
|
||||
r->hi >>= n;
|
||||
}
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE uint64_t secp256k1_u128_to_u64(const secp256k1_uint128 *a) {
|
||||
return a->lo;
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE uint64_t secp256k1_u128_hi_u64(const secp256k1_uint128 *a) {
|
||||
return a->hi;
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_u128_from_u64(secp256k1_uint128 *r, uint64_t a) {
|
||||
r->hi = 0;
|
||||
r->lo = a;
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE int secp256k1_u128_check_bits(const secp256k1_uint128 *r, unsigned int n) {
|
||||
VERIFY_CHECK(n < 128);
|
||||
return n >= 64 ? r->hi >> (n - 64) == 0
|
||||
: r->hi == 0 && r->lo >> n == 0;
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_i128_load(secp256k1_int128 *r, int64_t hi, uint64_t lo) {
|
||||
r->hi = hi;
|
||||
r->lo = lo;
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_i128_mul(secp256k1_int128 *r, int64_t a, int64_t b) {
|
||||
int64_t hi;
|
||||
r->lo = (uint64_t)secp256k1_mul128(a, b, &hi);
|
||||
r->hi = (uint64_t)hi;
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_i128_accum_mul(secp256k1_int128 *r, int64_t a, int64_t b) {
|
||||
int64_t hi;
|
||||
uint64_t lo = (uint64_t)secp256k1_mul128(a, b, &hi);
|
||||
r->lo += lo;
|
||||
hi += r->lo < lo;
|
||||
/* Verify no overflow.
|
||||
* If r represents a positive value (the sign bit is not set) and the value we are adding is a positive value (the sign bit is not set),
|
||||
* then we require that the resulting value also be positive (the sign bit is not set).
|
||||
* Note that (X <= Y) means (X implies Y) when X and Y are boolean values (i.e. 0 or 1).
|
||||
*/
|
||||
VERIFY_CHECK((r->hi <= 0x7fffffffffffffffu && (uint64_t)hi <= 0x7fffffffffffffffu) <= (r->hi + (uint64_t)hi <= 0x7fffffffffffffffu));
|
||||
/* Verify no underflow.
|
||||
* If r represents a negative value (the sign bit is set) and the value we are adding is a negative value (the sign bit is set),
|
||||
* then we require that the resulting value also be negative (the sign bit is set).
|
||||
*/
|
||||
VERIFY_CHECK((r->hi > 0x7fffffffffffffffu && (uint64_t)hi > 0x7fffffffffffffffu) <= (r->hi + (uint64_t)hi > 0x7fffffffffffffffu));
|
||||
r->hi += hi;
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_i128_dissip_mul(secp256k1_int128 *r, int64_t a, int64_t b) {
|
||||
int64_t hi;
|
||||
uint64_t lo = (uint64_t)secp256k1_mul128(a, b, &hi);
|
||||
hi += r->lo < lo;
|
||||
/* Verify no overflow.
|
||||
* If r represents a positive value (the sign bit is not set) and the value we are subtracting is a negative value (the sign bit is set),
|
||||
* then we require that the resulting value also be positive (the sign bit is not set).
|
||||
*/
|
||||
VERIFY_CHECK((r->hi <= 0x7fffffffffffffffu && (uint64_t)hi > 0x7fffffffffffffffu) <= (r->hi - (uint64_t)hi <= 0x7fffffffffffffffu));
|
||||
/* Verify no underflow.
|
||||
* If r represents a negative value (the sign bit is set) and the value we are subtracting is a positive value (the sign sign bit is not set),
|
||||
* then we require that the resulting value also be negative (the sign bit is set).
|
||||
*/
|
||||
VERIFY_CHECK((r->hi > 0x7fffffffffffffffu && (uint64_t)hi <= 0x7fffffffffffffffu) <= (r->hi - (uint64_t)hi > 0x7fffffffffffffffu));
|
||||
r->hi -= hi;
|
||||
r->lo -= lo;
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_i128_det(secp256k1_int128 *r, int64_t a, int64_t b, int64_t c, int64_t d) {
|
||||
secp256k1_i128_mul(r, a, d);
|
||||
secp256k1_i128_dissip_mul(r, b, c);
|
||||
}
|
||||
|
||||
/* Signed (arithmetic) right shift.
|
||||
* Non-constant time in n.
|
||||
*/
|
||||
static SECP256K1_INLINE void secp256k1_i128_rshift(secp256k1_int128 *r, unsigned int n) {
|
||||
VERIFY_CHECK(n < 128);
|
||||
if (n >= 64) {
|
||||
r->lo = (uint64_t)((int64_t)(r->hi) >> (n-64));
|
||||
r->hi = (uint64_t)((int64_t)(r->hi) >> 63);
|
||||
} else if (n > 0) {
|
||||
r->lo = ((1U * r->hi) << (64-n)) | r->lo >> n;
|
||||
r->hi = (uint64_t)((int64_t)(r->hi) >> n);
|
||||
}
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE uint64_t secp256k1_i128_to_u64(const secp256k1_int128 *a) {
|
||||
return a->lo;
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE int64_t secp256k1_i128_to_i64(const secp256k1_int128 *a) {
|
||||
/* Verify that a represents a 64 bit signed value by checking that the high bits are a sign extension of the low bits. */
|
||||
VERIFY_CHECK(a->hi == -(a->lo >> 63));
|
||||
return (int64_t)secp256k1_i128_to_u64(a);
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_i128_from_i64(secp256k1_int128 *r, int64_t a) {
|
||||
r->hi = (uint64_t)(a >> 63);
|
||||
r->lo = (uint64_t)a;
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE int secp256k1_i128_eq_var(const secp256k1_int128 *a, const secp256k1_int128 *b) {
|
||||
return a->hi == b->hi && a->lo == b->lo;
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n, int sign) {
|
||||
VERIFY_CHECK(n < 127);
|
||||
VERIFY_CHECK(sign == 1 || sign == -1);
|
||||
return n >= 64 ? r->hi == (uint64_t)sign << (n - 64) && r->lo == 0
|
||||
: r->hi == (uint64_t)(sign >> 1) && r->lo == (uint64_t)sign << n;
|
||||
}
|
||||
|
||||
#endif
|
||||
43
firmware/kb2040_hidden_signer/src/secp256k1/src/modinv32.h
Normal file
43
firmware/kb2040_hidden_signer/src/secp256k1/src/modinv32.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2020 Peter Dettman *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODINV32_H
|
||||
#define SECP256K1_MODINV32_H
|
||||
|
||||
#include "util.h"
|
||||
|
||||
/* A signed 30-bit limb representation of integers.
|
||||
*
|
||||
* Its value is sum(v[i] * 2^(30*i), i=0..8). */
|
||||
typedef struct {
|
||||
int32_t v[9];
|
||||
} secp256k1_modinv32_signed30;
|
||||
|
||||
typedef struct {
|
||||
/* The modulus in signed30 notation, must be odd and in [3, 2^256]. */
|
||||
secp256k1_modinv32_signed30 modulus;
|
||||
|
||||
/* modulus^{-1} mod 2^30 */
|
||||
uint32_t modulus_inv30;
|
||||
} secp256k1_modinv32_modinfo;
|
||||
|
||||
/* Replace x with its modular inverse mod modinfo->modulus. x must be in range [0, modulus).
|
||||
* If x is zero, the result will be zero as well. If not, the inverse must exist (i.e., the gcd of
|
||||
* x and modulus must be 1). These rules are automatically satisfied if the modulus is prime.
|
||||
*
|
||||
* On output, all of x's limbs will be in [0, 2^30).
|
||||
*/
|
||||
static void secp256k1_modinv32_var(secp256k1_modinv32_signed30 *x, const secp256k1_modinv32_modinfo *modinfo);
|
||||
|
||||
/* Same as secp256k1_modinv32_var, but constant time in x (not in the modulus). */
|
||||
static void secp256k1_modinv32(secp256k1_modinv32_signed30 *x, const secp256k1_modinv32_modinfo *modinfo);
|
||||
|
||||
/* Compute the Jacobi symbol for (x | modinfo->modulus). x must be coprime with modulus (and thus
|
||||
* cannot be 0, as modulus >= 3). All limbs of x must be non-negative. Returns 0 if the result
|
||||
* cannot be computed. */
|
||||
static int secp256k1_jacobi32_maybe_var(const secp256k1_modinv32_signed30 *x, const secp256k1_modinv32_modinfo *modinfo);
|
||||
|
||||
#endif /* SECP256K1_MODINV32_H */
|
||||
725
firmware/kb2040_hidden_signer/src/secp256k1/src/modinv32_impl.h
Normal file
725
firmware/kb2040_hidden_signer/src/secp256k1/src/modinv32_impl.h
Normal file
@@ -0,0 +1,725 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2020 Peter Dettman *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODINV32_IMPL_H
|
||||
#define SECP256K1_MODINV32_IMPL_H
|
||||
|
||||
#include "modinv32.h"
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* This file implements modular inversion based on the paper "Fast constant-time gcd computation and
|
||||
* modular inversion" by Daniel J. Bernstein and Bo-Yin Yang.
|
||||
*
|
||||
* For an explanation of the algorithm, see doc/safegcd_implementation.md. This file contains an
|
||||
* implementation for N=30, using 30-bit signed limbs represented as int32_t.
|
||||
*/
|
||||
|
||||
#ifdef VERIFY
|
||||
static const secp256k1_modinv32_signed30 SECP256K1_SIGNED30_ONE = {{1}};
|
||||
|
||||
/* Compute a*factor and put it in r. All but the top limb in r will be in range [0,2^30). */
|
||||
static void secp256k1_modinv32_mul_30(secp256k1_modinv32_signed30 *r, const secp256k1_modinv32_signed30 *a, int alen, int32_t factor) {
|
||||
const int32_t M30 = (int32_t)(UINT32_MAX >> 2);
|
||||
int64_t c = 0;
|
||||
int i;
|
||||
for (i = 0; i < 8; ++i) {
|
||||
if (i < alen) c += (int64_t)a->v[i] * factor;
|
||||
r->v[i] = (int32_t)c & M30; c >>= 30;
|
||||
}
|
||||
if (8 < alen) c += (int64_t)a->v[8] * factor;
|
||||
VERIFY_CHECK(c == (int32_t)c);
|
||||
r->v[8] = (int32_t)c;
|
||||
}
|
||||
|
||||
/* Return -1 for a<b*factor, 0 for a==b*factor, 1 for a>b*factor. A consists of alen limbs; b has 9. */
|
||||
static int secp256k1_modinv32_mul_cmp_30(const secp256k1_modinv32_signed30 *a, int alen, const secp256k1_modinv32_signed30 *b, int32_t factor) {
|
||||
int i;
|
||||
secp256k1_modinv32_signed30 am, bm;
|
||||
secp256k1_modinv32_mul_30(&am, a, alen, 1); /* Normalize all but the top limb of a. */
|
||||
secp256k1_modinv32_mul_30(&bm, b, 9, factor);
|
||||
for (i = 0; i < 8; ++i) {
|
||||
/* Verify that all but the top limb of a and b are normalized. */
|
||||
VERIFY_CHECK(am.v[i] >> 30 == 0);
|
||||
VERIFY_CHECK(bm.v[i] >> 30 == 0);
|
||||
}
|
||||
for (i = 8; i >= 0; --i) {
|
||||
if (am.v[i] < bm.v[i]) return -1;
|
||||
if (am.v[i] > bm.v[i]) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Take as input a signed30 number in range (-2*modulus,modulus), and add a multiple of the modulus
|
||||
* to it to bring it to range [0,modulus). If sign < 0, the input will also be negated in the
|
||||
* process. The input must have limbs in range (-2^30,2^30). The output will have limbs in range
|
||||
* [0,2^30). */
|
||||
static void secp256k1_modinv32_normalize_30(secp256k1_modinv32_signed30 *r, int32_t sign, const secp256k1_modinv32_modinfo *modinfo) {
|
||||
const int32_t M30 = (int32_t)(UINT32_MAX >> 2);
|
||||
int32_t r0 = r->v[0], r1 = r->v[1], r2 = r->v[2], r3 = r->v[3], r4 = r->v[4],
|
||||
r5 = r->v[5], r6 = r->v[6], r7 = r->v[7], r8 = r->v[8];
|
||||
volatile int32_t cond_add, cond_negate;
|
||||
|
||||
#ifdef VERIFY
|
||||
/* Verify that all limbs are in range (-2^30,2^30). */
|
||||
int i;
|
||||
for (i = 0; i < 9; ++i) {
|
||||
VERIFY_CHECK(r->v[i] >= -M30);
|
||||
VERIFY_CHECK(r->v[i] <= M30);
|
||||
}
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(r, 9, &modinfo->modulus, -2) > 0); /* r > -2*modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(r, 9, &modinfo->modulus, 1) < 0); /* r < modulus */
|
||||
#endif
|
||||
|
||||
/* In a first step, add the modulus if the input is negative, and then negate if requested.
|
||||
* This brings r from range (-2*modulus,modulus) to range (-modulus,modulus). As all input
|
||||
* limbs are in range (-2^30,2^30), this cannot overflow an int32_t. Note that the right
|
||||
* shifts below are signed sign-extending shifts (see assumptions.h for tests that that is
|
||||
* indeed the behavior of the right shift operator). */
|
||||
cond_add = r8 >> 31;
|
||||
r0 += modinfo->modulus.v[0] & cond_add;
|
||||
r1 += modinfo->modulus.v[1] & cond_add;
|
||||
r2 += modinfo->modulus.v[2] & cond_add;
|
||||
r3 += modinfo->modulus.v[3] & cond_add;
|
||||
r4 += modinfo->modulus.v[4] & cond_add;
|
||||
r5 += modinfo->modulus.v[5] & cond_add;
|
||||
r6 += modinfo->modulus.v[6] & cond_add;
|
||||
r7 += modinfo->modulus.v[7] & cond_add;
|
||||
r8 += modinfo->modulus.v[8] & cond_add;
|
||||
cond_negate = sign >> 31;
|
||||
r0 = (r0 ^ cond_negate) - cond_negate;
|
||||
r1 = (r1 ^ cond_negate) - cond_negate;
|
||||
r2 = (r2 ^ cond_negate) - cond_negate;
|
||||
r3 = (r3 ^ cond_negate) - cond_negate;
|
||||
r4 = (r4 ^ cond_negate) - cond_negate;
|
||||
r5 = (r5 ^ cond_negate) - cond_negate;
|
||||
r6 = (r6 ^ cond_negate) - cond_negate;
|
||||
r7 = (r7 ^ cond_negate) - cond_negate;
|
||||
r8 = (r8 ^ cond_negate) - cond_negate;
|
||||
/* Propagate the top bits, to bring limbs back to range (-2^30,2^30). */
|
||||
r1 += r0 >> 30; r0 &= M30;
|
||||
r2 += r1 >> 30; r1 &= M30;
|
||||
r3 += r2 >> 30; r2 &= M30;
|
||||
r4 += r3 >> 30; r3 &= M30;
|
||||
r5 += r4 >> 30; r4 &= M30;
|
||||
r6 += r5 >> 30; r5 &= M30;
|
||||
r7 += r6 >> 30; r6 &= M30;
|
||||
r8 += r7 >> 30; r7 &= M30;
|
||||
|
||||
/* In a second step add the modulus again if the result is still negative, bringing r to range
|
||||
* [0,modulus). */
|
||||
cond_add = r8 >> 31;
|
||||
r0 += modinfo->modulus.v[0] & cond_add;
|
||||
r1 += modinfo->modulus.v[1] & cond_add;
|
||||
r2 += modinfo->modulus.v[2] & cond_add;
|
||||
r3 += modinfo->modulus.v[3] & cond_add;
|
||||
r4 += modinfo->modulus.v[4] & cond_add;
|
||||
r5 += modinfo->modulus.v[5] & cond_add;
|
||||
r6 += modinfo->modulus.v[6] & cond_add;
|
||||
r7 += modinfo->modulus.v[7] & cond_add;
|
||||
r8 += modinfo->modulus.v[8] & cond_add;
|
||||
/* And propagate again. */
|
||||
r1 += r0 >> 30; r0 &= M30;
|
||||
r2 += r1 >> 30; r1 &= M30;
|
||||
r3 += r2 >> 30; r2 &= M30;
|
||||
r4 += r3 >> 30; r3 &= M30;
|
||||
r5 += r4 >> 30; r4 &= M30;
|
||||
r6 += r5 >> 30; r5 &= M30;
|
||||
r7 += r6 >> 30; r6 &= M30;
|
||||
r8 += r7 >> 30; r7 &= M30;
|
||||
|
||||
r->v[0] = r0;
|
||||
r->v[1] = r1;
|
||||
r->v[2] = r2;
|
||||
r->v[3] = r3;
|
||||
r->v[4] = r4;
|
||||
r->v[5] = r5;
|
||||
r->v[6] = r6;
|
||||
r->v[7] = r7;
|
||||
r->v[8] = r8;
|
||||
|
||||
VERIFY_CHECK(r0 >> 30 == 0);
|
||||
VERIFY_CHECK(r1 >> 30 == 0);
|
||||
VERIFY_CHECK(r2 >> 30 == 0);
|
||||
VERIFY_CHECK(r3 >> 30 == 0);
|
||||
VERIFY_CHECK(r4 >> 30 == 0);
|
||||
VERIFY_CHECK(r5 >> 30 == 0);
|
||||
VERIFY_CHECK(r6 >> 30 == 0);
|
||||
VERIFY_CHECK(r7 >> 30 == 0);
|
||||
VERIFY_CHECK(r8 >> 30 == 0);
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(r, 9, &modinfo->modulus, 0) >= 0); /* r >= 0 */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(r, 9, &modinfo->modulus, 1) < 0); /* r < modulus */
|
||||
}
|
||||
|
||||
/* Data type for transition matrices (see section 3 of explanation).
|
||||
*
|
||||
* t = [ u v ]
|
||||
* [ q r ]
|
||||
*/
|
||||
typedef struct {
|
||||
int32_t u, v, q, r;
|
||||
} secp256k1_modinv32_trans2x2;
|
||||
|
||||
/* Compute the transition matrix and zeta for 30 divsteps.
|
||||
*
|
||||
* Input: zeta: initial zeta
|
||||
* f0: bottom limb of initial f
|
||||
* g0: bottom limb of initial g
|
||||
* Output: t: transition matrix
|
||||
* Return: final zeta
|
||||
*
|
||||
* Implements the divsteps_n_matrix function from the explanation.
|
||||
*/
|
||||
static int32_t secp256k1_modinv32_divsteps_30(int32_t zeta, uint32_t f0, uint32_t g0, secp256k1_modinv32_trans2x2 *t) {
|
||||
/* u,v,q,r are the elements of the transformation matrix being built up,
|
||||
* starting with the identity matrix. Semantically they are signed integers
|
||||
* in range [-2^30,2^30], but here represented as unsigned mod 2^32. This
|
||||
* permits left shifting (which is UB for negative numbers). The range
|
||||
* being inside [-2^31,2^31) means that casting to signed works correctly.
|
||||
*/
|
||||
uint32_t u = 1, v = 0, q = 0, r = 1;
|
||||
volatile uint32_t c1, c2;
|
||||
uint32_t mask1, mask2, f = f0, g = g0, x, y, z;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 30; ++i) {
|
||||
VERIFY_CHECK((f & 1) == 1); /* f must always be odd */
|
||||
VERIFY_CHECK((u * f0 + v * g0) == f << i);
|
||||
VERIFY_CHECK((q * f0 + r * g0) == g << i);
|
||||
/* Compute conditional masks for (zeta < 0) and for (g & 1). */
|
||||
c1 = zeta >> 31;
|
||||
mask1 = c1;
|
||||
c2 = g & 1;
|
||||
mask2 = -c2;
|
||||
/* Compute x,y,z, conditionally negated versions of f,u,v. */
|
||||
x = (f ^ mask1) - mask1;
|
||||
y = (u ^ mask1) - mask1;
|
||||
z = (v ^ mask1) - mask1;
|
||||
/* Conditionally add x,y,z to g,q,r. */
|
||||
g += x & mask2;
|
||||
q += y & mask2;
|
||||
r += z & mask2;
|
||||
/* In what follows, mask1 is a condition mask for (zeta < 0) and (g & 1). */
|
||||
mask1 &= mask2;
|
||||
/* Conditionally change zeta into -zeta-2 or zeta-1. */
|
||||
zeta = (zeta ^ mask1) - 1;
|
||||
/* Conditionally add g,q,r to f,u,v. */
|
||||
f += g & mask1;
|
||||
u += q & mask1;
|
||||
v += r & mask1;
|
||||
/* Shifts */
|
||||
g >>= 1;
|
||||
u <<= 1;
|
||||
v <<= 1;
|
||||
/* Bounds on zeta that follow from the bounds on iteration count (max 20*30 divsteps). */
|
||||
VERIFY_CHECK(zeta >= -601 && zeta <= 601);
|
||||
}
|
||||
/* Return data in t and return value. */
|
||||
t->u = (int32_t)u;
|
||||
t->v = (int32_t)v;
|
||||
t->q = (int32_t)q;
|
||||
t->r = (int32_t)r;
|
||||
/* The determinant of t must be a power of two. This guarantees that multiplication with t
|
||||
* does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which
|
||||
* will be divided out again). As each divstep's individual matrix has determinant 2, the
|
||||
* aggregate of 30 of them will have determinant 2^30. */
|
||||
VERIFY_CHECK((int64_t)t->u * t->r - (int64_t)t->v * t->q == ((int64_t)1) << 30);
|
||||
return zeta;
|
||||
}
|
||||
|
||||
/* secp256k1_modinv32_inv256[i] = -(2*i+1)^-1 (mod 256) */
|
||||
static const uint8_t secp256k1_modinv32_inv256[128] = {
|
||||
0xFF, 0x55, 0x33, 0x49, 0xC7, 0x5D, 0x3B, 0x11, 0x0F, 0xE5, 0xC3, 0x59,
|
||||
0xD7, 0xED, 0xCB, 0x21, 0x1F, 0x75, 0x53, 0x69, 0xE7, 0x7D, 0x5B, 0x31,
|
||||
0x2F, 0x05, 0xE3, 0x79, 0xF7, 0x0D, 0xEB, 0x41, 0x3F, 0x95, 0x73, 0x89,
|
||||
0x07, 0x9D, 0x7B, 0x51, 0x4F, 0x25, 0x03, 0x99, 0x17, 0x2D, 0x0B, 0x61,
|
||||
0x5F, 0xB5, 0x93, 0xA9, 0x27, 0xBD, 0x9B, 0x71, 0x6F, 0x45, 0x23, 0xB9,
|
||||
0x37, 0x4D, 0x2B, 0x81, 0x7F, 0xD5, 0xB3, 0xC9, 0x47, 0xDD, 0xBB, 0x91,
|
||||
0x8F, 0x65, 0x43, 0xD9, 0x57, 0x6D, 0x4B, 0xA1, 0x9F, 0xF5, 0xD3, 0xE9,
|
||||
0x67, 0xFD, 0xDB, 0xB1, 0xAF, 0x85, 0x63, 0xF9, 0x77, 0x8D, 0x6B, 0xC1,
|
||||
0xBF, 0x15, 0xF3, 0x09, 0x87, 0x1D, 0xFB, 0xD1, 0xCF, 0xA5, 0x83, 0x19,
|
||||
0x97, 0xAD, 0x8B, 0xE1, 0xDF, 0x35, 0x13, 0x29, 0xA7, 0x3D, 0x1B, 0xF1,
|
||||
0xEF, 0xC5, 0xA3, 0x39, 0xB7, 0xCD, 0xAB, 0x01
|
||||
};
|
||||
|
||||
/* Compute the transition matrix and eta for 30 divsteps (variable time).
|
||||
*
|
||||
* Input: eta: initial eta
|
||||
* f0: bottom limb of initial f
|
||||
* g0: bottom limb of initial g
|
||||
* Output: t: transition matrix
|
||||
* Return: final eta
|
||||
*
|
||||
* Implements the divsteps_n_matrix_var function from the explanation.
|
||||
*/
|
||||
static int32_t secp256k1_modinv32_divsteps_30_var(int32_t eta, uint32_t f0, uint32_t g0, secp256k1_modinv32_trans2x2 *t) {
|
||||
/* Transformation matrix; see comments in secp256k1_modinv32_divsteps_30. */
|
||||
uint32_t u = 1, v = 0, q = 0, r = 1;
|
||||
uint32_t f = f0, g = g0, m;
|
||||
uint16_t w;
|
||||
int i = 30, limit, zeros;
|
||||
|
||||
for (;;) {
|
||||
/* Use a sentinel bit to count zeros only up to i. */
|
||||
zeros = secp256k1_ctz32_var(g | (UINT32_MAX << i));
|
||||
/* Perform zeros divsteps at once; they all just divide g by two. */
|
||||
g >>= zeros;
|
||||
u <<= zeros;
|
||||
v <<= zeros;
|
||||
eta -= zeros;
|
||||
i -= zeros;
|
||||
/* We're done once we've done 30 divsteps. */
|
||||
if (i == 0) break;
|
||||
VERIFY_CHECK((f & 1) == 1);
|
||||
VERIFY_CHECK((g & 1) == 1);
|
||||
VERIFY_CHECK((u * f0 + v * g0) == f << (30 - i));
|
||||
VERIFY_CHECK((q * f0 + r * g0) == g << (30 - i));
|
||||
/* Bounds on eta that follow from the bounds on iteration count (max 25*30 divsteps). */
|
||||
VERIFY_CHECK(eta >= -751 && eta <= 751);
|
||||
/* If eta is negative, negate it and replace f,g with g,-f. */
|
||||
if (eta < 0) {
|
||||
uint32_t tmp;
|
||||
eta = -eta;
|
||||
tmp = f; f = g; g = -tmp;
|
||||
tmp = u; u = q; q = -tmp;
|
||||
tmp = v; v = r; r = -tmp;
|
||||
}
|
||||
/* eta is now >= 0. In what follows we're going to cancel out the bottom bits of g. No more
|
||||
* than i can be cancelled out (as we'd be done before that point), and no more than eta+1
|
||||
* can be done as its sign will flip once that happens. */
|
||||
limit = ((int)eta + 1) > i ? i : ((int)eta + 1);
|
||||
/* m is a mask for the bottom min(limit, 8) bits (our table only supports 8 bits). */
|
||||
VERIFY_CHECK(limit > 0 && limit <= 30);
|
||||
m = (UINT32_MAX >> (32 - limit)) & 255U;
|
||||
/* Find what multiple of f must be added to g to cancel its bottom min(limit, 8) bits. */
|
||||
w = (g * secp256k1_modinv32_inv256[(f >> 1) & 127]) & m;
|
||||
/* Do so. */
|
||||
g += f * w;
|
||||
q += u * w;
|
||||
r += v * w;
|
||||
VERIFY_CHECK((g & m) == 0);
|
||||
}
|
||||
/* Return data in t and return value. */
|
||||
t->u = (int32_t)u;
|
||||
t->v = (int32_t)v;
|
||||
t->q = (int32_t)q;
|
||||
t->r = (int32_t)r;
|
||||
/* The determinant of t must be a power of two. This guarantees that multiplication with t
|
||||
* does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which
|
||||
* will be divided out again). As each divstep's individual matrix has determinant 2, the
|
||||
* aggregate of 30 of them will have determinant 2^30. */
|
||||
VERIFY_CHECK((int64_t)t->u * t->r - (int64_t)t->v * t->q == ((int64_t)1) << 30);
|
||||
return eta;
|
||||
}
|
||||
|
||||
/* Compute the transition matrix and eta for 30 posdivsteps (variable time, eta=-delta), and keeps track
|
||||
* of the Jacobi symbol along the way. f0 and g0 must be f and g mod 2^32 rather than 2^30, because
|
||||
* Jacobi tracking requires knowing (f mod 8) rather than just (f mod 2).
|
||||
*
|
||||
* Input: eta: initial eta
|
||||
* f0: bottom limb of initial f
|
||||
* g0: bottom limb of initial g
|
||||
* Output: t: transition matrix
|
||||
* Input/Output: (*jacp & 1) is bitflipped if and only if the Jacobi symbol of (f | g) changes sign
|
||||
* by applying the returned transformation matrix to it. The other bits of *jacp may
|
||||
* change, but are meaningless.
|
||||
* Return: final eta
|
||||
*/
|
||||
static int32_t secp256k1_modinv32_posdivsteps_30_var(int32_t eta, uint32_t f0, uint32_t g0, secp256k1_modinv32_trans2x2 *t, int *jacp) {
|
||||
/* Transformation matrix. */
|
||||
uint32_t u = 1, v = 0, q = 0, r = 1;
|
||||
uint32_t f = f0, g = g0, m;
|
||||
uint16_t w;
|
||||
int i = 30, limit, zeros;
|
||||
int jac = *jacp;
|
||||
|
||||
for (;;) {
|
||||
/* Use a sentinel bit to count zeros only up to i. */
|
||||
zeros = secp256k1_ctz32_var(g | (UINT32_MAX << i));
|
||||
/* Perform zeros divsteps at once; they all just divide g by two. */
|
||||
g >>= zeros;
|
||||
u <<= zeros;
|
||||
v <<= zeros;
|
||||
eta -= zeros;
|
||||
i -= zeros;
|
||||
/* Update the bottom bit of jac: when dividing g by an odd power of 2,
|
||||
* if (f mod 8) is 3 or 5, the Jacobi symbol changes sign. */
|
||||
jac ^= (zeros & ((f >> 1) ^ (f >> 2)));
|
||||
/* We're done once we've done 30 posdivsteps. */
|
||||
if (i == 0) break;
|
||||
VERIFY_CHECK((f & 1) == 1);
|
||||
VERIFY_CHECK((g & 1) == 1);
|
||||
VERIFY_CHECK((u * f0 + v * g0) == f << (30 - i));
|
||||
VERIFY_CHECK((q * f0 + r * g0) == g << (30 - i));
|
||||
/* If eta is negative, negate it and replace f,g with g,f. */
|
||||
if (eta < 0) {
|
||||
uint32_t tmp;
|
||||
eta = -eta;
|
||||
/* Update bottom bit of jac: when swapping f and g, the Jacobi symbol changes sign
|
||||
* if both f and g are 3 mod 4. */
|
||||
jac ^= ((f & g) >> 1);
|
||||
tmp = f; f = g; g = tmp;
|
||||
tmp = u; u = q; q = tmp;
|
||||
tmp = v; v = r; r = tmp;
|
||||
}
|
||||
/* eta is now >= 0. In what follows we're going to cancel out the bottom bits of g. No more
|
||||
* than i can be cancelled out (as we'd be done before that point), and no more than eta+1
|
||||
* can be done as its sign will flip once that happens. */
|
||||
limit = ((int)eta + 1) > i ? i : ((int)eta + 1);
|
||||
/* m is a mask for the bottom min(limit, 8) bits (our table only supports 8 bits). */
|
||||
VERIFY_CHECK(limit > 0 && limit <= 30);
|
||||
m = (UINT32_MAX >> (32 - limit)) & 255U;
|
||||
/* Find what multiple of f must be added to g to cancel its bottom min(limit, 8) bits. */
|
||||
w = (g * secp256k1_modinv32_inv256[(f >> 1) & 127]) & m;
|
||||
/* Do so. */
|
||||
g += f * w;
|
||||
q += u * w;
|
||||
r += v * w;
|
||||
VERIFY_CHECK((g & m) == 0);
|
||||
}
|
||||
/* Return data in t and return value. */
|
||||
t->u = (int32_t)u;
|
||||
t->v = (int32_t)v;
|
||||
t->q = (int32_t)q;
|
||||
t->r = (int32_t)r;
|
||||
/* The determinant of t must be a power of two. This guarantees that multiplication with t
|
||||
* does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which
|
||||
* will be divided out again). As each divstep's individual matrix has determinant 2 or -2,
|
||||
* the aggregate of 30 of them will have determinant 2^30 or -2^30. */
|
||||
VERIFY_CHECK((int64_t)t->u * t->r - (int64_t)t->v * t->q == ((int64_t)1) << 30 ||
|
||||
(int64_t)t->u * t->r - (int64_t)t->v * t->q == -(((int64_t)1) << 30));
|
||||
*jacp = jac;
|
||||
return eta;
|
||||
}
|
||||
|
||||
/* Compute (t/2^30) * [d, e] mod modulus, where t is a transition matrix for 30 divsteps.
|
||||
*
|
||||
* On input and output, d and e are in range (-2*modulus,modulus). All output limbs will be in range
|
||||
* (-2^30,2^30).
|
||||
*
|
||||
* This implements the update_de function from the explanation.
|
||||
*/
|
||||
static void secp256k1_modinv32_update_de_30(secp256k1_modinv32_signed30 *d, secp256k1_modinv32_signed30 *e, const secp256k1_modinv32_trans2x2 *t, const secp256k1_modinv32_modinfo* modinfo) {
|
||||
const int32_t M30 = (int32_t)(UINT32_MAX >> 2);
|
||||
const int32_t u = t->u, v = t->v, q = t->q, r = t->r;
|
||||
int32_t di, ei, md, me, sd, se;
|
||||
int64_t cd, ce;
|
||||
int i;
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, -2) > 0); /* d > -2*modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, 1) < 0); /* d < modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, -2) > 0); /* e > -2*modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, 1) < 0); /* e < modulus */
|
||||
VERIFY_CHECK(labs(u) <= (M30 + 1 - labs(v))); /* |u|+|v| <= 2^30 */
|
||||
VERIFY_CHECK(labs(q) <= (M30 + 1 - labs(r))); /* |q|+|r| <= 2^30 */
|
||||
|
||||
/* [md,me] start as zero; plus [u,q] if d is negative; plus [v,r] if e is negative. */
|
||||
sd = d->v[8] >> 31;
|
||||
se = e->v[8] >> 31;
|
||||
md = (u & sd) + (v & se);
|
||||
me = (q & sd) + (r & se);
|
||||
/* Begin computing t*[d,e]. */
|
||||
di = d->v[0];
|
||||
ei = e->v[0];
|
||||
cd = (int64_t)u * di + (int64_t)v * ei;
|
||||
ce = (int64_t)q * di + (int64_t)r * ei;
|
||||
/* Correct md,me so that t*[d,e]+modulus*[md,me] has 30 zero bottom bits. */
|
||||
md -= (modinfo->modulus_inv30 * (uint32_t)cd + md) & M30;
|
||||
me -= (modinfo->modulus_inv30 * (uint32_t)ce + me) & M30;
|
||||
/* Update the beginning of computation for t*[d,e]+modulus*[md,me] now md,me are known. */
|
||||
cd += (int64_t)modinfo->modulus.v[0] * md;
|
||||
ce += (int64_t)modinfo->modulus.v[0] * me;
|
||||
/* Verify that the low 30 bits of the computation are indeed zero, and then throw them away. */
|
||||
VERIFY_CHECK(((int32_t)cd & M30) == 0); cd >>= 30;
|
||||
VERIFY_CHECK(((int32_t)ce & M30) == 0); ce >>= 30;
|
||||
/* Now iteratively compute limb i=1..8 of t*[d,e]+modulus*[md,me], and store them in output
|
||||
* limb i-1 (shifting down by 30 bits). */
|
||||
for (i = 1; i < 9; ++i) {
|
||||
di = d->v[i];
|
||||
ei = e->v[i];
|
||||
cd += (int64_t)u * di + (int64_t)v * ei;
|
||||
ce += (int64_t)q * di + (int64_t)r * ei;
|
||||
cd += (int64_t)modinfo->modulus.v[i] * md;
|
||||
ce += (int64_t)modinfo->modulus.v[i] * me;
|
||||
d->v[i - 1] = (int32_t)cd & M30; cd >>= 30;
|
||||
e->v[i - 1] = (int32_t)ce & M30; ce >>= 30;
|
||||
}
|
||||
/* What remains is limb 9 of t*[d,e]+modulus*[md,me]; store it as output limb 8. */
|
||||
d->v[8] = (int32_t)cd;
|
||||
e->v[8] = (int32_t)ce;
|
||||
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, -2) > 0); /* d > -2*modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, 1) < 0); /* d < modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, -2) > 0); /* e > -2*modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, 1) < 0); /* e < modulus */
|
||||
}
|
||||
|
||||
/* Compute (t/2^30) * [f, g], where t is a transition matrix for 30 divsteps.
|
||||
*
|
||||
* This implements the update_fg function from the explanation.
|
||||
*/
|
||||
static void secp256k1_modinv32_update_fg_30(secp256k1_modinv32_signed30 *f, secp256k1_modinv32_signed30 *g, const secp256k1_modinv32_trans2x2 *t) {
|
||||
const int32_t M30 = (int32_t)(UINT32_MAX >> 2);
|
||||
const int32_t u = t->u, v = t->v, q = t->q, r = t->r;
|
||||
int32_t fi, gi;
|
||||
int64_t cf, cg;
|
||||
int i;
|
||||
/* Start computing t*[f,g]. */
|
||||
fi = f->v[0];
|
||||
gi = g->v[0];
|
||||
cf = (int64_t)u * fi + (int64_t)v * gi;
|
||||
cg = (int64_t)q * fi + (int64_t)r * gi;
|
||||
/* Verify that the bottom 30 bits of the result are zero, and then throw them away. */
|
||||
VERIFY_CHECK(((int32_t)cf & M30) == 0); cf >>= 30;
|
||||
VERIFY_CHECK(((int32_t)cg & M30) == 0); cg >>= 30;
|
||||
/* Now iteratively compute limb i=1..8 of t*[f,g], and store them in output limb i-1 (shifting
|
||||
* down by 30 bits). */
|
||||
for (i = 1; i < 9; ++i) {
|
||||
fi = f->v[i];
|
||||
gi = g->v[i];
|
||||
cf += (int64_t)u * fi + (int64_t)v * gi;
|
||||
cg += (int64_t)q * fi + (int64_t)r * gi;
|
||||
f->v[i - 1] = (int32_t)cf & M30; cf >>= 30;
|
||||
g->v[i - 1] = (int32_t)cg & M30; cg >>= 30;
|
||||
}
|
||||
/* What remains is limb 9 of t*[f,g]; store it as output limb 8. */
|
||||
f->v[8] = (int32_t)cf;
|
||||
g->v[8] = (int32_t)cg;
|
||||
}
|
||||
|
||||
/* Compute (t/2^30) * [f, g], where t is a transition matrix for 30 divsteps.
|
||||
*
|
||||
* Version that operates on a variable number of limbs in f and g.
|
||||
*
|
||||
* This implements the update_fg function from the explanation in modinv64_impl.h.
|
||||
*/
|
||||
static void secp256k1_modinv32_update_fg_30_var(int len, secp256k1_modinv32_signed30 *f, secp256k1_modinv32_signed30 *g, const secp256k1_modinv32_trans2x2 *t) {
|
||||
const int32_t M30 = (int32_t)(UINT32_MAX >> 2);
|
||||
const int32_t u = t->u, v = t->v, q = t->q, r = t->r;
|
||||
int32_t fi, gi;
|
||||
int64_t cf, cg;
|
||||
int i;
|
||||
VERIFY_CHECK(len > 0);
|
||||
/* Start computing t*[f,g]. */
|
||||
fi = f->v[0];
|
||||
gi = g->v[0];
|
||||
cf = (int64_t)u * fi + (int64_t)v * gi;
|
||||
cg = (int64_t)q * fi + (int64_t)r * gi;
|
||||
/* Verify that the bottom 62 bits of the result are zero, and then throw them away. */
|
||||
VERIFY_CHECK(((int32_t)cf & M30) == 0); cf >>= 30;
|
||||
VERIFY_CHECK(((int32_t)cg & M30) == 0); cg >>= 30;
|
||||
/* Now iteratively compute limb i=1..len of t*[f,g], and store them in output limb i-1 (shifting
|
||||
* down by 30 bits). */
|
||||
for (i = 1; i < len; ++i) {
|
||||
fi = f->v[i];
|
||||
gi = g->v[i];
|
||||
cf += (int64_t)u * fi + (int64_t)v * gi;
|
||||
cg += (int64_t)q * fi + (int64_t)r * gi;
|
||||
f->v[i - 1] = (int32_t)cf & M30; cf >>= 30;
|
||||
g->v[i - 1] = (int32_t)cg & M30; cg >>= 30;
|
||||
}
|
||||
/* What remains is limb (len) of t*[f,g]; store it as output limb (len-1). */
|
||||
f->v[len - 1] = (int32_t)cf;
|
||||
g->v[len - 1] = (int32_t)cg;
|
||||
}
|
||||
|
||||
/* Compute the inverse of x modulo modinfo->modulus, and replace x with it (constant time in x). */
|
||||
static void secp256k1_modinv32(secp256k1_modinv32_signed30 *x, const secp256k1_modinv32_modinfo *modinfo) {
|
||||
/* Start with d=0, e=1, f=modulus, g=x, zeta=-1. */
|
||||
secp256k1_modinv32_signed30 d = {{0}};
|
||||
secp256k1_modinv32_signed30 e = {{1}};
|
||||
secp256k1_modinv32_signed30 f = modinfo->modulus;
|
||||
secp256k1_modinv32_signed30 g = *x;
|
||||
int i;
|
||||
int32_t zeta = -1; /* zeta = -(delta+1/2); delta is initially 1/2. */
|
||||
|
||||
/* Do 20 iterations of 30 divsteps each = 600 divsteps. 590 suffices for 256-bit inputs. */
|
||||
for (i = 0; i < 20; ++i) {
|
||||
/* Compute transition matrix and new zeta after 30 divsteps. */
|
||||
secp256k1_modinv32_trans2x2 t;
|
||||
zeta = secp256k1_modinv32_divsteps_30(zeta, f.v[0], g.v[0], &t);
|
||||
/* Update d,e using that transition matrix. */
|
||||
secp256k1_modinv32_update_de_30(&d, &e, &t, modinfo);
|
||||
/* Update f,g using that transition matrix. */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, -1) > 0); /* f > -modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, 1) <= 0); /* f <= modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, 9, &modinfo->modulus, -1) > 0); /* g > -modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, 9, &modinfo->modulus, 1) < 0); /* g < modulus */
|
||||
|
||||
secp256k1_modinv32_update_fg_30(&f, &g, &t);
|
||||
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, -1) > 0); /* f > -modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, 1) <= 0); /* f <= modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, 9, &modinfo->modulus, -1) > 0); /* g > -modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, 9, &modinfo->modulus, 1) < 0); /* g < modulus */
|
||||
}
|
||||
|
||||
/* At this point sufficient iterations have been performed that g must have reached 0
|
||||
* and (if g was not originally 0) f must now equal +/- GCD of the initial f, g
|
||||
* values i.e. +/- 1, and d now contains +/- the modular inverse. */
|
||||
|
||||
/* g == 0 */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, 9, &SECP256K1_SIGNED30_ONE, 0) == 0);
|
||||
/* |f| == 1, or (x == 0 and d == 0 and f == modulus) */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, 9, &SECP256K1_SIGNED30_ONE, -1) == 0 ||
|
||||
secp256k1_modinv32_mul_cmp_30(&f, 9, &SECP256K1_SIGNED30_ONE, 1) == 0 ||
|
||||
(secp256k1_modinv32_mul_cmp_30(x, 9, &SECP256K1_SIGNED30_ONE, 0) == 0 &&
|
||||
secp256k1_modinv32_mul_cmp_30(&d, 9, &SECP256K1_SIGNED30_ONE, 0) == 0 &&
|
||||
secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, 1) == 0));
|
||||
|
||||
/* Optionally negate d, normalize to [0,modulus), and return it. */
|
||||
secp256k1_modinv32_normalize_30(&d, f.v[8], modinfo);
|
||||
*x = d;
|
||||
}
|
||||
|
||||
/* Compute the inverse of x modulo modinfo->modulus, and replace x with it (variable time). */
|
||||
static void secp256k1_modinv32_var(secp256k1_modinv32_signed30 *x, const secp256k1_modinv32_modinfo *modinfo) {
|
||||
/* Start with d=0, e=1, f=modulus, g=x, eta=-1. */
|
||||
secp256k1_modinv32_signed30 d = {{0, 0, 0, 0, 0, 0, 0, 0, 0}};
|
||||
secp256k1_modinv32_signed30 e = {{1, 0, 0, 0, 0, 0, 0, 0, 0}};
|
||||
secp256k1_modinv32_signed30 f = modinfo->modulus;
|
||||
secp256k1_modinv32_signed30 g = *x;
|
||||
#ifdef VERIFY
|
||||
int i = 0;
|
||||
#endif
|
||||
int j, len = 9;
|
||||
int32_t eta = -1; /* eta = -delta; delta is initially 1 (faster for the variable-time code) */
|
||||
int32_t cond, fn, gn;
|
||||
|
||||
/* Do iterations of 30 divsteps each until g=0. */
|
||||
while (1) {
|
||||
/* Compute transition matrix and new eta after 30 divsteps. */
|
||||
secp256k1_modinv32_trans2x2 t;
|
||||
eta = secp256k1_modinv32_divsteps_30_var(eta, f.v[0], g.v[0], &t);
|
||||
/* Update d,e using that transition matrix. */
|
||||
secp256k1_modinv32_update_de_30(&d, &e, &t, modinfo);
|
||||
/* Update f,g using that transition matrix. */
|
||||
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, -1) > 0); /* f > -modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, -1) > 0); /* g > -modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
|
||||
|
||||
secp256k1_modinv32_update_fg_30_var(len, &f, &g, &t);
|
||||
/* If the bottom limb of g is 0, there is a chance g=0. */
|
||||
if (g.v[0] == 0) {
|
||||
cond = 0;
|
||||
/* Check if all other limbs are also 0. */
|
||||
for (j = 1; j < len; ++j) {
|
||||
cond |= g.v[j];
|
||||
}
|
||||
/* If so, we're done. */
|
||||
if (cond == 0) break;
|
||||
}
|
||||
|
||||
/* Determine if len>1 and limb (len-1) of both f and g is 0 or -1. */
|
||||
fn = f.v[len - 1];
|
||||
gn = g.v[len - 1];
|
||||
cond = ((int32_t)len - 2) >> 31;
|
||||
cond |= fn ^ (fn >> 31);
|
||||
cond |= gn ^ (gn >> 31);
|
||||
/* If so, reduce length, propagating the sign of f and g's top limb into the one below. */
|
||||
if (cond == 0) {
|
||||
f.v[len - 2] |= (uint32_t)fn << 30;
|
||||
g.v[len - 2] |= (uint32_t)gn << 30;
|
||||
--len;
|
||||
}
|
||||
|
||||
VERIFY_CHECK(++i < 25); /* We should never need more than 25*30 = 750 divsteps */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, -1) > 0); /* f > -modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, -1) > 0); /* g > -modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
|
||||
}
|
||||
|
||||
/* At this point g is 0 and (if g was not originally 0) f must now equal +/- GCD of
|
||||
* the initial f, g values i.e. +/- 1, and d now contains +/- the modular inverse. */
|
||||
|
||||
/* g == 0 */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &SECP256K1_SIGNED30_ONE, 0) == 0);
|
||||
/* |f| == 1, or (x == 0 and d == 0 and f == modulus) */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &SECP256K1_SIGNED30_ONE, -1) == 0 ||
|
||||
secp256k1_modinv32_mul_cmp_30(&f, len, &SECP256K1_SIGNED30_ONE, 1) == 0 ||
|
||||
(secp256k1_modinv32_mul_cmp_30(x, 9, &SECP256K1_SIGNED30_ONE, 0) == 0 &&
|
||||
secp256k1_modinv32_mul_cmp_30(&d, 9, &SECP256K1_SIGNED30_ONE, 0) == 0 &&
|
||||
secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) == 0));
|
||||
|
||||
/* Optionally negate d, normalize to [0,modulus), and return it. */
|
||||
secp256k1_modinv32_normalize_30(&d, f.v[len - 1], modinfo);
|
||||
*x = d;
|
||||
}
|
||||
|
||||
/* Do up to 50 iterations of 30 posdivsteps (up to 1500 steps; more is extremely rare) each until f=1.
|
||||
* In VERIFY mode use a lower number of iterations (750, close to the median 756), so failure actually occurs. */
|
||||
#ifdef VERIFY
|
||||
#define JACOBI32_ITERATIONS 25
|
||||
#else
|
||||
#define JACOBI32_ITERATIONS 50
|
||||
#endif
|
||||
|
||||
/* Compute the Jacobi symbol of x modulo modinfo->modulus (variable time). gcd(x,modulus) must be 1. */
|
||||
static int secp256k1_jacobi32_maybe_var(const secp256k1_modinv32_signed30 *x, const secp256k1_modinv32_modinfo *modinfo) {
|
||||
/* Start with f=modulus, g=x, eta=-1. */
|
||||
secp256k1_modinv32_signed30 f = modinfo->modulus;
|
||||
secp256k1_modinv32_signed30 g = *x;
|
||||
int j, len = 9;
|
||||
int32_t eta = -1; /* eta = -delta; delta is initially 1 */
|
||||
int32_t cond, fn, gn;
|
||||
int jac = 0;
|
||||
int count;
|
||||
|
||||
/* The input limbs must all be non-negative. */
|
||||
VERIFY_CHECK(g.v[0] >= 0 && g.v[1] >= 0 && g.v[2] >= 0 && g.v[3] >= 0 && g.v[4] >= 0 && g.v[5] >= 0 && g.v[6] >= 0 && g.v[7] >= 0 && g.v[8] >= 0);
|
||||
|
||||
/* If x > 0, then if the loop below converges, it converges to f=g=gcd(x,modulus). Since we
|
||||
* require that gcd(x,modulus)=1 and modulus>=3, x cannot be 0. Thus, we must reach f=1 (or
|
||||
* time out). */
|
||||
VERIFY_CHECK((g.v[0] | g.v[1] | g.v[2] | g.v[3] | g.v[4] | g.v[5] | g.v[6] | g.v[7] | g.v[8]) != 0);
|
||||
|
||||
for (count = 0; count < JACOBI32_ITERATIONS; ++count) {
|
||||
/* Compute transition matrix and new eta after 30 posdivsteps. */
|
||||
secp256k1_modinv32_trans2x2 t;
|
||||
eta = secp256k1_modinv32_posdivsteps_30_var(eta, f.v[0] | ((uint32_t)f.v[1] << 30), g.v[0] | ((uint32_t)g.v[1] << 30), &t, &jac);
|
||||
/* Update f,g using that transition matrix. */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
|
||||
|
||||
secp256k1_modinv32_update_fg_30_var(len, &f, &g, &t);
|
||||
/* If the bottom limb of f is 1, there is a chance that f=1. */
|
||||
if (f.v[0] == 1) {
|
||||
cond = 0;
|
||||
/* Check if the other limbs are also 0. */
|
||||
for (j = 1; j < len; ++j) {
|
||||
cond |= f.v[j];
|
||||
}
|
||||
/* If so, we're done. If f=1, the Jacobi symbol (g | f)=1. */
|
||||
if (cond == 0) return 1 - 2*(jac & 1);
|
||||
}
|
||||
|
||||
/* Determine if len>1 and limb (len-1) of both f and g is 0. */
|
||||
fn = f.v[len - 1];
|
||||
gn = g.v[len - 1];
|
||||
cond = ((int32_t)len - 2) >> 31;
|
||||
cond |= fn;
|
||||
cond |= gn;
|
||||
/* If so, reduce length. */
|
||||
if (cond == 0) --len;
|
||||
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
|
||||
}
|
||||
|
||||
/* The loop failed to converge to f=g after 1500 iterations. Return 0, indicating unknown result. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* SECP256K1_MODINV32_IMPL_H */
|
||||
47
firmware/kb2040_hidden_signer/src/secp256k1/src/modinv64.h
Normal file
47
firmware/kb2040_hidden_signer/src/secp256k1/src/modinv64.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2020 Peter Dettman *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODINV64_H
|
||||
#define SECP256K1_MODINV64_H
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#ifndef SECP256K1_WIDEMUL_INT128
|
||||
#error "modinv64 requires 128-bit wide multiplication support"
|
||||
#endif
|
||||
|
||||
/* A signed 62-bit limb representation of integers.
|
||||
*
|
||||
* Its value is sum(v[i] * 2^(62*i), i=0..4). */
|
||||
typedef struct {
|
||||
int64_t v[5];
|
||||
} secp256k1_modinv64_signed62;
|
||||
|
||||
typedef struct {
|
||||
/* The modulus in signed62 notation, must be odd and in [3, 2^256]. */
|
||||
secp256k1_modinv64_signed62 modulus;
|
||||
|
||||
/* modulus^{-1} mod 2^62 */
|
||||
uint64_t modulus_inv62;
|
||||
} secp256k1_modinv64_modinfo;
|
||||
|
||||
/* Replace x with its modular inverse mod modinfo->modulus. x must be in range [0, modulus).
|
||||
* If x is zero, the result will be zero as well. If not, the inverse must exist (i.e., the gcd of
|
||||
* x and modulus must be 1). These rules are automatically satisfied if the modulus is prime.
|
||||
*
|
||||
* On output, all of x's limbs will be in [0, 2^62).
|
||||
*/
|
||||
static void secp256k1_modinv64_var(secp256k1_modinv64_signed62 *x, const secp256k1_modinv64_modinfo *modinfo);
|
||||
|
||||
/* Same as secp256k1_modinv64_var, but constant time in x (not in the modulus). */
|
||||
static void secp256k1_modinv64(secp256k1_modinv64_signed62 *x, const secp256k1_modinv64_modinfo *modinfo);
|
||||
|
||||
/* Compute the Jacobi symbol for (x | modinfo->modulus). x must be coprime with modulus (and thus
|
||||
* cannot be 0, as modulus >= 3). All limbs of x must be non-negative. Returns 0 if the result
|
||||
* cannot be computed. */
|
||||
static int secp256k1_jacobi64_maybe_var(const secp256k1_modinv64_signed62 *x, const secp256k1_modinv64_modinfo *modinfo);
|
||||
|
||||
#endif /* SECP256K1_MODINV64_H */
|
||||
780
firmware/kb2040_hidden_signer/src/secp256k1/src/modinv64_impl.h
Normal file
780
firmware/kb2040_hidden_signer/src/secp256k1/src/modinv64_impl.h
Normal file
@@ -0,0 +1,780 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2020 Peter Dettman *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODINV64_IMPL_H
|
||||
#define SECP256K1_MODINV64_IMPL_H
|
||||
|
||||
#include "int128.h"
|
||||
#include "modinv64.h"
|
||||
|
||||
/* This file implements modular inversion based on the paper "Fast constant-time gcd computation and
|
||||
* modular inversion" by Daniel J. Bernstein and Bo-Yin Yang.
|
||||
*
|
||||
* For an explanation of the algorithm, see doc/safegcd_implementation.md. This file contains an
|
||||
* implementation for N=62, using 62-bit signed limbs represented as int64_t.
|
||||
*/
|
||||
|
||||
/* Data type for transition matrices (see section 3 of explanation).
|
||||
*
|
||||
* t = [ u v ]
|
||||
* [ q r ]
|
||||
*/
|
||||
typedef struct {
|
||||
int64_t u, v, q, r;
|
||||
} secp256k1_modinv64_trans2x2;
|
||||
|
||||
#ifdef VERIFY
|
||||
/* Helper function to compute the absolute value of an int64_t.
|
||||
* (we don't use abs/labs/llabs as it depends on the int sizes). */
|
||||
static int64_t secp256k1_modinv64_abs(int64_t v) {
|
||||
VERIFY_CHECK(v > INT64_MIN);
|
||||
if (v < 0) return -v;
|
||||
return v;
|
||||
}
|
||||
|
||||
static const secp256k1_modinv64_signed62 SECP256K1_SIGNED62_ONE = {{1}};
|
||||
|
||||
/* Compute a*factor and put it in r. All but the top limb in r will be in range [0,2^62). */
|
||||
static void secp256k1_modinv64_mul_62(secp256k1_modinv64_signed62 *r, const secp256k1_modinv64_signed62 *a, int alen, int64_t factor) {
|
||||
const uint64_t M62 = UINT64_MAX >> 2;
|
||||
secp256k1_int128 c, d;
|
||||
int i;
|
||||
secp256k1_i128_from_i64(&c, 0);
|
||||
for (i = 0; i < 4; ++i) {
|
||||
if (i < alen) secp256k1_i128_accum_mul(&c, a->v[i], factor);
|
||||
r->v[i] = secp256k1_i128_to_u64(&c) & M62; secp256k1_i128_rshift(&c, 62);
|
||||
}
|
||||
if (4 < alen) secp256k1_i128_accum_mul(&c, a->v[4], factor);
|
||||
secp256k1_i128_from_i64(&d, secp256k1_i128_to_i64(&c));
|
||||
VERIFY_CHECK(secp256k1_i128_eq_var(&c, &d));
|
||||
r->v[4] = secp256k1_i128_to_i64(&c);
|
||||
}
|
||||
|
||||
/* Return -1 for a<b*factor, 0 for a==b*factor, 1 for a>b*factor. A has alen limbs; b has 5. */
|
||||
static int secp256k1_modinv64_mul_cmp_62(const secp256k1_modinv64_signed62 *a, int alen, const secp256k1_modinv64_signed62 *b, int64_t factor) {
|
||||
int i;
|
||||
secp256k1_modinv64_signed62 am, bm;
|
||||
secp256k1_modinv64_mul_62(&am, a, alen, 1); /* Normalize all but the top limb of a. */
|
||||
secp256k1_modinv64_mul_62(&bm, b, 5, factor);
|
||||
for (i = 0; i < 4; ++i) {
|
||||
/* Verify that all but the top limb of a and b are normalized. */
|
||||
VERIFY_CHECK(am.v[i] >> 62 == 0);
|
||||
VERIFY_CHECK(bm.v[i] >> 62 == 0);
|
||||
}
|
||||
for (i = 4; i >= 0; --i) {
|
||||
if (am.v[i] < bm.v[i]) return -1;
|
||||
if (am.v[i] > bm.v[i]) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check if the determinant of t is equal to 1 << n. If abs, check if |det t| == 1 << n. */
|
||||
static int secp256k1_modinv64_det_check_pow2(const secp256k1_modinv64_trans2x2 *t, unsigned int n, int abs) {
|
||||
secp256k1_int128 a;
|
||||
secp256k1_i128_det(&a, t->u, t->v, t->q, t->r);
|
||||
if (secp256k1_i128_check_pow2(&a, n, 1)) return 1;
|
||||
if (abs && secp256k1_i128_check_pow2(&a, n, -1)) return 1;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Take as input a signed62 number in range (-2*modulus,modulus), and add a multiple of the modulus
|
||||
* to it to bring it to range [0,modulus). If sign < 0, the input will also be negated in the
|
||||
* process. The input must have limbs in range (-2^62,2^62). The output will have limbs in range
|
||||
* [0,2^62). */
|
||||
static void secp256k1_modinv64_normalize_62(secp256k1_modinv64_signed62 *r, int64_t sign, const secp256k1_modinv64_modinfo *modinfo) {
|
||||
const int64_t M62 = (int64_t)(UINT64_MAX >> 2);
|
||||
int64_t r0 = r->v[0], r1 = r->v[1], r2 = r->v[2], r3 = r->v[3], r4 = r->v[4];
|
||||
volatile int64_t cond_add, cond_negate;
|
||||
|
||||
#ifdef VERIFY
|
||||
/* Verify that all limbs are in range (-2^62,2^62). */
|
||||
int i;
|
||||
for (i = 0; i < 5; ++i) {
|
||||
VERIFY_CHECK(r->v[i] >= -M62);
|
||||
VERIFY_CHECK(r->v[i] <= M62);
|
||||
}
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(r, 5, &modinfo->modulus, -2) > 0); /* r > -2*modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(r, 5, &modinfo->modulus, 1) < 0); /* r < modulus */
|
||||
#endif
|
||||
|
||||
/* In a first step, add the modulus if the input is negative, and then negate if requested.
|
||||
* This brings r from range (-2*modulus,modulus) to range (-modulus,modulus). As all input
|
||||
* limbs are in range (-2^62,2^62), this cannot overflow an int64_t. Note that the right
|
||||
* shifts below are signed sign-extending shifts (see assumptions.h for tests that that is
|
||||
* indeed the behavior of the right shift operator). */
|
||||
cond_add = r4 >> 63;
|
||||
r0 += modinfo->modulus.v[0] & cond_add;
|
||||
r1 += modinfo->modulus.v[1] & cond_add;
|
||||
r2 += modinfo->modulus.v[2] & cond_add;
|
||||
r3 += modinfo->modulus.v[3] & cond_add;
|
||||
r4 += modinfo->modulus.v[4] & cond_add;
|
||||
cond_negate = sign >> 63;
|
||||
r0 = (r0 ^ cond_negate) - cond_negate;
|
||||
r1 = (r1 ^ cond_negate) - cond_negate;
|
||||
r2 = (r2 ^ cond_negate) - cond_negate;
|
||||
r3 = (r3 ^ cond_negate) - cond_negate;
|
||||
r4 = (r4 ^ cond_negate) - cond_negate;
|
||||
/* Propagate the top bits, to bring limbs back to range (-2^62,2^62). */
|
||||
r1 += r0 >> 62; r0 &= M62;
|
||||
r2 += r1 >> 62; r1 &= M62;
|
||||
r3 += r2 >> 62; r2 &= M62;
|
||||
r4 += r3 >> 62; r3 &= M62;
|
||||
|
||||
/* In a second step add the modulus again if the result is still negative, bringing
|
||||
* r to range [0,modulus). */
|
||||
cond_add = r4 >> 63;
|
||||
r0 += modinfo->modulus.v[0] & cond_add;
|
||||
r1 += modinfo->modulus.v[1] & cond_add;
|
||||
r2 += modinfo->modulus.v[2] & cond_add;
|
||||
r3 += modinfo->modulus.v[3] & cond_add;
|
||||
r4 += modinfo->modulus.v[4] & cond_add;
|
||||
/* And propagate again. */
|
||||
r1 += r0 >> 62; r0 &= M62;
|
||||
r2 += r1 >> 62; r1 &= M62;
|
||||
r3 += r2 >> 62; r2 &= M62;
|
||||
r4 += r3 >> 62; r3 &= M62;
|
||||
|
||||
r->v[0] = r0;
|
||||
r->v[1] = r1;
|
||||
r->v[2] = r2;
|
||||
r->v[3] = r3;
|
||||
r->v[4] = r4;
|
||||
|
||||
VERIFY_CHECK(r0 >> 62 == 0);
|
||||
VERIFY_CHECK(r1 >> 62 == 0);
|
||||
VERIFY_CHECK(r2 >> 62 == 0);
|
||||
VERIFY_CHECK(r3 >> 62 == 0);
|
||||
VERIFY_CHECK(r4 >> 62 == 0);
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(r, 5, &modinfo->modulus, 0) >= 0); /* r >= 0 */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(r, 5, &modinfo->modulus, 1) < 0); /* r < modulus */
|
||||
}
|
||||
|
||||
/* Compute the transition matrix and eta for 59 divsteps (where zeta=-(delta+1/2)).
|
||||
* Note that the transformation matrix is scaled by 2^62 and not 2^59.
|
||||
*
|
||||
* Input: zeta: initial zeta
|
||||
* f0: bottom limb of initial f
|
||||
* g0: bottom limb of initial g
|
||||
* Output: t: transition matrix
|
||||
* Return: final zeta
|
||||
*
|
||||
* Implements the divsteps_n_matrix function from the explanation.
|
||||
*/
|
||||
static int64_t secp256k1_modinv64_divsteps_59(int64_t zeta, uint64_t f0, uint64_t g0, secp256k1_modinv64_trans2x2 *t) {
|
||||
/* u,v,q,r are the elements of the transformation matrix being built up,
|
||||
* starting with the identity matrix times 8 (because the caller expects
|
||||
* a result scaled by 2^62). Semantically they are signed integers
|
||||
* in range [-2^62,2^62], but here represented as unsigned mod 2^64. This
|
||||
* permits left shifting (which is UB for negative numbers). The range
|
||||
* being inside [-2^63,2^63) means that casting to signed works correctly.
|
||||
*/
|
||||
uint64_t u = 8, v = 0, q = 0, r = 8;
|
||||
volatile uint64_t c1, c2;
|
||||
uint64_t mask1, mask2, f = f0, g = g0, x, y, z;
|
||||
int i;
|
||||
|
||||
for (i = 3; i < 62; ++i) {
|
||||
VERIFY_CHECK((f & 1) == 1); /* f must always be odd */
|
||||
VERIFY_CHECK((u * f0 + v * g0) == f << i);
|
||||
VERIFY_CHECK((q * f0 + r * g0) == g << i);
|
||||
/* Compute conditional masks for (zeta < 0) and for (g & 1). */
|
||||
c1 = zeta >> 63;
|
||||
mask1 = c1;
|
||||
c2 = g & 1;
|
||||
mask2 = -c2;
|
||||
/* Compute x,y,z, conditionally negated versions of f,u,v. */
|
||||
x = (f ^ mask1) - mask1;
|
||||
y = (u ^ mask1) - mask1;
|
||||
z = (v ^ mask1) - mask1;
|
||||
/* Conditionally add x,y,z to g,q,r. */
|
||||
g += x & mask2;
|
||||
q += y & mask2;
|
||||
r += z & mask2;
|
||||
/* In what follows, c1 is a condition mask for (zeta < 0) and (g & 1). */
|
||||
mask1 &= mask2;
|
||||
/* Conditionally change zeta into -zeta-2 or zeta-1. */
|
||||
zeta = (zeta ^ mask1) - 1;
|
||||
/* Conditionally add g,q,r to f,u,v. */
|
||||
f += g & mask1;
|
||||
u += q & mask1;
|
||||
v += r & mask1;
|
||||
/* Shifts */
|
||||
g >>= 1;
|
||||
u <<= 1;
|
||||
v <<= 1;
|
||||
/* Bounds on zeta that follow from the bounds on iteration count (max 10*59 divsteps). */
|
||||
VERIFY_CHECK(zeta >= -591 && zeta <= 591);
|
||||
}
|
||||
/* Return data in t and return value. */
|
||||
t->u = (int64_t)u;
|
||||
t->v = (int64_t)v;
|
||||
t->q = (int64_t)q;
|
||||
t->r = (int64_t)r;
|
||||
|
||||
/* The determinant of t must be a power of two. This guarantees that multiplication with t
|
||||
* does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which
|
||||
* will be divided out again). As each divstep's individual matrix has determinant 2, the
|
||||
* aggregate of 59 of them will have determinant 2^59. Multiplying with the initial
|
||||
* 8*identity (which has determinant 2^6) means the overall outputs has determinant
|
||||
* 2^65. */
|
||||
VERIFY_CHECK(secp256k1_modinv64_det_check_pow2(t, 65, 0));
|
||||
|
||||
return zeta;
|
||||
}
|
||||
|
||||
/* Compute the transition matrix and eta for 62 divsteps (variable time, eta=-delta).
|
||||
*
|
||||
* Input: eta: initial eta
|
||||
* f0: bottom limb of initial f
|
||||
* g0: bottom limb of initial g
|
||||
* Output: t: transition matrix
|
||||
* Return: final eta
|
||||
*
|
||||
* Implements the divsteps_n_matrix_var function from the explanation.
|
||||
*/
|
||||
static int64_t secp256k1_modinv64_divsteps_62_var(int64_t eta, uint64_t f0, uint64_t g0, secp256k1_modinv64_trans2x2 *t) {
|
||||
/* Transformation matrix; see comments in secp256k1_modinv64_divsteps_62. */
|
||||
uint64_t u = 1, v = 0, q = 0, r = 1;
|
||||
uint64_t f = f0, g = g0, m;
|
||||
uint32_t w;
|
||||
int i = 62, limit, zeros;
|
||||
|
||||
for (;;) {
|
||||
/* Use a sentinel bit to count zeros only up to i. */
|
||||
zeros = secp256k1_ctz64_var(g | (UINT64_MAX << i));
|
||||
/* Perform zeros divsteps at once; they all just divide g by two. */
|
||||
g >>= zeros;
|
||||
u <<= zeros;
|
||||
v <<= zeros;
|
||||
eta -= zeros;
|
||||
i -= zeros;
|
||||
/* We're done once we've done 62 divsteps. */
|
||||
if (i == 0) break;
|
||||
VERIFY_CHECK((f & 1) == 1);
|
||||
VERIFY_CHECK((g & 1) == 1);
|
||||
VERIFY_CHECK((u * f0 + v * g0) == f << (62 - i));
|
||||
VERIFY_CHECK((q * f0 + r * g0) == g << (62 - i));
|
||||
/* Bounds on eta that follow from the bounds on iteration count (max 12*62 divsteps). */
|
||||
VERIFY_CHECK(eta >= -745 && eta <= 745);
|
||||
/* If eta is negative, negate it and replace f,g with g,-f. */
|
||||
if (eta < 0) {
|
||||
uint64_t tmp;
|
||||
eta = -eta;
|
||||
tmp = f; f = g; g = -tmp;
|
||||
tmp = u; u = q; q = -tmp;
|
||||
tmp = v; v = r; r = -tmp;
|
||||
/* Use a formula to cancel out up to 6 bits of g. Also, no more than i can be cancelled
|
||||
* out (as we'd be done before that point), and no more than eta+1 can be done as its
|
||||
* sign will flip again once that happens. */
|
||||
limit = ((int)eta + 1) > i ? i : ((int)eta + 1);
|
||||
VERIFY_CHECK(limit > 0 && limit <= 62);
|
||||
/* m is a mask for the bottom min(limit, 6) bits. */
|
||||
m = (UINT64_MAX >> (64 - limit)) & 63U;
|
||||
/* Find what multiple of f must be added to g to cancel its bottom min(limit, 6)
|
||||
* bits. */
|
||||
w = (f * g * (f * f - 2)) & m;
|
||||
} else {
|
||||
/* In this branch, use a simpler formula that only lets us cancel up to 4 bits of g, as
|
||||
* eta tends to be smaller here. */
|
||||
limit = ((int)eta + 1) > i ? i : ((int)eta + 1);
|
||||
VERIFY_CHECK(limit > 0 && limit <= 62);
|
||||
/* m is a mask for the bottom min(limit, 4) bits. */
|
||||
m = (UINT64_MAX >> (64 - limit)) & 15U;
|
||||
/* Find what multiple of f must be added to g to cancel its bottom min(limit, 4)
|
||||
* bits. */
|
||||
w = f + (((f + 1) & 4) << 1);
|
||||
w = (-w * g) & m;
|
||||
}
|
||||
g += f * w;
|
||||
q += u * w;
|
||||
r += v * w;
|
||||
VERIFY_CHECK((g & m) == 0);
|
||||
}
|
||||
/* Return data in t and return value. */
|
||||
t->u = (int64_t)u;
|
||||
t->v = (int64_t)v;
|
||||
t->q = (int64_t)q;
|
||||
t->r = (int64_t)r;
|
||||
|
||||
/* The determinant of t must be a power of two. This guarantees that multiplication with t
|
||||
* does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which
|
||||
* will be divided out again). As each divstep's individual matrix has determinant 2, the
|
||||
* aggregate of 62 of them will have determinant 2^62. */
|
||||
VERIFY_CHECK(secp256k1_modinv64_det_check_pow2(t, 62, 0));
|
||||
|
||||
return eta;
|
||||
}
|
||||
|
||||
/* Compute the transition matrix and eta for 62 posdivsteps (variable time, eta=-delta), and keeps track
|
||||
* of the Jacobi symbol along the way. f0 and g0 must be f and g mod 2^64 rather than 2^62, because
|
||||
* Jacobi tracking requires knowing (f mod 8) rather than just (f mod 2).
|
||||
*
|
||||
* Input: eta: initial eta
|
||||
* f0: bottom limb of initial f
|
||||
* g0: bottom limb of initial g
|
||||
* Output: t: transition matrix
|
||||
* Input/Output: (*jacp & 1) is bitflipped if and only if the Jacobi symbol of (f | g) changes sign
|
||||
* by applying the returned transformation matrix to it. The other bits of *jacp may
|
||||
* change, but are meaningless.
|
||||
* Return: final eta
|
||||
*/
|
||||
static int64_t secp256k1_modinv64_posdivsteps_62_var(int64_t eta, uint64_t f0, uint64_t g0, secp256k1_modinv64_trans2x2 *t, int *jacp) {
|
||||
/* Transformation matrix; see comments in secp256k1_modinv64_divsteps_62. */
|
||||
uint64_t u = 1, v = 0, q = 0, r = 1;
|
||||
uint64_t f = f0, g = g0, m;
|
||||
uint32_t w;
|
||||
int i = 62, limit, zeros;
|
||||
int jac = *jacp;
|
||||
|
||||
for (;;) {
|
||||
/* Use a sentinel bit to count zeros only up to i. */
|
||||
zeros = secp256k1_ctz64_var(g | (UINT64_MAX << i));
|
||||
/* Perform zeros divsteps at once; they all just divide g by two. */
|
||||
g >>= zeros;
|
||||
u <<= zeros;
|
||||
v <<= zeros;
|
||||
eta -= zeros;
|
||||
i -= zeros;
|
||||
/* Update the bottom bit of jac: when dividing g by an odd power of 2,
|
||||
* if (f mod 8) is 3 or 5, the Jacobi symbol changes sign. */
|
||||
jac ^= (zeros & ((f >> 1) ^ (f >> 2)));
|
||||
/* We're done once we've done 62 posdivsteps. */
|
||||
if (i == 0) break;
|
||||
VERIFY_CHECK((f & 1) == 1);
|
||||
VERIFY_CHECK((g & 1) == 1);
|
||||
VERIFY_CHECK((u * f0 + v * g0) == f << (62 - i));
|
||||
VERIFY_CHECK((q * f0 + r * g0) == g << (62 - i));
|
||||
/* If eta is negative, negate it and replace f,g with g,f. */
|
||||
if (eta < 0) {
|
||||
uint64_t tmp;
|
||||
eta = -eta;
|
||||
tmp = f; f = g; g = tmp;
|
||||
tmp = u; u = q; q = tmp;
|
||||
tmp = v; v = r; r = tmp;
|
||||
/* Update bottom bit of jac: when swapping f and g, the Jacobi symbol changes sign
|
||||
* if both f and g are 3 mod 4. */
|
||||
jac ^= ((f & g) >> 1);
|
||||
/* Use a formula to cancel out up to 6 bits of g. Also, no more than i can be cancelled
|
||||
* out (as we'd be done before that point), and no more than eta+1 can be done as its
|
||||
* sign will flip again once that happens. */
|
||||
limit = ((int)eta + 1) > i ? i : ((int)eta + 1);
|
||||
VERIFY_CHECK(limit > 0 && limit <= 62);
|
||||
/* m is a mask for the bottom min(limit, 6) bits. */
|
||||
m = (UINT64_MAX >> (64 - limit)) & 63U;
|
||||
/* Find what multiple of f must be added to g to cancel its bottom min(limit, 6)
|
||||
* bits. */
|
||||
w = (f * g * (f * f - 2)) & m;
|
||||
} else {
|
||||
/* In this branch, use a simpler formula that only lets us cancel up to 4 bits of g, as
|
||||
* eta tends to be smaller here. */
|
||||
limit = ((int)eta + 1) > i ? i : ((int)eta + 1);
|
||||
VERIFY_CHECK(limit > 0 && limit <= 62);
|
||||
/* m is a mask for the bottom min(limit, 4) bits. */
|
||||
m = (UINT64_MAX >> (64 - limit)) & 15U;
|
||||
/* Find what multiple of f must be added to g to cancel its bottom min(limit, 4)
|
||||
* bits. */
|
||||
w = f + (((f + 1) & 4) << 1);
|
||||
w = (-w * g) & m;
|
||||
}
|
||||
g += f * w;
|
||||
q += u * w;
|
||||
r += v * w;
|
||||
VERIFY_CHECK((g & m) == 0);
|
||||
}
|
||||
/* Return data in t and return value. */
|
||||
t->u = (int64_t)u;
|
||||
t->v = (int64_t)v;
|
||||
t->q = (int64_t)q;
|
||||
t->r = (int64_t)r;
|
||||
|
||||
/* The determinant of t must be a power of two. This guarantees that multiplication with t
|
||||
* does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which
|
||||
* will be divided out again). As each divstep's individual matrix has determinant 2 or -2,
|
||||
* the aggregate of 62 of them will have determinant 2^62 or -2^62. */
|
||||
VERIFY_CHECK(secp256k1_modinv64_det_check_pow2(t, 62, 1));
|
||||
|
||||
*jacp = jac;
|
||||
return eta;
|
||||
}
|
||||
|
||||
/* Compute (t/2^62) * [d, e] mod modulus, where t is a transition matrix scaled by 2^62.
|
||||
*
|
||||
* On input and output, d and e are in range (-2*modulus,modulus). All output limbs will be in range
|
||||
* (-2^62,2^62).
|
||||
*
|
||||
* This implements the update_de function from the explanation.
|
||||
*/
|
||||
static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp256k1_modinv64_signed62 *e, const secp256k1_modinv64_trans2x2 *t, const secp256k1_modinv64_modinfo* modinfo) {
|
||||
const uint64_t M62 = UINT64_MAX >> 2;
|
||||
const int64_t d0 = d->v[0], d1 = d->v[1], d2 = d->v[2], d3 = d->v[3], d4 = d->v[4];
|
||||
const int64_t e0 = e->v[0], e1 = e->v[1], e2 = e->v[2], e3 = e->v[3], e4 = e->v[4];
|
||||
const int64_t u = t->u, v = t->v, q = t->q, r = t->r;
|
||||
int64_t md, me, sd, se;
|
||||
secp256k1_int128 cd, ce;
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, -2) > 0); /* d > -2*modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, 1) < 0); /* d < modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, -2) > 0); /* e > -2*modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, 1) < 0); /* e < modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv64_abs(u) <= (((int64_t)1 << 62) - secp256k1_modinv64_abs(v))); /* |u|+|v| <= 2^62 */
|
||||
VERIFY_CHECK(secp256k1_modinv64_abs(q) <= (((int64_t)1 << 62) - secp256k1_modinv64_abs(r))); /* |q|+|r| <= 2^62 */
|
||||
|
||||
/* [md,me] start as zero; plus [u,q] if d is negative; plus [v,r] if e is negative. */
|
||||
sd = d4 >> 63;
|
||||
se = e4 >> 63;
|
||||
md = (u & sd) + (v & se);
|
||||
me = (q & sd) + (r & se);
|
||||
/* Begin computing t*[d,e]. */
|
||||
secp256k1_i128_mul(&cd, u, d0);
|
||||
secp256k1_i128_accum_mul(&cd, v, e0);
|
||||
secp256k1_i128_mul(&ce, q, d0);
|
||||
secp256k1_i128_accum_mul(&ce, r, e0);
|
||||
/* Correct md,me so that t*[d,e]+modulus*[md,me] has 62 zero bottom bits. */
|
||||
md -= (modinfo->modulus_inv62 * secp256k1_i128_to_u64(&cd) + md) & M62;
|
||||
me -= (modinfo->modulus_inv62 * secp256k1_i128_to_u64(&ce) + me) & M62;
|
||||
/* Update the beginning of computation for t*[d,e]+modulus*[md,me] now md,me are known. */
|
||||
secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[0], md);
|
||||
secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[0], me);
|
||||
/* Verify that the low 62 bits of the computation are indeed zero, and then throw them away. */
|
||||
VERIFY_CHECK((secp256k1_i128_to_u64(&cd) & M62) == 0); secp256k1_i128_rshift(&cd, 62);
|
||||
VERIFY_CHECK((secp256k1_i128_to_u64(&ce) & M62) == 0); secp256k1_i128_rshift(&ce, 62);
|
||||
/* Compute limb 1 of t*[d,e]+modulus*[md,me], and store it as output limb 0 (= down shift). */
|
||||
secp256k1_i128_accum_mul(&cd, u, d1);
|
||||
secp256k1_i128_accum_mul(&cd, v, e1);
|
||||
secp256k1_i128_accum_mul(&ce, q, d1);
|
||||
secp256k1_i128_accum_mul(&ce, r, e1);
|
||||
if (modinfo->modulus.v[1]) { /* Optimize for the case where limb of modulus is zero. */
|
||||
secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[1], md);
|
||||
secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[1], me);
|
||||
}
|
||||
d->v[0] = secp256k1_i128_to_u64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
|
||||
e->v[0] = secp256k1_i128_to_u64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
|
||||
/* Compute limb 2 of t*[d,e]+modulus*[md,me], and store it as output limb 1. */
|
||||
secp256k1_i128_accum_mul(&cd, u, d2);
|
||||
secp256k1_i128_accum_mul(&cd, v, e2);
|
||||
secp256k1_i128_accum_mul(&ce, q, d2);
|
||||
secp256k1_i128_accum_mul(&ce, r, e2);
|
||||
if (modinfo->modulus.v[2]) { /* Optimize for the case where limb of modulus is zero. */
|
||||
secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[2], md);
|
||||
secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[2], me);
|
||||
}
|
||||
d->v[1] = secp256k1_i128_to_u64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
|
||||
e->v[1] = secp256k1_i128_to_u64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
|
||||
/* Compute limb 3 of t*[d,e]+modulus*[md,me], and store it as output limb 2. */
|
||||
secp256k1_i128_accum_mul(&cd, u, d3);
|
||||
secp256k1_i128_accum_mul(&cd, v, e3);
|
||||
secp256k1_i128_accum_mul(&ce, q, d3);
|
||||
secp256k1_i128_accum_mul(&ce, r, e3);
|
||||
if (modinfo->modulus.v[3]) { /* Optimize for the case where limb of modulus is zero. */
|
||||
secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[3], md);
|
||||
secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[3], me);
|
||||
}
|
||||
d->v[2] = secp256k1_i128_to_u64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
|
||||
e->v[2] = secp256k1_i128_to_u64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
|
||||
/* Compute limb 4 of t*[d,e]+modulus*[md,me], and store it as output limb 3. */
|
||||
secp256k1_i128_accum_mul(&cd, u, d4);
|
||||
secp256k1_i128_accum_mul(&cd, v, e4);
|
||||
secp256k1_i128_accum_mul(&ce, q, d4);
|
||||
secp256k1_i128_accum_mul(&ce, r, e4);
|
||||
secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[4], md);
|
||||
secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[4], me);
|
||||
d->v[3] = secp256k1_i128_to_u64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
|
||||
e->v[3] = secp256k1_i128_to_u64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
|
||||
/* What remains is limb 5 of t*[d,e]+modulus*[md,me]; store it as output limb 4. */
|
||||
d->v[4] = secp256k1_i128_to_i64(&cd);
|
||||
e->v[4] = secp256k1_i128_to_i64(&ce);
|
||||
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, -2) > 0); /* d > -2*modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, 1) < 0); /* d < modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, -2) > 0); /* e > -2*modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, 1) < 0); /* e < modulus */
|
||||
}
|
||||
|
||||
/* Compute (t/2^62) * [f, g], where t is a transition matrix scaled by 2^62.
|
||||
*
|
||||
* This implements the update_fg function from the explanation.
|
||||
*/
|
||||
static void secp256k1_modinv64_update_fg_62(secp256k1_modinv64_signed62 *f, secp256k1_modinv64_signed62 *g, const secp256k1_modinv64_trans2x2 *t) {
|
||||
const uint64_t M62 = UINT64_MAX >> 2;
|
||||
const int64_t f0 = f->v[0], f1 = f->v[1], f2 = f->v[2], f3 = f->v[3], f4 = f->v[4];
|
||||
const int64_t g0 = g->v[0], g1 = g->v[1], g2 = g->v[2], g3 = g->v[3], g4 = g->v[4];
|
||||
const int64_t u = t->u, v = t->v, q = t->q, r = t->r;
|
||||
secp256k1_int128 cf, cg;
|
||||
/* Start computing t*[f,g]. */
|
||||
secp256k1_i128_mul(&cf, u, f0);
|
||||
secp256k1_i128_accum_mul(&cf, v, g0);
|
||||
secp256k1_i128_mul(&cg, q, f0);
|
||||
secp256k1_i128_accum_mul(&cg, r, g0);
|
||||
/* Verify that the bottom 62 bits of the result are zero, and then throw them away. */
|
||||
VERIFY_CHECK((secp256k1_i128_to_u64(&cf) & M62) == 0); secp256k1_i128_rshift(&cf, 62);
|
||||
VERIFY_CHECK((secp256k1_i128_to_u64(&cg) & M62) == 0); secp256k1_i128_rshift(&cg, 62);
|
||||
/* Compute limb 1 of t*[f,g], and store it as output limb 0 (= down shift). */
|
||||
secp256k1_i128_accum_mul(&cf, u, f1);
|
||||
secp256k1_i128_accum_mul(&cf, v, g1);
|
||||
secp256k1_i128_accum_mul(&cg, q, f1);
|
||||
secp256k1_i128_accum_mul(&cg, r, g1);
|
||||
f->v[0] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
|
||||
g->v[0] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
|
||||
/* Compute limb 2 of t*[f,g], and store it as output limb 1. */
|
||||
secp256k1_i128_accum_mul(&cf, u, f2);
|
||||
secp256k1_i128_accum_mul(&cf, v, g2);
|
||||
secp256k1_i128_accum_mul(&cg, q, f2);
|
||||
secp256k1_i128_accum_mul(&cg, r, g2);
|
||||
f->v[1] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
|
||||
g->v[1] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
|
||||
/* Compute limb 3 of t*[f,g], and store it as output limb 2. */
|
||||
secp256k1_i128_accum_mul(&cf, u, f3);
|
||||
secp256k1_i128_accum_mul(&cf, v, g3);
|
||||
secp256k1_i128_accum_mul(&cg, q, f3);
|
||||
secp256k1_i128_accum_mul(&cg, r, g3);
|
||||
f->v[2] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
|
||||
g->v[2] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
|
||||
/* Compute limb 4 of t*[f,g], and store it as output limb 3. */
|
||||
secp256k1_i128_accum_mul(&cf, u, f4);
|
||||
secp256k1_i128_accum_mul(&cf, v, g4);
|
||||
secp256k1_i128_accum_mul(&cg, q, f4);
|
||||
secp256k1_i128_accum_mul(&cg, r, g4);
|
||||
f->v[3] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
|
||||
g->v[3] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
|
||||
/* What remains is limb 5 of t*[f,g]; store it as output limb 4. */
|
||||
f->v[4] = secp256k1_i128_to_i64(&cf);
|
||||
g->v[4] = secp256k1_i128_to_i64(&cg);
|
||||
}
|
||||
|
||||
/* Compute (t/2^62) * [f, g], where t is a transition matrix for 62 divsteps.
|
||||
*
|
||||
* Version that operates on a variable number of limbs in f and g.
|
||||
*
|
||||
* This implements the update_fg function from the explanation.
|
||||
*/
|
||||
static void secp256k1_modinv64_update_fg_62_var(int len, secp256k1_modinv64_signed62 *f, secp256k1_modinv64_signed62 *g, const secp256k1_modinv64_trans2x2 *t) {
|
||||
const uint64_t M62 = UINT64_MAX >> 2;
|
||||
const int64_t u = t->u, v = t->v, q = t->q, r = t->r;
|
||||
int64_t fi, gi;
|
||||
secp256k1_int128 cf, cg;
|
||||
int i;
|
||||
VERIFY_CHECK(len > 0);
|
||||
/* Start computing t*[f,g]. */
|
||||
fi = f->v[0];
|
||||
gi = g->v[0];
|
||||
secp256k1_i128_mul(&cf, u, fi);
|
||||
secp256k1_i128_accum_mul(&cf, v, gi);
|
||||
secp256k1_i128_mul(&cg, q, fi);
|
||||
secp256k1_i128_accum_mul(&cg, r, gi);
|
||||
/* Verify that the bottom 62 bits of the result are zero, and then throw them away. */
|
||||
VERIFY_CHECK((secp256k1_i128_to_u64(&cf) & M62) == 0); secp256k1_i128_rshift(&cf, 62);
|
||||
VERIFY_CHECK((secp256k1_i128_to_u64(&cg) & M62) == 0); secp256k1_i128_rshift(&cg, 62);
|
||||
/* Now iteratively compute limb i=1..len of t*[f,g], and store them in output limb i-1 (shifting
|
||||
* down by 62 bits). */
|
||||
for (i = 1; i < len; ++i) {
|
||||
fi = f->v[i];
|
||||
gi = g->v[i];
|
||||
secp256k1_i128_accum_mul(&cf, u, fi);
|
||||
secp256k1_i128_accum_mul(&cf, v, gi);
|
||||
secp256k1_i128_accum_mul(&cg, q, fi);
|
||||
secp256k1_i128_accum_mul(&cg, r, gi);
|
||||
f->v[i - 1] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
|
||||
g->v[i - 1] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
|
||||
}
|
||||
/* What remains is limb (len) of t*[f,g]; store it as output limb (len-1). */
|
||||
f->v[len - 1] = secp256k1_i128_to_i64(&cf);
|
||||
g->v[len - 1] = secp256k1_i128_to_i64(&cg);
|
||||
}
|
||||
|
||||
/* Compute the inverse of x modulo modinfo->modulus, and replace x with it (constant time in x). */
|
||||
static void secp256k1_modinv64(secp256k1_modinv64_signed62 *x, const secp256k1_modinv64_modinfo *modinfo) {
|
||||
/* Start with d=0, e=1, f=modulus, g=x, zeta=-1. */
|
||||
secp256k1_modinv64_signed62 d = {{0, 0, 0, 0, 0}};
|
||||
secp256k1_modinv64_signed62 e = {{1, 0, 0, 0, 0}};
|
||||
secp256k1_modinv64_signed62 f = modinfo->modulus;
|
||||
secp256k1_modinv64_signed62 g = *x;
|
||||
int i;
|
||||
int64_t zeta = -1; /* zeta = -(delta+1/2); delta starts at 1/2. */
|
||||
|
||||
/* Do 10 iterations of 59 divsteps each = 590 divsteps. This suffices for 256-bit inputs. */
|
||||
for (i = 0; i < 10; ++i) {
|
||||
/* Compute transition matrix and new zeta after 59 divsteps. */
|
||||
secp256k1_modinv64_trans2x2 t;
|
||||
zeta = secp256k1_modinv64_divsteps_59(zeta, f.v[0], g.v[0], &t);
|
||||
/* Update d,e using that transition matrix. */
|
||||
secp256k1_modinv64_update_de_62(&d, &e, &t, modinfo);
|
||||
/* Update f,g using that transition matrix. */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, -1) > 0); /* f > -modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, 1) <= 0); /* f <= modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, 5, &modinfo->modulus, -1) > 0); /* g > -modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, 5, &modinfo->modulus, 1) < 0); /* g < modulus */
|
||||
|
||||
secp256k1_modinv64_update_fg_62(&f, &g, &t);
|
||||
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, -1) > 0); /* f > -modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, 1) <= 0); /* f <= modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, 5, &modinfo->modulus, -1) > 0); /* g > -modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, 5, &modinfo->modulus, 1) < 0); /* g < modulus */
|
||||
}
|
||||
|
||||
/* At this point sufficient iterations have been performed that g must have reached 0
|
||||
* and (if g was not originally 0) f must now equal +/- GCD of the initial f, g
|
||||
* values i.e. +/- 1, and d now contains +/- the modular inverse. */
|
||||
|
||||
/* g == 0 */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, 5, &SECP256K1_SIGNED62_ONE, 0) == 0);
|
||||
/* |f| == 1, or (x == 0 and d == 0 and f == modulus) */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, 5, &SECP256K1_SIGNED62_ONE, -1) == 0 ||
|
||||
secp256k1_modinv64_mul_cmp_62(&f, 5, &SECP256K1_SIGNED62_ONE, 1) == 0 ||
|
||||
(secp256k1_modinv64_mul_cmp_62(x, 5, &SECP256K1_SIGNED62_ONE, 0) == 0 &&
|
||||
secp256k1_modinv64_mul_cmp_62(&d, 5, &SECP256K1_SIGNED62_ONE, 0) == 0 &&
|
||||
secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, 1) == 0));
|
||||
|
||||
/* Optionally negate d, normalize to [0,modulus), and return it. */
|
||||
secp256k1_modinv64_normalize_62(&d, f.v[4], modinfo);
|
||||
*x = d;
|
||||
}
|
||||
|
||||
/* Compute the inverse of x modulo modinfo->modulus, and replace x with it (variable time). */
|
||||
static void secp256k1_modinv64_var(secp256k1_modinv64_signed62 *x, const secp256k1_modinv64_modinfo *modinfo) {
|
||||
/* Start with d=0, e=1, f=modulus, g=x, eta=-1. */
|
||||
secp256k1_modinv64_signed62 d = {{0, 0, 0, 0, 0}};
|
||||
secp256k1_modinv64_signed62 e = {{1, 0, 0, 0, 0}};
|
||||
secp256k1_modinv64_signed62 f = modinfo->modulus;
|
||||
secp256k1_modinv64_signed62 g = *x;
|
||||
#ifdef VERIFY
|
||||
int i = 0;
|
||||
#endif
|
||||
int j, len = 5;
|
||||
int64_t eta = -1; /* eta = -delta; delta is initially 1 */
|
||||
int64_t cond, fn, gn;
|
||||
|
||||
/* Do iterations of 62 divsteps each until g=0. */
|
||||
while (1) {
|
||||
/* Compute transition matrix and new eta after 62 divsteps. */
|
||||
secp256k1_modinv64_trans2x2 t;
|
||||
eta = secp256k1_modinv64_divsteps_62_var(eta, f.v[0], g.v[0], &t);
|
||||
/* Update d,e using that transition matrix. */
|
||||
secp256k1_modinv64_update_de_62(&d, &e, &t, modinfo);
|
||||
/* Update f,g using that transition matrix. */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, -1) > 0); /* f > -modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, -1) > 0); /* g > -modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
|
||||
|
||||
secp256k1_modinv64_update_fg_62_var(len, &f, &g, &t);
|
||||
/* If the bottom limb of g is zero, there is a chance that g=0. */
|
||||
if (g.v[0] == 0) {
|
||||
cond = 0;
|
||||
/* Check if the other limbs are also 0. */
|
||||
for (j = 1; j < len; ++j) {
|
||||
cond |= g.v[j];
|
||||
}
|
||||
/* If so, we're done. */
|
||||
if (cond == 0) break;
|
||||
}
|
||||
|
||||
/* Determine if len>1 and limb (len-1) of both f and g is 0 or -1. */
|
||||
fn = f.v[len - 1];
|
||||
gn = g.v[len - 1];
|
||||
cond = ((int64_t)len - 2) >> 63;
|
||||
cond |= fn ^ (fn >> 63);
|
||||
cond |= gn ^ (gn >> 63);
|
||||
/* If so, reduce length, propagating the sign of f and g's top limb into the one below. */
|
||||
if (cond == 0) {
|
||||
f.v[len - 2] |= (uint64_t)fn << 62;
|
||||
g.v[len - 2] |= (uint64_t)gn << 62;
|
||||
--len;
|
||||
}
|
||||
|
||||
VERIFY_CHECK(++i < 12); /* We should never need more than 12*62 = 744 divsteps */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, -1) > 0); /* f > -modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, -1) > 0); /* g > -modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
|
||||
}
|
||||
|
||||
/* At this point g is 0 and (if g was not originally 0) f must now equal +/- GCD of
|
||||
* the initial f, g values i.e. +/- 1, and d now contains +/- the modular inverse. */
|
||||
|
||||
/* g == 0 */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &SECP256K1_SIGNED62_ONE, 0) == 0);
|
||||
/* |f| == 1, or (x == 0 and d == 0 and f == modulus) */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &SECP256K1_SIGNED62_ONE, -1) == 0 ||
|
||||
secp256k1_modinv64_mul_cmp_62(&f, len, &SECP256K1_SIGNED62_ONE, 1) == 0 ||
|
||||
(secp256k1_modinv64_mul_cmp_62(x, 5, &SECP256K1_SIGNED62_ONE, 0) == 0 &&
|
||||
secp256k1_modinv64_mul_cmp_62(&d, 5, &SECP256K1_SIGNED62_ONE, 0) == 0 &&
|
||||
secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) == 0));
|
||||
|
||||
/* Optionally negate d, normalize to [0,modulus), and return it. */
|
||||
secp256k1_modinv64_normalize_62(&d, f.v[len - 1], modinfo);
|
||||
*x = d;
|
||||
}
|
||||
|
||||
/* Do up to 25 iterations of 62 posdivsteps (up to 1550 steps; more is extremely rare) each until f=1.
|
||||
* In VERIFY mode use a lower number of iterations (744, close to the median 756), so failure actually occurs. */
|
||||
#ifdef VERIFY
|
||||
#define JACOBI64_ITERATIONS 12
|
||||
#else
|
||||
#define JACOBI64_ITERATIONS 25
|
||||
#endif
|
||||
|
||||
/* Compute the Jacobi symbol of x modulo modinfo->modulus (variable time). gcd(x,modulus) must be 1. */
|
||||
static int secp256k1_jacobi64_maybe_var(const secp256k1_modinv64_signed62 *x, const secp256k1_modinv64_modinfo *modinfo) {
|
||||
/* Start with f=modulus, g=x, eta=-1. */
|
||||
secp256k1_modinv64_signed62 f = modinfo->modulus;
|
||||
secp256k1_modinv64_signed62 g = *x;
|
||||
int j, len = 5;
|
||||
int64_t eta = -1; /* eta = -delta; delta is initially 1 */
|
||||
int64_t cond, fn, gn;
|
||||
int jac = 0;
|
||||
int count;
|
||||
|
||||
/* The input limbs must all be non-negative. */
|
||||
VERIFY_CHECK(g.v[0] >= 0 && g.v[1] >= 0 && g.v[2] >= 0 && g.v[3] >= 0 && g.v[4] >= 0);
|
||||
|
||||
/* If x > 0, then if the loop below converges, it converges to f=g=gcd(x,modulus). Since we
|
||||
* require that gcd(x,modulus)=1 and modulus>=3, x cannot be 0. Thus, we must reach f=1 (or
|
||||
* time out). */
|
||||
VERIFY_CHECK((g.v[0] | g.v[1] | g.v[2] | g.v[3] | g.v[4]) != 0);
|
||||
|
||||
for (count = 0; count < JACOBI64_ITERATIONS; ++count) {
|
||||
/* Compute transition matrix and new eta after 62 posdivsteps. */
|
||||
secp256k1_modinv64_trans2x2 t;
|
||||
eta = secp256k1_modinv64_posdivsteps_62_var(eta, f.v[0] | ((uint64_t)f.v[1] << 62), g.v[0] | ((uint64_t)g.v[1] << 62), &t, &jac);
|
||||
/* Update f,g using that transition matrix. */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
|
||||
|
||||
secp256k1_modinv64_update_fg_62_var(len, &f, &g, &t);
|
||||
/* If the bottom limb of f is 1, there is a chance that f=1. */
|
||||
if (f.v[0] == 1) {
|
||||
cond = 0;
|
||||
/* Check if the other limbs are also 0. */
|
||||
for (j = 1; j < len; ++j) {
|
||||
cond |= f.v[j];
|
||||
}
|
||||
/* If so, we're done. When f=1, the Jacobi symbol (g | f)=1. */
|
||||
if (cond == 0) return 1 - 2*(jac & 1);
|
||||
}
|
||||
|
||||
/* Determine if len>1 and limb (len-1) of both f and g is 0. */
|
||||
fn = f.v[len - 1];
|
||||
gn = g.v[len - 1];
|
||||
cond = ((int64_t)len - 2) >> 63;
|
||||
cond |= fn;
|
||||
cond |= gn;
|
||||
/* If so, reduce length. */
|
||||
if (cond == 0) --len;
|
||||
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
|
||||
}
|
||||
|
||||
/* The loop failed to converge to f=g after 1550 iterations. Return 0, indicating unknown result. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* SECP256K1_MODINV64_IMPL_H */
|
||||
@@ -0,0 +1,5 @@
|
||||
include_HEADERS += include/secp256k1_ecdh.h
|
||||
noinst_HEADERS += src/modules/ecdh/main_impl.h
|
||||
noinst_HEADERS += src/modules/ecdh/tests_impl.h
|
||||
noinst_HEADERS += src/modules/ecdh/bench_impl.h
|
||||
noinst_HEADERS += src/wycheproof/ecdh_secp256k1_test.h
|
||||
@@ -0,0 +1,54 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2015 Pieter Wuille, Andrew Poelstra *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_ECDH_BENCH_H
|
||||
#define SECP256K1_MODULE_ECDH_BENCH_H
|
||||
|
||||
#include "../../../include/secp256k1_ecdh.h"
|
||||
|
||||
typedef struct {
|
||||
const secp256k1_context *ctx;
|
||||
secp256k1_pubkey point;
|
||||
unsigned char scalar[32];
|
||||
} bench_ecdh_data;
|
||||
|
||||
static void bench_ecdh_setup(void* arg) {
|
||||
int i;
|
||||
bench_ecdh_data *data = (bench_ecdh_data*)arg;
|
||||
const unsigned char point[] = {
|
||||
0x03,
|
||||
0x54, 0x94, 0xc1, 0x5d, 0x32, 0x09, 0x97, 0x06,
|
||||
0xc2, 0x39, 0x5f, 0x94, 0x34, 0x87, 0x45, 0xfd,
|
||||
0x75, 0x7c, 0xe3, 0x0e, 0x4e, 0x8c, 0x90, 0xfb,
|
||||
0xa2, 0xba, 0xd1, 0x84, 0xf8, 0x83, 0xc6, 0x9f
|
||||
};
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
data->scalar[i] = i + 1;
|
||||
}
|
||||
CHECK(secp256k1_ec_pubkey_parse(data->ctx, &data->point, point, sizeof(point)) == 1);
|
||||
}
|
||||
|
||||
static void bench_ecdh(void* arg, int iters) {
|
||||
int i;
|
||||
unsigned char res[32];
|
||||
bench_ecdh_data *data = (bench_ecdh_data*)arg;
|
||||
|
||||
for (i = 0; i < iters; i++) {
|
||||
CHECK(secp256k1_ecdh(data->ctx, res, &data->point, data->scalar, NULL, NULL) == 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void run_ecdh_bench(int iters, int argc, char** argv) {
|
||||
bench_ecdh_data data;
|
||||
int d = argc == 1;
|
||||
|
||||
data.ctx = secp256k1_context_static;
|
||||
|
||||
if (d || have_flag(argc, argv, "ecdh")) run_benchmark("ecdh", bench_ecdh, bench_ecdh_setup, NULL, &data, 10, iters);
|
||||
}
|
||||
|
||||
#endif /* SECP256K1_MODULE_ECDH_BENCH_H */
|
||||
@@ -0,0 +1,79 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2015 Andrew Poelstra *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_ECDH_MAIN_H
|
||||
#define SECP256K1_MODULE_ECDH_MAIN_H
|
||||
|
||||
#include "../../../include/secp256k1_ecdh.h"
|
||||
#include "../../ecmult_const_impl.h"
|
||||
|
||||
static int ecdh_hash_function_sha256_impl(const secp256k1_hash_ctx *hash_ctx, unsigned char *output, const unsigned char *x32, const unsigned char *y32, void *data) {
|
||||
unsigned char version = (y32[31] & 0x01) | 0x02;
|
||||
secp256k1_sha256 sha;
|
||||
(void)data;
|
||||
|
||||
secp256k1_sha256_initialize(&sha);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, &version, 1);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, x32, 32);
|
||||
secp256k1_sha256_finalize(hash_ctx, &sha, output);
|
||||
secp256k1_sha256_clear(&sha);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ecdh_hash_function_sha256(unsigned char *output, const unsigned char *x32, const unsigned char *y32, void *data) {
|
||||
return ecdh_hash_function_sha256_impl(secp256k1_get_hash_context(secp256k1_context_static), output, x32, y32, data);
|
||||
}
|
||||
|
||||
const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_sha256 = ecdh_hash_function_sha256;
|
||||
const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_default = ecdh_hash_function_sha256;
|
||||
|
||||
int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *output, const secp256k1_pubkey *point, const unsigned char *scalar, secp256k1_ecdh_hash_function hashfp, void *data) {
|
||||
int ret = 0;
|
||||
int overflow = 0;
|
||||
secp256k1_gej res;
|
||||
secp256k1_ge pt;
|
||||
secp256k1_scalar s;
|
||||
unsigned char x[32];
|
||||
unsigned char y[32];
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(output != NULL);
|
||||
ARG_CHECK(point != NULL);
|
||||
ARG_CHECK(scalar != NULL);
|
||||
|
||||
secp256k1_pubkey_load(ctx, &pt, point);
|
||||
secp256k1_scalar_set_b32(&s, scalar, &overflow);
|
||||
|
||||
overflow |= secp256k1_scalar_is_zero(&s);
|
||||
secp256k1_scalar_cmov(&s, &secp256k1_scalar_one, overflow);
|
||||
|
||||
secp256k1_ecmult_const(&res, &pt, &s);
|
||||
secp256k1_ge_set_gej(&pt, &res);
|
||||
|
||||
/* Compute a hash of the point */
|
||||
secp256k1_fe_normalize(&pt.x);
|
||||
secp256k1_fe_normalize(&pt.y);
|
||||
secp256k1_fe_get_b32(x, &pt.x);
|
||||
secp256k1_fe_get_b32(y, &pt.y);
|
||||
|
||||
if (hashfp == NULL) {
|
||||
/* Use ctx-aware function by default */
|
||||
ret = ecdh_hash_function_sha256_impl(secp256k1_get_hash_context(ctx), output, x, y, data);
|
||||
} else {
|
||||
ret = hashfp(output, x, y, data);
|
||||
}
|
||||
|
||||
secp256k1_memclear_explicit(x, sizeof(x));
|
||||
secp256k1_memclear_explicit(y, sizeof(y));
|
||||
secp256k1_scalar_clear(&s);
|
||||
secp256k1_ge_clear(&pt);
|
||||
secp256k1_gej_clear(&res);
|
||||
|
||||
return !!ret & !overflow;
|
||||
}
|
||||
|
||||
#endif /* SECP256K1_MODULE_ECDH_MAIN_H */
|
||||
@@ -0,0 +1,218 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2015 Andrew Poelstra *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_ECDH_TESTS_H
|
||||
#define SECP256K1_MODULE_ECDH_TESTS_H
|
||||
|
||||
#include "../../unit_test.h"
|
||||
#include "../../testutil.h"
|
||||
|
||||
static int ecdh_hash_function_test_xpassthru(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) {
|
||||
(void)y;
|
||||
(void)data;
|
||||
memcpy(output, x, 32);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ecdh_hash_function_test_fail(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) {
|
||||
(void)output;
|
||||
(void)x;
|
||||
(void)y;
|
||||
(void)data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ecdh_hash_function_custom(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) {
|
||||
(void)data;
|
||||
/* Save x and y as uncompressed public key */
|
||||
output[0] = 0x04;
|
||||
memcpy(output + 1, x, 32);
|
||||
memcpy(output + 33, y, 32);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void test_ecdh_api(void) {
|
||||
secp256k1_pubkey point;
|
||||
unsigned char res[32];
|
||||
unsigned char s_one[32] = { 0 };
|
||||
s_one[31] = 1;
|
||||
|
||||
CHECK(secp256k1_ec_pubkey_create(CTX, &point, s_one) == 1);
|
||||
|
||||
/* Check all NULLs are detected */
|
||||
CHECK(secp256k1_ecdh(CTX, res, &point, s_one, NULL, NULL) == 1);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_ecdh(CTX, NULL, &point, s_one, NULL, NULL));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_ecdh(CTX, res, NULL, s_one, NULL, NULL));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_ecdh(CTX, res, &point, NULL, NULL, NULL));
|
||||
CHECK(secp256k1_ecdh(CTX, res, &point, s_one, NULL, NULL) == 1);
|
||||
}
|
||||
|
||||
static void test_ecdh_generator_basepoint(void) {
|
||||
unsigned char s_one[32] = { 0 };
|
||||
secp256k1_pubkey point[2];
|
||||
int i;
|
||||
|
||||
s_one[31] = 1;
|
||||
/* Check against pubkey creation when the basepoint is the generator */
|
||||
for (i = 0; i < 2 * COUNT; ++i) {
|
||||
secp256k1_sha256 sha;
|
||||
unsigned char s_b32[32];
|
||||
unsigned char output_ecdh[65];
|
||||
unsigned char output_ser[32];
|
||||
unsigned char point_ser[65];
|
||||
size_t point_ser_len = sizeof(point_ser);
|
||||
secp256k1_scalar s;
|
||||
|
||||
testutil_random_scalar_order(&s);
|
||||
secp256k1_scalar_get_b32(s_b32, &s);
|
||||
|
||||
CHECK(secp256k1_ec_pubkey_create(CTX, &point[0], s_one) == 1);
|
||||
CHECK(secp256k1_ec_pubkey_create(CTX, &point[1], s_b32) == 1);
|
||||
|
||||
/* compute using ECDH function with custom hash function */
|
||||
CHECK(secp256k1_ecdh(CTX, output_ecdh, &point[0], s_b32, ecdh_hash_function_custom, NULL) == 1);
|
||||
/* compute "explicitly" */
|
||||
CHECK(secp256k1_ec_pubkey_serialize(CTX, point_ser, &point_ser_len, &point[1], SECP256K1_EC_UNCOMPRESSED) == 1);
|
||||
/* compare */
|
||||
CHECK(secp256k1_memcmp_var(output_ecdh, point_ser, 65) == 0);
|
||||
|
||||
/* compute using ECDH function with default hash function */
|
||||
CHECK(secp256k1_ecdh(CTX, output_ecdh, &point[0], s_b32, NULL, NULL) == 1);
|
||||
/* compute "explicitly" */
|
||||
CHECK(secp256k1_ec_pubkey_serialize(CTX, point_ser, &point_ser_len, &point[1], SECP256K1_EC_COMPRESSED) == 1);
|
||||
secp256k1_sha256_initialize(&sha);
|
||||
secp256k1_sha256_write(secp256k1_get_hash_context(CTX), &sha, point_ser, point_ser_len);
|
||||
secp256k1_sha256_finalize(secp256k1_get_hash_context(CTX), &sha, output_ser);
|
||||
/* compare */
|
||||
CHECK(secp256k1_memcmp_var(output_ecdh, output_ser, 32) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_SHA256_TRANSFORM_PROBE(sha256_ecdh)
|
||||
static void test_ecdh_ctx_sha256(void) {
|
||||
/* Check ctx-provided SHA256 compression override takes effect */
|
||||
secp256k1_context *ctx = secp256k1_context_clone(CTX);
|
||||
unsigned char out_default[65], out_custom[65];
|
||||
const unsigned char sk[32] = {1};
|
||||
secp256k1_pubkey pubkey;
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, sk) == 1);
|
||||
|
||||
/* Default behavior */
|
||||
CHECK(secp256k1_ecdh(ctx, out_default, &pubkey, sk, NULL, NULL) == 1);
|
||||
CHECK(!sha256_ecdh_called);
|
||||
|
||||
/* Override SHA256 compression directly, bypassing the ctx setter sanity checks */
|
||||
ctx->hash_ctx.fn_sha256_compression = sha256_ecdh;
|
||||
CHECK(secp256k1_ecdh(ctx, out_custom, &pubkey, sk, NULL, NULL) == 1);
|
||||
|
||||
/* Outputs must differ if custom compression was used */
|
||||
CHECK(secp256k1_memcmp_var(out_default, out_custom, 32) != 0);
|
||||
CHECK(sha256_ecdh_called);
|
||||
|
||||
secp256k1_context_destroy(ctx);
|
||||
}
|
||||
|
||||
static void test_bad_scalar(void) {
|
||||
unsigned char s_zero[32] = { 0 };
|
||||
unsigned char s_overflow[32] = { 0 };
|
||||
unsigned char s_rand[32] = { 0 };
|
||||
unsigned char output[32];
|
||||
secp256k1_scalar rand;
|
||||
secp256k1_pubkey point;
|
||||
|
||||
/* Create random point */
|
||||
testutil_random_scalar_order(&rand);
|
||||
secp256k1_scalar_get_b32(s_rand, &rand);
|
||||
CHECK(secp256k1_ec_pubkey_create(CTX, &point, s_rand) == 1);
|
||||
|
||||
/* Try to multiply it by bad values */
|
||||
memcpy(s_overflow, secp256k1_group_order_bytes, 32);
|
||||
CHECK(secp256k1_ecdh(CTX, output, &point, s_zero, NULL, NULL) == 0);
|
||||
CHECK(secp256k1_ecdh(CTX, output, &point, s_overflow, NULL, NULL) == 0);
|
||||
/* ...and a good one */
|
||||
s_overflow[31] -= 1;
|
||||
CHECK(secp256k1_ecdh(CTX, output, &point, s_overflow, NULL, NULL) == 1);
|
||||
|
||||
/* Hash function failure results in ecdh failure */
|
||||
CHECK(secp256k1_ecdh(CTX, output, &point, s_overflow, ecdh_hash_function_test_fail, NULL) == 0);
|
||||
}
|
||||
|
||||
/** Test that ECDH(sG, 1/s) == ECDH((1/s)G, s) == ECDH(G, 1) for a few random s. */
|
||||
static void test_result_basepoint(void) {
|
||||
secp256k1_pubkey point;
|
||||
secp256k1_scalar rand;
|
||||
unsigned char s[32];
|
||||
unsigned char s_inv[32];
|
||||
unsigned char out[32];
|
||||
unsigned char out_inv[32];
|
||||
unsigned char out_base[32];
|
||||
int i;
|
||||
|
||||
unsigned char s_one[32] = { 0 };
|
||||
s_one[31] = 1;
|
||||
CHECK(secp256k1_ec_pubkey_create(CTX, &point, s_one) == 1);
|
||||
CHECK(secp256k1_ecdh(CTX, out_base, &point, s_one, NULL, NULL) == 1);
|
||||
|
||||
for (i = 0; i < 2 * COUNT; i++) {
|
||||
testutil_random_scalar_order(&rand);
|
||||
secp256k1_scalar_get_b32(s, &rand);
|
||||
secp256k1_scalar_inverse(&rand, &rand);
|
||||
secp256k1_scalar_get_b32(s_inv, &rand);
|
||||
|
||||
CHECK(secp256k1_ec_pubkey_create(CTX, &point, s) == 1);
|
||||
CHECK(secp256k1_ecdh(CTX, out, &point, s_inv, NULL, NULL) == 1);
|
||||
CHECK(secp256k1_memcmp_var(out, out_base, 32) == 0);
|
||||
|
||||
CHECK(secp256k1_ec_pubkey_create(CTX, &point, s_inv) == 1);
|
||||
CHECK(secp256k1_ecdh(CTX, out_inv, &point, s, NULL, NULL) == 1);
|
||||
CHECK(secp256k1_memcmp_var(out_inv, out_base, 32) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_ecdh_wycheproof(void) {
|
||||
#include "../../wycheproof/ecdh_secp256k1_test.h"
|
||||
int t;
|
||||
for (t = 0; t < SECP256K1_ECDH_WYCHEPROOF_NUMBER_TESTVECTORS; t++) {
|
||||
int parsed_ok;
|
||||
secp256k1_pubkey point;
|
||||
const unsigned char *pk;
|
||||
const unsigned char *sk;
|
||||
const unsigned char *expected_shared_secret;
|
||||
unsigned char output_ecdh[65] = { 0 };
|
||||
|
||||
int expected_result;
|
||||
|
||||
memset(&point, 0, sizeof(point));
|
||||
pk = &wycheproof_ecdh_public_keys[testvectors[t].pk_offset];
|
||||
parsed_ok = secp256k1_ec_pubkey_parse(CTX, &point, pk, testvectors[t].pk_len);
|
||||
|
||||
expected_result = testvectors[t].expected_result;
|
||||
CHECK(parsed_ok == expected_result);
|
||||
if (!parsed_ok) {
|
||||
continue;
|
||||
}
|
||||
|
||||
sk = &wycheproof_ecdh_private_keys[testvectors[t].sk_offset];
|
||||
CHECK(testvectors[t].sk_len == 32);
|
||||
|
||||
CHECK(secp256k1_ecdh(CTX, output_ecdh, &point, sk, ecdh_hash_function_test_xpassthru, NULL) == 1);
|
||||
expected_shared_secret = &wycheproof_ecdh_shared_secrets[testvectors[t].shared_offset];
|
||||
|
||||
CHECK(secp256k1_memcmp_var(output_ecdh, expected_shared_secret, testvectors[t].shared_len) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* --- Test registry --- */
|
||||
static const struct tf_test_entry tests_ecdh[] = {
|
||||
CASE1(test_ecdh_api),
|
||||
CASE1(test_ecdh_generator_basepoint),
|
||||
CASE1(test_bad_scalar),
|
||||
CASE1(test_result_basepoint),
|
||||
CASE1(test_ecdh_wycheproof),
|
||||
CASE1(test_ecdh_ctx_sha256),
|
||||
};
|
||||
|
||||
#endif /* SECP256K1_MODULE_ECDH_TESTS_H */
|
||||
@@ -0,0 +1,5 @@
|
||||
include_HEADERS += include/secp256k1_ellswift.h
|
||||
noinst_HEADERS += src/modules/ellswift/bench_impl.h
|
||||
noinst_HEADERS += src/modules/ellswift/main_impl.h
|
||||
noinst_HEADERS += src/modules/ellswift/tests_impl.h
|
||||
noinst_HEADERS += src/modules/ellswift/tests_exhaustive_impl.h
|
||||
@@ -0,0 +1,106 @@
|
||||
/***********************************************************************
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_ELLSWIFT_BENCH_H
|
||||
#define SECP256K1_MODULE_ELLSWIFT_BENCH_H
|
||||
|
||||
#include "../../../include/secp256k1_ellswift.h"
|
||||
|
||||
typedef struct {
|
||||
secp256k1_context *ctx;
|
||||
secp256k1_pubkey point[256];
|
||||
unsigned char rnd64[64];
|
||||
} bench_ellswift_data;
|
||||
|
||||
static void bench_ellswift_setup(void *arg) {
|
||||
int i;
|
||||
bench_ellswift_data *data = (bench_ellswift_data*)arg;
|
||||
static const unsigned char init[64] = {
|
||||
0x78, 0x1f, 0xb7, 0xd4, 0x67, 0x7f, 0x08, 0x68,
|
||||
0xdb, 0xe3, 0x1d, 0x7f, 0x1b, 0xb0, 0xf6, 0x9e,
|
||||
0x0a, 0x64, 0xca, 0x32, 0x9e, 0xc6, 0x20, 0x79,
|
||||
0x03, 0xf3, 0xd0, 0x46, 0x7a, 0x0f, 0xd2, 0x21,
|
||||
0xb0, 0x2c, 0x46, 0xd8, 0xba, 0xca, 0x26, 0x4f,
|
||||
0x8f, 0x8c, 0xd4, 0xdd, 0x2d, 0x04, 0xbe, 0x30,
|
||||
0x48, 0x51, 0x1e, 0xd4, 0x16, 0xfd, 0x42, 0x85,
|
||||
0x62, 0xc9, 0x02, 0xf9, 0x89, 0x84, 0xff, 0xdc
|
||||
};
|
||||
memcpy(data->rnd64, init, 64);
|
||||
for (i = 0; i < 256; ++i) {
|
||||
int j;
|
||||
CHECK(secp256k1_ellswift_decode(data->ctx, &data->point[i], data->rnd64));
|
||||
for (j = 0; j < 64; ++j) {
|
||||
data->rnd64[j] += 1;
|
||||
}
|
||||
}
|
||||
CHECK(secp256k1_ellswift_encode(data->ctx, data->rnd64, &data->point[255], init + 16));
|
||||
}
|
||||
|
||||
static void bench_ellswift_encode(void *arg, int iters) {
|
||||
int i;
|
||||
bench_ellswift_data *data = (bench_ellswift_data*)arg;
|
||||
|
||||
for (i = 0; i < iters; i++) {
|
||||
CHECK(secp256k1_ellswift_encode(data->ctx, data->rnd64, &data->point[i & 255], data->rnd64 + 16));
|
||||
}
|
||||
}
|
||||
|
||||
static void bench_ellswift_create(void *arg, int iters) {
|
||||
int i;
|
||||
bench_ellswift_data *data = (bench_ellswift_data*)arg;
|
||||
|
||||
for (i = 0; i < iters; i++) {
|
||||
unsigned char buf[64];
|
||||
CHECK(secp256k1_ellswift_create(data->ctx, buf, data->rnd64, data->rnd64 + 32));
|
||||
memcpy(data->rnd64, buf, 64);
|
||||
}
|
||||
}
|
||||
|
||||
static void bench_ellswift_decode(void *arg, int iters) {
|
||||
int i;
|
||||
secp256k1_pubkey out;
|
||||
size_t len;
|
||||
bench_ellswift_data *data = (bench_ellswift_data*)arg;
|
||||
|
||||
for (i = 0; i < iters; i++) {
|
||||
CHECK(secp256k1_ellswift_decode(data->ctx, &out, data->rnd64) == 1);
|
||||
len = 33;
|
||||
CHECK(secp256k1_ec_pubkey_serialize(data->ctx, data->rnd64 + (i % 32), &len, &out, SECP256K1_EC_COMPRESSED));
|
||||
}
|
||||
}
|
||||
|
||||
static void bench_ellswift_xdh(void *arg, int iters) {
|
||||
int i;
|
||||
bench_ellswift_data *data = (bench_ellswift_data*)arg;
|
||||
|
||||
for (i = 0; i < iters; i++) {
|
||||
int party = i & 1;
|
||||
CHECK(secp256k1_ellswift_xdh(data->ctx,
|
||||
data->rnd64 + (i % 33),
|
||||
data->rnd64,
|
||||
data->rnd64,
|
||||
data->rnd64 + ((i + 16) % 33),
|
||||
party,
|
||||
secp256k1_ellswift_xdh_hash_function_bip324,
|
||||
NULL) == 1);
|
||||
}
|
||||
}
|
||||
|
||||
void run_ellswift_bench(int iters, int argc, char **argv) {
|
||||
bench_ellswift_data data;
|
||||
int d = argc == 1;
|
||||
|
||||
/* create a context with signing capabilities */
|
||||
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
||||
|
||||
if (d || have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "encode") || have_flag(argc, argv, "ellswift_encode")) run_benchmark("ellswift_encode", bench_ellswift_encode, bench_ellswift_setup, NULL, &data, 10, iters);
|
||||
if (d || have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "decode") || have_flag(argc, argv, "ellswift_decode")) run_benchmark("ellswift_decode", bench_ellswift_decode, bench_ellswift_setup, NULL, &data, 10, iters);
|
||||
if (d || have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "keygen") || have_flag(argc, argv, "ellswift_keygen")) run_benchmark("ellswift_keygen", bench_ellswift_create, bench_ellswift_setup, NULL, &data, 10, iters);
|
||||
if (d || have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "ecdh") || have_flag(argc, argv, "ellswift_ecdh")) run_benchmark("ellswift_ecdh", bench_ellswift_xdh, bench_ellswift_setup, NULL, &data, 10, iters);
|
||||
|
||||
secp256k1_context_destroy(data.ctx);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,581 @@
|
||||
/***********************************************************************
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_ELLSWIFT_MAIN_H
|
||||
#define SECP256K1_MODULE_ELLSWIFT_MAIN_H
|
||||
|
||||
#include "../../../include/secp256k1.h"
|
||||
#include "../../../include/secp256k1_ellswift.h"
|
||||
#include "../../eckey.h"
|
||||
#include "../../hash.h"
|
||||
|
||||
/** c1 = (sqrt(-3)-1)/2 */
|
||||
static const secp256k1_fe secp256k1_ellswift_c1 = SECP256K1_FE_CONST(0x851695d4, 0x9a83f8ef, 0x919bb861, 0x53cbcb16, 0x630fb68a, 0xed0a766a, 0x3ec693d6, 0x8e6afa40);
|
||||
/** c2 = (-sqrt(-3)-1)/2 = -(c1+1) */
|
||||
static const secp256k1_fe secp256k1_ellswift_c2 = SECP256K1_FE_CONST(0x7ae96a2b, 0x657c0710, 0x6e64479e, 0xac3434e9, 0x9cf04975, 0x12f58995, 0xc1396c28, 0x719501ee);
|
||||
/** c3 = (-sqrt(-3)+1)/2 = -c1 = c2+1 */
|
||||
static const secp256k1_fe secp256k1_ellswift_c3 = SECP256K1_FE_CONST(0x7ae96a2b, 0x657c0710, 0x6e64479e, 0xac3434e9, 0x9cf04975, 0x12f58995, 0xc1396c28, 0x719501ef);
|
||||
/** c4 = (sqrt(-3)+1)/2 = -c2 = c1+1 */
|
||||
static const secp256k1_fe secp256k1_ellswift_c4 = SECP256K1_FE_CONST(0x851695d4, 0x9a83f8ef, 0x919bb861, 0x53cbcb16, 0x630fb68a, 0xed0a766a, 0x3ec693d6, 0x8e6afa41);
|
||||
|
||||
/** Decode ElligatorSwift encoding (u, t) to a fraction xn/xd representing a curve X coordinate. */
|
||||
static void secp256k1_ellswift_xswiftec_frac_var(secp256k1_fe *xn, secp256k1_fe *xd, const secp256k1_fe *u, const secp256k1_fe *t) {
|
||||
/* The implemented algorithm is the following (all operations in GF(p)):
|
||||
*
|
||||
* - Let c0 = sqrt(-3) = 0xa2d2ba93507f1df233770c2a797962cc61f6d15da14ecd47d8d27ae1cd5f852.
|
||||
* - If u = 0, set u = 1.
|
||||
* - If t = 0, set t = 1.
|
||||
* - If u^3+7+t^2 = 0, set t = 2*t.
|
||||
* - Let X = (u^3+7-t^2)/(2*t).
|
||||
* - Let Y = (X+t)/(c0*u).
|
||||
* - If x3 = u+4*Y^2 is a valid x coordinate, return it.
|
||||
* - If x2 = (-X/Y-u)/2 is a valid x coordinate, return it.
|
||||
* - Return x1 = (X/Y-u)/2 (which is now guaranteed to be a valid x coordinate).
|
||||
*
|
||||
* Introducing s=t^2, g=u^3+7, and simplifying x1=-(x2+u) we get:
|
||||
*
|
||||
* - Let c0 = ...
|
||||
* - If u = 0, set u = 1.
|
||||
* - If t = 0, set t = 1.
|
||||
* - Let s = t^2
|
||||
* - Let g = u^3+7
|
||||
* - If g+s = 0, set t = 2*t, s = 4*s
|
||||
* - Let X = (g-s)/(2*t).
|
||||
* - Let Y = (X+t)/(c0*u) = (g+s)/(2*c0*t*u).
|
||||
* - If x3 = u+4*Y^2 is a valid x coordinate, return it.
|
||||
* - If x2 = (-X/Y-u)/2 is a valid x coordinate, return it.
|
||||
* - Return x1 = -(x2+u).
|
||||
*
|
||||
* Now substitute Y^2 = -(g+s)^2/(12*s*u^2) and X/Y = c0*u*(g-s)/(g+s). This
|
||||
* means X and Y do not need to be evaluated explicitly anymore.
|
||||
*
|
||||
* - ...
|
||||
* - If g+s = 0, set s = 4*s.
|
||||
* - If x3 = u-(g+s)^2/(3*s*u^2) is a valid x coordinate, return it.
|
||||
* - If x2 = (-c0*u*(g-s)/(g+s)-u)/2 is a valid x coordinate, return it.
|
||||
* - Return x1 = -(x2+u).
|
||||
*
|
||||
* Simplifying x2 using 2 additional constants:
|
||||
*
|
||||
* - Let c1 = (c0-1)/2 = 0x851695d49a83f8ef919bb86153cbcb16630fb68aed0a766a3ec693d68e6afa40.
|
||||
* - Let c2 = (-c0-1)/2 = 0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee.
|
||||
* - ...
|
||||
* - If x2 = u*(c1*s+c2*g)/(g+s) is a valid x coordinate, return it.
|
||||
* - ...
|
||||
*
|
||||
* Writing x3 as a fraction:
|
||||
*
|
||||
* - ...
|
||||
* - If x3 = (3*s*u^3-(g+s)^2)/(3*s*u^2) ...
|
||||
* - ...
|
||||
|
||||
* Overall, we get:
|
||||
*
|
||||
* - Let c1 = 0x851695d49a83f8ef919bb86153cbcb16630fb68aed0a766a3ec693d68e6afa40.
|
||||
* - Let c2 = 0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee.
|
||||
* - If u = 0, set u = 1.
|
||||
* - If t = 0, set s = 1, else set s = t^2.
|
||||
* - Let g = u^3+7.
|
||||
* - If g+s = 0, set s = 4*s.
|
||||
* - If x3 = (3*s*u^3-(g+s)^2)/(3*s*u^2) is a valid x coordinate, return it.
|
||||
* - If x2 = u*(c1*s+c2*g)/(g+s) is a valid x coordinate, return it.
|
||||
* - Return x1 = -(x2+u).
|
||||
*/
|
||||
secp256k1_fe u1, s, g, p, d, n, l;
|
||||
u1 = *u;
|
||||
if (EXPECT(secp256k1_fe_normalizes_to_zero_var(&u1), 0)) u1 = secp256k1_fe_one;
|
||||
secp256k1_fe_sqr(&s, t);
|
||||
if (EXPECT(secp256k1_fe_normalizes_to_zero_var(t), 0)) s = secp256k1_fe_one;
|
||||
secp256k1_fe_sqr(&l, &u1); /* l = u^2 */
|
||||
secp256k1_fe_mul(&g, &l, &u1); /* g = u^3 */
|
||||
secp256k1_fe_add_int(&g, SECP256K1_B); /* g = u^3 + 7 */
|
||||
p = g; /* p = g */
|
||||
secp256k1_fe_add(&p, &s); /* p = g+s */
|
||||
if (EXPECT(secp256k1_fe_normalizes_to_zero_var(&p), 0)) {
|
||||
secp256k1_fe_mul_int(&s, 4);
|
||||
/* Recompute p = g+s */
|
||||
p = g; /* p = g */
|
||||
secp256k1_fe_add(&p, &s); /* p = g+s */
|
||||
}
|
||||
secp256k1_fe_mul(&d, &s, &l); /* d = s*u^2 */
|
||||
secp256k1_fe_mul_int(&d, 3); /* d = 3*s*u^2 */
|
||||
secp256k1_fe_sqr(&l, &p); /* l = (g+s)^2 */
|
||||
secp256k1_fe_negate(&l, &l, 1); /* l = -(g+s)^2 */
|
||||
secp256k1_fe_mul(&n, &d, &u1); /* n = 3*s*u^3 */
|
||||
secp256k1_fe_add(&n, &l); /* n = 3*s*u^3-(g+s)^2 */
|
||||
if (secp256k1_ge_x_frac_on_curve_var(&n, &d)) {
|
||||
/* Return x3 = n/d = (3*s*u^3-(g+s)^2)/(3*s*u^2) */
|
||||
*xn = n;
|
||||
*xd = d;
|
||||
return;
|
||||
}
|
||||
*xd = p;
|
||||
secp256k1_fe_mul(&l, &secp256k1_ellswift_c1, &s); /* l = c1*s */
|
||||
secp256k1_fe_mul(&n, &secp256k1_ellswift_c2, &g); /* n = c2*g */
|
||||
secp256k1_fe_add(&n, &l); /* n = c1*s+c2*g */
|
||||
secp256k1_fe_mul(&n, &n, &u1); /* n = u*(c1*s+c2*g) */
|
||||
/* Possible optimization: in the invocation below, p^2 = (g+s)^2 is computed,
|
||||
* which we already have computed above. This could be deduplicated. */
|
||||
if (secp256k1_ge_x_frac_on_curve_var(&n, &p)) {
|
||||
/* Return x2 = n/p = u*(c1*s+c2*g)/(g+s) */
|
||||
*xn = n;
|
||||
return;
|
||||
}
|
||||
secp256k1_fe_mul(&l, &p, &u1); /* l = u*(g+s) */
|
||||
secp256k1_fe_add(&n, &l); /* n = u*(c1*s+c2*g)+u*(g+s) */
|
||||
secp256k1_fe_negate(xn, &n, 2); /* n = -u*(c1*s+c2*g)-u*(g+s) */
|
||||
|
||||
VERIFY_CHECK(secp256k1_ge_x_frac_on_curve_var(xn, &p));
|
||||
/* Return x3 = n/p = -(u*(c1*s+c2*g)/(g+s)+u) */
|
||||
}
|
||||
|
||||
/** Decode ElligatorSwift encoding (u, t) to X coordinate. */
|
||||
static void secp256k1_ellswift_xswiftec_var(secp256k1_fe *x, const secp256k1_fe *u, const secp256k1_fe *t) {
|
||||
secp256k1_fe xn, xd;
|
||||
secp256k1_ellswift_xswiftec_frac_var(&xn, &xd, u, t);
|
||||
secp256k1_fe_inv_var(&xd, &xd);
|
||||
secp256k1_fe_mul(x, &xn, &xd);
|
||||
}
|
||||
|
||||
/** Decode ElligatorSwift encoding (u, t) to point P. */
|
||||
static void secp256k1_ellswift_swiftec_var(secp256k1_ge *p, const secp256k1_fe *u, const secp256k1_fe *t) {
|
||||
secp256k1_fe x;
|
||||
secp256k1_ellswift_xswiftec_var(&x, u, t);
|
||||
secp256k1_ge_set_xo_var(p, &x, secp256k1_fe_is_odd(t));
|
||||
}
|
||||
|
||||
/* Try to complete an ElligatorSwift encoding (u, t) for X coordinate x, given u and x.
|
||||
*
|
||||
* There may be up to 8 distinct t values such that (u, t) decodes back to x, but also
|
||||
* fewer, or none at all. Each such partial inverse can be accessed individually using a
|
||||
* distinct input argument c (in range 0-7), and some or all of these may return failure.
|
||||
* The following guarantees exist:
|
||||
* - Given (x, u), no two distinct c values give the same successful result t.
|
||||
* - Every successful result maps back to x through secp256k1_ellswift_xswiftec_var.
|
||||
* - Given (x, u), all t values that map back to x can be reached by combining the
|
||||
* successful results from this function over all c values, with the exception of:
|
||||
* - this function cannot be called with u=0
|
||||
* - no result with t=0 will be returned
|
||||
* - no result for which u^3 + t^2 + 7 = 0 will be returned.
|
||||
*
|
||||
* The rather unusual encoding of bits in c (a large "if" based on the middle bit, and then
|
||||
* using the low and high bits to pick signs of square roots) is to match the paper's
|
||||
* encoding more closely: c=0 through c=3 match branches 1..4 in the paper, while c=4 through
|
||||
* c=7 are copies of those with an additional negation of sqrt(w).
|
||||
*/
|
||||
static int secp256k1_ellswift_xswiftec_inv_var(secp256k1_fe *t, const secp256k1_fe *x_in, const secp256k1_fe *u_in, int c) {
|
||||
/* The implemented algorithm is this (all arithmetic, except involving c, is mod p):
|
||||
*
|
||||
* - If (c & 2) = 0:
|
||||
* - If (-x-u) is a valid X coordinate, fail.
|
||||
* - Let s=-(u^3+7)/(u^2+u*x+x^2).
|
||||
* - If s is not square, fail.
|
||||
* - Let v=x.
|
||||
* - If (c & 2) = 2:
|
||||
* - Let s=x-u.
|
||||
* - If s is not square, fail.
|
||||
* - Let r=sqrt(-s*(4*(u^3+7)+3*u^2*s)); fail if it doesn't exist.
|
||||
* - If (c & 1) = 1 and r = 0, fail.
|
||||
* - If s=0, fail.
|
||||
* - Let v=(r/s-u)/2.
|
||||
* - Let w=sqrt(s).
|
||||
* - If (c & 5) = 0: return -w*(c3*u + v).
|
||||
* - If (c & 5) = 1: return w*(c4*u + v).
|
||||
* - If (c & 5) = 4: return w*(c3*u + v).
|
||||
* - If (c & 5) = 5: return -w*(c4*u + v).
|
||||
*/
|
||||
secp256k1_fe x = *x_in, u = *u_in, g, v, s, m, r, q;
|
||||
int ret;
|
||||
|
||||
secp256k1_fe_normalize_weak(&x);
|
||||
secp256k1_fe_normalize_weak(&u);
|
||||
|
||||
VERIFY_CHECK(c >= 0 && c < 8);
|
||||
VERIFY_CHECK(secp256k1_ge_x_on_curve_var(&x));
|
||||
|
||||
if (!(c & 2)) {
|
||||
/* c is in {0, 1, 4, 5}. In this case we look for an inverse under the x1 (if c=0 or
|
||||
* c=4) formula, or x2 (if c=1 or c=5) formula. */
|
||||
|
||||
/* If -u-x is a valid X coordinate, fail. This would yield an encoding that roundtrips
|
||||
* back under the x3 formula instead (which has priority over x1 and x2, so the decoding
|
||||
* would not match x). */
|
||||
m = x; /* m = x */
|
||||
secp256k1_fe_add(&m, &u); /* m = u+x */
|
||||
secp256k1_fe_negate(&m, &m, 2); /* m = -u-x */
|
||||
/* Test if (-u-x) is a valid X coordinate. If so, fail. */
|
||||
if (secp256k1_ge_x_on_curve_var(&m)) return 0;
|
||||
|
||||
/* Let s = -(u^3 + 7)/(u^2 + u*x + x^2) [first part] */
|
||||
secp256k1_fe_sqr(&s, &m); /* s = (u+x)^2 */
|
||||
secp256k1_fe_negate(&s, &s, 1); /* s = -(u+x)^2 */
|
||||
secp256k1_fe_mul(&m, &u, &x); /* m = u*x */
|
||||
secp256k1_fe_add(&s, &m); /* s = -(u^2 + u*x + x^2) */
|
||||
|
||||
/* Note that at this point, s = 0 is impossible. If it were the case:
|
||||
* s = -(u^2 + u*x + x^2) = 0
|
||||
* => u^2 + u*x + x^2 = 0
|
||||
* => (u + 2*x) * (u^2 + u*x + x^2) = 0
|
||||
* => 2*x^3 + 3*x^2*u + 3*x*u^2 + u^3 = 0
|
||||
* => (x + u)^3 + x^3 = 0
|
||||
* => x^3 = -(x + u)^3
|
||||
* => x^3 + B = (-u - x)^3 + B
|
||||
*
|
||||
* However, we know x^3 + B is square (because x is on the curve) and
|
||||
* that (-u-x)^3 + B is not square (the secp256k1_ge_x_on_curve_var(&m)
|
||||
* test above would have failed). This is a contradiction, and thus the
|
||||
* assumption s=0 is false. */
|
||||
VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero_var(&s));
|
||||
|
||||
/* If s is not square, fail. We have not fully computed s yet, but s is square iff
|
||||
* -(u^3+7)*(u^2+u*x+x^2) is square (because a/b is square iff a*b is square and b is
|
||||
* nonzero). */
|
||||
secp256k1_fe_sqr(&g, &u); /* g = u^2 */
|
||||
secp256k1_fe_mul(&g, &g, &u); /* g = u^3 */
|
||||
secp256k1_fe_add_int(&g, SECP256K1_B); /* g = u^3+7 */
|
||||
secp256k1_fe_mul(&m, &s, &g); /* m = -(u^3 + 7)*(u^2 + u*x + x^2) */
|
||||
if (!secp256k1_fe_is_square_var(&m)) return 0;
|
||||
|
||||
/* Let s = -(u^3 + 7)/(u^2 + u*x + x^2) [second part] */
|
||||
secp256k1_fe_inv_var(&s, &s); /* s = -1/(u^2 + u*x + x^2) [no div by 0] */
|
||||
secp256k1_fe_mul(&s, &s, &g); /* s = -(u^3 + 7)/(u^2 + u*x + x^2) */
|
||||
|
||||
/* Let v = x. */
|
||||
v = x;
|
||||
} else {
|
||||
/* c is in {2, 3, 6, 7}. In this case we look for an inverse under the x3 formula. */
|
||||
|
||||
/* Let s = x-u. */
|
||||
secp256k1_fe_negate(&m, &u, 1); /* m = -u */
|
||||
s = m; /* s = -u */
|
||||
secp256k1_fe_add(&s, &x); /* s = x-u */
|
||||
|
||||
/* If s is not square, fail. */
|
||||
if (!secp256k1_fe_is_square_var(&s)) return 0;
|
||||
|
||||
/* Let r = sqrt(-s*(4*(u^3+7)+3*u^2*s)); fail if it doesn't exist. */
|
||||
secp256k1_fe_sqr(&g, &u); /* g = u^2 */
|
||||
secp256k1_fe_mul(&q, &s, &g); /* q = s*u^2 */
|
||||
secp256k1_fe_mul_int(&q, 3); /* q = 3*s*u^2 */
|
||||
secp256k1_fe_mul(&g, &g, &u); /* g = u^3 */
|
||||
secp256k1_fe_mul_int(&g, 4); /* g = 4*u^3 */
|
||||
secp256k1_fe_add_int(&g, 4 * SECP256K1_B); /* g = 4*(u^3+7) */
|
||||
secp256k1_fe_add(&q, &g); /* q = 4*(u^3+7)+3*s*u^2 */
|
||||
secp256k1_fe_mul(&q, &q, &s); /* q = s*(4*(u^3+7)+3*u^2*s) */
|
||||
secp256k1_fe_negate(&q, &q, 1); /* q = -s*(4*(u^3+7)+3*u^2*s) */
|
||||
if (!secp256k1_fe_is_square_var(&q)) return 0;
|
||||
ret = secp256k1_fe_sqrt(&r, &q); /* r = sqrt(-s*(4*(u^3+7)+3*u^2*s)) */
|
||||
#ifdef VERIFY
|
||||
VERIFY_CHECK(ret);
|
||||
#else
|
||||
(void)ret;
|
||||
#endif
|
||||
|
||||
/* If (c & 1) = 1 and r = 0, fail. */
|
||||
if (EXPECT((c & 1) && secp256k1_fe_normalizes_to_zero_var(&r), 0)) return 0;
|
||||
|
||||
/* If s = 0, fail. */
|
||||
if (EXPECT(secp256k1_fe_normalizes_to_zero_var(&s), 0)) return 0;
|
||||
|
||||
/* Let v = (r/s-u)/2. */
|
||||
secp256k1_fe_inv_var(&v, &s); /* v = 1/s [no div by 0] */
|
||||
secp256k1_fe_mul(&v, &v, &r); /* v = r/s */
|
||||
secp256k1_fe_add(&v, &m); /* v = r/s-u */
|
||||
secp256k1_fe_half(&v); /* v = (r/s-u)/2 */
|
||||
}
|
||||
|
||||
/* Let w = sqrt(s). */
|
||||
ret = secp256k1_fe_sqrt(&m, &s); /* m = sqrt(s) = w */
|
||||
VERIFY_CHECK(ret);
|
||||
|
||||
/* Return logic. */
|
||||
if ((c & 5) == 0 || (c & 5) == 5) {
|
||||
secp256k1_fe_negate(&m, &m, 1); /* m = -w */
|
||||
}
|
||||
/* Now m = {-w if c&5=0 or c&5=5; w otherwise}. */
|
||||
secp256k1_fe_mul(&u, &u, c&1 ? &secp256k1_ellswift_c4 : &secp256k1_ellswift_c3);
|
||||
/* u = {c4 if c&1=1; c3 otherwise}*u */
|
||||
secp256k1_fe_add(&u, &v); /* u = {c4 if c&1=1; c3 otherwise}*u + v */
|
||||
secp256k1_fe_mul(t, &m, &u);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Use SHA256 as a PRNG, returning SHA256(hasher || cnt).
|
||||
*
|
||||
* hasher is a SHA256 object to which an incrementing 4-byte counter is written to generate randomness.
|
||||
* Writing 13 bytes (4 bytes for counter, plus 9 bytes for the SHA256 padding) cannot cross a
|
||||
* 64-byte block size boundary (to make sure it only triggers a single SHA256 compression). */
|
||||
static void secp256k1_ellswift_prng(const secp256k1_hash_ctx *hash_ctx, unsigned char* out32, const secp256k1_sha256 *hasher, uint32_t cnt) {
|
||||
secp256k1_sha256 hash = *hasher;
|
||||
unsigned char buf4[4];
|
||||
#ifdef VERIFY
|
||||
size_t blocks = hash.bytes >> 6;
|
||||
#endif
|
||||
buf4[0] = cnt;
|
||||
buf4[1] = cnt >> 8;
|
||||
buf4[2] = cnt >> 16;
|
||||
buf4[3] = cnt >> 24;
|
||||
secp256k1_sha256_write(hash_ctx, &hash, buf4, 4);
|
||||
secp256k1_sha256_finalize(hash_ctx, &hash, out32);
|
||||
|
||||
/* Writing and finalizing together should trigger exactly one SHA256 compression. */
|
||||
VERIFY_CHECK(((hash.bytes) >> 6) == (blocks + 1));
|
||||
}
|
||||
|
||||
/** Find an ElligatorSwift encoding (u, t) for X coordinate x, and random Y coordinate.
|
||||
*
|
||||
* u32 is the 32-byte big endian encoding of u; t is the output field element t that still
|
||||
* needs encoding.
|
||||
*
|
||||
* hasher is a hasher in the secp256k1_ellswift_prng sense, with the same restrictions. */
|
||||
static void secp256k1_ellswift_xelligatorswift_var(const secp256k1_context *ctx, unsigned char *u32, secp256k1_fe *t, const secp256k1_fe *x, const secp256k1_sha256 *hasher) {
|
||||
/* Pool of 3-bit branch values. */
|
||||
unsigned char branch_hash[32];
|
||||
/* Number of 3-bit values in branch_hash left. */
|
||||
int branches_left = 0;
|
||||
/* Field elements u and branch values are extracted from RNG based on hasher for consecutive
|
||||
* values of cnt. cnt==0 is first used to populate a pool of 64 4-bit branch values. The 64
|
||||
* cnt values that follow are used to generate field elements u. cnt==65 (and multiples
|
||||
* thereof) are used to repopulate the pool and start over, if that were ever necessary.
|
||||
* On average, 4 iterations are needed. */
|
||||
uint32_t cnt = 0;
|
||||
while (1) {
|
||||
int branch;
|
||||
secp256k1_fe u;
|
||||
/* If the pool of branch values is empty, populate it. */
|
||||
if (branches_left == 0) {
|
||||
secp256k1_ellswift_prng(secp256k1_get_hash_context(ctx), branch_hash, hasher, cnt++);
|
||||
branches_left = 64;
|
||||
}
|
||||
/* Take a 3-bit branch value from the branch pool (top bit is discarded). */
|
||||
--branches_left;
|
||||
branch = (branch_hash[branches_left >> 1] >> ((branches_left & 1) << 2)) & 7;
|
||||
/* Compute a new u value by hashing. */
|
||||
secp256k1_ellswift_prng(secp256k1_get_hash_context(ctx), u32, hasher, cnt++);
|
||||
/* overflow is not a problem (we prefer uniform u32 over uniform u). */
|
||||
secp256k1_fe_set_b32_mod(&u, u32);
|
||||
/* Since u is the output of a hash, it should practically never be 0. We could apply the
|
||||
* u=0 to u=1 correction here too to deal with that case still, but it's such a low
|
||||
* probability event that we do not bother. */
|
||||
VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero_var(&u));
|
||||
|
||||
/* Find a remainder t, and return it if found. */
|
||||
if (EXPECT(secp256k1_ellswift_xswiftec_inv_var(t, x, &u, branch), 0)) break;
|
||||
}
|
||||
}
|
||||
|
||||
/** Find an ElligatorSwift encoding (u, t) for point P.
|
||||
*
|
||||
* This is similar secp256k1_ellswift_xelligatorswift_var, except it takes a full group element p
|
||||
* as input, and returns an encoding that matches the provided Y coordinate rather than a random
|
||||
* one.
|
||||
*/
|
||||
static void secp256k1_ellswift_elligatorswift_var(const secp256k1_context *ctx, unsigned char *u32, secp256k1_fe *t, const secp256k1_ge *p, const secp256k1_sha256 *hasher) {
|
||||
secp256k1_ellswift_xelligatorswift_var(ctx, u32, t, &p->x, hasher);
|
||||
secp256k1_fe_normalize_var(t);
|
||||
if (secp256k1_fe_is_odd(t) != secp256k1_fe_is_odd(&p->y)) {
|
||||
secp256k1_fe_negate(t, t, 1);
|
||||
secp256k1_fe_normalize_var(t);
|
||||
}
|
||||
}
|
||||
|
||||
/** Set hash state to the BIP340 tagged hash midstate for "secp256k1_ellswift_encode". */
|
||||
static void secp256k1_ellswift_sha256_init_encode(secp256k1_sha256* hash) {
|
||||
static const uint32_t midstate[8] = {
|
||||
0xd1a6524bul, 0x028594b3ul, 0x96e42f4eul, 0x1037a177ul,
|
||||
0x1b8fcb8bul, 0x56023885ul, 0x2560ede1ul, 0xd626b715ul
|
||||
};
|
||||
secp256k1_sha256_initialize_midstate(hash, 64, midstate);
|
||||
}
|
||||
|
||||
int secp256k1_ellswift_encode(const secp256k1_context *ctx, unsigned char *ell64, const secp256k1_pubkey *pubkey, const unsigned char *rnd32) {
|
||||
secp256k1_ge p;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(ell64 != NULL);
|
||||
ARG_CHECK(pubkey != NULL);
|
||||
ARG_CHECK(rnd32 != NULL);
|
||||
|
||||
if (secp256k1_pubkey_load(ctx, &p, pubkey)) {
|
||||
secp256k1_fe t;
|
||||
unsigned char p64[64] = {0};
|
||||
secp256k1_sha256 hash;
|
||||
|
||||
/* Set up hasher state; the used RNG is H(pubkey || "\x00"*31 || rnd32 || cnt++), using
|
||||
* BIP340 tagged hash with tag "secp256k1_ellswift_encode". */
|
||||
secp256k1_ellswift_sha256_init_encode(&hash);
|
||||
secp256k1_eckey_pubkey_serialize33(&p, p64);
|
||||
secp256k1_sha256_write(secp256k1_get_hash_context(ctx), &hash, p64, sizeof(p64));
|
||||
secp256k1_sha256_write(secp256k1_get_hash_context(ctx), &hash, rnd32, 32);
|
||||
|
||||
/* Compute ElligatorSwift encoding and construct output. */
|
||||
secp256k1_ellswift_elligatorswift_var(ctx, ell64, &t, &p, &hash); /* puts u in ell64[0..32] */
|
||||
secp256k1_fe_get_b32(ell64 + 32, &t); /* puts t in ell64[32..64] */
|
||||
return 1;
|
||||
}
|
||||
/* Only reached in case the provided pubkey is invalid. */
|
||||
memset(ell64, 0, 64);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Set hash state to the BIP340 tagged hash midstate for "secp256k1_ellswift_create". */
|
||||
static void secp256k1_ellswift_sha256_init_create(secp256k1_sha256* hash) {
|
||||
static const uint32_t midstate[8] = {
|
||||
0xd29e1bf5ul, 0xf7025f42ul, 0x9b024773ul, 0x094cb7d5ul,
|
||||
0xe59ed789ul, 0x03bc9786ul, 0x68335b35ul, 0x4e363b53ul
|
||||
};
|
||||
secp256k1_sha256_initialize_midstate(hash, 64, midstate);
|
||||
}
|
||||
|
||||
int secp256k1_ellswift_create(const secp256k1_context *ctx, unsigned char *ell64, const unsigned char *seckey32, const unsigned char *auxrnd32) {
|
||||
secp256k1_ge p;
|
||||
secp256k1_fe t;
|
||||
secp256k1_sha256 hash;
|
||||
secp256k1_scalar seckey_scalar;
|
||||
int ret;
|
||||
static const unsigned char zero32[32] = {0};
|
||||
|
||||
/* Sanity check inputs. */
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(ell64 != NULL);
|
||||
memset(ell64, 0, 64);
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
ARG_CHECK(seckey32 != NULL);
|
||||
|
||||
/* Compute (affine) public key */
|
||||
ret = secp256k1_ec_pubkey_create_helper(&ctx->ecmult_gen_ctx, &seckey_scalar, &p, seckey32);
|
||||
secp256k1_declassify(ctx, &p, sizeof(p)); /* not constant time in produced pubkey */
|
||||
secp256k1_fe_normalize_var(&p.x);
|
||||
secp256k1_fe_normalize_var(&p.y);
|
||||
|
||||
/* Set up hasher state. The used RNG is H(privkey || "\x00"*32 [|| auxrnd32] || cnt++),
|
||||
* using BIP340 tagged hash with tag "secp256k1_ellswift_create". */
|
||||
secp256k1_ellswift_sha256_init_create(&hash);
|
||||
secp256k1_sha256_write(secp256k1_get_hash_context(ctx), &hash, seckey32, 32);
|
||||
secp256k1_sha256_write(secp256k1_get_hash_context(ctx), &hash, zero32, sizeof(zero32));
|
||||
secp256k1_declassify(ctx, &hash, sizeof(hash)); /* private key is hashed now */
|
||||
if (auxrnd32) secp256k1_sha256_write(secp256k1_get_hash_context(ctx), &hash, auxrnd32, 32);
|
||||
|
||||
/* Compute ElligatorSwift encoding and construct output. */
|
||||
secp256k1_ellswift_elligatorswift_var(ctx, ell64, &t, &p, &hash); /* puts u in ell64[0..32] */
|
||||
secp256k1_fe_get_b32(ell64 + 32, &t); /* puts t in ell64[32..64] */
|
||||
|
||||
secp256k1_memczero(ell64, 64, !ret);
|
||||
secp256k1_scalar_clear(&seckey_scalar);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int secp256k1_ellswift_decode(const secp256k1_context *ctx, secp256k1_pubkey *pubkey, const unsigned char *ell64) {
|
||||
secp256k1_fe u, t;
|
||||
secp256k1_ge p;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(pubkey != NULL);
|
||||
ARG_CHECK(ell64 != NULL);
|
||||
|
||||
secp256k1_fe_set_b32_mod(&u, ell64);
|
||||
secp256k1_fe_set_b32_mod(&t, ell64 + 32);
|
||||
secp256k1_fe_normalize_var(&t);
|
||||
secp256k1_ellswift_swiftec_var(&p, &u, &t);
|
||||
secp256k1_pubkey_save(pubkey, &p);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ellswift_xdh_hash_function_prefix_impl(const secp256k1_hash_ctx *hash_ctx, unsigned char *output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) {
|
||||
secp256k1_sha256 sha;
|
||||
|
||||
secp256k1_sha256_initialize(&sha);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, data, 64);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, ell_a64, 64);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, ell_b64, 64);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, x32, 32);
|
||||
secp256k1_sha256_finalize(hash_ctx, &sha, output);
|
||||
secp256k1_sha256_clear(&sha);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ellswift_xdh_hash_function_prefix(unsigned char *output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) {
|
||||
return ellswift_xdh_hash_function_prefix_impl(secp256k1_get_hash_context(secp256k1_context_static), output, x32, ell_a64, ell_b64, data);
|
||||
}
|
||||
|
||||
/** Set hash state to the BIP340 tagged hash midstate for "bip324_ellswift_xonly_ecdh". */
|
||||
static void secp256k1_ellswift_sha256_init_bip324(secp256k1_sha256* hash) {
|
||||
static const uint32_t midstate[8] = {
|
||||
0x8c12d730ul, 0x827bd392ul, 0x9e4fb2eeul, 0x207b373eul,
|
||||
0x2292bd7aul, 0xaa5441bcul, 0x15c3779ful, 0xcfb52549ul
|
||||
};
|
||||
secp256k1_sha256_initialize_midstate(hash, 64, midstate);
|
||||
}
|
||||
|
||||
static int ellswift_xdh_hash_function_bip324_impl(const secp256k1_hash_ctx *hash_ctx, unsigned char* output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) {
|
||||
secp256k1_sha256 sha;
|
||||
|
||||
(void)data;
|
||||
|
||||
secp256k1_ellswift_sha256_init_bip324(&sha);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, ell_a64, 64);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, ell_b64, 64);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, x32, 32);
|
||||
secp256k1_sha256_finalize(hash_ctx, &sha, output);
|
||||
secp256k1_sha256_clear(&sha);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ellswift_xdh_hash_function_bip324(unsigned char* output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) {
|
||||
return ellswift_xdh_hash_function_bip324_impl(secp256k1_get_hash_context(secp256k1_context_static), output, x32, ell_a64, ell_b64, data);
|
||||
}
|
||||
|
||||
const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_prefix = ellswift_xdh_hash_function_prefix;
|
||||
const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_bip324 = ellswift_xdh_hash_function_bip324;
|
||||
|
||||
int secp256k1_ellswift_xdh(const secp256k1_context *ctx, unsigned char *output, const unsigned char *ell_a64, const unsigned char *ell_b64, const unsigned char *seckey32, int party, secp256k1_ellswift_xdh_hash_function hashfp, void *data) {
|
||||
int ret = 0;
|
||||
int overflow;
|
||||
secp256k1_scalar s;
|
||||
secp256k1_fe xn, xd, px, u, t;
|
||||
unsigned char sx[32];
|
||||
const unsigned char* theirs64;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(output != NULL);
|
||||
ARG_CHECK(ell_a64 != NULL);
|
||||
ARG_CHECK(ell_b64 != NULL);
|
||||
ARG_CHECK(seckey32 != NULL);
|
||||
ARG_CHECK(hashfp != NULL);
|
||||
|
||||
/* Load remote public key (as fraction). */
|
||||
theirs64 = party ? ell_a64 : ell_b64;
|
||||
secp256k1_fe_set_b32_mod(&u, theirs64);
|
||||
secp256k1_fe_set_b32_mod(&t, theirs64 + 32);
|
||||
secp256k1_ellswift_xswiftec_frac_var(&xn, &xd, &u, &t);
|
||||
|
||||
/* Load private key (using one if invalid). */
|
||||
secp256k1_scalar_set_b32(&s, seckey32, &overflow);
|
||||
overflow |= secp256k1_scalar_is_zero(&s);
|
||||
secp256k1_scalar_cmov(&s, &secp256k1_scalar_one, overflow);
|
||||
|
||||
/* Compute shared X coordinate. */
|
||||
secp256k1_ecmult_const_xonly(&px, &xn, &xd, &s, 1);
|
||||
secp256k1_fe_normalize(&px);
|
||||
secp256k1_fe_get_b32(sx, &px);
|
||||
|
||||
/* Invoke hasher. Use ctx-aware function by default */
|
||||
if (hashfp == secp256k1_ellswift_xdh_hash_function_bip324) {
|
||||
ret = ellswift_xdh_hash_function_bip324_impl(secp256k1_get_hash_context(ctx), output, sx, ell_a64, ell_b64, data);
|
||||
} else if (hashfp == secp256k1_ellswift_xdh_hash_function_prefix) {
|
||||
ret = ellswift_xdh_hash_function_prefix_impl(secp256k1_get_hash_context(ctx), output, sx, ell_a64, ell_b64, data);
|
||||
} else {
|
||||
ret = hashfp(output, sx, ell_a64, ell_b64, data);
|
||||
}
|
||||
|
||||
secp256k1_memclear_explicit(sx, sizeof(sx));
|
||||
secp256k1_fe_clear(&px);
|
||||
secp256k1_scalar_clear(&s);
|
||||
|
||||
return !!ret & !overflow;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,39 @@
|
||||
/***********************************************************************
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_ELLSWIFT_TESTS_EXHAUSTIVE_H
|
||||
#define SECP256K1_MODULE_ELLSWIFT_TESTS_EXHAUSTIVE_H
|
||||
|
||||
#include "../../../include/secp256k1_ellswift.h"
|
||||
#include "main_impl.h"
|
||||
|
||||
static void test_exhaustive_ellswift(const secp256k1_context *ctx, const secp256k1_ge *group) {
|
||||
int i;
|
||||
|
||||
/* Note that SwiftEC/ElligatorSwift are inherently curve operations, not
|
||||
* group operations, and this test only checks the curve points which are in
|
||||
* a tiny subgroup. In that sense it can't be really seen as exhaustive as
|
||||
* it doesn't (and for computational reasons obviously cannot) test the
|
||||
* entire domain ellswift operates under. */
|
||||
for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) {
|
||||
secp256k1_scalar scalar_i;
|
||||
unsigned char sec32[32];
|
||||
unsigned char ell64[64];
|
||||
secp256k1_pubkey pub_decoded;
|
||||
secp256k1_ge ge_decoded;
|
||||
|
||||
/* Construct ellswift pubkey from exhaustive loop scalar i. */
|
||||
secp256k1_scalar_set_int(&scalar_i, i);
|
||||
secp256k1_scalar_get_b32(sec32, &scalar_i);
|
||||
CHECK(secp256k1_ellswift_create(ctx, ell64, sec32, NULL));
|
||||
|
||||
/* Decode ellswift pubkey and check that it matches the precomputed group element. */
|
||||
secp256k1_ellswift_decode(ctx, &pub_decoded, ell64);
|
||||
secp256k1_pubkey_load(ctx, &ge_decoded, &pub_decoded);
|
||||
CHECK(secp256k1_ge_eq_var(&ge_decoded, &group[i]));
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,544 @@
|
||||
/***********************************************************************
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_ELLSWIFT_TESTS_H
|
||||
#define SECP256K1_MODULE_ELLSWIFT_TESTS_H
|
||||
|
||||
#include "../../../include/secp256k1_ellswift.h"
|
||||
#include "../../unit_test.h"
|
||||
#include "../../util.h"
|
||||
|
||||
struct ellswift_xswiftec_inv_test {
|
||||
int enc_bitmap;
|
||||
secp256k1_fe u;
|
||||
secp256k1_fe x;
|
||||
secp256k1_fe encs[8];
|
||||
};
|
||||
|
||||
struct ellswift_decode_test {
|
||||
unsigned char enc[64];
|
||||
secp256k1_fe x;
|
||||
int odd_y;
|
||||
};
|
||||
|
||||
struct ellswift_xdh_test {
|
||||
unsigned char priv_ours[32];
|
||||
unsigned char ellswift_ours[64];
|
||||
unsigned char ellswift_theirs[64];
|
||||
int initiating;
|
||||
unsigned char shared_secret[32];
|
||||
};
|
||||
|
||||
/* Set of (point, encodings) test vectors, selected to maximize branch coverage, part of the BIP324
|
||||
* test vectors. Created using an independent implementation, and tested decoding against paper
|
||||
* authors' code. */
|
||||
static const struct ellswift_xswiftec_inv_test ellswift_xswiftec_inv_tests[] = {
|
||||
{0xcc, SECP256K1_FE_CONST(0x05ff6bda, 0xd900fc32, 0x61bc7fe3, 0x4e2fb0f5, 0x69f06e09, 0x1ae437d3, 0xa52e9da0, 0xcbfb9590), SECP256K1_FE_CONST(0x80cdf637, 0x74ec7022, 0xc89a5a85, 0x58e373a2, 0x79170285, 0xe0ab2741, 0x2dbce510, 0xbdfe23fc), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x45654798, 0xece071ba, 0x79286d04, 0xf7f3eb1c, 0x3f1d17dd, 0x883610f2, 0xad2efd82, 0xa287466b), SECP256K1_FE_CONST(0x0aeaa886, 0xf6b76c71, 0x58452418, 0xcbf5033a, 0xdc5747e9, 0xe9b5d3b2, 0x303db969, 0x36528557), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xba9ab867, 0x131f8e45, 0x86d792fb, 0x080c14e3, 0xc0e2e822, 0x77c9ef0d, 0x52d1027c, 0x5d78b5c4), SECP256K1_FE_CONST(0xf5155779, 0x0948938e, 0xa7badbe7, 0x340afcc5, 0x23a8b816, 0x164a2c4d, 0xcfc24695, 0xc9ad76d8)}},
|
||||
{0x33, SECP256K1_FE_CONST(0x1737a85f, 0x4c8d146c, 0xec96e3ff, 0xdca76d99, 0x03dcf3bd, 0x53061868, 0xd478c78c, 0x63c2aa9e), SECP256K1_FE_CONST(0x39e48dd1, 0x50d2f429, 0xbe088dfd, 0x5b61882e, 0x7e840748, 0x3702ae9a, 0x5ab35927, 0xb15f85ea), {SECP256K1_FE_CONST(0x1be8cc0b, 0x04be0c68, 0x1d0c6a68, 0xf733f82c, 0x6c896e0c, 0x8a262fcd, 0x392918e3, 0x03a7abf4), SECP256K1_FE_CONST(0x605b5814, 0xbf9b8cb0, 0x66667c9e, 0x5480d22d, 0xc5b6c92f, 0x14b4af3e, 0xe0a9eb83, 0xb03685e3), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xe41733f4, 0xfb41f397, 0xe2f39597, 0x08cc07d3, 0x937691f3, 0x75d9d032, 0xc6d6e71b, 0xfc58503b), SECP256K1_FE_CONST(0x9fa4a7eb, 0x4064734f, 0x99998361, 0xab7f2dd2, 0x3a4936d0, 0xeb4b50c1, 0x1f56147b, 0x4fc9764c), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
|
||||
{0x00, SECP256K1_FE_CONST(0x1aaa1cce, 0xbf9c7241, 0x91033df3, 0x66b36f69, 0x1c4d902c, 0x228033ff, 0x4516d122, 0xb2564f68), SECP256K1_FE_CONST(0xc7554125, 0x9d3ba98f, 0x207eaa30, 0xc69634d1, 0x87d0b6da, 0x594e719e, 0x420f4898, 0x638fc5b0), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
|
||||
{0x33, SECP256K1_FE_CONST(0x2323a1d0, 0x79b0fd72, 0xfc8bb62e, 0xc34230a8, 0x15cb0596, 0xc2bfac99, 0x8bd6b842, 0x60f5dc26), SECP256K1_FE_CONST(0x239342df, 0xb675500a, 0x34a19631, 0x0b8d87d5, 0x4f49dcac, 0x9da50c17, 0x43ceab41, 0xa7b249ff), {SECP256K1_FE_CONST(0xf63580b8, 0xaa49c484, 0x6de56e39, 0xe1b3e73f, 0x171e881e, 0xba8c66f6, 0x14e67e5c, 0x975dfc07), SECP256K1_FE_CONST(0xb6307b33, 0x2e699f1c, 0xf77841d9, 0x0af25365, 0x404deb7f, 0xed5edb30, 0x90db49e6, 0x42a156b6), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x09ca7f47, 0x55b63b7b, 0x921a91c6, 0x1e4c18c0, 0xe8e177e1, 0x45739909, 0xeb1981a2, 0x68a20028), SECP256K1_FE_CONST(0x49cf84cc, 0xd19660e3, 0x0887be26, 0xf50dac9a, 0xbfb21480, 0x12a124cf, 0x6f24b618, 0xbd5ea579), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
|
||||
{0x33, SECP256K1_FE_CONST(0x2dc90e64, 0x0cb646ae, 0x9164c0b5, 0xa9ef0169, 0xfebe34dc, 0x4437d6e4, 0x6acb0e27, 0xe219d1e8), SECP256K1_FE_CONST(0xd236f19b, 0xf349b951, 0x6e9b3f4a, 0x5610fe96, 0x0141cb23, 0xbbc8291b, 0x9534f1d7, 0x1de62a47), {SECP256K1_FE_CONST(0xe69df7d9, 0xc026c366, 0x00ebdf58, 0x80726758, 0x47c0c431, 0xc8eb7306, 0x82533e96, 0x4b6252c9), SECP256K1_FE_CONST(0x4f18bbdf, 0x7c2d6c5f, 0x818c1880, 0x2fa35cd0, 0x69eaa79f, 0xff74e4fc, 0x837c80d9, 0x3fece2f8), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x19620826, 0x3fd93c99, 0xff1420a7, 0x7f8d98a7, 0xb83f3bce, 0x37148cf9, 0x7dacc168, 0xb49da966), SECP256K1_FE_CONST(0xb0e74420, 0x83d293a0, 0x7e73e77f, 0xd05ca32f, 0x96155860, 0x008b1b03, 0x7c837f25, 0xc0131937), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
|
||||
{0xcc, SECP256K1_FE_CONST(0x3edd7b39, 0x80e2f2f3, 0x4d1409a2, 0x07069f88, 0x1fda5f96, 0xf08027ac, 0x4465b63d, 0xc278d672), SECP256K1_FE_CONST(0x053a98de, 0x4a27b196, 0x1155822b, 0x3a3121f0, 0x3b2a1445, 0x8bd80eb4, 0xa560c4c7, 0xa85c149c), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xb3dae4b7, 0xdcf858e4, 0xc6968057, 0xcef2b156, 0x46543152, 0x6538199c, 0xf52dc1b2, 0xd62fda30), SECP256K1_FE_CONST(0x4aa77dd5, 0x5d6b6d3c, 0xfa10cc9d, 0x0fe42f79, 0x232e4575, 0x661049ae, 0x36779c1d, 0x0c666d88), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x4c251b48, 0x2307a71b, 0x39697fa8, 0x310d4ea9, 0xb9abcead, 0x9ac7e663, 0x0ad23e4c, 0x29d021ff), SECP256K1_FE_CONST(0xb558822a, 0xa29492c3, 0x05ef3362, 0xf01bd086, 0xdcd1ba8a, 0x99efb651, 0xc98863e1, 0xf3998ea7)}},
|
||||
{0x00, SECP256K1_FE_CONST(0x4295737e, 0xfcb1da6f, 0xb1d96b9c, 0xa7dcd1e3, 0x20024b37, 0xa736c494, 0x8b625981, 0x73069f70), SECP256K1_FE_CONST(0xfa7ffe4f, 0x25f88362, 0x831c087a, 0xfe2e8a9b, 0x0713e2ca, 0xc1ddca6a, 0x383205a2, 0x66f14307), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
|
||||
{0xff, SECP256K1_FE_CONST(0x587c1a0c, 0xee91939e, 0x7f784d23, 0xb963004a, 0x3bf44f5d, 0x4e32a008, 0x1995ba20, 0xb0fca59e), SECP256K1_FE_CONST(0x2ea98853, 0x0715e8d1, 0x0363907f, 0xf2512452, 0x4d471ba2, 0x454d5ce3, 0xbe3f0419, 0x4dfd3a3c), {SECP256K1_FE_CONST(0xcfd5a094, 0xaa0b9b88, 0x91b76c6a, 0xb9438f66, 0xaa1c095a, 0x65f9f701, 0x35e81712, 0x92245e74), SECP256K1_FE_CONST(0xa89057d7, 0xc6563f0d, 0x6efa19ae, 0x84412b8a, 0x7b47e791, 0xa191ecdf, 0xdf2af84f, 0xd97bc339), SECP256K1_FE_CONST(0x475d0ae9, 0xef46920d, 0xf07b3411, 0x7be5a081, 0x7de1023e, 0x3cc32689, 0xe9be145b, 0x406b0aef), SECP256K1_FE_CONST(0xa0759178, 0xad802324, 0x54f827ef, 0x05ea3e72, 0xad8d7541, 0x8e6d4cc1, 0xcd4f5306, 0xc5e7c453), SECP256K1_FE_CONST(0x302a5f6b, 0x55f46477, 0x6e489395, 0x46bc7099, 0x55e3f6a5, 0x9a0608fe, 0xca17e8ec, 0x6ddb9dbb), SECP256K1_FE_CONST(0x576fa828, 0x39a9c0f2, 0x9105e651, 0x7bbed475, 0x84b8186e, 0x5e6e1320, 0x20d507af, 0x268438f6), SECP256K1_FE_CONST(0xb8a2f516, 0x10b96df2, 0x0f84cbee, 0x841a5f7e, 0x821efdc1, 0xc33cd976, 0x1641eba3, 0xbf94f140), SECP256K1_FE_CONST(0x5f8a6e87, 0x527fdcdb, 0xab07d810, 0xfa15c18d, 0x52728abe, 0x7192b33e, 0x32b0acf8, 0x3a1837dc)}},
|
||||
{0xcc, SECP256K1_FE_CONST(0x5fa88b33, 0x65a635cb, 0xbcee003c, 0xce9ef51d, 0xd1a310de, 0x277e441a, 0xbccdb7be, 0x1e4ba249), SECP256K1_FE_CONST(0x79461ff6, 0x2bfcbcac, 0x4249ba84, 0xdd040f2c, 0xec3c63f7, 0x25204dc7, 0xf464c16b, 0xf0ff3170), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x6bb700e1, 0xf4d7e236, 0xe8d193ff, 0x4a76c1b3, 0xbcd4e2b2, 0x5acac3d5, 0x1c8dac65, 0x3fe909a0), SECP256K1_FE_CONST(0xf4c73410, 0x633da7f6, 0x3a4f1d55, 0xaec6dd32, 0xc4c6d89e, 0xe74075ed, 0xb5515ed9, 0x0da9e683), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x9448ff1e, 0x0b281dc9, 0x172e6c00, 0xb5893e4c, 0x432b1d4d, 0xa5353c2a, 0xe3725399, 0xc016f28f), SECP256K1_FE_CONST(0x0b38cbef, 0x9cc25809, 0xc5b0e2aa, 0x513922cd, 0x3b392761, 0x18bf8a12, 0x4aaea125, 0xf25615ac)}},
|
||||
{0xcc, SECP256K1_FE_CONST(0x6fb31c75, 0x31f03130, 0xb42b155b, 0x952779ef, 0xbb46087d, 0xd9807d24, 0x1a48eac6, 0x3c3d96d6), SECP256K1_FE_CONST(0x56f81be7, 0x53e8d4ae, 0x4940ea6f, 0x46f6ec9f, 0xda66a6f9, 0x6cc95f50, 0x6cb2b574, 0x90e94260), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x59059774, 0x795bdb7a, 0x837fbe11, 0x40a5fa59, 0x984f48af, 0x8df95d57, 0xdd6d1c05, 0x437dcec1), SECP256K1_FE_CONST(0x22a644db, 0x79376ad4, 0xe7b3a009, 0xe58b3f13, 0x137c54fd, 0xf911122c, 0xc93667c4, 0x7077d784), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xa6fa688b, 0x86a42485, 0x7c8041ee, 0xbf5a05a6, 0x67b0b750, 0x7206a2a8, 0x2292e3f9, 0xbc822d6e), SECP256K1_FE_CONST(0xdd59bb24, 0x86c8952b, 0x184c5ff6, 0x1a74c0ec, 0xec83ab02, 0x06eeedd3, 0x36c9983a, 0x8f8824ab)}},
|
||||
{0x00, SECP256K1_FE_CONST(0x704cd226, 0xe71cb682, 0x6a590e80, 0xdac90f2d, 0x2f5830f0, 0xfdf135a3, 0xeae3965b, 0xff25ff12), SECP256K1_FE_CONST(0x138e0afa, 0x68936ee6, 0x70bd2b8d, 0xb53aedbb, 0x7bea2a85, 0x97388b24, 0xd0518edd, 0x22ad66ec), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
|
||||
{0x33, SECP256K1_FE_CONST(0x725e9147, 0x92cb8c89, 0x49e7e116, 0x8b7cdd8a, 0x8094c91c, 0x6ec2202c, 0xcd53a6a1, 0x8771edeb), SECP256K1_FE_CONST(0x8da16eb8, 0x6d347376, 0xb6181ee9, 0x74832275, 0x7f6b36e3, 0x913ddfd3, 0x32ac595d, 0x788e0e44), {SECP256K1_FE_CONST(0xdd357786, 0xb9f68733, 0x30391aa5, 0x62580965, 0x4e43116e, 0x82a5a5d8, 0x2ffd1d66, 0x24101fc4), SECP256K1_FE_CONST(0xa0b7efca, 0x01814594, 0xc59c9aae, 0x8e497001, 0x86ca5d95, 0xe88bcc80, 0x399044d9, 0xc2d8613d), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x22ca8879, 0x460978cc, 0xcfc6e55a, 0x9da7f69a, 0xb1bcee91, 0x7d5a5a27, 0xd002e298, 0xdbefdc6b), SECP256K1_FE_CONST(0x5f481035, 0xfe7eba6b, 0x3a636551, 0x71b68ffe, 0x7935a26a, 0x1774337f, 0xc66fbb25, 0x3d279af2), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
|
||||
{0x00, SECP256K1_FE_CONST(0x78fe6b71, 0x7f2ea4a3, 0x2708d79c, 0x151bf503, 0xa5312a18, 0xc0963437, 0xe865cc6e, 0xd3f6ae97), SECP256K1_FE_CONST(0x8701948e, 0x80d15b5c, 0xd8f72863, 0xeae40afc, 0x5aced5e7, 0x3f69cbc8, 0x179a3390, 0x2c094d98), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
|
||||
{0x44, SECP256K1_FE_CONST(0x7c37bb9c, 0x5061dc07, 0x413f11ac, 0xd5a34006, 0xe64c5c45, 0x7fdb9a43, 0x8f217255, 0xa961f50d), SECP256K1_FE_CONST(0x5c1a76b4, 0x4568eb59, 0xd6789a74, 0x42d9ed7c, 0xdc6226b7, 0x752b4ff8, 0xeaf8e1a9, 0x5736e507), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xb94d30cd, 0x7dbff60b, 0x64620c17, 0xca0fafaa, 0x40b3d1f5, 0x2d077a60, 0xa2e0cafd, 0x145086c2), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x46b2cf32, 0x824009f4, 0x9b9df3e8, 0x35f05055, 0xbf4c2e0a, 0xd2f8859f, 0x5d1f3501, 0xebaf756d), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
|
||||
{0x00, SECP256K1_FE_CONST(0x82388888, 0x967f82a6, 0xb444438a, 0x7d44838e, 0x13c0d478, 0xb9ca060d, 0xa95a41fb, 0x94303de6), SECP256K1_FE_CONST(0x29e96541, 0x70628fec, 0x8b497289, 0x8b113cf9, 0x8807f460, 0x9274f4f3, 0x140d0674, 0x157c90a0), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
|
||||
{0x33, SECP256K1_FE_CONST(0x91298f57, 0x70af7a27, 0xf0a47188, 0xd24c3b7b, 0xf98ab299, 0x0d84b0b8, 0x98507e3c, 0x561d6472), SECP256K1_FE_CONST(0x144f4ccb, 0xd9a74698, 0xa88cbf6f, 0xd00ad886, 0xd339d29e, 0xa19448f2, 0xc572cac0, 0xa07d5562), {SECP256K1_FE_CONST(0xe6a0ffa3, 0x807f09da, 0xdbe71e0f, 0x4be4725f, 0x2832e76c, 0xad8dc1d9, 0x43ce8393, 0x75eff248), SECP256K1_FE_CONST(0x837b8e68, 0xd4917544, 0x764ad090, 0x3cb11f86, 0x15d2823c, 0xefbb06d8, 0x9049dbab, 0xc69befda), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x195f005c, 0x7f80f625, 0x2418e1f0, 0xb41b8da0, 0xd7cd1893, 0x52723e26, 0xbc317c6b, 0x8a1009e7), SECP256K1_FE_CONST(0x7c847197, 0x2b6e8abb, 0x89b52f6f, 0xc34ee079, 0xea2d7dc3, 0x1044f927, 0x6fb62453, 0x39640c55), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
|
||||
{0x00, SECP256K1_FE_CONST(0xb682f3d0, 0x3bbb5dee, 0x4f54b5eb, 0xfba931b4, 0xf52f6a19, 0x1e5c2f48, 0x3c73c66e, 0x9ace97e1), SECP256K1_FE_CONST(0x904717bf, 0x0bc0cb78, 0x73fcdc38, 0xaa97f19e, 0x3a626309, 0x72acff92, 0xb24cc6dd, 0xa197cb96), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
|
||||
{0x77, SECP256K1_FE_CONST(0xc17ec69e, 0x665f0fb0, 0xdbab48d9, 0xc2f94d12, 0xec8a9d7e, 0xacb58084, 0x83309180, 0x1eb0b80b), SECP256K1_FE_CONST(0x147756e6, 0x6d96e31c, 0x426d3cc8, 0x5ed0c4cf, 0xbef6341d, 0xd8b28558, 0x5aa574ea, 0x0204b55e), {SECP256K1_FE_CONST(0x6f4aea43, 0x1a0043bd, 0xd03134d6, 0xd9159119, 0xce034b88, 0xc32e50e8, 0xe36c4ee4, 0x5eac7ae9), SECP256K1_FE_CONST(0xfd5be16d, 0x4ffa2690, 0x126c67c3, 0xef7cb9d2, 0x9b74d397, 0xc78b06b3, 0x605fda34, 0xdc9696a6), SECP256K1_FE_CONST(0x5e9c6079, 0x2a2f000e, 0x45c6250f, 0x296f875e, 0x174efc0e, 0x9703e628, 0x706103a9, 0xdd2d82c7), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x90b515bc, 0xe5ffbc42, 0x2fcecb29, 0x26ea6ee6, 0x31fcb477, 0x3cd1af17, 0x1c93b11a, 0xa1538146), SECP256K1_FE_CONST(0x02a41e92, 0xb005d96f, 0xed93983c, 0x1083462d, 0x648b2c68, 0x3874f94c, 0x9fa025ca, 0x23696589), SECP256K1_FE_CONST(0xa1639f86, 0xd5d0fff1, 0xba39daf0, 0xd69078a1, 0xe8b103f1, 0x68fc19d7, 0x8f9efc55, 0x22d27968), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
|
||||
{0xcc, SECP256K1_FE_CONST(0xc25172fc, 0x3f29b6fc, 0x4a1155b8, 0x57523315, 0x5486b274, 0x64b74b8b, 0x260b499a, 0x3f53cb14), SECP256K1_FE_CONST(0x1ea9cbdb, 0x35cf6e03, 0x29aa31b0, 0xbb0a702a, 0x65123ed0, 0x08655a93, 0xb7dcd528, 0x0e52e1ab), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x7422edc7, 0x843136af, 0x0053bb88, 0x54448a82, 0x99994f9d, 0xdcefd3a9, 0xa92d4546, 0x2c59298a), SECP256K1_FE_CONST(0x78c7774a, 0x266f8b97, 0xea23d05d, 0x064f033c, 0x77319f92, 0x3f6b78bc, 0xe4e20bf0, 0x5fa5398d), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x8bdd1238, 0x7bcec950, 0xffac4477, 0xabbb757d, 0x6666b062, 0x23102c56, 0x56d2bab8, 0xd3a6d2a5), SECP256K1_FE_CONST(0x873888b5, 0xd9907468, 0x15dc2fa2, 0xf9b0fcc3, 0x88ce606d, 0xc0948743, 0x1b1df40e, 0xa05ac2a2)}},
|
||||
{0x00, SECP256K1_FE_CONST(0xcab6626f, 0x832a4b12, 0x80ba7add, 0x2fc5322f, 0xf011caed, 0xedf7ff4d, 0xb6735d50, 0x26dc0367), SECP256K1_FE_CONST(0x2b2bef08, 0x52c6f7c9, 0x5d72ac99, 0xa23802b8, 0x75029cd5, 0x73b248d1, 0xf1b3fc80, 0x33788eb6), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
|
||||
{0x33, SECP256K1_FE_CONST(0xd8621b4f, 0xfc85b9ed, 0x56e99d8d, 0xd1dd24ae, 0xdcecb147, 0x63b861a1, 0x7112dc77, 0x1a104fd2), SECP256K1_FE_CONST(0x812cabe9, 0x72a22aa6, 0x7c7da0c9, 0x4d8a9362, 0x96eb9949, 0xd70c37cb, 0x2b248757, 0x4cb3ce58), {SECP256K1_FE_CONST(0xfbc5febc, 0x6fdbc9ae, 0x3eb88a93, 0xb982196e, 0x8b6275a6, 0xd5a73c17, 0x387e000c, 0x711bd0e3), SECP256K1_FE_CONST(0x8724c96b, 0xd4e5527f, 0x2dd195a5, 0x1c468d2d, 0x211ba2fa, 0xc7cbe0b4, 0xb3434253, 0x409fb42d), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x043a0143, 0x90243651, 0xc147756c, 0x467de691, 0x749d8a59, 0x2a58c3e8, 0xc781fff2, 0x8ee42b4c), SECP256K1_FE_CONST(0x78db3694, 0x2b1aad80, 0xd22e6a5a, 0xe3b972d2, 0xdee45d05, 0x38341f4b, 0x4cbcbdab, 0xbf604802), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
|
||||
{0x00, SECP256K1_FE_CONST(0xda463164, 0xc6f4bf71, 0x29ee5f0e, 0xc00f65a6, 0x75a8adf1, 0xbd931b39, 0xb64806af, 0xdcda9a22), SECP256K1_FE_CONST(0x25b9ce9b, 0x390b408e, 0xd611a0f1, 0x3ff09a59, 0x8a57520e, 0x426ce4c6, 0x49b7f94f, 0x2325620d), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
|
||||
{0xcc, SECP256K1_FE_CONST(0xdafc971e, 0x4a3a7b6d, 0xcfb42a08, 0xd9692d82, 0xad9e7838, 0x523fcbda, 0x1d4827e1, 0x4481ae2d), SECP256K1_FE_CONST(0x250368e1, 0xb5c58492, 0x304bd5f7, 0x2696d27d, 0x526187c7, 0xadc03425, 0xe2b7d81d, 0xbb7e4e02), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x370c28f1, 0xbe665efa, 0xcde6aa43, 0x6bf86fe2, 0x1e6e314c, 0x1e53dd04, 0x0e6c73a4, 0x6b4c8c49), SECP256K1_FE_CONST(0xcd8acee9, 0x8ffe5653, 0x1a84d7eb, 0x3e48fa40, 0x34206ce8, 0x25ace907, 0xd0edf0ea, 0xeb5e9ca2), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xc8f3d70e, 0x4199a105, 0x321955bc, 0x9407901d, 0xe191ceb3, 0xe1ac22fb, 0xf1938c5a, 0x94b36fe6), SECP256K1_FE_CONST(0x32753116, 0x7001a9ac, 0xe57b2814, 0xc1b705bf, 0xcbdf9317, 0xda5316f8, 0x2f120f14, 0x14a15f8d)}},
|
||||
{0x44, SECP256K1_FE_CONST(0xe0294c8b, 0xc1a36b41, 0x66ee92bf, 0xa70a5c34, 0x976fa982, 0x9405efea, 0x8f9cd54d, 0xcb29b99e), SECP256K1_FE_CONST(0xae9690d1, 0x3b8d20a0, 0xfbbf37be, 0xd8474f67, 0xa04e142f, 0x56efd787, 0x70a76b35, 0x9165d8a1), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xdcd45d93, 0x5613916a, 0xf167b029, 0x058ba3a7, 0x00d37150, 0xb9df3472, 0x8cb05412, 0xc16d4182), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x232ba26c, 0xa9ec6e95, 0x0e984fd6, 0xfa745c58, 0xff2c8eaf, 0x4620cb8d, 0x734fabec, 0x3e92baad), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
|
||||
{0x00, SECP256K1_FE_CONST(0xe148441c, 0xd7b92b8b, 0x0e4fa3bd, 0x68712cfd, 0x0d709ad1, 0x98cace61, 0x1493c10e, 0x97f5394e), SECP256K1_FE_CONST(0x164a6397, 0x94d74c53, 0xafc4d329, 0x4e79cdb3, 0xcd25f99f, 0x6df45c00, 0x0f758aba, 0x54d699c0), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
|
||||
{0xff, SECP256K1_FE_CONST(0xe4b00ec9, 0x7aadcca9, 0x7644d3b0, 0xc8a931b1, 0x4ce7bcf7, 0xbc877954, 0x6d6e35aa, 0x5937381c), SECP256K1_FE_CONST(0x94e9588d, 0x41647b3f, 0xcc772dc8, 0xd83c67ce, 0x3be00353, 0x8517c834, 0x103d2cd4, 0x9d62ef4d), {SECP256K1_FE_CONST(0xc88d25f4, 0x1407376b, 0xb2c03a7f, 0xffeb3ec7, 0x811cc434, 0x91a0c3aa, 0xc0378cdc, 0x78357bee), SECP256K1_FE_CONST(0x51c02636, 0xce00c234, 0x5ecd89ad, 0xb6089fe4, 0xd5e18ac9, 0x24e3145e, 0x6669501c, 0xd37a00d4), SECP256K1_FE_CONST(0x205b3512, 0xdb40521c, 0xb200952e, 0x67b46f67, 0xe09e7839, 0xe0de4400, 0x4138329e, 0xbd9138c5), SECP256K1_FE_CONST(0x58aab390, 0xab6fb55c, 0x1d1b8089, 0x7a207ce9, 0x4a78fa5b, 0x4aa61a33, 0x398bcae9, 0xadb20d3e), SECP256K1_FE_CONST(0x3772da0b, 0xebf8c894, 0x4d3fc580, 0x0014c138, 0x7ee33bcb, 0x6e5f3c55, 0x3fc87322, 0x87ca8041), SECP256K1_FE_CONST(0xae3fd9c9, 0x31ff3dcb, 0xa1327652, 0x49f7601b, 0x2a1e7536, 0xdb1ceba1, 0x9996afe2, 0x2c85fb5b), SECP256K1_FE_CONST(0xdfa4caed, 0x24bfade3, 0x4dff6ad1, 0x984b9098, 0x1f6187c6, 0x1f21bbff, 0xbec7cd60, 0x426ec36a), SECP256K1_FE_CONST(0xa7554c6f, 0x54904aa3, 0xe2e47f76, 0x85df8316, 0xb58705a4, 0xb559e5cc, 0xc6743515, 0x524deef1)}},
|
||||
{0x00, SECP256K1_FE_CONST(0xe5bbb9ef, 0x360d0a50, 0x1618f006, 0x7d36dceb, 0x75f5be9a, 0x620232aa, 0x9fd5139d, 0x0863fde5), SECP256K1_FE_CONST(0xe5bbb9ef, 0x360d0a50, 0x1618f006, 0x7d36dceb, 0x75f5be9a, 0x620232aa, 0x9fd5139d, 0x0863fde5), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
|
||||
{0xff, SECP256K1_FE_CONST(0xe6bcb5c3, 0xd63467d4, 0x90bfa54f, 0xbbc6092a, 0x7248c25e, 0x11b248dc, 0x2964a6e1, 0x5edb1457), SECP256K1_FE_CONST(0x19434a3c, 0x29cb982b, 0x6f405ab0, 0x4439f6d5, 0x8db73da1, 0xee4db723, 0xd69b591d, 0xa124e7d8), {SECP256K1_FE_CONST(0x67119877, 0x832ab8f4, 0x59a82165, 0x6d8261f5, 0x44a553b8, 0x9ae4f25c, 0x52a97134, 0xb70f3426), SECP256K1_FE_CONST(0xffee02f5, 0xe649c07f, 0x0560eff1, 0x867ec7b3, 0x2d0e595e, 0x9b1c0ea6, 0xe2a4fc70, 0xc97cd71f), SECP256K1_FE_CONST(0xb5e0c189, 0xeb5b4bac, 0xd025b744, 0x4d74178b, 0xe8d5246c, 0xfa4a9a20, 0x7964a057, 0xee969992), SECP256K1_FE_CONST(0x5746e459, 0x1bf7f4c3, 0x044609ea, 0x372e9086, 0x03975d27, 0x9fdef834, 0x9f0b08d3, 0x2f07619d), SECP256K1_FE_CONST(0x98ee6788, 0x7cd5470b, 0xa657de9a, 0x927d9e0a, 0xbb5aac47, 0x651b0da3, 0xad568eca, 0x48f0c809), SECP256K1_FE_CONST(0x0011fd0a, 0x19b63f80, 0xfa9f100e, 0x7981384c, 0xd2f1a6a1, 0x64e3f159, 0x1d5b038e, 0x36832510), SECP256K1_FE_CONST(0x4a1f3e76, 0x14a4b453, 0x2fda48bb, 0xb28be874, 0x172adb93, 0x05b565df, 0x869b5fa7, 0x1169629d), SECP256K1_FE_CONST(0xa8b91ba6, 0xe4080b3c, 0xfbb9f615, 0xc8d16f79, 0xfc68a2d8, 0x602107cb, 0x60f4f72b, 0xd0f89a92)}},
|
||||
{0x33, SECP256K1_FE_CONST(0xf28fba64, 0xaf766845, 0xeb2f4302, 0x456e2b9f, 0x8d80affe, 0x57e7aae4, 0x2738d7cd, 0xdb1c2ce6), SECP256K1_FE_CONST(0xf28fba64, 0xaf766845, 0xeb2f4302, 0x456e2b9f, 0x8d80affe, 0x57e7aae4, 0x2738d7cd, 0xdb1c2ce6), {SECP256K1_FE_CONST(0x4f867ad8, 0xbb3d8404, 0x09d26b67, 0x307e6210, 0x0153273f, 0x72fa4b74, 0x84becfa1, 0x4ebe7408), SECP256K1_FE_CONST(0x5bbc4f59, 0xe452cc5f, 0x22a99144, 0xb10ce898, 0x9a89a995, 0xec3cea1c, 0x91ae10e8, 0xf721bb5d), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xb0798527, 0x44c27bfb, 0xf62d9498, 0xcf819def, 0xfeacd8c0, 0x8d05b48b, 0x7b41305d, 0xb1418827), SECP256K1_FE_CONST(0xa443b0a6, 0x1bad33a0, 0xdd566ebb, 0x4ef31767, 0x6576566a, 0x13c315e3, 0x6e51ef16, 0x08de40d2), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
|
||||
{0xcc, SECP256K1_FE_CONST(0xf455605b, 0xc85bf48e, 0x3a908c31, 0x023faf98, 0x381504c6, 0xc6d3aeb9, 0xede55f8d, 0xd528924d), SECP256K1_FE_CONST(0xd31fbcd5, 0xcdb798f6, 0xc00db669, 0x2f8fe896, 0x7fa9c79d, 0xd10958f4, 0xa194f013, 0x74905e99), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x0c00c571, 0x5b56fe63, 0x2d814ad8, 0xa77f8e66, 0x628ea47a, 0x6116834f, 0x8c1218f3, 0xa03cbd50), SECP256K1_FE_CONST(0xdf88e44f, 0xac84fa52, 0xdf4d59f4, 0x8819f18f, 0x6a8cd415, 0x1d162afa, 0xf773166f, 0x57c7ff46), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xf3ff3a8e, 0xa4a9019c, 0xd27eb527, 0x58807199, 0x9d715b85, 0x9ee97cb0, 0x73ede70b, 0x5fc33edf), SECP256K1_FE_CONST(0x20771bb0, 0x537b05ad, 0x20b2a60b, 0x77e60e70, 0x95732bea, 0xe2e9d505, 0x088ce98f, 0xa837fce9)}},
|
||||
{0xff, SECP256K1_FE_CONST(0xf58cd4d9, 0x830bad32, 0x2699035e, 0x8246007d, 0x4be27e19, 0xb6f53621, 0x317b4f30, 0x9b3daa9d), SECP256K1_FE_CONST(0x78ec2b3d, 0xc0948de5, 0x60148bbc, 0x7c6dc963, 0x3ad5df70, 0xa5a5750c, 0xbed72180, 0x4f082a3b), {SECP256K1_FE_CONST(0x6c4c580b, 0x76c75940, 0x43569f9d, 0xae16dc28, 0x01c16a1f, 0xbe128608, 0x81b75f8e, 0xf929bce5), SECP256K1_FE_CONST(0x94231355, 0xe7385c5f, 0x25ca436a, 0xa6419147, 0x1aea4393, 0xd6e86ab7, 0xa35fe2af, 0xacaefd0d), SECP256K1_FE_CONST(0xdff2a195, 0x1ada6db5, 0x74df8340, 0x48149da3, 0x397a75b8, 0x29abf58c, 0x7e69db1b, 0x41ac0989), SECP256K1_FE_CONST(0xa52b66d3, 0xc9070355, 0x48028bf8, 0x04711bf4, 0x22aba95f, 0x1a666fc8, 0x6f4648e0, 0x5f29caae), SECP256K1_FE_CONST(0x93b3a7f4, 0x8938a6bf, 0xbca96062, 0x51e923d7, 0xfe3e95e0, 0x41ed79f7, 0x7e48a070, 0x06d63f4a), SECP256K1_FE_CONST(0x6bdcecaa, 0x18c7a3a0, 0xda35bc95, 0x59be6eb8, 0xe515bc6c, 0x29179548, 0x5ca01d4f, 0x5350ff22), SECP256K1_FE_CONST(0x200d5e6a, 0xe525924a, 0x8b207cbf, 0xb7eb625c, 0xc6858a47, 0xd6540a73, 0x819624e3, 0xbe53f2a6), SECP256K1_FE_CONST(0x5ad4992c, 0x36f8fcaa, 0xb7fd7407, 0xfb8ee40b, 0xdd5456a0, 0xe5999037, 0x90b9b71e, 0xa0d63181)}},
|
||||
{0x00, SECP256K1_FE_CONST(0xfd7d912a, 0x40f182a3, 0x588800d6, 0x9ebfb504, 0x8766da20, 0x6fd7ebc8, 0xd2436c81, 0xcbef6421), SECP256K1_FE_CONST(0x8d37c862, 0x054debe7, 0x31694536, 0xff46b273, 0xec122b35, 0xa9bf1445, 0xac3c4ff9, 0xf262c952), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
|
||||
};
|
||||
|
||||
/* Set of (encoding, xcoord) test vectors, selected to maximize branch coverage, part of the BIP324
|
||||
* test vectors. Created using an independent implementation, and tested decoding against the paper
|
||||
* authors' code. */
|
||||
static const struct ellswift_decode_test ellswift_decode_tests[] = {
|
||||
{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c), 0},
|
||||
{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd3, 0x47, 0x5b, 0xf7, 0x65, 0x5b, 0x0f, 0xb2, 0xd8, 0x52, 0x92, 0x10, 0x35, 0xb2, 0xef, 0x60, 0x7f, 0x49, 0x06, 0x9b, 0x97, 0x45, 0x4e, 0x67, 0x95, 0x25, 0x10, 0x62, 0x74, 0x17, 0x71}, SECP256K1_FE_CONST(0xb5da00b7, 0x3cd65605, 0x20e7c364, 0x086e7cd2, 0x3a34bf60, 0xd0e707be, 0x9fc34d4c, 0xd5fdfa2c), 1},
|
||||
{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0x27, 0x7c, 0x4a, 0x71, 0xf9, 0xd2, 0x2e, 0x66, 0xec, 0xe5, 0x23, 0xf8, 0xfa, 0x08, 0x74, 0x1a, 0x7c, 0x09, 0x12, 0xc6, 0x6a, 0x69, 0xce, 0x68, 0x51, 0x4b, 0xfd, 0x35, 0x15, 0xb4, 0x9f}, SECP256K1_FE_CONST(0xf482f2e2, 0x41753ad0, 0xfb89150d, 0x8491dc1e, 0x34ff0b8a, 0xcfbb442c, 0xfe999e2e, 0x5e6fd1d2), 1},
|
||||
{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x21, 0xcc, 0x93, 0x0e, 0x77, 0xc9, 0xf5, 0x14, 0xb6, 0x91, 0x5c, 0x3d, 0xbe, 0x2a, 0x94, 0xc6, 0xd8, 0xf6, 0x90, 0xb5, 0xb7, 0x39, 0x86, 0x4b, 0xa6, 0x78, 0x9f, 0xb8, 0xa5, 0x5d, 0xd0}, SECP256K1_FE_CONST(0x9f59c402, 0x75f5085a, 0x006f05da, 0xe77eb98c, 0x6fd0db1a, 0xb4a72ac4, 0x7eae90a4, 0xfc9e57e0), 0},
|
||||
{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0xe7, 0x0d, 0xf5, 0x19, 0x39, 0xb9, 0x4c, 0x9c, 0x24, 0x97, 0x9f, 0xa7, 0xdd, 0x04, 0xeb, 0xd9, 0xb3, 0x57, 0x2d, 0xa7, 0x80, 0x22, 0x90, 0x43, 0x8a, 0xf2, 0xa6, 0x81, 0x89, 0x54, 0x41}, SECP256K1_FE_CONST(0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaa9, 0xfffffd6b), 1},
|
||||
{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd1, 0x9c, 0x18, 0x2d, 0x27, 0x59, 0xcd, 0x99, 0x82, 0x42, 0x28, 0xd9, 0x47, 0x99, 0xf8, 0xc6, 0x55, 0x7c, 0x38, 0xa1, 0xc0, 0xd6, 0x77, 0x9b, 0x9d, 0x4b, 0x72, 0x9c, 0x6f, 0x1c, 0xcc, 0x42}, SECP256K1_FE_CONST(0x70720db7, 0xe238d041, 0x21f5b1af, 0xd8cc5ad9, 0xd18944c6, 0xbdc94881, 0xf502b7a3, 0xaf3aecff), 0},
|
||||
{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c), 0},
|
||||
{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x26, 0x64, 0xbb, 0xd5}, SECP256K1_FE_CONST(0x50873db3, 0x1badcc71, 0x890e4f67, 0x753a6575, 0x7f97aaa7, 0xdd5f1e82, 0xb753ace3, 0x2219064b), 0},
|
||||
{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x70, 0x28, 0xde, 0x7d}, SECP256K1_FE_CONST(0x1eea9cc5, 0x9cfcf2fa, 0x151ac6c2, 0x74eea411, 0x0feb4f7b, 0x68c59657, 0x32e9992e, 0x976ef68e), 0},
|
||||
{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcb, 0xcf, 0xb7, 0xe7}, SECP256K1_FE_CONST(0x12303941, 0xaedc2088, 0x80735b1f, 0x1795c8e5, 0x5be520ea, 0x93e10335, 0x7b5d2adb, 0x7ed59b8e), 0},
|
||||
{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0x11, 0x3a, 0xd9}, SECP256K1_FE_CONST(0x7eed6b70, 0xe7b0767c, 0x7d7feac0, 0x4e57aa2a, 0x12fef5e0, 0xf48f878f, 0xcbb88b3b, 0x6b5e0783), 0},
|
||||
{{0x0a, 0x2d, 0x2b, 0xa9, 0x35, 0x07, 0xf1, 0xdf, 0x23, 0x37, 0x70, 0xc2, 0xa7, 0x97, 0x96, 0x2c, 0xc6, 0x1f, 0x6d, 0x15, 0xda, 0x14, 0xec, 0xd4, 0x7d, 0x8d, 0x27, 0xae, 0x1c, 0xd5, 0xf8, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x532167c1, 0x1200b08c, 0x0e84a354, 0xe74dcc40, 0xf8b25f4f, 0xe686e308, 0x69526366, 0x278a0688), 0},
|
||||
{{0x0a, 0x2d, 0x2b, 0xa9, 0x35, 0x07, 0xf1, 0xdf, 0x23, 0x37, 0x70, 0xc2, 0xa7, 0x97, 0x96, 0x2c, 0xc6, 0x1f, 0x6d, 0x15, 0xda, 0x14, 0xec, 0xd4, 0x7d, 0x8d, 0x27, 0xae, 0x1c, 0xd5, 0xf8, 0x53, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x532167c1, 0x1200b08c, 0x0e84a354, 0xe74dcc40, 0xf8b25f4f, 0xe686e308, 0x69526366, 0x278a0688), 0},
|
||||
{{0x0f, 0xfd, 0xe9, 0xca, 0x81, 0xd7, 0x51, 0xe9, 0xcd, 0xaf, 0xfc, 0x1a, 0x50, 0x77, 0x92, 0x45, 0x32, 0x0b, 0x28, 0x99, 0x6d, 0xba, 0xf3, 0x2f, 0x82, 0x2f, 0x20, 0x11, 0x7c, 0x22, 0xfb, 0xd6, 0xc7, 0x4d, 0x99, 0xef, 0xce, 0xaa, 0x55, 0x0f, 0x1a, 0xd1, 0xc0, 0xf4, 0x3f, 0x46, 0xe7, 0xff, 0x1e, 0xe3, 0xbd, 0x01, 0x62, 0xb7, 0xbf, 0x55, 0xf2, 0x96, 0x5d, 0xa9, 0xc3, 0x45, 0x06, 0x46}, SECP256K1_FE_CONST(0x74e880b3, 0xffd18fe3, 0xcddf7902, 0x522551dd, 0xf97fa4a3, 0x5a3cfda8, 0x197f9470, 0x81a57b8f), 0},
|
||||
{{0x0f, 0xfd, 0xe9, 0xca, 0x81, 0xd7, 0x51, 0xe9, 0xcd, 0xaf, 0xfc, 0x1a, 0x50, 0x77, 0x92, 0x45, 0x32, 0x0b, 0x28, 0x99, 0x6d, 0xba, 0xf3, 0x2f, 0x82, 0x2f, 0x20, 0x11, 0x7c, 0x22, 0xfb, 0xd6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x15, 0x6c, 0xa8, 0x96}, SECP256K1_FE_CONST(0x377b643f, 0xce2271f6, 0x4e5c8101, 0x566107c1, 0xbe498074, 0x50917838, 0x04f65478, 0x1ac9217c), 1},
|
||||
{{0x12, 0x36, 0x58, 0x44, 0x4f, 0x32, 0xbe, 0x8f, 0x02, 0xea, 0x20, 0x34, 0xaf, 0xa7, 0xef, 0x4b, 0xbe, 0x8a, 0xdc, 0x91, 0x8c, 0xeb, 0x49, 0xb1, 0x27, 0x73, 0xb6, 0x25, 0xf4, 0x90, 0xb3, 0x68, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8d, 0xc5, 0xfe, 0x11}, SECP256K1_FE_CONST(0xed16d65c, 0xf3a9538f, 0xcb2c139f, 0x1ecbc143, 0xee148271, 0x20cbc265, 0x9e667256, 0x800b8142), 0},
|
||||
{{0x14, 0x6f, 0x92, 0x46, 0x4d, 0x15, 0xd3, 0x6e, 0x35, 0x38, 0x2b, 0xd3, 0xca, 0x5b, 0x0f, 0x97, 0x6c, 0x95, 0xcb, 0x08, 0xac, 0xdc, 0xf2, 0xd5, 0xb3, 0x57, 0x06, 0x17, 0x99, 0x08, 0x39, 0xd7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x31, 0x45, 0xe9, 0x3b}, SECP256K1_FE_CONST(0x0d5cd840, 0x427f941f, 0x65193079, 0xab8e2e83, 0x024ef2ee, 0x7ca558d8, 0x8879ffd8, 0x79fb6657), 0},
|
||||
{{0x15, 0xfd, 0xf5, 0xcf, 0x09, 0xc9, 0x07, 0x59, 0xad, 0xd2, 0x27, 0x2d, 0x57, 0x4d, 0x2b, 0xb5, 0xfe, 0x14, 0x29, 0xf9, 0xf3, 0xc1, 0x4c, 0x65, 0xe3, 0x19, 0x4b, 0xf6, 0x1b, 0x82, 0xaa, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x04, 0xcf, 0xd9, 0x06}, SECP256K1_FE_CONST(0x16d0e439, 0x46aec93f, 0x62d57eb8, 0xcde68951, 0xaf136cf4, 0xb307938d, 0xd1447411, 0xe07bffe1), 1},
|
||||
{{0x1f, 0x67, 0xed, 0xf7, 0x79, 0xa8, 0xa6, 0x49, 0xd6, 0xde, 0xf6, 0x00, 0x35, 0xf2, 0xfa, 0x22, 0xd0, 0x22, 0xdd, 0x35, 0x90, 0x79, 0xa1, 0xa1, 0x44, 0x07, 0x3d, 0x84, 0xf1, 0x9b, 0x92, 0xd5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x025661f9, 0xaba9d15c, 0x3118456b, 0xbe980e3e, 0x1b8ba2e0, 0x47c737a4, 0xeb48a040, 0xbb566f6c), 0},
|
||||
{{0x1f, 0x67, 0xed, 0xf7, 0x79, 0xa8, 0xa6, 0x49, 0xd6, 0xde, 0xf6, 0x00, 0x35, 0xf2, 0xfa, 0x22, 0xd0, 0x22, 0xdd, 0x35, 0x90, 0x79, 0xa1, 0xa1, 0x44, 0x07, 0x3d, 0x84, 0xf1, 0x9b, 0x92, 0xd5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x025661f9, 0xaba9d15c, 0x3118456b, 0xbe980e3e, 0x1b8ba2e0, 0x47c737a4, 0xeb48a040, 0xbb566f6c), 0},
|
||||
{{0x1f, 0xe1, 0xe5, 0xef, 0x3f, 0xce, 0xb5, 0xc1, 0x35, 0xab, 0x77, 0x41, 0x33, 0x3c, 0xe5, 0xa6, 0xe8, 0x0d, 0x68, 0x16, 0x76, 0x53, 0xf6, 0xb2, 0xb2, 0x4b, 0xcb, 0xcf, 0xaa, 0xaf, 0xf5, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x98bec3b2, 0xa351fa96, 0xcfd191c1, 0x77835193, 0x1b9e9ba9, 0xad1149f6, 0xd9eadca8, 0x0981b801), 0},
|
||||
{{0x40, 0x56, 0xa3, 0x4a, 0x21, 0x0e, 0xec, 0x78, 0x92, 0xe8, 0x82, 0x06, 0x75, 0xc8, 0x60, 0x09, 0x9f, 0x85, 0x7b, 0x26, 0xaa, 0xd8, 0x54, 0x70, 0xee, 0x6d, 0x3c, 0xf1, 0x30, 0x4a, 0x9d, 0xcf, 0x37, 0x5e, 0x70, 0x37, 0x42, 0x71, 0xf2, 0x0b, 0x13, 0xc9, 0x98, 0x6e, 0xd7, 0xd3, 0xc1, 0x77, 0x99, 0x69, 0x8c, 0xfc, 0x43, 0x5d, 0xbe, 0xd3, 0xa9, 0xf3, 0x4b, 0x38, 0xc8, 0x23, 0xc2, 0xb4}, SECP256K1_FE_CONST(0x868aac20, 0x03b29dbc, 0xad1a3e80, 0x3855e078, 0xa89d1654, 0x3ac64392, 0xd1224172, 0x98cec76e), 0},
|
||||
{{0x41, 0x97, 0xec, 0x37, 0x23, 0xc6, 0x54, 0xcf, 0xdd, 0x32, 0xab, 0x07, 0x55, 0x06, 0x64, 0x8b, 0x2f, 0xf5, 0x07, 0x03, 0x62, 0xd0, 0x1a, 0x4f, 0xff, 0x14, 0xb3, 0x36, 0xb7, 0x8f, 0x96, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb3, 0xab, 0x1e, 0x95}, SECP256K1_FE_CONST(0xba5a6314, 0x502a8952, 0xb8f456e0, 0x85928105, 0xf665377a, 0x8ce27726, 0xa5b0eb7e, 0xc1ac0286), 0},
|
||||
{{0x47, 0xeb, 0x3e, 0x20, 0x8f, 0xed, 0xcd, 0xf8, 0x23, 0x4c, 0x94, 0x21, 0xe9, 0xcd, 0x9a, 0x7a, 0xe8, 0x73, 0xbf, 0xbd, 0xbc, 0x39, 0x37, 0x23, 0xd1, 0xba, 0x1e, 0x1e, 0x6a, 0x8e, 0x6b, 0x24, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7c, 0xd1, 0x2c, 0xb1}, SECP256K1_FE_CONST(0xd192d520, 0x07e541c9, 0x807006ed, 0x0468df77, 0xfd214af0, 0xa795fe11, 0x9359666f, 0xdcf08f7c), 0},
|
||||
{{0x5e, 0xb9, 0x69, 0x6a, 0x23, 0x36, 0xfe, 0x2c, 0x3c, 0x66, 0x6b, 0x02, 0xc7, 0x55, 0xdb, 0x4c, 0x0c, 0xfd, 0x62, 0x82, 0x5c, 0x7b, 0x58, 0x9a, 0x7b, 0x7b, 0xb4, 0x42, 0xe1, 0x41, 0xc1, 0xd6, 0x93, 0x41, 0x3f, 0x00, 0x52, 0xd4, 0x9e, 0x64, 0xab, 0xec, 0x6d, 0x58, 0x31, 0xd6, 0x6c, 0x43, 0x61, 0x28, 0x30, 0xa1, 0x7d, 0xf1, 0xfe, 0x43, 0x83, 0xdb, 0x89, 0x64, 0x68, 0x10, 0x02, 0x21}, SECP256K1_FE_CONST(0xef6e1da6, 0xd6c7627e, 0x80f7a723, 0x4cb08a02, 0x2c1ee1cf, 0x29e4d0f9, 0x642ae924, 0xcef9eb38), 1},
|
||||
{{0x7b, 0xf9, 0x6b, 0x7b, 0x6d, 0xa1, 0x5d, 0x34, 0x76, 0xa2, 0xb1, 0x95, 0x93, 0x4b, 0x69, 0x0a, 0x3a, 0x3d, 0xe3, 0xe8, 0xab, 0x84, 0x74, 0x85, 0x68, 0x63, 0xb0, 0xde, 0x3a, 0xf9, 0x0b, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x50851dfc, 0x9f418c31, 0x4a437295, 0xb24feeea, 0x27af3d0c, 0xd2308348, 0xfda6e21c, 0x463e46ff), 0},
|
||||
{{0x7b, 0xf9, 0x6b, 0x7b, 0x6d, 0xa1, 0x5d, 0x34, 0x76, 0xa2, 0xb1, 0x95, 0x93, 0x4b, 0x69, 0x0a, 0x3a, 0x3d, 0xe3, 0xe8, 0xab, 0x84, 0x74, 0x85, 0x68, 0x63, 0xb0, 0xde, 0x3a, 0xf9, 0x0b, 0x0e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x50851dfc, 0x9f418c31, 0x4a437295, 0xb24feeea, 0x27af3d0c, 0xd2308348, 0xfda6e21c, 0x463e46ff), 0},
|
||||
{{0x85, 0x1b, 0x1c, 0xa9, 0x45, 0x49, 0x37, 0x1c, 0x4f, 0x1f, 0x71, 0x87, 0x32, 0x1d, 0x39, 0xbf, 0x51, 0xc6, 0xb7, 0xfb, 0x61, 0xf7, 0xcb, 0xf0, 0x27, 0xc9, 0xda, 0x62, 0x02, 0x1b, 0x7a, 0x65, 0xfc, 0x54, 0xc9, 0x68, 0x37, 0xfb, 0x22, 0xb3, 0x62, 0xed, 0xa6, 0x3e, 0xc5, 0x2e, 0xc8, 0x3d, 0x81, 0xbe, 0xdd, 0x16, 0x0c, 0x11, 0xb2, 0x2d, 0x96, 0x5d, 0x9f, 0x4a, 0x6d, 0x64, 0xd2, 0x51}, SECP256K1_FE_CONST(0x3e731051, 0xe12d3323, 0x7eb324f2, 0xaa5b16bb, 0x868eb49a, 0x1aa1fadc, 0x19b6e876, 0x1b5a5f7b), 1},
|
||||
{{0x94, 0x3c, 0x2f, 0x77, 0x51, 0x08, 0xb7, 0x37, 0xfe, 0x65, 0xa9, 0x53, 0x1e, 0x19, 0xf2, 0xfc, 0x2a, 0x19, 0x7f, 0x56, 0x03, 0xe3, 0xa2, 0x88, 0x1d, 0x1d, 0x83, 0xe4, 0x00, 0x8f, 0x91, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x311c61f0, 0xab2f32b7, 0xb1f0223f, 0xa72f0a78, 0x752b8146, 0xe46107f8, 0x876dd9c4, 0xf92b2942), 0},
|
||||
{{0x94, 0x3c, 0x2f, 0x77, 0x51, 0x08, 0xb7, 0x37, 0xfe, 0x65, 0xa9, 0x53, 0x1e, 0x19, 0xf2, 0xfc, 0x2a, 0x19, 0x7f, 0x56, 0x03, 0xe3, 0xa2, 0x88, 0x1d, 0x1d, 0x83, 0xe4, 0x00, 0x8f, 0x91, 0x25, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x311c61f0, 0xab2f32b7, 0xb1f0223f, 0xa72f0a78, 0x752b8146, 0xe46107f8, 0x876dd9c4, 0xf92b2942), 0},
|
||||
{{0xa0, 0xf1, 0x84, 0x92, 0x18, 0x3e, 0x61, 0xe8, 0x06, 0x3e, 0x57, 0x36, 0x06, 0x59, 0x14, 0x21, 0xb0, 0x6b, 0xc3, 0x51, 0x36, 0x31, 0x57, 0x8a, 0x73, 0xa3, 0x9c, 0x1c, 0x33, 0x06, 0x23, 0x9f, 0x2f, 0x32, 0x90, 0x4f, 0x0d, 0x2a, 0x33, 0xec, 0xca, 0x8a, 0x54, 0x51, 0x70, 0x5b, 0xb5, 0x37, 0xd3, 0xbf, 0x44, 0xe0, 0x71, 0x22, 0x60, 0x25, 0xcd, 0xbf, 0xd2, 0x49, 0xfe, 0x0f, 0x7a, 0xd6}, SECP256K1_FE_CONST(0x97a09cf1, 0xa2eae7c4, 0x94df3c6f, 0x8a9445bf, 0xb8c09d60, 0x832f9b0b, 0x9d5eabe2, 0x5fbd14b9), 0},
|
||||
{{0xa1, 0xed, 0x0a, 0x0b, 0xd7, 0x9d, 0x8a, 0x23, 0xcf, 0xe4, 0xec, 0x5f, 0xef, 0x5b, 0xa5, 0xcc, 0xcf, 0xd8, 0x44, 0xe4, 0xff, 0x5c, 0xb4, 0xb0, 0xf2, 0xe7, 0x16, 0x27, 0x34, 0x1f, 0x1c, 0x5b, 0x17, 0xc4, 0x99, 0x24, 0x9e, 0x0a, 0xc0, 0x8d, 0x5d, 0x11, 0xea, 0x1c, 0x2c, 0x8c, 0xa7, 0x00, 0x16, 0x16, 0x55, 0x9a, 0x79, 0x94, 0xea, 0xde, 0xc9, 0xca, 0x10, 0xfb, 0x4b, 0x85, 0x16, 0xdc}, SECP256K1_FE_CONST(0x65a89640, 0x744192cd, 0xac64b2d2, 0x1ddf989c, 0xdac75007, 0x25b645be, 0xf8e2200a, 0xe39691f2), 0},
|
||||
{{0xba, 0x94, 0x59, 0x4a, 0x43, 0x27, 0x21, 0xaa, 0x35, 0x80, 0xb8, 0x4c, 0x16, 0x1d, 0x0d, 0x13, 0x4b, 0xc3, 0x54, 0xb6, 0x90, 0x40, 0x4d, 0x7c, 0xd4, 0xec, 0x57, 0xc1, 0x6d, 0x3f, 0xbe, 0x98, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xea, 0x50, 0x7d, 0xd7}, SECP256K1_FE_CONST(0x5e0d7656, 0x4aae92cb, 0x347e01a6, 0x2afd389a, 0x9aa401c7, 0x6c8dd227, 0x543dc9cd, 0x0efe685a), 0},
|
||||
{{0xbc, 0xaf, 0x72, 0x19, 0xf2, 0xf6, 0xfb, 0xf5, 0x5f, 0xe5, 0xe0, 0x62, 0xdc, 0xe0, 0xe4, 0x8c, 0x18, 0xf6, 0x81, 0x03, 0xf1, 0x0b, 0x81, 0x98, 0xe9, 0x74, 0xc1, 0x84, 0x75, 0x0e, 0x1b, 0xe3, 0x93, 0x20, 0x16, 0xcb, 0xf6, 0x9c, 0x44, 0x71, 0xbd, 0x1f, 0x65, 0x6c, 0x6a, 0x10, 0x7f, 0x19, 0x73, 0xde, 0x4a, 0xf7, 0x08, 0x6d, 0xb8, 0x97, 0x27, 0x70, 0x60, 0xe2, 0x56, 0x77, 0xf1, 0x9a}, SECP256K1_FE_CONST(0x2d97f96c, 0xac882dfe, 0x73dc44db, 0x6ce0f1d3, 0x1d624135, 0x8dd5d74e, 0xb3d3b500, 0x03d24c2b), 0},
|
||||
{{0xbc, 0xaf, 0x72, 0x19, 0xf2, 0xf6, 0xfb, 0xf5, 0x5f, 0xe5, 0xe0, 0x62, 0xdc, 0xe0, 0xe4, 0x8c, 0x18, 0xf6, 0x81, 0x03, 0xf1, 0x0b, 0x81, 0x98, 0xe9, 0x74, 0xc1, 0x84, 0x75, 0x0e, 0x1b, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x65, 0x07, 0xd0, 0x9a}, SECP256K1_FE_CONST(0xe7008afe, 0x6e8cbd50, 0x55df120b, 0xd748757c, 0x686dadb4, 0x1cce75e4, 0xaddcc5e0, 0x2ec02b44), 1},
|
||||
{{0xc5, 0x98, 0x1b, 0xae, 0x27, 0xfd, 0x84, 0x40, 0x1c, 0x72, 0xa1, 0x55, 0xe5, 0x70, 0x7f, 0xbb, 0x81, 0x1b, 0x2b, 0x62, 0x06, 0x45, 0xd1, 0x02, 0x8e, 0xa2, 0x70, 0xcb, 0xe0, 0xee, 0x22, 0x5d, 0x4b, 0x62, 0xaa, 0x4d, 0xca, 0x65, 0x06, 0xc1, 0xac, 0xdb, 0xec, 0xc0, 0x55, 0x25, 0x69, 0xb4, 0xb2, 0x14, 0x36, 0xa5, 0x69, 0x2e, 0x25, 0xd9, 0x0d, 0x3b, 0xc2, 0xeb, 0x7c, 0xe2, 0x40, 0x78}, SECP256K1_FE_CONST(0x948b40e7, 0x181713bc, 0x018ec170, 0x2d3d054d, 0x15746c59, 0xa7020730, 0xdd13ecf9, 0x85a010d7), 0},
|
||||
{{0xc8, 0x94, 0xce, 0x48, 0xbf, 0xec, 0x43, 0x30, 0x14, 0xb9, 0x31, 0xa6, 0xad, 0x42, 0x26, 0xd7, 0xdb, 0xd8, 0xea, 0xa7, 0xb6, 0xe3, 0xfa, 0xa8, 0xd0, 0xef, 0x94, 0x05, 0x2b, 0xcf, 0x8c, 0xff, 0x33, 0x6e, 0xeb, 0x39, 0x19, 0xe2, 0xb4, 0xef, 0xb7, 0x46, 0xc7, 0xf7, 0x1b, 0xbc, 0xa7, 0xe9, 0x38, 0x32, 0x30, 0xfb, 0xbc, 0x48, 0xff, 0xaf, 0xe7, 0x7e, 0x8b, 0xcc, 0x69, 0x54, 0x24, 0x71}, SECP256K1_FE_CONST(0xf1c91acd, 0xc2525330, 0xf9b53158, 0x434a4d43, 0xa1c547cf, 0xf29f1550, 0x6f5da4eb, 0x4fe8fa5a), 1},
|
||||
{{0xcb, 0xb0, 0xde, 0xab, 0x12, 0x57, 0x54, 0xf1, 0xfd, 0xb2, 0x03, 0x8b, 0x04, 0x34, 0xed, 0x9c, 0xb3, 0xfb, 0x53, 0xab, 0x73, 0x53, 0x91, 0x12, 0x99, 0x94, 0xa5, 0x35, 0xd9, 0x25, 0xf6, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x872d81ed, 0x8831d999, 0x8b67cb71, 0x05243edb, 0xf86c10ed, 0xfebb786c, 0x110b02d0, 0x7b2e67cd), 0},
|
||||
{{0xd9, 0x17, 0xb7, 0x86, 0xda, 0xc3, 0x56, 0x70, 0xc3, 0x30, 0xc9, 0xc5, 0xae, 0x59, 0x71, 0xdf, 0xb4, 0x95, 0xc8, 0xae, 0x52, 0x3e, 0xd9, 0x7e, 0xe2, 0x42, 0x01, 0x17, 0xb1, 0x71, 0xf4, 0x1e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x20, 0x01, 0xf6, 0xf6}, SECP256K1_FE_CONST(0xe45b71e1, 0x10b831f2, 0xbdad8651, 0x994526e5, 0x8393fde4, 0x328b1ec0, 0x4d598971, 0x42584691), 1},
|
||||
{{0xe2, 0x8b, 0xd8, 0xf5, 0x92, 0x9b, 0x46, 0x7e, 0xb7, 0x0e, 0x04, 0x33, 0x23, 0x74, 0xff, 0xb7, 0xe7, 0x18, 0x02, 0x18, 0xad, 0x16, 0xea, 0xa4, 0x6b, 0x71, 0x61, 0xaa, 0x67, 0x9e, 0xb4, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x66b8c980, 0xa75c72e5, 0x98d383a3, 0x5a62879f, 0x844242ad, 0x1e73ff12, 0xedaa59f4, 0xe58632b5), 0},
|
||||
{{0xe2, 0x8b, 0xd8, 0xf5, 0x92, 0x9b, 0x46, 0x7e, 0xb7, 0x0e, 0x04, 0x33, 0x23, 0x74, 0xff, 0xb7, 0xe7, 0x18, 0x02, 0x18, 0xad, 0x16, 0xea, 0xa4, 0x6b, 0x71, 0x61, 0xaa, 0x67, 0x9e, 0xb4, 0x26, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x66b8c980, 0xa75c72e5, 0x98d383a3, 0x5a62879f, 0x844242ad, 0x1e73ff12, 0xedaa59f4, 0xe58632b5), 0},
|
||||
{{0xe7, 0xee, 0x58, 0x14, 0xc1, 0x70, 0x6b, 0xf8, 0xa8, 0x93, 0x96, 0xa9, 0xb0, 0x32, 0xbc, 0x01, 0x4c, 0x2c, 0xac, 0x9c, 0x12, 0x11, 0x27, 0xdb, 0xf6, 0xc9, 0x92, 0x78, 0xf8, 0xbb, 0x53, 0xd1, 0xdf, 0xd0, 0x4d, 0xbc, 0xda, 0x8e, 0x35, 0x24, 0x66, 0xb6, 0xfc, 0xd5, 0xf2, 0xde, 0xa3, 0xe1, 0x7d, 0x5e, 0x13, 0x31, 0x15, 0x88, 0x6e, 0xda, 0x20, 0xdb, 0x8a, 0x12, 0xb5, 0x4d, 0xe7, 0x1b}, SECP256K1_FE_CONST(0xe842c6e3, 0x529b2342, 0x70a5e977, 0x44edc34a, 0x04d7ba94, 0xe44b6d25, 0x23c9cf01, 0x95730a50), 1},
|
||||
{{0xf2, 0x92, 0xe4, 0x68, 0x25, 0xf9, 0x22, 0x5a, 0xd2, 0x3d, 0xc0, 0x57, 0xc1, 0xd9, 0x1c, 0x4f, 0x57, 0xfc, 0xb1, 0x38, 0x6f, 0x29, 0xef, 0x10, 0x48, 0x1c, 0xb1, 0xd2, 0x25, 0x18, 0x59, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x70, 0x11, 0xc9, 0x89}, SECP256K1_FE_CONST(0x3cea2c53, 0xb8b01701, 0x66ac7da6, 0x7194694a, 0xdacc84d5, 0x6389225e, 0x330134da, 0xb85a4d55), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x01, 0xd3, 0x47, 0x5b, 0xf7, 0x65, 0x5b, 0x0f, 0xb2, 0xd8, 0x52, 0x92, 0x10, 0x35, 0xb2, 0xef, 0x60, 0x7f, 0x49, 0x06, 0x9b, 0x97, 0x45, 0x4e, 0x67, 0x95, 0x25, 0x10, 0x62, 0x74, 0x17, 0x71}, SECP256K1_FE_CONST(0xb5da00b7, 0x3cd65605, 0x20e7c364, 0x086e7cd2, 0x3a34bf60, 0xd0e707be, 0x9fc34d4c, 0xd5fdfa2c), 1},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x42, 0x18, 0xf2, 0x0a, 0xe6, 0xc6, 0x46, 0xb3, 0x63, 0xdb, 0x68, 0x60, 0x58, 0x22, 0xfb, 0x14, 0x26, 0x4c, 0xa8, 0xd2, 0x58, 0x7f, 0xdd, 0x6f, 0xbc, 0x75, 0x0d, 0x58, 0x7e, 0x76, 0xa7, 0xee}, SECP256K1_FE_CONST(0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaa9, 0xfffffd6b), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x82, 0x27, 0x7c, 0x4a, 0x71, 0xf9, 0xd2, 0x2e, 0x66, 0xec, 0xe5, 0x23, 0xf8, 0xfa, 0x08, 0x74, 0x1a, 0x7c, 0x09, 0x12, 0xc6, 0x6a, 0x69, 0xce, 0x68, 0x51, 0x4b, 0xfd, 0x35, 0x15, 0xb4, 0x9f}, SECP256K1_FE_CONST(0xf482f2e2, 0x41753ad0, 0xfb89150d, 0x8491dc1e, 0x34ff0b8a, 0xcfbb442c, 0xfe999e2e, 0x5e6fd1d2), 1},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x84, 0x21, 0xcc, 0x93, 0x0e, 0x77, 0xc9, 0xf5, 0x14, 0xb6, 0x91, 0x5c, 0x3d, 0xbe, 0x2a, 0x94, 0xc6, 0xd8, 0xf6, 0x90, 0xb5, 0xb7, 0x39, 0x86, 0x4b, 0xa6, 0x78, 0x9f, 0xb8, 0xa5, 0x5d, 0xd0}, SECP256K1_FE_CONST(0x9f59c402, 0x75f5085a, 0x006f05da, 0xe77eb98c, 0x6fd0db1a, 0xb4a72ac4, 0x7eae90a4, 0xfc9e57e0), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xd1, 0x9c, 0x18, 0x2d, 0x27, 0x59, 0xcd, 0x99, 0x82, 0x42, 0x28, 0xd9, 0x47, 0x99, 0xf8, 0xc6, 0x55, 0x7c, 0x38, 0xa1, 0xc0, 0xd6, 0x77, 0x9b, 0x9d, 0x4b, 0x72, 0x9c, 0x6f, 0x1c, 0xcc, 0x42}, SECP256K1_FE_CONST(0x70720db7, 0xe238d041, 0x21f5b1af, 0xd8cc5ad9, 0xd18944c6, 0xbdc94881, 0xf502b7a3, 0xaf3aecff), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x26, 0x64, 0xbb, 0xd5}, SECP256K1_FE_CONST(0x50873db3, 0x1badcc71, 0x890e4f67, 0x753a6575, 0x7f97aaa7, 0xdd5f1e82, 0xb753ace3, 0x2219064b), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x70, 0x28, 0xde, 0x7d}, SECP256K1_FE_CONST(0x1eea9cc5, 0x9cfcf2fa, 0x151ac6c2, 0x74eea411, 0x0feb4f7b, 0x68c59657, 0x32e9992e, 0x976ef68e), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcb, 0xcf, 0xb7, 0xe7}, SECP256K1_FE_CONST(0x12303941, 0xaedc2088, 0x80735b1f, 0x1795c8e5, 0x5be520ea, 0x93e10335, 0x7b5d2adb, 0x7ed59b8e), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0x11, 0x3a, 0xd9}, SECP256K1_FE_CONST(0x7eed6b70, 0xe7b0767c, 0x7d7feac0, 0x4e57aa2a, 0x12fef5e0, 0xf48f878f, 0xcbb88b3b, 0x6b5e0783), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x13, 0xce, 0xa4, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x64998443, 0x5b62b4a2, 0x5d40c613, 0x3e8d9ab8, 0xc53d4b05, 0x9ee8a154, 0xa3be0fcf, 0x4e892edb), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x13, 0xce, 0xa4, 0xa7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x64998443, 0x5b62b4a2, 0x5d40c613, 0x3e8d9ab8, 0xc53d4b05, 0x9ee8a154, 0xa3be0fcf, 0x4e892edb), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x15, 0x02, 0x8c, 0x59, 0x00, 0x63, 0xf6, 0x4d, 0x5a, 0x7f, 0x1c, 0x14, 0x91, 0x5c, 0xd6, 0x1e, 0xac, 0x88, 0x6a, 0xb2, 0x95, 0xbe, 0xbd, 0x91, 0x99, 0x25, 0x04, 0xcf, 0x77, 0xed, 0xb0, 0x28, 0xbd, 0xd6, 0x26, 0x7f}, SECP256K1_FE_CONST(0x3fde5713, 0xf8282eea, 0xd7d39d42, 0x01f44a7c, 0x85a5ac8a, 0x0681f35e, 0x54085c6b, 0x69543374), 1},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x27, 0x15, 0xde, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x3524f77f, 0xa3a6eb43, 0x89c3cb5d, 0x27f1f914, 0x62086429, 0xcd6c0cb0, 0xdf43ea8f, 0x1e7b3fb4), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x27, 0x15, 0xde, 0x86, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x3524f77f, 0xa3a6eb43, 0x89c3cb5d, 0x27f1f914, 0x62086429, 0xcd6c0cb0, 0xdf43ea8f, 0x1e7b3fb4), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x2c, 0x2c, 0x57, 0x09, 0xe7, 0x15, 0x6c, 0x41, 0x77, 0x17, 0xf2, 0xfe, 0xab, 0x14, 0x71, 0x41, 0xec, 0x3d, 0xa1, 0x9f, 0xb7, 0x59, 0x57, 0x5c, 0xc6, 0xe3, 0x7b, 0x2e, 0xa5, 0xac, 0x93, 0x09, 0xf2, 0x6f, 0x0f, 0x66}, SECP256K1_FE_CONST(0xd2469ab3, 0xe04acbb2, 0x1c65a180, 0x9f39caaf, 0xe7a77c13, 0xd10f9dd3, 0x8f391c01, 0xdc499c52), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3a, 0x08, 0xcc, 0x1e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0x60, 0xe9, 0xf0}, SECP256K1_FE_CONST(0x38e2a5ce, 0x6a93e795, 0xe16d2c39, 0x8bc99f03, 0x69202ce2, 0x1e8f09d5, 0x6777b40f, 0xc512bccc), 1},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0x91, 0x25, 0x7d, 0x93, 0x20, 0x16, 0xcb, 0xf6, 0x9c, 0x44, 0x71, 0xbd, 0x1f, 0x65, 0x6c, 0x6a, 0x10, 0x7f, 0x19, 0x73, 0xde, 0x4a, 0xf7, 0x08, 0x6d, 0xb8, 0x97, 0x27, 0x70, 0x60, 0xe2, 0x56, 0x77, 0xf1, 0x9a}, SECP256K1_FE_CONST(0x864b3dc9, 0x02c37670, 0x9c10a93a, 0xd4bbe29f, 0xce0012f3, 0xdc8672c6, 0x286bba28, 0xd7d6d6fc), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x79, 0x5d, 0x6c, 0x1c, 0x32, 0x2c, 0xad, 0xf5, 0x99, 0xdb, 0xb8, 0x64, 0x81, 0x52, 0x2b, 0x3c, 0xc5, 0x5f, 0x15, 0xa6, 0x79, 0x32, 0xdb, 0x2a, 0xfa, 0x01, 0x11, 0xd9, 0xed, 0x69, 0x81, 0xbc, 0xd1, 0x24, 0xbf, 0x44}, SECP256K1_FE_CONST(0x766dfe4a, 0x700d9bee, 0x288b903a, 0xd58870e3, 0xd4fe2f0e, 0xf780bcac, 0x5c823f32, 0x0d9a9bef), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8e, 0x42, 0x6f, 0x03, 0x92, 0x38, 0x90, 0x78, 0xc1, 0x2b, 0x1a, 0x89, 0xe9, 0x54, 0x2f, 0x05, 0x93, 0xbc, 0x96, 0xb6, 0xbf, 0xde, 0x82, 0x24, 0xf8, 0x65, 0x4e, 0xf5, 0xd5, 0xcd, 0xa9, 0x35, 0xa3, 0x58, 0x21, 0x94}, SECP256K1_FE_CONST(0xfaec7bc1, 0x987b6323, 0x3fbc5f95, 0x6edbf37d, 0x54404e74, 0x61c58ab8, 0x631bc68e, 0x451a0478), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x91, 0x19, 0x21, 0x39, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x45, 0xf0, 0xf1, 0xeb}, SECP256K1_FE_CONST(0xec29a50b, 0xae138dbf, 0x7d8e2482, 0x5006bb5f, 0xc1a2cc12, 0x43ba335b, 0xc6116fb9, 0xe498ec1f), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x98, 0xeb, 0x9a, 0xb7, 0x6e, 0x84, 0x49, 0x9c, 0x48, 0x3b, 0x3b, 0xf0, 0x62, 0x14, 0xab, 0xfe, 0x06, 0x5d, 0xdd, 0xf4, 0x3b, 0x86, 0x01, 0xde, 0x59, 0x6d, 0x63, 0xb9, 0xe4, 0x5a, 0x16, 0x6a, 0x58, 0x05, 0x41, 0xfe}, SECP256K1_FE_CONST(0x1e0ff2de, 0xe9b09b13, 0x6292a9e9, 0x10f0d6ac, 0x3e552a64, 0x4bba39e6, 0x4e9dd3e3, 0xbbd3d4d4), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9b, 0x77, 0xb7, 0xf2, 0xc7, 0x4d, 0x99, 0xef, 0xce, 0xaa, 0x55, 0x0f, 0x1a, 0xd1, 0xc0, 0xf4, 0x3f, 0x46, 0xe7, 0xff, 0x1e, 0xe3, 0xbd, 0x01, 0x62, 0xb7, 0xbf, 0x55, 0xf2, 0x96, 0x5d, 0xa9, 0xc3, 0x45, 0x06, 0x46}, SECP256K1_FE_CONST(0x8b7dd5c3, 0xedba9ee9, 0x7b70eff4, 0x38f22dca, 0x9849c825, 0x4a2f3345, 0xa0a572ff, 0xeaae0928), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9b, 0x77, 0xb7, 0xf2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x15, 0x6c, 0xa8, 0x96}, SECP256K1_FE_CONST(0x0881950c, 0x8f51d6b9, 0xa6387465, 0xd5f12609, 0xef1bb254, 0x12a08a74, 0xcb2dfb20, 0x0c74bfbf), 1},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa2, 0xf5, 0xcd, 0x83, 0x88, 0x16, 0xc1, 0x6c, 0x4f, 0xe8, 0xa1, 0x66, 0x1d, 0x60, 0x6f, 0xdb, 0x13, 0xcf, 0x9a, 0xf0, 0x4b, 0x97, 0x9a, 0x2e, 0x15, 0x9a, 0x09, 0x40, 0x9e, 0xbc, 0x86, 0x45, 0xd5, 0x8f, 0xde, 0x02}, SECP256K1_FE_CONST(0x2f083207, 0xb9fd9b55, 0x0063c31c, 0xd62b8746, 0xbd543bdc, 0x5bbf10e3, 0xa35563e9, 0x27f440c8), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb1, 0x3f, 0x75, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x4f51e0be, 0x078e0cdd, 0xab274215, 0x6adba7e7, 0xa148e731, 0x57072fd6, 0x18cd6094, 0x2b146bd0), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb1, 0x3f, 0x75, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x4f51e0be, 0x078e0cdd, 0xab274215, 0x6adba7e7, 0xa148e731, 0x57072fd6, 0x18cd6094, 0x2b146bd0), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xbc, 0x1f, 0x8d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x16c2ccb5, 0x4352ff4b, 0xd794f6ef, 0xd613c721, 0x97ab7082, 0xda5b563b, 0xdf9cb3ed, 0xaafe74c2), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xbc, 0x1f, 0x8d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x16c2ccb5, 0x4352ff4b, 0xd794f6ef, 0xd613c721, 0x97ab7082, 0xda5b563b, 0xdf9cb3ed, 0xaafe74c2), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0x64, 0xd1, 0x62, 0x75, 0x05, 0x46, 0xce, 0x42, 0xb0, 0x43, 0x13, 0x61, 0xe5, 0x2d, 0x4f, 0x52, 0x42, 0xd8, 0xf2, 0x4f, 0x33, 0xe6, 0xb1, 0xf9, 0x9b, 0x59, 0x16, 0x47, 0xcb, 0xc8, 0x08, 0xf4, 0x62, 0xaf, 0x51}, SECP256K1_FE_CONST(0xd41244d1, 0x1ca4f652, 0x40687759, 0xf95ca9ef, 0xbab767ed, 0xedb38fd1, 0x8c36e18c, 0xd3b6f6a9), 1},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xe5, 0xbe, 0x52, 0x37, 0x2d, 0xd6, 0xe8, 0x94, 0xb2, 0xa3, 0x26, 0xfc, 0x36, 0x05, 0xa6, 0xe8, 0xf3, 0xc6, 0x9c, 0x71, 0x0b, 0xf2, 0x7d, 0x63, 0x0d, 0xfe, 0x20, 0x04, 0x98, 0x8b, 0x78, 0xeb, 0x6e, 0xab, 0x36}, SECP256K1_FE_CONST(0x64bf84dd, 0x5e03670f, 0xdb24c0f5, 0xd3c2c365, 0x736f51db, 0x6c92d950, 0x10716ad2, 0xd36134c8), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfb, 0xb9, 0x82, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf6, 0xd6, 0xdb, 0x1f}, SECP256K1_FE_CONST(0x1c92ccdf, 0xcf4ac550, 0xc28db57c, 0xff0c8515, 0xcb26936c, 0x786584a7, 0x0114008d, 0x6c33a34b), 0},
|
||||
};
|
||||
|
||||
/* Set of expected ellswift_xdh BIP324 shared secrets, given private key, encodings, initiating,
|
||||
* taken from the BIP324 test vectors. Created using an independent implementation, and tested
|
||||
* against the paper authors' decoding code. */
|
||||
static const struct ellswift_xdh_test ellswift_xdh_tests_bip324[] = {
|
||||
{{0x61, 0x06, 0x2e, 0xa5, 0x07, 0x1d, 0x80, 0x0b, 0xbf, 0xd5, 0x9e, 0x2e, 0x8b, 0x53, 0xd4, 0x7d, 0x19, 0x4b, 0x09, 0x5a, 0xe5, 0xa4, 0xdf, 0x04, 0x93, 0x6b, 0x49, 0x77, 0x2e, 0xf0, 0xd4, 0xd7}, {0xec, 0x0a, 0xdf, 0xf2, 0x57, 0xbb, 0xfe, 0x50, 0x0c, 0x18, 0x8c, 0x80, 0xb4, 0xfd, 0xd6, 0x40, 0xf6, 0xb4, 0x5a, 0x48, 0x2b, 0xbc, 0x15, 0xfc, 0x7c, 0xef, 0x59, 0x31, 0xde, 0xff, 0x0a, 0xa1, 0x86, 0xf6, 0xeb, 0x9b, 0xba, 0x7b, 0x85, 0xdc, 0x4d, 0xcc, 0x28, 0xb2, 0x87, 0x22, 0xde, 0x1e, 0x3d, 0x91, 0x08, 0xb9, 0x85, 0xe2, 0x96, 0x70, 0x45, 0x66, 0x8f, 0x66, 0x09, 0x8e, 0x47, 0x5b}, {0xa4, 0xa9, 0x4d, 0xfc, 0xe6, 0x9b, 0x4a, 0x2a, 0x0a, 0x09, 0x93, 0x13, 0xd1, 0x0f, 0x9f, 0x7e, 0x7d, 0x64, 0x9d, 0x60, 0x50, 0x1c, 0x9e, 0x1d, 0x27, 0x4c, 0x30, 0x0e, 0x0d, 0x89, 0xaa, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, 0xaf, 0x88, 0xd5}, 1, {0xc6, 0x99, 0x2a, 0x11, 0x7f, 0x5e, 0xdb, 0xea, 0x70, 0xc3, 0xf5, 0x11, 0xd3, 0x2d, 0x26, 0xb9, 0x79, 0x8b, 0xe4, 0xb8, 0x1a, 0x62, 0xea, 0xee, 0x1a, 0x5a, 0xca, 0xa8, 0x45, 0x9a, 0x35, 0x92}},
|
||||
{{0x1f, 0x9c, 0x58, 0x1b, 0x35, 0x23, 0x18, 0x38, 0xf0, 0xf1, 0x7c, 0xf0, 0xc9, 0x79, 0x83, 0x5b, 0xac, 0xcb, 0x7f, 0x3a, 0xbb, 0xbb, 0x96, 0xff, 0xcc, 0x31, 0x8a, 0xb7, 0x1e, 0x6e, 0x12, 0x6f}, {0xa1, 0x85, 0x5e, 0x10, 0xe9, 0x4e, 0x00, 0xba, 0xa2, 0x30, 0x41, 0xd9, 0x16, 0xe2, 0x59, 0xf7, 0x04, 0x4e, 0x49, 0x1d, 0xa6, 0x17, 0x12, 0x69, 0x69, 0x47, 0x63, 0xf0, 0x18, 0xc7, 0xe6, 0x36, 0x93, 0xd2, 0x95, 0x75, 0xdc, 0xb4, 0x64, 0xac, 0x81, 0x6b, 0xaa, 0x1b, 0xe3, 0x53, 0xba, 0x12, 0xe3, 0x87, 0x6c, 0xba, 0x76, 0x28, 0xbd, 0x0b, 0xd8, 0xe7, 0x55, 0xe7, 0x21, 0xeb, 0x01, 0x40}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0, {0xa0, 0x13, 0x8f, 0x56, 0x4f, 0x74, 0xd0, 0xad, 0x70, 0xbc, 0x33, 0x7d, 0xac, 0xc9, 0xd0, 0xbf, 0x1d, 0x23, 0x49, 0x36, 0x4c, 0xaf, 0x11, 0x88, 0xa1, 0xe6, 0xe8, 0xdd, 0xb3, 0xb7, 0xb1, 0x84}},
|
||||
{{0x02, 0x86, 0xc4, 0x1c, 0xd3, 0x09, 0x13, 0xdb, 0x0f, 0xdf, 0xf7, 0xa6, 0x4e, 0xbd, 0xa5, 0xc8, 0xe3, 0xe7, 0xce, 0xf1, 0x0f, 0x2a, 0xeb, 0xc0, 0x0a, 0x76, 0x50, 0x44, 0x3c, 0xf4, 0xc6, 0x0d}, {0xd1, 0xee, 0x8a, 0x93, 0xa0, 0x11, 0x30, 0xcb, 0xf2, 0x99, 0x24, 0x9a, 0x25, 0x8f, 0x94, 0xfe, 0xb5, 0xf4, 0x69, 0xe7, 0xd0, 0xf2, 0xf2, 0x8f, 0x69, 0xee, 0x5e, 0x9a, 0xa8, 0xf9, 0xb5, 0x4a, 0x60, 0xf2, 0xc3, 0xff, 0x2d, 0x02, 0x36, 0x34, 0xec, 0x7f, 0x41, 0x27, 0xa9, 0x6c, 0xc1, 0x16, 0x62, 0xe4, 0x02, 0x89, 0x4c, 0xf1, 0xf6, 0x94, 0xfb, 0x9a, 0x7e, 0xaa, 0x5f, 0x1d, 0x92, 0x44}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x22, 0xd5, 0xe4, 0x41, 0x52, 0x4d, 0x57, 0x1a, 0x52, 0xb3, 0xde, 0xf1, 0x26, 0x18, 0x9d, 0x3f, 0x41, 0x68, 0x90, 0xa9, 0x9d, 0x4d, 0xa6, 0xed, 0xe2, 0xb0, 0xcd, 0xe1, 0x76, 0x0c, 0xe2, 0xc3, 0xf9, 0x84, 0x57, 0xae}, 1, {0x25, 0x0b, 0x93, 0x57, 0x0d, 0x41, 0x11, 0x49, 0x10, 0x5a, 0xb8, 0xcb, 0x0b, 0xc5, 0x07, 0x99, 0x14, 0x90, 0x63, 0x06, 0x36, 0x8c, 0x23, 0xe9, 0xd7, 0x7c, 0x2a, 0x33, 0x26, 0x5b, 0x99, 0x4c}},
|
||||
{{0x6c, 0x77, 0x43, 0x2d, 0x1f, 0xda, 0x31, 0xe9, 0xf9, 0x42, 0xf8, 0xaf, 0x44, 0x60, 0x7e, 0x10, 0xf3, 0xad, 0x38, 0xa6, 0x5f, 0x8a, 0x4b, 0xdd, 0xae, 0x82, 0x3e, 0x5e, 0xff, 0x90, 0xdc, 0x38}, {0xd2, 0x68, 0x50, 0x70, 0xc1, 0xe6, 0x37, 0x6e, 0x63, 0x3e, 0x82, 0x52, 0x96, 0x63, 0x4f, 0xd4, 0x61, 0xfa, 0x9e, 0x5b, 0xdf, 0x21, 0x09, 0xbc, 0xeb, 0xd7, 0x35, 0xe5, 0xa9, 0x1f, 0x3e, 0x58, 0x7c, 0x5c, 0xb7, 0x82, 0xab, 0xb7, 0x97, 0xfb, 0xf6, 0xbb, 0x50, 0x74, 0xfd, 0x15, 0x42, 0xa4, 0x74, 0xf2, 0xa4, 0x5b, 0x67, 0x37, 0x63, 0xec, 0x2d, 0xb7, 0xfb, 0x99, 0xb7, 0x37, 0xbb, 0xb9}, {0x56, 0xbd, 0x0c, 0x06, 0xf1, 0x03, 0x52, 0xc3, 0xa1, 0xa9, 0xf4, 0xb4, 0xc9, 0x2f, 0x6f, 0xa2, 0xb2, 0x6d, 0xf1, 0x24, 0xb5, 0x78, 0x78, 0x35, 0x3c, 0x1f, 0xc6, 0x91, 0xc5, 0x1a, 0xbe, 0xa7, 0x7c, 0x88, 0x17, 0xda, 0xee, 0xb9, 0xfa, 0x54, 0x6b, 0x77, 0xc8, 0xda, 0xf7, 0x9d, 0x89, 0xb2, 0x2b, 0x0e, 0x1b, 0x87, 0x57, 0x4e, 0xce, 0x42, 0x37, 0x1f, 0x00, 0x23, 0x7a, 0xa9, 0xd8, 0x3a}, 0, {0x19, 0x18, 0xb7, 0x41, 0xef, 0x5f, 0x9d, 0x1d, 0x76, 0x70, 0xb0, 0x50, 0xc1, 0x52, 0xb4, 0xa4, 0xea, 0xd2, 0xc3, 0x1b, 0xe9, 0xae, 0xcb, 0x06, 0x81, 0xc0, 0xcd, 0x43, 0x24, 0x15, 0x08, 0x53}},
|
||||
{{0xa6, 0xec, 0x25, 0x12, 0x7c, 0xa1, 0xaa, 0x4c, 0xf1, 0x6b, 0x20, 0x08, 0x4b, 0xa1, 0xe6, 0x51, 0x6b, 0xaa, 0xe4, 0xd3, 0x24, 0x22, 0x28, 0x8e, 0x9b, 0x36, 0xd8, 0xbd, 0xdd, 0x2d, 0xe3, 0x5a}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x05, 0x3d, 0x7e, 0xcc, 0xa5, 0x3e, 0x33, 0xe1, 0x85, 0xa8, 0xb9, 0xbe, 0x4e, 0x76, 0x99, 0xa9, 0x7c, 0x6f, 0xf4, 0xc7, 0x95, 0x52, 0x2e, 0x59, 0x18, 0xab, 0x7c, 0xd6, 0xb6, 0x88, 0x4f, 0x67, 0xe6, 0x83, 0xf3, 0xdc}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa7, 0x73, 0x0b, 0xe3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 1, {0xdd, 0x21, 0x0a, 0xa6, 0x62, 0x9f, 0x20, 0xbb, 0x32, 0x8e, 0x5d, 0x89, 0xda, 0xa6, 0xeb, 0x2a, 0xc3, 0xd1, 0xc6, 0x58, 0xa7, 0x25, 0x53, 0x6f, 0xf1, 0x54, 0xf3, 0x1b, 0x53, 0x6c, 0x23, 0xb2}},
|
||||
{{0x0a, 0xf9, 0x52, 0x65, 0x9e, 0xd7, 0x6f, 0x80, 0xf5, 0x85, 0x96, 0x6b, 0x95, 0xab, 0x6e, 0x6f, 0xd6, 0x86, 0x54, 0x67, 0x28, 0x27, 0x87, 0x86, 0x84, 0xc8, 0xb5, 0x47, 0xb1, 0xb9, 0x4f, 0x5a}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc8, 0x10, 0x17, 0xfd, 0x92, 0xfd, 0x31, 0x63, 0x7c, 0x26, 0xc9, 0x06, 0xb4, 0x20, 0x92, 0xe1, 0x1c, 0xc0, 0xd3, 0xaf, 0xae, 0x8d, 0x90, 0x19, 0xd2, 0x57, 0x8a, 0xf2, 0x27, 0x35, 0xce, 0x7b, 0xc4, 0x69, 0xc7, 0x2d}, {0x96, 0x52, 0xd7, 0x8b, 0xae, 0xfc, 0x02, 0x8c, 0xd3, 0x7a, 0x6a, 0x92, 0x62, 0x5b, 0x8b, 0x8f, 0x85, 0xfd, 0xe1, 0xe4, 0xc9, 0x44, 0xad, 0x3f, 0x20, 0xe1, 0x98, 0xbe, 0xf8, 0xc0, 0x2f, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf2, 0xe9, 0x18, 0x70}, 0, {0x35, 0x68, 0xf2, 0xae, 0xa2, 0xe1, 0x4e, 0xf4, 0xee, 0x4a, 0x3c, 0x2a, 0x8b, 0x8d, 0x31, 0xbc, 0x5e, 0x31, 0x87, 0xba, 0x86, 0xdb, 0x10, 0x73, 0x9b, 0x4f, 0xf8, 0xec, 0x92, 0xff, 0x66, 0x55}},
|
||||
{{0xf9, 0x0e, 0x08, 0x0c, 0x64, 0xb0, 0x58, 0x24, 0xc5, 0xa2, 0x4b, 0x25, 0x01, 0xd5, 0xae, 0xaf, 0x08, 0xaf, 0x38, 0x72, 0xee, 0x86, 0x0a, 0xa8, 0x0b, 0xdc, 0xd4, 0x30, 0xf7, 0xb6, 0x34, 0x94}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x11, 0x51, 0x73, 0x76, 0x5d, 0xc2, 0x02, 0xcf, 0x02, 0x9a, 0xd3, 0xf1, 0x54, 0x79, 0x73, 0x5d, 0x57, 0x69, 0x7a, 0xf1, 0x2b, 0x01, 0x31, 0xdd, 0x21, 0x43, 0x0d, 0x57, 0x72, 0xe4, 0xef, 0x11, 0x47, 0x4d, 0x58, 0xb9}, {0x12, 0xa5, 0x0f, 0x3f, 0xaf, 0xea, 0x7c, 0x1e, 0xea, 0xda, 0x4c, 0xf8, 0xd3, 0x37, 0x77, 0x70, 0x4b, 0x77, 0x36, 0x14, 0x53, 0xaf, 0xc8, 0x3b, 0xda, 0x91, 0xee, 0xf3, 0x49, 0xae, 0x04, 0x4d, 0x20, 0x12, 0x6c, 0x62, 0x00, 0x54, 0x7e, 0xa5, 0xa6, 0x91, 0x17, 0x76, 0xc0, 0x5d, 0xee, 0x2a, 0x7f, 0x1a, 0x9b, 0xa7, 0xdf, 0xba, 0xbb, 0xbd, 0x27, 0x3c, 0x3e, 0xf2, 0x9e, 0xf4, 0x6e, 0x46}, 1, {0xe2, 0x54, 0x61, 0xfb, 0x0e, 0x4c, 0x16, 0x2e, 0x18, 0x12, 0x3e, 0xcd, 0xe8, 0x83, 0x42, 0xd5, 0x4d, 0x44, 0x96, 0x31, 0xe9, 0xb7, 0x5a, 0x26, 0x6f, 0xd9, 0x26, 0x0c, 0x2b, 0xb2, 0xf4, 0x1d}},
|
||||
};
|
||||
|
||||
/** This is a hasher for ellswift_xdh which just returns the shared X coordinate.
|
||||
*
|
||||
* This is generally a bad idea as it means changes to the encoding of the
|
||||
* exchanged public keys do not affect the shared secret. However, it's used here
|
||||
* in tests to be able to verify the X coordinate through other means.
|
||||
*/
|
||||
static int ellswift_xdh_hash_x32(unsigned char *output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) {
|
||||
(void)ell_a64;
|
||||
(void)ell_b64;
|
||||
(void)data;
|
||||
memcpy(output, x32, 32);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Run the test vectors for ellswift encoding */
|
||||
void ellswift_encoding_test_vectors_tests(void) {
|
||||
int i;
|
||||
for (i = 0; (unsigned)i < ARRAY_SIZE(ellswift_xswiftec_inv_tests); ++i) {
|
||||
const struct ellswift_xswiftec_inv_test *testcase = &ellswift_xswiftec_inv_tests[i];
|
||||
int c;
|
||||
for (c = 0; c < 8; ++c) {
|
||||
secp256k1_fe t;
|
||||
int ret = secp256k1_ellswift_xswiftec_inv_var(&t, &testcase->x, &testcase->u, c);
|
||||
CHECK(ret == ((testcase->enc_bitmap >> c) & 1));
|
||||
if (ret) {
|
||||
secp256k1_fe x2;
|
||||
CHECK(fe_equal(&t, &testcase->encs[c]));
|
||||
secp256k1_ellswift_xswiftec_var(&x2, &testcase->u, &testcase->encs[c]);
|
||||
CHECK(fe_equal(&testcase->x, &x2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Run the test vectors for ellswift decoding */
|
||||
void ellswift_decoding_test_vectors_tests(void) {
|
||||
int i;
|
||||
for (i = 0; (unsigned)i < ARRAY_SIZE(ellswift_decode_tests); ++i) {
|
||||
const struct ellswift_decode_test *testcase = &ellswift_decode_tests[i];
|
||||
secp256k1_pubkey pubkey;
|
||||
secp256k1_ge ge;
|
||||
int ret;
|
||||
ret = secp256k1_ellswift_decode(CTX, &pubkey, testcase->enc);
|
||||
CHECK(ret);
|
||||
ret = secp256k1_pubkey_load(CTX, &ge, &pubkey);
|
||||
CHECK(ret);
|
||||
CHECK(fe_equal(&testcase->x, &ge.x));
|
||||
CHECK(secp256k1_fe_is_odd(&ge.y) == testcase->odd_y);
|
||||
}
|
||||
}
|
||||
|
||||
/* Run the test vectors for ellswift expected xdh BIP324 shared secrets */
|
||||
void ellswift_xdh_test_vectors_tests(void) {
|
||||
int i;
|
||||
for (i = 0; (unsigned)i < ARRAY_SIZE(ellswift_xdh_tests_bip324); ++i) {
|
||||
const struct ellswift_xdh_test *test = &ellswift_xdh_tests_bip324[i];
|
||||
unsigned char shared_secret[32];
|
||||
int ret;
|
||||
int party = !test->initiating;
|
||||
const unsigned char* ell_a64 = party ? test->ellswift_theirs : test->ellswift_ours;
|
||||
const unsigned char* ell_b64 = party ? test->ellswift_ours : test->ellswift_theirs;
|
||||
ret = secp256k1_ellswift_xdh(CTX, shared_secret,
|
||||
ell_a64, ell_b64,
|
||||
test->priv_ours,
|
||||
party,
|
||||
secp256k1_ellswift_xdh_hash_function_bip324,
|
||||
NULL);
|
||||
CHECK(ret);
|
||||
CHECK(secp256k1_memcmp_var(shared_secret, test->shared_secret, 32) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Verify that secp256k1_ellswift_encode + decode roundtrips */
|
||||
void ellswift_encode_decode_roundtrip_tests(void) {
|
||||
int i;
|
||||
for (i = 0; i < 1000 * COUNT; i++) {
|
||||
unsigned char rnd32[32];
|
||||
unsigned char ell64[64];
|
||||
secp256k1_ge g, g2;
|
||||
secp256k1_pubkey pubkey, pubkey2;
|
||||
/* Generate random public key and random randomizer. */
|
||||
testutil_random_ge_test(&g);
|
||||
secp256k1_pubkey_save(&pubkey, &g);
|
||||
testrand256(rnd32);
|
||||
/* Convert the public key to ElligatorSwift and back. */
|
||||
secp256k1_ellswift_encode(CTX, ell64, &pubkey, rnd32);
|
||||
secp256k1_ellswift_decode(CTX, &pubkey2, ell64);
|
||||
secp256k1_pubkey_load(CTX, &g2, &pubkey2);
|
||||
/* Compare with original. */
|
||||
CHECK(secp256k1_ge_eq_var(&g, &g2));
|
||||
}
|
||||
}
|
||||
|
||||
/* Verify the behavior of secp256k1_ellswift_create */
|
||||
void ellswift_create_tests(void) {
|
||||
int i;
|
||||
for (i = 0; i < 400 * COUNT; i++) {
|
||||
unsigned char auxrnd32[32], sec32[32];
|
||||
secp256k1_scalar sec;
|
||||
secp256k1_gej res;
|
||||
secp256k1_ge dec;
|
||||
secp256k1_pubkey pub;
|
||||
unsigned char ell64[64];
|
||||
int ret;
|
||||
/* Generate random secret key and random randomizer. */
|
||||
if (i & 1) testrand256_test(auxrnd32);
|
||||
testutil_random_scalar_order_test(&sec);
|
||||
secp256k1_scalar_get_b32(sec32, &sec);
|
||||
/* Construct ElligatorSwift-encoded public keys for that key. */
|
||||
ret = secp256k1_ellswift_create(CTX, ell64, sec32, (i & 1) ? auxrnd32 : NULL);
|
||||
CHECK(ret);
|
||||
/* Decode it, and compare with traditionally-computed public key. */
|
||||
secp256k1_ellswift_decode(CTX, &pub, ell64);
|
||||
secp256k1_pubkey_load(CTX, &dec, &pub);
|
||||
secp256k1_ecmult(&res, NULL, &secp256k1_scalar_zero, &sec);
|
||||
CHECK(secp256k1_gej_eq_ge_var(&res, &dec));
|
||||
}
|
||||
}
|
||||
|
||||
/* Verify that secp256k1_ellswift_xdh computes the right shared X coordinate */
|
||||
void ellswift_compute_shared_secret_tests(void) {
|
||||
int i;
|
||||
for (i = 0; i < 800 * COUNT; i++) {
|
||||
unsigned char ell64[64], sec32[32], share32[32];
|
||||
secp256k1_scalar sec;
|
||||
secp256k1_ge dec, res;
|
||||
secp256k1_fe share_x;
|
||||
secp256k1_gej decj, resj;
|
||||
secp256k1_pubkey pub;
|
||||
int ret;
|
||||
/* Generate random secret key. */
|
||||
testutil_random_scalar_order_test(&sec);
|
||||
secp256k1_scalar_get_b32(sec32, &sec);
|
||||
/* Generate random ElligatorSwift encoding for the remote key and decode it. */
|
||||
testrand256_test(ell64);
|
||||
testrand256_test(ell64 + 32);
|
||||
secp256k1_ellswift_decode(CTX, &pub, ell64);
|
||||
secp256k1_pubkey_load(CTX, &dec, &pub);
|
||||
secp256k1_gej_set_ge(&decj, &dec);
|
||||
/* Compute the X coordinate of seckey*pubkey using ellswift_xdh. Note that we
|
||||
* pass ell64 as claimed (but incorrect) encoding for sec32 here; this works
|
||||
* because the "hasher" function we use here ignores the ell64 arguments. */
|
||||
ret = secp256k1_ellswift_xdh(CTX, share32, ell64, ell64, sec32, i & 1, &ellswift_xdh_hash_x32, NULL);
|
||||
CHECK(ret);
|
||||
(void)secp256k1_fe_set_b32_limit(&share_x, share32); /* no overflow is possible */
|
||||
SECP256K1_FE_VERIFY(&share_x);
|
||||
/* Compute seckey*pubkey directly. */
|
||||
secp256k1_ecmult(&resj, &decj, &sec, NULL);
|
||||
secp256k1_ge_set_gej(&res, &resj);
|
||||
/* Compare. */
|
||||
CHECK(fe_equal(&res.x, &share_x));
|
||||
}
|
||||
}
|
||||
|
||||
void ellswift_xdh_correctness_tests(void) {
|
||||
int i;
|
||||
/* Verify the joint behavior of secp256k1_ellswift_xdh */
|
||||
for (i = 0; i < 200 * COUNT; i++) {
|
||||
unsigned char auxrnd32a[32], auxrnd32b[32], auxrnd32a_bad[32], auxrnd32b_bad[32];
|
||||
unsigned char sec32a[32], sec32b[32], sec32a_bad[32], sec32b_bad[32];
|
||||
secp256k1_scalar seca, secb;
|
||||
unsigned char ell64a[64], ell64b[64], ell64a_bad[64], ell64b_bad[64];
|
||||
unsigned char share32a[32], share32b[32], share32_bad[32];
|
||||
unsigned char prefix64[64];
|
||||
secp256k1_ellswift_xdh_hash_function hash_function;
|
||||
void* data;
|
||||
int ret;
|
||||
|
||||
/* Pick hasher to use. */
|
||||
if ((i % 3) == 0) {
|
||||
hash_function = ellswift_xdh_hash_x32;
|
||||
data = NULL;
|
||||
} else if ((i % 3) == 1) {
|
||||
hash_function = secp256k1_ellswift_xdh_hash_function_bip324;
|
||||
data = NULL;
|
||||
} else {
|
||||
hash_function = secp256k1_ellswift_xdh_hash_function_prefix;
|
||||
testrand256_test(prefix64);
|
||||
testrand256_test(prefix64 + 32);
|
||||
data = prefix64;
|
||||
}
|
||||
|
||||
/* Generate random secret keys and random randomizers. */
|
||||
testrand256_test(auxrnd32a);
|
||||
testrand256_test(auxrnd32b);
|
||||
testutil_random_scalar_order_test(&seca);
|
||||
/* Draw secb uniformly at random to make sure that the secret keys
|
||||
* differ */
|
||||
testutil_random_scalar_order(&secb);
|
||||
secp256k1_scalar_get_b32(sec32a, &seca);
|
||||
secp256k1_scalar_get_b32(sec32b, &secb);
|
||||
|
||||
/* Construct ElligatorSwift-encoded public keys for those keys. */
|
||||
/* For A: */
|
||||
ret = secp256k1_ellswift_create(CTX, ell64a, sec32a, auxrnd32a);
|
||||
CHECK(ret);
|
||||
/* For B: */
|
||||
ret = secp256k1_ellswift_create(CTX, ell64b, sec32b, auxrnd32b);
|
||||
CHECK(ret);
|
||||
|
||||
/* Compute the shared secret both ways and compare with each other. */
|
||||
/* For A: */
|
||||
ret = secp256k1_ellswift_xdh(CTX, share32a, ell64a, ell64b, sec32a, 0, hash_function, data);
|
||||
CHECK(ret);
|
||||
/* For B: */
|
||||
ret = secp256k1_ellswift_xdh(CTX, share32b, ell64a, ell64b, sec32b, 1, hash_function, data);
|
||||
CHECK(ret);
|
||||
/* And compare: */
|
||||
CHECK(secp256k1_memcmp_var(share32a, share32b, 32) == 0);
|
||||
|
||||
/* Verify that the shared secret doesn't match if other side's public key is incorrect. */
|
||||
/* For A (using a bad public key for B): */
|
||||
memcpy(ell64b_bad, ell64b, sizeof(ell64a_bad));
|
||||
testrand_flip(ell64b_bad, sizeof(ell64b_bad));
|
||||
ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b_bad, sec32a, 0, hash_function, data);
|
||||
CHECK(ret); /* Mismatching encodings don't get detected by secp256k1_ellswift_xdh. */
|
||||
CHECK(secp256k1_memcmp_var(share32_bad, share32a, 32) != 0);
|
||||
/* For B (using a bad public key for A): */
|
||||
memcpy(ell64a_bad, ell64a, sizeof(ell64a_bad));
|
||||
testrand_flip(ell64a_bad, sizeof(ell64a_bad));
|
||||
ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a_bad, ell64b, sec32b, 1, hash_function, data);
|
||||
CHECK(ret);
|
||||
CHECK(secp256k1_memcmp_var(share32_bad, share32b, 32) != 0);
|
||||
|
||||
/* Verify that the shared secret doesn't match if the private key is incorrect. */
|
||||
/* For A: */
|
||||
memcpy(sec32a_bad, sec32a, sizeof(sec32a_bad));
|
||||
testrand_flip(sec32a_bad, sizeof(sec32a_bad));
|
||||
ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b, sec32a_bad, 0, hash_function, data);
|
||||
CHECK(!ret || secp256k1_memcmp_var(share32_bad, share32a, 32) != 0);
|
||||
/* For B: */
|
||||
memcpy(sec32b_bad, sec32b, sizeof(sec32b_bad));
|
||||
testrand_flip(sec32b_bad, sizeof(sec32b_bad));
|
||||
ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b, sec32b_bad, 1, hash_function, data);
|
||||
CHECK(!ret || secp256k1_memcmp_var(share32_bad, share32b, 32) != 0);
|
||||
|
||||
if (hash_function != ellswift_xdh_hash_x32) {
|
||||
/* Verify that the shared secret doesn't match when a different encoding of the same public key is used. */
|
||||
/* For A (changing B's public key): */
|
||||
memcpy(auxrnd32b_bad, auxrnd32b, sizeof(auxrnd32b_bad));
|
||||
testrand_flip(auxrnd32b_bad, sizeof(auxrnd32b_bad));
|
||||
ret = secp256k1_ellswift_create(CTX, ell64b_bad, sec32b, auxrnd32b_bad);
|
||||
CHECK(ret);
|
||||
ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b_bad, sec32a, 0, hash_function, data);
|
||||
CHECK(ret);
|
||||
CHECK(secp256k1_memcmp_var(share32_bad, share32a, 32) != 0);
|
||||
/* For B (changing A's public key): */
|
||||
memcpy(auxrnd32a_bad, auxrnd32a, sizeof(auxrnd32a_bad));
|
||||
testrand_flip(auxrnd32a_bad, sizeof(auxrnd32a_bad));
|
||||
ret = secp256k1_ellswift_create(CTX, ell64a_bad, sec32a, auxrnd32a_bad);
|
||||
CHECK(ret);
|
||||
ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a_bad, ell64b, sec32b, 1, hash_function, data);
|
||||
CHECK(ret);
|
||||
CHECK(secp256k1_memcmp_var(share32_bad, share32b, 32) != 0);
|
||||
|
||||
/* Verify that swapping sides changes the shared secret. */
|
||||
/* For A (claiming to be B): */
|
||||
ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b, sec32a, 1, hash_function, data);
|
||||
CHECK(ret);
|
||||
CHECK(secp256k1_memcmp_var(share32_bad, share32a, 32) != 0);
|
||||
/* For B (claiming to be A): */
|
||||
ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b, sec32b, 0, hash_function, data);
|
||||
CHECK(ret);
|
||||
CHECK(secp256k1_memcmp_var(share32_bad, share32b, 32) != 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_SHA256_TRANSFORM_PROBE(sha256_ellswift_xdh)
|
||||
void ellswift_xdh_ctx_sha256_tests(void) {
|
||||
/* Check ctx-provided SHA256 compression override takes effect */
|
||||
secp256k1_context *ctx = secp256k1_context_clone(CTX);
|
||||
unsigned char out_default[65], out_custom[65];
|
||||
const unsigned char skA[32] = {1}, skB[32] = {2};
|
||||
unsigned char keyA[64], keyB[64], data[64] = {0};
|
||||
secp256k1_ellswift_xdh_hash_function hash_fn;
|
||||
int i;
|
||||
|
||||
CHECK(secp256k1_ellswift_create(ctx, keyA, skA, NULL));
|
||||
CHECK(secp256k1_ellswift_create(ctx, keyB, skB, NULL));
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
if (i == 0) {
|
||||
hash_fn = secp256k1_ellswift_xdh_hash_function_bip324;
|
||||
} else {
|
||||
hash_fn = secp256k1_ellswift_xdh_hash_function_prefix;
|
||||
}
|
||||
/* Default behavior. No ctx-provided SHA256 compression */
|
||||
CHECK(secp256k1_ellswift_xdh(ctx, out_default, keyA, keyB, skA, 0, hash_fn, data));
|
||||
CHECK(!sha256_ellswift_xdh_called);
|
||||
|
||||
/* Override SHA256 compression directly, bypassing the ctx setter sanity checks */
|
||||
ctx->hash_ctx.fn_sha256_compression = sha256_ellswift_xdh;
|
||||
CHECK(secp256k1_ellswift_xdh(ctx, out_custom, keyA, keyB, skA, 0, hash_fn, data));
|
||||
CHECK(sha256_ellswift_xdh_called);
|
||||
/* Outputs must differ if custom compression was used */
|
||||
CHECK(secp256k1_memcmp_var(out_default, out_custom, 32) != 0);
|
||||
|
||||
/* Restore defaults */
|
||||
sha256_ellswift_xdh_called = 0;
|
||||
secp256k1_context_set_sha256_compression(ctx, NULL);
|
||||
}
|
||||
|
||||
secp256k1_context_destroy(ctx);
|
||||
}
|
||||
|
||||
/* Test hash initializers */
|
||||
void ellswift_hash_init_tests(void) {
|
||||
secp256k1_sha256 sha_optimized;
|
||||
const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(CTX);
|
||||
/* "secp256k1_ellswift_encode" */
|
||||
static const unsigned char encode_tag[] = {'s', 'e', 'c', 'p', '2', '5', '6', 'k', '1', '_', 'e', 'l', 'l', 's', 'w', 'i', 'f', 't', '_', 'e', 'n', 'c', 'o', 'd', 'e'};
|
||||
/* "secp256k1_ellswift_create" */
|
||||
static const unsigned char create_tag[] = {'s', 'e', 'c', 'p', '2', '5', '6', 'k', '1', '_', 'e', 'l', 'l', 's', 'w', 'i', 'f', 't', '_', 'c', 'r', 'e', 'a', 't', 'e'};
|
||||
/* "bip324_ellswift_xonly_ecdh" */
|
||||
static const unsigned char bip324_tag[] = {'b', 'i', 'p', '3', '2', '4', '_', 'e', 'l', 'l', 's', 'w', 'i', 'f', 't', '_', 'x', 'o', 'n', 'l', 'y', '_', 'e', 'c', 'd', 'h'};
|
||||
|
||||
/* Check that hash initialized by
|
||||
* secp256k1_ellswift_sha256_init_encode has the expected
|
||||
* state. */
|
||||
secp256k1_ellswift_sha256_init_encode(&sha_optimized);
|
||||
test_sha256_tag_midstate(hash_ctx, &sha_optimized, encode_tag, sizeof(encode_tag));
|
||||
|
||||
/* Check that hash initialized by
|
||||
* secp256k1_ellswift_sha256_init_create has the expected
|
||||
* state. */
|
||||
secp256k1_ellswift_sha256_init_create(&sha_optimized);
|
||||
test_sha256_tag_midstate(hash_ctx, &sha_optimized, create_tag, sizeof(create_tag));
|
||||
|
||||
/* Check that hash initialized by
|
||||
* secp256k1_ellswift_sha256_init_bip324 has the expected
|
||||
* state. */
|
||||
secp256k1_ellswift_sha256_init_bip324(&sha_optimized);
|
||||
test_sha256_tag_midstate(hash_ctx, &sha_optimized, bip324_tag, sizeof(bip324_tag));
|
||||
}
|
||||
|
||||
void ellswift_xdh_bad_scalar_tests(void) {
|
||||
unsigned char s_zero[32] = { 0 };
|
||||
unsigned char s_overflow_minus1[32] = { 0 };
|
||||
unsigned char s_overflow_plus1[32] = { 0 };
|
||||
unsigned char s_good[32] = { 0 };
|
||||
unsigned char ell_a64[64], ell_b64[64];
|
||||
unsigned char output[32];
|
||||
secp256k1_scalar rand_scalar;
|
||||
|
||||
testutil_random_scalar_order(&rand_scalar);
|
||||
secp256k1_scalar_get_b32(s_good, &rand_scalar);
|
||||
|
||||
CHECK(secp256k1_ellswift_create(CTX, ell_a64, s_good, NULL) == 1);
|
||||
|
||||
testrand256_test(ell_b64);
|
||||
testrand256_test(ell_b64 + 32);
|
||||
|
||||
memcpy(s_overflow_minus1, secp256k1_group_order_bytes, 32);
|
||||
s_overflow_minus1[31] -= 1;
|
||||
memcpy(s_overflow_plus1, secp256k1_group_order_bytes, 32);
|
||||
s_overflow_plus1[31] += 1;
|
||||
CHECK(secp256k1_ellswift_xdh(CTX, output, ell_a64, ell_b64, s_zero, 0, &ellswift_xdh_hash_x32, NULL) == 0);
|
||||
CHECK(secp256k1_ellswift_xdh(CTX, output, ell_a64, ell_b64, secp256k1_group_order_bytes, 0, &ellswift_xdh_hash_x32, NULL) == 0);
|
||||
CHECK(secp256k1_ellswift_xdh(CTX, output, ell_a64, ell_b64, s_overflow_plus1, 0, &ellswift_xdh_hash_x32, NULL) == 0);
|
||||
CHECK(secp256k1_ellswift_xdh(CTX, output, ell_a64, ell_b64, s_overflow_minus1, 0, &ellswift_xdh_hash_x32, NULL) == 1);
|
||||
}
|
||||
|
||||
/* --- Test registry --- */
|
||||
static const struct tf_test_entry tests_ellswift[] = {
|
||||
CASE1(ellswift_encoding_test_vectors_tests),
|
||||
CASE1(ellswift_decoding_test_vectors_tests),
|
||||
CASE1(ellswift_xdh_test_vectors_tests),
|
||||
CASE1(ellswift_encode_decode_roundtrip_tests),
|
||||
CASE1(ellswift_create_tests),
|
||||
CASE1(ellswift_compute_shared_secret_tests),
|
||||
CASE1(ellswift_xdh_correctness_tests),
|
||||
CASE1(ellswift_hash_init_tests),
|
||||
CASE1(ellswift_xdh_bad_scalar_tests),
|
||||
CASE1(ellswift_xdh_ctx_sha256_tests),
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,4 @@
|
||||
include_HEADERS += include/secp256k1_extrakeys.h
|
||||
noinst_HEADERS += src/modules/extrakeys/tests_impl.h
|
||||
noinst_HEADERS += src/modules/extrakeys/tests_exhaustive_impl.h
|
||||
noinst_HEADERS += src/modules/extrakeys/main_impl.h
|
||||
@@ -0,0 +1,285 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2020 Jonas Nick *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_EXTRAKEYS_MAIN_H
|
||||
#define SECP256K1_MODULE_EXTRAKEYS_MAIN_H
|
||||
|
||||
#include "../../../include/secp256k1.h"
|
||||
#include "../../../include/secp256k1_extrakeys.h"
|
||||
#include "../../util.h"
|
||||
|
||||
static SECP256K1_INLINE int secp256k1_xonly_pubkey_load(const secp256k1_context* ctx, secp256k1_ge *ge, const secp256k1_xonly_pubkey *pubkey) {
|
||||
return secp256k1_pubkey_load(ctx, ge, (const secp256k1_pubkey *) pubkey);
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_xonly_pubkey_save(secp256k1_xonly_pubkey *pubkey, secp256k1_ge *ge) {
|
||||
secp256k1_pubkey_save((secp256k1_pubkey *) pubkey, ge);
|
||||
}
|
||||
|
||||
int secp256k1_xonly_pubkey_parse(const secp256k1_context* ctx, secp256k1_xonly_pubkey *pubkey, const unsigned char *input32) {
|
||||
secp256k1_ge pk;
|
||||
secp256k1_fe x;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(pubkey != NULL);
|
||||
memset(pubkey, 0, sizeof(*pubkey));
|
||||
ARG_CHECK(input32 != NULL);
|
||||
|
||||
if (!secp256k1_fe_set_b32_limit(&x, input32)) {
|
||||
return 0;
|
||||
}
|
||||
if (!secp256k1_ge_set_xo_var(&pk, &x, 0)) {
|
||||
return 0;
|
||||
}
|
||||
if (!secp256k1_ge_is_in_correct_subgroup(&pk)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_xonly_pubkey_save(pubkey, &pk);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_xonly_pubkey_serialize(const secp256k1_context* ctx, unsigned char *output32, const secp256k1_xonly_pubkey *pubkey) {
|
||||
secp256k1_ge pk;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(output32 != NULL);
|
||||
memset(output32, 0, 32);
|
||||
ARG_CHECK(pubkey != NULL);
|
||||
|
||||
if (!secp256k1_xonly_pubkey_load(ctx, &pk, pubkey)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_fe_get_b32(output32, &pk.x);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_xonly_pubkey_cmp(const secp256k1_context* ctx, const secp256k1_xonly_pubkey* pk0, const secp256k1_xonly_pubkey* pk1) {
|
||||
unsigned char out[2][32];
|
||||
const secp256k1_xonly_pubkey* pk[2];
|
||||
int i;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
pk[0] = pk0; pk[1] = pk1;
|
||||
for (i = 0; i < 2; i++) {
|
||||
/* If the public key is NULL or invalid, xonly_pubkey_serialize will
|
||||
* call the illegal_callback and return 0. In that case we will
|
||||
* serialize the key as all zeros which is less than any valid public
|
||||
* key. This results in consistent comparisons even if NULL or invalid
|
||||
* pubkeys are involved and prevents edge cases such as sorting
|
||||
* algorithms that use this function and do not terminate as a
|
||||
* result. */
|
||||
if (!secp256k1_xonly_pubkey_serialize(ctx, out[i], pk[i])) {
|
||||
/* Note that xonly_pubkey_serialize should already set the output to
|
||||
* zero in that case, but it's not guaranteed by the API, we can't
|
||||
* test it and writing a VERIFY_CHECK is more complex than
|
||||
* explicitly memsetting (again). */
|
||||
memset(out[i], 0, sizeof(out[i]));
|
||||
}
|
||||
}
|
||||
return secp256k1_memcmp_var(out[0], out[1], sizeof(out[1]));
|
||||
}
|
||||
|
||||
/** Keeps a group element as is if it has an even Y and otherwise negates it.
|
||||
* y_parity is set to 0 in the former case and to 1 in the latter case.
|
||||
* Requires that the coordinates of r are normalized. */
|
||||
static int secp256k1_extrakeys_ge_even_y(secp256k1_ge *r) {
|
||||
int y_parity = 0;
|
||||
VERIFY_CHECK(!secp256k1_ge_is_infinity(r));
|
||||
|
||||
if (secp256k1_fe_is_odd(&r->y)) {
|
||||
secp256k1_fe_negate(&r->y, &r->y, 1);
|
||||
y_parity = 1;
|
||||
}
|
||||
return y_parity;
|
||||
}
|
||||
|
||||
int secp256k1_xonly_pubkey_from_pubkey(const secp256k1_context* ctx, secp256k1_xonly_pubkey *xonly_pubkey, int *pk_parity, const secp256k1_pubkey *pubkey) {
|
||||
secp256k1_ge pk;
|
||||
int tmp;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(xonly_pubkey != NULL);
|
||||
ARG_CHECK(pubkey != NULL);
|
||||
|
||||
if (!secp256k1_pubkey_load(ctx, &pk, pubkey)) {
|
||||
return 0;
|
||||
}
|
||||
tmp = secp256k1_extrakeys_ge_even_y(&pk);
|
||||
if (pk_parity != NULL) {
|
||||
*pk_parity = tmp;
|
||||
}
|
||||
secp256k1_xonly_pubkey_save(xonly_pubkey, &pk);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_xonly_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey *output_pubkey, const secp256k1_xonly_pubkey *internal_pubkey, const unsigned char *tweak32) {
|
||||
secp256k1_ge pk;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(output_pubkey != NULL);
|
||||
memset(output_pubkey, 0, sizeof(*output_pubkey));
|
||||
ARG_CHECK(internal_pubkey != NULL);
|
||||
ARG_CHECK(tweak32 != NULL);
|
||||
|
||||
if (!secp256k1_xonly_pubkey_load(ctx, &pk, internal_pubkey)
|
||||
|| !secp256k1_ec_pubkey_tweak_add_helper(&pk, tweak32)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_pubkey_save(output_pubkey, &pk);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_xonly_pubkey_tweak_add_check(const secp256k1_context* ctx, const unsigned char *tweaked_pubkey32, int tweaked_pk_parity, const secp256k1_xonly_pubkey *internal_pubkey, const unsigned char *tweak32) {
|
||||
secp256k1_ge pk;
|
||||
unsigned char pk_expected32[32];
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(internal_pubkey != NULL);
|
||||
ARG_CHECK(tweaked_pubkey32 != NULL);
|
||||
ARG_CHECK(tweak32 != NULL);
|
||||
|
||||
if (!secp256k1_xonly_pubkey_load(ctx, &pk, internal_pubkey)
|
||||
|| !secp256k1_ec_pubkey_tweak_add_helper(&pk, tweak32)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_fe_normalize_var(&pk.x);
|
||||
secp256k1_fe_normalize_var(&pk.y);
|
||||
secp256k1_fe_get_b32(pk_expected32, &pk.x);
|
||||
|
||||
return secp256k1_memcmp_var(&pk_expected32, tweaked_pubkey32, 32) == 0
|
||||
&& secp256k1_fe_is_odd(&pk.y) == tweaked_pk_parity;
|
||||
}
|
||||
|
||||
static void secp256k1_keypair_save(secp256k1_keypair *keypair, const secp256k1_scalar *sk, secp256k1_ge *pk) {
|
||||
secp256k1_scalar_get_b32(&keypair->data[0], sk);
|
||||
secp256k1_pubkey_save((secp256k1_pubkey *)&keypair->data[32], pk);
|
||||
}
|
||||
|
||||
|
||||
static int secp256k1_keypair_seckey_load(const secp256k1_context* ctx, secp256k1_scalar *sk, const secp256k1_keypair *keypair) {
|
||||
int ret;
|
||||
|
||||
ret = secp256k1_scalar_set_b32_seckey(sk, &keypair->data[0]);
|
||||
/* We can declassify ret here because sk is only zero if a keypair function
|
||||
* failed (which zeroes the keypair) and its return value is ignored. */
|
||||
secp256k1_declassify(ctx, &ret, sizeof(ret));
|
||||
ARG_CHECK(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Load a keypair into pk and sk (if non-NULL). This function declassifies pk
|
||||
* and ARG_CHECKs that the keypair is not invalid. It always initializes sk and
|
||||
* pk with dummy values. */
|
||||
static int secp256k1_keypair_load(const secp256k1_context* ctx, secp256k1_scalar *sk, secp256k1_ge *pk, const secp256k1_keypair *keypair) {
|
||||
int ret;
|
||||
const secp256k1_pubkey *pubkey = (const secp256k1_pubkey *)&keypair->data[32];
|
||||
|
||||
/* Need to declassify the pubkey because pubkey_load ARG_CHECKs if it's
|
||||
* invalid. */
|
||||
secp256k1_declassify(ctx, pubkey, sizeof(*pubkey));
|
||||
ret = secp256k1_pubkey_load(ctx, pk, pubkey);
|
||||
if (sk != NULL) {
|
||||
ret = ret && secp256k1_keypair_seckey_load(ctx, sk, keypair);
|
||||
}
|
||||
if (!ret) {
|
||||
*pk = secp256k1_ge_const_g;
|
||||
if (sk != NULL) {
|
||||
*sk = secp256k1_scalar_one;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int secp256k1_keypair_create(const secp256k1_context* ctx, secp256k1_keypair *keypair, const unsigned char *seckey32) {
|
||||
secp256k1_scalar sk;
|
||||
secp256k1_ge pk;
|
||||
int ret = 0;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(keypair != NULL);
|
||||
memset(keypair, 0, sizeof(*keypair));
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
ARG_CHECK(seckey32 != NULL);
|
||||
|
||||
ret = secp256k1_ec_pubkey_create_helper(&ctx->ecmult_gen_ctx, &sk, &pk, seckey32);
|
||||
secp256k1_keypair_save(keypair, &sk, &pk);
|
||||
secp256k1_memczero(keypair, sizeof(*keypair), !ret);
|
||||
|
||||
secp256k1_scalar_clear(&sk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int secp256k1_keypair_sec(const secp256k1_context* ctx, unsigned char *seckey, const secp256k1_keypair *keypair) {
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(seckey != NULL);
|
||||
memset(seckey, 0, 32);
|
||||
ARG_CHECK(keypair != NULL);
|
||||
|
||||
memcpy(seckey, &keypair->data[0], 32);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_keypair_pub(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const secp256k1_keypair *keypair) {
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(pubkey != NULL);
|
||||
memset(pubkey, 0, sizeof(*pubkey));
|
||||
ARG_CHECK(keypair != NULL);
|
||||
|
||||
memcpy(pubkey->data, &keypair->data[32], sizeof(*pubkey));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_keypair_xonly_pub(const secp256k1_context* ctx, secp256k1_xonly_pubkey *pubkey, int *pk_parity, const secp256k1_keypair *keypair) {
|
||||
secp256k1_ge pk;
|
||||
int tmp;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(pubkey != NULL);
|
||||
memset(pubkey, 0, sizeof(*pubkey));
|
||||
ARG_CHECK(keypair != NULL);
|
||||
|
||||
if (!secp256k1_keypair_load(ctx, NULL, &pk, keypair)) {
|
||||
return 0;
|
||||
}
|
||||
tmp = secp256k1_extrakeys_ge_even_y(&pk);
|
||||
if (pk_parity != NULL) {
|
||||
*pk_parity = tmp;
|
||||
}
|
||||
secp256k1_xonly_pubkey_save(pubkey, &pk);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_keypair_xonly_tweak_add(const secp256k1_context* ctx, secp256k1_keypair *keypair, const unsigned char *tweak32) {
|
||||
secp256k1_ge pk;
|
||||
secp256k1_scalar sk;
|
||||
int y_parity;
|
||||
int ret;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(keypair != NULL);
|
||||
ARG_CHECK(tweak32 != NULL);
|
||||
|
||||
ret = secp256k1_keypair_load(ctx, &sk, &pk, keypair);
|
||||
memset(keypair, 0, sizeof(*keypair));
|
||||
|
||||
y_parity = secp256k1_extrakeys_ge_even_y(&pk);
|
||||
if (y_parity == 1) {
|
||||
secp256k1_scalar_negate(&sk, &sk);
|
||||
}
|
||||
|
||||
ret &= secp256k1_ec_seckey_tweak_add_helper(&sk, tweak32);
|
||||
ret &= secp256k1_ec_pubkey_tweak_add_helper(&pk, tweak32);
|
||||
|
||||
secp256k1_declassify(ctx, &ret, sizeof(ret));
|
||||
if (ret) {
|
||||
secp256k1_keypair_save(keypair, &sk, &pk);
|
||||
}
|
||||
|
||||
secp256k1_scalar_clear(&sk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,68 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2020 Pieter Wuille *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_EXTRAKEYS_TESTS_EXHAUSTIVE_H
|
||||
#define SECP256K1_MODULE_EXTRAKEYS_TESTS_EXHAUSTIVE_H
|
||||
|
||||
#include "../../../include/secp256k1_extrakeys.h"
|
||||
#include "main_impl.h"
|
||||
|
||||
static void test_exhaustive_extrakeys(const secp256k1_context *ctx, const secp256k1_ge* group) {
|
||||
secp256k1_keypair keypair[EXHAUSTIVE_TEST_ORDER - 1];
|
||||
secp256k1_pubkey pubkey[EXHAUSTIVE_TEST_ORDER - 1];
|
||||
secp256k1_xonly_pubkey xonly_pubkey[EXHAUSTIVE_TEST_ORDER - 1];
|
||||
int parities[EXHAUSTIVE_TEST_ORDER - 1];
|
||||
unsigned char xonly_pubkey_bytes[EXHAUSTIVE_TEST_ORDER - 1][32];
|
||||
int i;
|
||||
|
||||
for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) {
|
||||
secp256k1_fe fe;
|
||||
secp256k1_scalar scalar_i;
|
||||
unsigned char buf[33];
|
||||
int parity;
|
||||
|
||||
secp256k1_scalar_set_int(&scalar_i, i);
|
||||
secp256k1_scalar_get_b32(buf, &scalar_i);
|
||||
|
||||
/* Construct pubkey and keypair. */
|
||||
CHECK(secp256k1_keypair_create(ctx, &keypair[i - 1], buf));
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey[i - 1], buf));
|
||||
|
||||
/* Construct serialized xonly_pubkey from keypair. */
|
||||
CHECK(secp256k1_keypair_xonly_pub(ctx, &xonly_pubkey[i - 1], &parities[i - 1], &keypair[i - 1]));
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(ctx, xonly_pubkey_bytes[i - 1], &xonly_pubkey[i - 1]));
|
||||
|
||||
/* Parse the xonly_pubkey back and verify it matches the previously serialized value. */
|
||||
CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pubkey[i - 1], xonly_pubkey_bytes[i - 1]));
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf, &xonly_pubkey[i - 1]));
|
||||
CHECK(secp256k1_memcmp_var(xonly_pubkey_bytes[i - 1], buf, 32) == 0);
|
||||
|
||||
/* Construct the xonly_pubkey from the pubkey, and verify it matches the same. */
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pubkey[i - 1], &parity, &pubkey[i - 1]));
|
||||
CHECK(parity == parities[i - 1]);
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf, &xonly_pubkey[i - 1]));
|
||||
CHECK(secp256k1_memcmp_var(xonly_pubkey_bytes[i - 1], buf, 32) == 0);
|
||||
|
||||
/* Compare the xonly_pubkey bytes against the precomputed group. */
|
||||
secp256k1_fe_set_b32_mod(&fe, xonly_pubkey_bytes[i - 1]);
|
||||
CHECK(secp256k1_fe_equal(&fe, &group[i].x));
|
||||
|
||||
/* Check the parity against the precomputed group. */
|
||||
fe = group[i].y;
|
||||
secp256k1_fe_normalize_var(&fe);
|
||||
CHECK(secp256k1_fe_is_odd(&fe) == parities[i - 1]);
|
||||
|
||||
/* Verify that the higher half is identical to the lower half mirrored. */
|
||||
if (i > EXHAUSTIVE_TEST_ORDER / 2) {
|
||||
CHECK(secp256k1_memcmp_var(xonly_pubkey_bytes[i - 1], xonly_pubkey_bytes[EXHAUSTIVE_TEST_ORDER - i - 1], 32) == 0);
|
||||
CHECK(parities[i - 1] == 1 - parities[EXHAUSTIVE_TEST_ORDER - i - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: keypair/xonly_pubkey tweak tests */
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,484 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2020 Jonas Nick *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_EXTRAKEYS_TESTS_H
|
||||
#define SECP256K1_MODULE_EXTRAKEYS_TESTS_H
|
||||
|
||||
#include "../../../include/secp256k1_extrakeys.h"
|
||||
#include "../../unit_test.h"
|
||||
|
||||
static void test_xonly_pubkey(void) {
|
||||
secp256k1_pubkey pk;
|
||||
secp256k1_xonly_pubkey xonly_pk, xonly_pk_tmp;
|
||||
secp256k1_ge pk1;
|
||||
secp256k1_ge pk2;
|
||||
secp256k1_fe y;
|
||||
unsigned char sk[32];
|
||||
unsigned char xy_sk[32];
|
||||
unsigned char buf32[32];
|
||||
unsigned char ones32[32];
|
||||
unsigned char zeros64[64] = { 0 };
|
||||
int pk_parity;
|
||||
int i;
|
||||
|
||||
testrand256(sk);
|
||||
memset(ones32, 0xFF, 32);
|
||||
testrand256(xy_sk);
|
||||
CHECK(secp256k1_ec_pubkey_create(CTX, &pk, sk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 1);
|
||||
|
||||
/* Test xonly_pubkey_from_pubkey */
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 1);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_from_pubkey(CTX, NULL, &pk_parity, &pk));
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, NULL, &pk) == 1);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, NULL));
|
||||
memset(&pk, 0, sizeof(pk));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk));
|
||||
|
||||
/* Choose a secret key such that the resulting pubkey and xonly_pubkey match. */
|
||||
memset(sk, 0, sizeof(sk));
|
||||
sk[0] = 1;
|
||||
CHECK(secp256k1_ec_pubkey_create(CTX, &pk, sk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 1);
|
||||
CHECK(secp256k1_memcmp_var(&pk, &xonly_pk, sizeof(pk)) == 0);
|
||||
CHECK(pk_parity == 0);
|
||||
|
||||
/* Choose a secret key such that pubkey and xonly_pubkey are each others
|
||||
* negation. */
|
||||
sk[0] = 2;
|
||||
CHECK(secp256k1_ec_pubkey_create(CTX, &pk, sk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 1);
|
||||
CHECK(secp256k1_memcmp_var(&xonly_pk, &pk, sizeof(xonly_pk)) != 0);
|
||||
CHECK(pk_parity == 1);
|
||||
secp256k1_pubkey_load(CTX, &pk1, &pk);
|
||||
secp256k1_pubkey_load(CTX, &pk2, (secp256k1_pubkey *) &xonly_pk);
|
||||
CHECK(secp256k1_fe_equal(&pk1.x, &pk2.x) == 1);
|
||||
secp256k1_fe_negate(&y, &pk2.y, 1);
|
||||
CHECK(secp256k1_fe_equal(&pk1.y, &y) == 1);
|
||||
|
||||
/* Test xonly_pubkey_serialize and xonly_pubkey_parse */
|
||||
CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_serialize(CTX, NULL, &xonly_pk));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_serialize(CTX, buf32, NULL));
|
||||
CHECK(secp256k1_memcmp_var(buf32, zeros64, 32) == 0);
|
||||
{
|
||||
/* A pubkey filled with 0s will fail to serialize due to pubkey_load
|
||||
* special casing. */
|
||||
secp256k1_xonly_pubkey pk_tmp;
|
||||
memset(&pk_tmp, 0, sizeof(pk_tmp));
|
||||
/* pubkey_load calls illegal callback */
|
||||
CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_serialize(CTX, buf32, &pk_tmp));
|
||||
}
|
||||
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(CTX, buf32, &xonly_pk) == 1);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_parse(CTX, NULL, buf32));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_parse(CTX, &xonly_pk, NULL));
|
||||
|
||||
/* Serialization and parse roundtrip */
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, NULL, &pk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(CTX, buf32, &xonly_pk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_parse(CTX, &xonly_pk_tmp, buf32) == 1);
|
||||
CHECK(secp256k1_memcmp_var(&xonly_pk, &xonly_pk_tmp, sizeof(xonly_pk)) == 0);
|
||||
|
||||
/* Test parsing invalid field elements */
|
||||
memset(&xonly_pk, 1, sizeof(xonly_pk));
|
||||
/* Overflowing field element */
|
||||
CHECK(secp256k1_xonly_pubkey_parse(CTX, &xonly_pk, ones32) == 0);
|
||||
CHECK(secp256k1_memcmp_var(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0);
|
||||
memset(&xonly_pk, 1, sizeof(xonly_pk));
|
||||
/* There's no point with x-coordinate 0 on secp256k1 */
|
||||
CHECK(secp256k1_xonly_pubkey_parse(CTX, &xonly_pk, zeros64) == 0);
|
||||
CHECK(secp256k1_memcmp_var(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0);
|
||||
/* If a random 32-byte string can not be parsed with ec_pubkey_parse
|
||||
* (because interpreted as X coordinate it does not correspond to a point on
|
||||
* the curve) then xonly_pubkey_parse should fail as well. */
|
||||
for (i = 0; i < COUNT; i++) {
|
||||
unsigned char rand33[33];
|
||||
testrand256(&rand33[1]);
|
||||
rand33[0] = SECP256K1_TAG_PUBKEY_EVEN;
|
||||
if (!secp256k1_ec_pubkey_parse(CTX, &pk, rand33, 33)) {
|
||||
memset(&xonly_pk, 1, sizeof(xonly_pk));
|
||||
CHECK(secp256k1_xonly_pubkey_parse(CTX, &xonly_pk, &rand33[1]) == 0);
|
||||
CHECK(secp256k1_memcmp_var(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0);
|
||||
} else {
|
||||
CHECK(secp256k1_xonly_pubkey_parse(CTX, &xonly_pk, &rand33[1]) == 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void test_xonly_pubkey_comparison(void) {
|
||||
unsigned char pk1_ser[32] = {
|
||||
0x58, 0x84, 0xb3, 0xa2, 0x4b, 0x97, 0x37, 0x88, 0x92, 0x38, 0xa6, 0x26, 0x62, 0x52, 0x35, 0x11,
|
||||
0xd0, 0x9a, 0xa1, 0x1b, 0x80, 0x0b, 0x5e, 0x93, 0x80, 0x26, 0x11, 0xef, 0x67, 0x4b, 0xd9, 0x23
|
||||
};
|
||||
const unsigned char pk2_ser[32] = {
|
||||
0xde, 0x36, 0x0e, 0x87, 0x59, 0x8f, 0x3c, 0x01, 0x36, 0x2a, 0x2a, 0xb8, 0xc6, 0xf4, 0x5e, 0x4d,
|
||||
0xb2, 0xc2, 0xd5, 0x03, 0xa7, 0xf9, 0xf1, 0x4f, 0xa8, 0xfa, 0x95, 0xa8, 0xe9, 0x69, 0x76, 0x1c
|
||||
};
|
||||
secp256k1_xonly_pubkey pk1;
|
||||
secp256k1_xonly_pubkey pk2;
|
||||
|
||||
CHECK(secp256k1_xonly_pubkey_parse(CTX, &pk1, pk1_ser) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_parse(CTX, &pk2, pk2_ser) == 1);
|
||||
|
||||
CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_xonly_pubkey_cmp(CTX, NULL, &pk2) < 0));
|
||||
CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, NULL) > 0));
|
||||
CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, &pk2) < 0);
|
||||
CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk2, &pk1) > 0);
|
||||
CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, &pk1) == 0);
|
||||
CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk2, &pk2) == 0);
|
||||
memset(&pk1, 0, sizeof(pk1)); /* illegal pubkey */
|
||||
CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, &pk2) < 0));
|
||||
{
|
||||
int32_t ecount = 0;
|
||||
secp256k1_context_set_illegal_callback(CTX, counting_callback_fn, &ecount);
|
||||
CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, &pk1) == 0);
|
||||
CHECK(ecount == 2);
|
||||
secp256k1_context_set_illegal_callback(CTX, NULL, NULL);
|
||||
}
|
||||
CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk2, &pk1) > 0));
|
||||
}
|
||||
|
||||
static void test_xonly_pubkey_tweak(void) {
|
||||
unsigned char zeros64[64] = { 0 };
|
||||
unsigned char overflows[32];
|
||||
unsigned char sk[32];
|
||||
secp256k1_pubkey internal_pk;
|
||||
secp256k1_xonly_pubkey internal_xonly_pk;
|
||||
secp256k1_pubkey output_pk;
|
||||
int pk_parity;
|
||||
unsigned char tweak[32];
|
||||
int i;
|
||||
|
||||
memset(overflows, 0xff, sizeof(overflows));
|
||||
testrand256(tweak);
|
||||
testrand256(sk);
|
||||
CHECK(secp256k1_ec_pubkey_create(CTX, &internal_pk, sk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &internal_xonly_pk, &pk_parity, &internal_pk) == 1);
|
||||
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add(CTX, NULL, &internal_xonly_pk, tweak));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, NULL, tweak));
|
||||
/* NULL internal_xonly_pk zeroes the output_pk */
|
||||
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, NULL));
|
||||
/* NULL tweak zeroes the output_pk */
|
||||
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
|
||||
|
||||
/* Invalid tweak zeroes the output_pk */
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, overflows) == 0);
|
||||
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
|
||||
|
||||
/* A zero tweak is fine */
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, zeros64) == 1);
|
||||
|
||||
/* Fails if the resulting key was infinity */
|
||||
for (i = 0; i < COUNT; i++) {
|
||||
secp256k1_scalar scalar_tweak;
|
||||
/* Because sk may be negated before adding, we need to try with tweak =
|
||||
* sk as well as tweak = -sk. */
|
||||
secp256k1_scalar_set_b32(&scalar_tweak, sk, NULL);
|
||||
secp256k1_scalar_negate(&scalar_tweak, &scalar_tweak);
|
||||
secp256k1_scalar_get_b32(tweak, &scalar_tweak);
|
||||
CHECK((secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, sk) == 0)
|
||||
|| (secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 0));
|
||||
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
|
||||
}
|
||||
|
||||
/* Invalid pk with a valid tweak */
|
||||
memset(&internal_xonly_pk, 0, sizeof(internal_xonly_pk));
|
||||
testrand256(tweak);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak));
|
||||
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
|
||||
}
|
||||
|
||||
static void test_xonly_pubkey_tweak_check(void) {
|
||||
unsigned char zeros64[64] = { 0 };
|
||||
unsigned char overflows[32];
|
||||
unsigned char sk[32];
|
||||
secp256k1_pubkey internal_pk;
|
||||
secp256k1_xonly_pubkey internal_xonly_pk;
|
||||
secp256k1_pubkey output_pk;
|
||||
secp256k1_xonly_pubkey output_xonly_pk;
|
||||
unsigned char output_pk32[32];
|
||||
unsigned char buf32[32];
|
||||
int pk_parity;
|
||||
unsigned char tweak[32];
|
||||
|
||||
memset(overflows, 0xff, sizeof(overflows));
|
||||
testrand256(tweak);
|
||||
testrand256(sk);
|
||||
CHECK(secp256k1_ec_pubkey_create(CTX, &internal_pk, sk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &internal_xonly_pk, &pk_parity, &internal_pk) == 1);
|
||||
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &output_xonly_pk, &pk_parity, &output_pk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(CTX, buf32, &output_xonly_pk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, tweak) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, tweak) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, tweak) == 1);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add_check(CTX, NULL, pk_parity, &internal_xonly_pk, tweak));
|
||||
/* invalid pk_parity value */
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, 2, &internal_xonly_pk, tweak) == 0);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, NULL, tweak));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, NULL));
|
||||
|
||||
memset(tweak, 1, sizeof(tweak));
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &internal_xonly_pk, NULL, &internal_pk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &output_xonly_pk, &pk_parity, &output_pk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(CTX, output_pk32, &output_xonly_pk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, output_pk32, pk_parity, &internal_xonly_pk, tweak) == 1);
|
||||
|
||||
/* Wrong pk_parity */
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, output_pk32, !pk_parity, &internal_xonly_pk, tweak) == 0);
|
||||
/* Wrong public key */
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(CTX, buf32, &internal_xonly_pk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, tweak) == 0);
|
||||
|
||||
/* Overflowing tweak not allowed */
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, output_pk32, pk_parity, &internal_xonly_pk, overflows) == 0);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, overflows) == 0);
|
||||
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
|
||||
}
|
||||
|
||||
/* Starts with an initial pubkey and recursively creates N_PUBKEYS - 1
|
||||
* additional pubkeys by calling tweak_add. Then verifies every tweak starting
|
||||
* from the last pubkey. */
|
||||
#define N_PUBKEYS 32
|
||||
static void test_xonly_pubkey_tweak_recursive(void) {
|
||||
unsigned char sk[32];
|
||||
secp256k1_pubkey pk[N_PUBKEYS];
|
||||
unsigned char pk_serialized[32];
|
||||
unsigned char tweak[N_PUBKEYS - 1][32];
|
||||
int i;
|
||||
|
||||
testrand256(sk);
|
||||
CHECK(secp256k1_ec_pubkey_create(CTX, &pk[0], sk) == 1);
|
||||
/* Add tweaks */
|
||||
for (i = 0; i < N_PUBKEYS - 1; i++) {
|
||||
secp256k1_xonly_pubkey xonly_pk;
|
||||
memset(tweak[i], i + 1, sizeof(tweak[i]));
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, NULL, &pk[i]) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &pk[i + 1], &xonly_pk, tweak[i]) == 1);
|
||||
}
|
||||
|
||||
/* Verify tweaks */
|
||||
for (i = N_PUBKEYS - 1; i > 0; i--) {
|
||||
secp256k1_xonly_pubkey xonly_pk;
|
||||
int pk_parity;
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk[i]) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(CTX, pk_serialized, &xonly_pk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, NULL, &pk[i - 1]) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, pk_serialized, pk_parity, &xonly_pk, tweak[i - 1]) == 1);
|
||||
}
|
||||
}
|
||||
#undef N_PUBKEYS
|
||||
|
||||
static void test_keypair(void) {
|
||||
unsigned char sk[32];
|
||||
unsigned char sk_tmp[32];
|
||||
unsigned char zeros96[96] = { 0 };
|
||||
unsigned char overflows[32];
|
||||
secp256k1_keypair keypair;
|
||||
secp256k1_pubkey pk, pk_tmp;
|
||||
secp256k1_xonly_pubkey xonly_pk, xonly_pk_tmp;
|
||||
int pk_parity, pk_parity_tmp;
|
||||
|
||||
CHECK(sizeof(zeros96) == sizeof(keypair));
|
||||
memset(overflows, 0xFF, sizeof(overflows));
|
||||
|
||||
/* Test keypair_create */
|
||||
testrand256(sk);
|
||||
CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
|
||||
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) != 0);
|
||||
CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
|
||||
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) != 0);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_keypair_create(CTX, NULL, sk));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_keypair_create(CTX, &keypair, NULL));
|
||||
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0);
|
||||
CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
|
||||
CHECK_ILLEGAL(STATIC_CTX, secp256k1_keypair_create(STATIC_CTX, &keypair, sk));
|
||||
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0);
|
||||
|
||||
/* Invalid secret key */
|
||||
CHECK(secp256k1_keypair_create(CTX, &keypair, zeros96) == 0);
|
||||
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0);
|
||||
CHECK(secp256k1_keypair_create(CTX, &keypair, overflows) == 0);
|
||||
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0);
|
||||
|
||||
/* Test keypair_pub */
|
||||
testrand256(sk);
|
||||
CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
|
||||
CHECK(secp256k1_keypair_pub(CTX, &pk, &keypair) == 1);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_keypair_pub(CTX, NULL, &keypair));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_keypair_pub(CTX, &pk, NULL));
|
||||
CHECK(secp256k1_memcmp_var(zeros96, &pk, sizeof(pk)) == 0);
|
||||
|
||||
/* Using an invalid keypair is fine for keypair_pub */
|
||||
memset(&keypair, 0, sizeof(keypair));
|
||||
CHECK(secp256k1_keypair_pub(CTX, &pk, &keypair) == 1);
|
||||
CHECK(secp256k1_memcmp_var(zeros96, &pk, sizeof(pk)) == 0);
|
||||
|
||||
/* keypair holds the same pubkey as pubkey_create */
|
||||
CHECK(secp256k1_ec_pubkey_create(CTX, &pk, sk) == 1);
|
||||
CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
|
||||
CHECK(secp256k1_keypair_pub(CTX, &pk_tmp, &keypair) == 1);
|
||||
CHECK(secp256k1_memcmp_var(&pk, &pk_tmp, sizeof(pk)) == 0);
|
||||
|
||||
/** Test keypair_xonly_pub **/
|
||||
testrand256(sk);
|
||||
CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
|
||||
CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, &keypair) == 1);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_pub(CTX, NULL, &pk_parity, &keypair));
|
||||
CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk, NULL, &keypair) == 1);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, NULL));
|
||||
CHECK(secp256k1_memcmp_var(zeros96, &xonly_pk, sizeof(xonly_pk)) == 0);
|
||||
/* Using an invalid keypair will set the xonly_pk to 0 (first reset
|
||||
* xonly_pk). */
|
||||
CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, &keypair) == 1);
|
||||
memset(&keypair, 0, sizeof(keypair));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, &keypair));
|
||||
CHECK(secp256k1_memcmp_var(zeros96, &xonly_pk, sizeof(xonly_pk)) == 0);
|
||||
|
||||
/** keypair holds the same xonly pubkey as pubkey_create **/
|
||||
CHECK(secp256k1_ec_pubkey_create(CTX, &pk, sk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 1);
|
||||
CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
|
||||
CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk_tmp, &pk_parity_tmp, &keypair) == 1);
|
||||
CHECK(secp256k1_memcmp_var(&xonly_pk, &xonly_pk_tmp, sizeof(pk)) == 0);
|
||||
CHECK(pk_parity == pk_parity_tmp);
|
||||
|
||||
/* Test keypair_seckey */
|
||||
testrand256(sk);
|
||||
CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
|
||||
CHECK(secp256k1_keypair_sec(CTX, sk_tmp, &keypair) == 1);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_keypair_sec(CTX, NULL, &keypair));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_keypair_sec(CTX, sk_tmp, NULL));
|
||||
CHECK(secp256k1_memcmp_var(zeros96, sk_tmp, sizeof(sk_tmp)) == 0);
|
||||
|
||||
/* keypair returns the same seckey it got */
|
||||
CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
|
||||
CHECK(secp256k1_keypair_sec(CTX, sk_tmp, &keypair) == 1);
|
||||
CHECK(secp256k1_memcmp_var(sk, sk_tmp, sizeof(sk_tmp)) == 0);
|
||||
|
||||
|
||||
/* Using an invalid keypair is fine for keypair_seckey */
|
||||
memset(&keypair, 0, sizeof(keypair));
|
||||
CHECK(secp256k1_keypair_sec(CTX, sk_tmp, &keypair) == 1);
|
||||
CHECK(secp256k1_memcmp_var(zeros96, sk_tmp, sizeof(sk_tmp)) == 0);
|
||||
}
|
||||
|
||||
static void test_keypair_add(void) {
|
||||
unsigned char sk[32];
|
||||
secp256k1_keypair keypair;
|
||||
unsigned char overflows[32];
|
||||
unsigned char zeros96[96] = { 0 };
|
||||
unsigned char tweak[32];
|
||||
int i;
|
||||
|
||||
CHECK(sizeof(zeros96) == sizeof(keypair));
|
||||
testrand256(sk);
|
||||
testrand256(tweak);
|
||||
memset(overflows, 0xFF, 32);
|
||||
CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
|
||||
|
||||
CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1);
|
||||
CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1);
|
||||
CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_tweak_add(CTX, NULL, tweak));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_tweak_add(CTX, &keypair, NULL));
|
||||
/* This does not set the keypair to zeroes */
|
||||
CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) != 0);
|
||||
|
||||
/* Invalid tweak zeroes the keypair */
|
||||
CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
|
||||
CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, overflows) == 0);
|
||||
CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) == 0);
|
||||
|
||||
/* A zero tweak is fine */
|
||||
CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
|
||||
CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, zeros96) == 1);
|
||||
|
||||
/* Fails if the resulting keypair was (sk=0, pk=infinity) */
|
||||
for (i = 0; i < COUNT; i++) {
|
||||
secp256k1_scalar scalar_tweak;
|
||||
secp256k1_keypair keypair_tmp;
|
||||
testrand256(sk);
|
||||
CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
|
||||
memcpy(&keypair_tmp, &keypair, sizeof(keypair));
|
||||
/* Because sk may be negated before adding, we need to try with tweak =
|
||||
* sk as well as tweak = -sk. */
|
||||
secp256k1_scalar_set_b32(&scalar_tweak, sk, NULL);
|
||||
secp256k1_scalar_negate(&scalar_tweak, &scalar_tweak);
|
||||
secp256k1_scalar_get_b32(tweak, &scalar_tweak);
|
||||
CHECK((secp256k1_keypair_xonly_tweak_add(CTX, &keypair, sk) == 0)
|
||||
|| (secp256k1_keypair_xonly_tweak_add(CTX, &keypair_tmp, tweak) == 0));
|
||||
CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) == 0
|
||||
|| secp256k1_memcmp_var(&keypair_tmp, zeros96, sizeof(keypair_tmp)) == 0);
|
||||
}
|
||||
|
||||
/* Invalid keypair with a valid tweak */
|
||||
memset(&keypair, 0, sizeof(keypair));
|
||||
testrand256(tweak);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak));
|
||||
CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) == 0);
|
||||
/* Only seckey part of keypair invalid */
|
||||
CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
|
||||
memset(&keypair, 0, 32);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak));
|
||||
/* Only pubkey part of keypair invalid */
|
||||
CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
|
||||
memset(&keypair.data[32], 0, 64);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak));
|
||||
|
||||
/* Check that the keypair_tweak_add implementation is correct */
|
||||
CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
|
||||
for (i = 0; i < COUNT; i++) {
|
||||
secp256k1_xonly_pubkey internal_pk;
|
||||
secp256k1_xonly_pubkey output_pk;
|
||||
secp256k1_pubkey output_pk_xy;
|
||||
secp256k1_pubkey output_pk_expected;
|
||||
unsigned char pk32[32];
|
||||
unsigned char sk32[32];
|
||||
int pk_parity;
|
||||
|
||||
testrand256(tweak);
|
||||
CHECK(secp256k1_keypair_xonly_pub(CTX, &internal_pk, NULL, &keypair) == 1);
|
||||
CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1);
|
||||
CHECK(secp256k1_keypair_xonly_pub(CTX, &output_pk, &pk_parity, &keypair) == 1);
|
||||
|
||||
/* Check that it passes xonly_pubkey_tweak_add_check */
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(CTX, pk32, &output_pk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, pk32, pk_parity, &internal_pk, tweak) == 1);
|
||||
|
||||
/* Check that the resulting pubkey matches xonly_pubkey_tweak_add */
|
||||
CHECK(secp256k1_keypair_pub(CTX, &output_pk_xy, &keypair) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk_expected, &internal_pk, tweak) == 1);
|
||||
CHECK(secp256k1_memcmp_var(&output_pk_xy, &output_pk_expected, sizeof(output_pk_xy)) == 0);
|
||||
|
||||
/* Check that the secret key in the keypair is tweaked correctly */
|
||||
CHECK(secp256k1_keypair_sec(CTX, sk32, &keypair) == 1);
|
||||
CHECK(secp256k1_ec_pubkey_create(CTX, &output_pk_expected, sk32) == 1);
|
||||
CHECK(secp256k1_memcmp_var(&output_pk_xy, &output_pk_expected, sizeof(output_pk_xy)) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* --- Test registry --- */
|
||||
static const struct tf_test_entry tests_extrakeys[] = {
|
||||
/* xonly key test cases */
|
||||
CASE1(test_xonly_pubkey),
|
||||
CASE1(test_xonly_pubkey_tweak),
|
||||
CASE1(test_xonly_pubkey_tweak_check),
|
||||
CASE1(test_xonly_pubkey_tweak_recursive),
|
||||
CASE1(test_xonly_pubkey_comparison),
|
||||
/* keypair tests */
|
||||
CASE1(test_keypair),
|
||||
CASE1(test_keypair_add),
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,8 @@
|
||||
include_HEADERS += include/secp256k1_musig.h
|
||||
noinst_HEADERS += src/modules/musig/main_impl.h
|
||||
noinst_HEADERS += src/modules/musig/keyagg.h
|
||||
noinst_HEADERS += src/modules/musig/keyagg_impl.h
|
||||
noinst_HEADERS += src/modules/musig/session.h
|
||||
noinst_HEADERS += src/modules/musig/session_impl.h
|
||||
noinst_HEADERS += src/modules/musig/tests_impl.h
|
||||
noinst_HEADERS += src/modules/musig/vectors.h
|
||||
@@ -0,0 +1,32 @@
|
||||
/***********************************************************************
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_MUSIG_KEYAGG_H
|
||||
#define SECP256K1_MODULE_MUSIG_KEYAGG_H
|
||||
|
||||
#include "../../../include/secp256k1.h"
|
||||
#include "../../../include/secp256k1_musig.h"
|
||||
|
||||
#include "../../group.h"
|
||||
#include "../../scalar.h"
|
||||
|
||||
typedef struct {
|
||||
secp256k1_ge pk;
|
||||
/* If there is no "second" public key, second_pk is set to the point at
|
||||
* infinity */
|
||||
secp256k1_ge second_pk;
|
||||
unsigned char pks_hash[32];
|
||||
/* tweak is identical to value tacc[v] in the specification. */
|
||||
secp256k1_scalar tweak;
|
||||
/* parity_acc corresponds to (1 - gacc[v])/2 in the spec. So if gacc[v] is
|
||||
* -1, parity_acc is 1. Otherwise, parity_acc is 0. */
|
||||
int parity_acc;
|
||||
} secp256k1_keyagg_cache_internal;
|
||||
|
||||
static int secp256k1_keyagg_cache_load(const secp256k1_context* ctx, secp256k1_keyagg_cache_internal *cache_i, const secp256k1_musig_keyagg_cache *cache);
|
||||
|
||||
static void secp256k1_musig_keyaggcoef(const secp256k1_hash_ctx *hash_ctx, secp256k1_scalar *r, const secp256k1_keyagg_cache_internal *cache_i, secp256k1_ge *pk);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,275 @@
|
||||
/***********************************************************************
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_MUSIG_KEYAGG_IMPL_H
|
||||
#define SECP256K1_MODULE_MUSIG_KEYAGG_IMPL_H
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "keyagg.h"
|
||||
#include "../../eckey.h"
|
||||
#include "../../ecmult.h"
|
||||
#include "../../field.h"
|
||||
#include "../../group.h"
|
||||
#include "../../hash.h"
|
||||
#include "../../util.h"
|
||||
|
||||
static const unsigned char secp256k1_musig_keyagg_cache_magic[4] = { 0xf4, 0xad, 0xbb, 0xdf };
|
||||
|
||||
/* A keyagg cache consists of
|
||||
* - 4 byte magic set during initialization to allow detecting an uninitialized
|
||||
* object.
|
||||
* - 64 byte aggregate (and potentially tweaked) public key
|
||||
* - 64 byte "second" public key (set to the point at infinity if not present)
|
||||
* - 32 byte hash of all public keys
|
||||
* - 1 byte the parity of the internal key (if tweaked, otherwise 0)
|
||||
* - 32 byte tweak
|
||||
*/
|
||||
/* Requires that cache_i->pk is not infinity. */
|
||||
static void secp256k1_keyagg_cache_save(secp256k1_musig_keyagg_cache *cache, const secp256k1_keyagg_cache_internal *cache_i) {
|
||||
unsigned char *ptr = cache->data;
|
||||
memcpy(ptr, secp256k1_musig_keyagg_cache_magic, 4);
|
||||
ptr += 4;
|
||||
secp256k1_ge_to_bytes(ptr, &cache_i->pk);
|
||||
ptr += 64;
|
||||
secp256k1_ge_to_bytes_ext(ptr, &cache_i->second_pk);
|
||||
ptr += 64;
|
||||
memcpy(ptr, cache_i->pks_hash, 32);
|
||||
ptr += 32;
|
||||
*ptr = cache_i->parity_acc;
|
||||
ptr += 1;
|
||||
secp256k1_scalar_get_b32(ptr, &cache_i->tweak);
|
||||
}
|
||||
|
||||
static int secp256k1_keyagg_cache_load(const secp256k1_context* ctx, secp256k1_keyagg_cache_internal *cache_i, const secp256k1_musig_keyagg_cache *cache) {
|
||||
const unsigned char *ptr = cache->data;
|
||||
ARG_CHECK(secp256k1_memcmp_var(ptr, secp256k1_musig_keyagg_cache_magic, 4) == 0);
|
||||
ptr += 4;
|
||||
secp256k1_ge_from_bytes(&cache_i->pk, ptr);
|
||||
ptr += 64;
|
||||
secp256k1_ge_from_bytes_ext(&cache_i->second_pk, ptr);
|
||||
ptr += 64;
|
||||
memcpy(cache_i->pks_hash, ptr, 32);
|
||||
ptr += 32;
|
||||
cache_i->parity_acc = *ptr & 1;
|
||||
ptr += 1;
|
||||
secp256k1_scalar_set_b32(&cache_i->tweak, ptr, NULL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
|
||||
* SHA256 to SHA256("KeyAgg list")||SHA256("KeyAgg list"). */
|
||||
static void secp256k1_musig_keyagglist_sha256(secp256k1_sha256 *sha) {
|
||||
static const uint32_t midstate[8] = {
|
||||
0xb399d5e0ul, 0xc8fff302ul, 0x6badac71ul, 0x07c5b7f1ul,
|
||||
0x9701e2eful, 0x2a72ecf8ul, 0x201a4c7bul, 0xab148a38ul
|
||||
};
|
||||
secp256k1_sha256_initialize_midstate(sha, 64, midstate);
|
||||
}
|
||||
|
||||
/* Computes pks_hash = tagged_hash(pk[0], ..., pk[np-1]) */
|
||||
static int secp256k1_musig_compute_pks_hash(const secp256k1_context *ctx, unsigned char *pks_hash, const secp256k1_pubkey * const* pks, size_t np) {
|
||||
secp256k1_sha256 sha;
|
||||
size_t i;
|
||||
|
||||
secp256k1_musig_keyagglist_sha256(&sha);
|
||||
for (i = 0; i < np; i++) {
|
||||
unsigned char ser[33];
|
||||
size_t ser_len = sizeof(ser);
|
||||
if (!secp256k1_ec_pubkey_serialize(ctx, ser, &ser_len, pks[i], SECP256K1_EC_COMPRESSED)) {
|
||||
return 0;
|
||||
}
|
||||
VERIFY_CHECK(ser_len == sizeof(ser));
|
||||
secp256k1_sha256_write(secp256k1_get_hash_context(ctx), &sha, ser, sizeof(ser));
|
||||
}
|
||||
secp256k1_sha256_finalize(secp256k1_get_hash_context(ctx), &sha, pks_hash);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
|
||||
* SHA256 to SHA256("KeyAgg coefficient")||SHA256("KeyAgg coefficient"). */
|
||||
static void secp256k1_musig_keyaggcoef_sha256(secp256k1_sha256 *sha) {
|
||||
static const uint32_t midstate[8] = {
|
||||
0x6ef02c5aul, 0x06a480deul, 0x1f298665ul, 0x1d1134f2ul,
|
||||
0x56a0b063ul, 0x52da4147ul, 0xf280d9d4ul, 0x4484be15ul
|
||||
};
|
||||
secp256k1_sha256_initialize_midstate(sha, 64, midstate);
|
||||
}
|
||||
|
||||
/* Compute KeyAgg coefficient which is constant 1 for the second pubkey and
|
||||
* otherwise tagged_hash(pks_hash, pk) where pks_hash is the hash of public keys.
|
||||
* second_pk is the point at infinity in case there is no second_pk. Assumes
|
||||
* that pk is not the point at infinity and that the Y-coordinates of pk and
|
||||
* second_pk are normalized. */
|
||||
static void secp256k1_musig_keyaggcoef_internal(const secp256k1_hash_ctx *hash_ctx, secp256k1_scalar *r, const unsigned char *pks_hash, secp256k1_ge *pk, const secp256k1_ge *second_pk) {
|
||||
VERIFY_CHECK(!secp256k1_ge_is_infinity(pk));
|
||||
|
||||
if (!secp256k1_ge_is_infinity(second_pk)
|
||||
&& secp256k1_ge_eq_var(pk, second_pk)) {
|
||||
secp256k1_scalar_set_int(r, 1);
|
||||
} else {
|
||||
secp256k1_sha256 sha;
|
||||
unsigned char buf[33];
|
||||
secp256k1_musig_keyaggcoef_sha256(&sha);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, pks_hash, 32);
|
||||
/* Serialization does not fail since the pk is not the point at infinity
|
||||
* (according to this function's precondition). */
|
||||
secp256k1_eckey_pubkey_serialize33(pk, buf);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, buf, sizeof(buf));
|
||||
secp256k1_sha256_finalize(hash_ctx, &sha, buf);
|
||||
secp256k1_scalar_set_b32(r, buf, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* Assumes that pk is not the point at infinity and that the Y-coordinates of pk
|
||||
* and cache_i->second_pk are normalized. */
|
||||
static void secp256k1_musig_keyaggcoef(const secp256k1_hash_ctx *hash_ctx, secp256k1_scalar *r, const secp256k1_keyagg_cache_internal *cache_i, secp256k1_ge *pk) {
|
||||
secp256k1_musig_keyaggcoef_internal(hash_ctx, r, cache_i->pks_hash, pk, &cache_i->second_pk);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
const secp256k1_context *ctx;
|
||||
/* pks_hash is the hash of the public keys */
|
||||
unsigned char pks_hash[32];
|
||||
const secp256k1_pubkey * const* pks;
|
||||
secp256k1_ge second_pk;
|
||||
} secp256k1_musig_pubkey_agg_ecmult_data;
|
||||
|
||||
/* Callback for batch EC multiplication to compute keyaggcoef_0*P0 + keyaggcoef_1*P1 + ... */
|
||||
static int secp256k1_musig_pubkey_agg_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data) {
|
||||
secp256k1_musig_pubkey_agg_ecmult_data *ctx = (secp256k1_musig_pubkey_agg_ecmult_data *) data;
|
||||
int ret;
|
||||
ret = secp256k1_pubkey_load(ctx->ctx, pt, ctx->pks[idx]);
|
||||
#ifdef VERIFY
|
||||
/* pubkey_load can't fail because the same pks have already been loaded in
|
||||
* `musig_compute_pks_hash` (and we test this). */
|
||||
VERIFY_CHECK(ret);
|
||||
#else
|
||||
(void) ret;
|
||||
#endif
|
||||
secp256k1_musig_keyaggcoef_internal(secp256k1_get_hash_context(ctx->ctx), sc, ctx->pks_hash, pt, &ctx->second_pk);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_pubkey_agg(const secp256k1_context* ctx, secp256k1_xonly_pubkey *agg_pk, secp256k1_musig_keyagg_cache *keyagg_cache, const secp256k1_pubkey * const* pubkeys, size_t n_pubkeys) {
|
||||
secp256k1_musig_pubkey_agg_ecmult_data ecmult_data;
|
||||
secp256k1_gej pkj;
|
||||
secp256k1_ge pkp;
|
||||
size_t i;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
if (agg_pk != NULL) {
|
||||
memset(agg_pk, 0, sizeof(*agg_pk));
|
||||
}
|
||||
ARG_CHECK(pubkeys != NULL);
|
||||
ARG_CHECK(n_pubkeys > 0);
|
||||
for (i = 0; i < n_pubkeys; i++) {
|
||||
ARG_CHECK(pubkeys[i] != NULL);
|
||||
}
|
||||
|
||||
ecmult_data.ctx = ctx;
|
||||
ecmult_data.pks = pubkeys;
|
||||
|
||||
secp256k1_ge_set_infinity(&ecmult_data.second_pk);
|
||||
for (i = 1; i < n_pubkeys; i++) {
|
||||
if (secp256k1_memcmp_var(pubkeys[0], pubkeys[i], sizeof(*pubkeys[0])) != 0) {
|
||||
secp256k1_ge pk;
|
||||
if (!secp256k1_pubkey_load(ctx, &pk, pubkeys[i])) {
|
||||
return 0;
|
||||
}
|
||||
ecmult_data.second_pk = pk;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!secp256k1_musig_compute_pks_hash(ctx, ecmult_data.pks_hash, pubkeys, n_pubkeys)) {
|
||||
return 0;
|
||||
}
|
||||
/* TODO: actually use optimized ecmult_multi algorithms by providing a
|
||||
* scratch space */
|
||||
if (!secp256k1_ecmult_multi_var(&ctx->error_callback, NULL, &pkj, NULL, secp256k1_musig_pubkey_agg_callback, (void *) &ecmult_data, n_pubkeys)) {
|
||||
/* In order to reach this line with the current implementation of
|
||||
* ecmult_multi_var one would need to provide a callback that can
|
||||
* fail. */
|
||||
return 0;
|
||||
}
|
||||
secp256k1_ge_set_gej(&pkp, &pkj);
|
||||
secp256k1_fe_normalize_var(&pkp.y);
|
||||
/* The resulting public key is infinity with negligible probability */
|
||||
VERIFY_CHECK(!secp256k1_ge_is_infinity(&pkp));
|
||||
if (keyagg_cache != NULL) {
|
||||
secp256k1_keyagg_cache_internal cache_i = { 0 };
|
||||
cache_i.pk = pkp;
|
||||
cache_i.second_pk = ecmult_data.second_pk;
|
||||
memcpy(cache_i.pks_hash, ecmult_data.pks_hash, sizeof(cache_i.pks_hash));
|
||||
secp256k1_keyagg_cache_save(keyagg_cache, &cache_i);
|
||||
}
|
||||
|
||||
if (agg_pk != NULL) {
|
||||
secp256k1_extrakeys_ge_even_y(&pkp);
|
||||
secp256k1_xonly_pubkey_save(agg_pk, &pkp);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_pubkey_get(const secp256k1_context* ctx, secp256k1_pubkey *agg_pk, const secp256k1_musig_keyagg_cache *keyagg_cache) {
|
||||
secp256k1_keyagg_cache_internal cache_i;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(agg_pk != NULL);
|
||||
memset(agg_pk, 0, sizeof(*agg_pk));
|
||||
ARG_CHECK(keyagg_cache != NULL);
|
||||
|
||||
if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_pubkey_save(agg_pk, &cache_i.pk);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int secp256k1_musig_pubkey_tweak_add_internal(const secp256k1_context* ctx, secp256k1_pubkey *output_pubkey, secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *tweak32, int xonly) {
|
||||
secp256k1_keyagg_cache_internal cache_i;
|
||||
int overflow = 0;
|
||||
secp256k1_scalar tweak;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
if (output_pubkey != NULL) {
|
||||
memset(output_pubkey, 0, sizeof(*output_pubkey));
|
||||
}
|
||||
ARG_CHECK(keyagg_cache != NULL);
|
||||
ARG_CHECK(tweak32 != NULL);
|
||||
|
||||
if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_scalar_set_b32(&tweak, tweak32, &overflow);
|
||||
if (overflow) {
|
||||
return 0;
|
||||
}
|
||||
if (xonly && secp256k1_extrakeys_ge_even_y(&cache_i.pk)) {
|
||||
cache_i.parity_acc ^= 1;
|
||||
secp256k1_scalar_negate(&cache_i.tweak, &cache_i.tweak);
|
||||
}
|
||||
secp256k1_scalar_add(&cache_i.tweak, &cache_i.tweak, &tweak);
|
||||
if (!secp256k1_eckey_pubkey_tweak_add(&cache_i.pk, &tweak)) {
|
||||
return 0;
|
||||
}
|
||||
/* eckey_pubkey_tweak_add fails if cache_i.pk is infinity */
|
||||
VERIFY_CHECK(!secp256k1_ge_is_infinity(&cache_i.pk));
|
||||
secp256k1_keyagg_cache_save(keyagg_cache, &cache_i);
|
||||
if (output_pubkey != NULL) {
|
||||
secp256k1_pubkey_save(output_pubkey, &cache_i.pk);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_pubkey_ec_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey *output_pubkey, secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *tweak32) {
|
||||
return secp256k1_musig_pubkey_tweak_add_internal(ctx, output_pubkey, keyagg_cache, tweak32, 0);
|
||||
}
|
||||
|
||||
int secp256k1_musig_pubkey_xonly_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey *output_pubkey, secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *tweak32) {
|
||||
return secp256k1_musig_pubkey_tweak_add_internal(ctx, output_pubkey, keyagg_cache, tweak32, 1);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
/**********************************************************************
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_MUSIG_MAIN_H
|
||||
#define SECP256K1_MODULE_MUSIG_MAIN_H
|
||||
|
||||
#include "keyagg_impl.h"
|
||||
#include "session_impl.h"
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,24 @@
|
||||
/***********************************************************************
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_MUSIG_SESSION_H
|
||||
#define SECP256K1_MODULE_MUSIG_SESSION_H
|
||||
|
||||
#include "../../../include/secp256k1.h"
|
||||
#include "../../../include/secp256k1_musig.h"
|
||||
|
||||
#include "../../scalar.h"
|
||||
|
||||
typedef struct {
|
||||
int fin_nonce_parity;
|
||||
unsigned char fin_nonce[32];
|
||||
secp256k1_scalar noncecoef;
|
||||
secp256k1_scalar challenge;
|
||||
secp256k1_scalar s_part;
|
||||
} secp256k1_musig_session_internal;
|
||||
|
||||
static int secp256k1_musig_session_load(const secp256k1_context* ctx, secp256k1_musig_session_internal *session_i, const secp256k1_musig_session *session);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,795 @@
|
||||
/***********************************************************************
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_MUSIG_SESSION_IMPL_H
|
||||
#define SECP256K1_MODULE_MUSIG_SESSION_IMPL_H
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "../../../include/secp256k1.h"
|
||||
#include "../../../include/secp256k1_extrakeys.h"
|
||||
#include "../../../include/secp256k1_musig.h"
|
||||
|
||||
#include "keyagg.h"
|
||||
#include "session.h"
|
||||
#include "../../eckey.h"
|
||||
#include "../../hash.h"
|
||||
#include "../../scalar.h"
|
||||
#include "../../util.h"
|
||||
|
||||
/* Outputs 33 zero bytes if the given group element is the point at infinity and
|
||||
* otherwise outputs the compressed serialization */
|
||||
static void secp256k1_musig_ge_serialize_ext(unsigned char *out33, secp256k1_ge* ge) {
|
||||
if (secp256k1_ge_is_infinity(ge)) {
|
||||
memset(out33, 0, 33);
|
||||
} else {
|
||||
/* Serialize must succeed because the point is not at infinity */
|
||||
secp256k1_eckey_pubkey_serialize33(ge, out33);
|
||||
}
|
||||
}
|
||||
|
||||
/* Outputs the point at infinity if the given byte array is all zero, otherwise
|
||||
* attempts to parse compressed point serialization. */
|
||||
static int secp256k1_musig_ge_parse_ext(secp256k1_ge* ge, const unsigned char *in33) {
|
||||
unsigned char zeros[33] = { 0 };
|
||||
|
||||
if (secp256k1_memcmp_var(in33, zeros, sizeof(zeros)) == 0) {
|
||||
secp256k1_ge_set_infinity(ge);
|
||||
return 1;
|
||||
}
|
||||
if (!secp256k1_eckey_pubkey_parse(ge, in33, 33)) {
|
||||
return 0;
|
||||
}
|
||||
return secp256k1_ge_is_in_correct_subgroup(ge);
|
||||
}
|
||||
|
||||
static const unsigned char secp256k1_musig_secnonce_magic[4] = { 0x22, 0x0e, 0xdc, 0xf1 };
|
||||
|
||||
static void secp256k1_musig_secnonce_save(secp256k1_musig_secnonce *secnonce, const secp256k1_scalar *k, const secp256k1_ge *pk) {
|
||||
memcpy(&secnonce->data[0], secp256k1_musig_secnonce_magic, 4);
|
||||
secp256k1_scalar_get_b32(&secnonce->data[4], &k[0]);
|
||||
secp256k1_scalar_get_b32(&secnonce->data[36], &k[1]);
|
||||
secp256k1_ge_to_bytes(&secnonce->data[68], pk);
|
||||
}
|
||||
|
||||
static int secp256k1_musig_secnonce_load(const secp256k1_context* ctx, secp256k1_scalar *k, secp256k1_ge *pk, const secp256k1_musig_secnonce *secnonce) {
|
||||
int is_zero;
|
||||
ARG_CHECK(secp256k1_memcmp_var(&secnonce->data[0], secp256k1_musig_secnonce_magic, 4) == 0);
|
||||
/* We make very sure that the nonce isn't invalidated by checking the values
|
||||
* in addition to the magic. */
|
||||
is_zero = secp256k1_is_zero_array(&secnonce->data[4], 2 * 32);
|
||||
secp256k1_declassify(ctx, &is_zero, sizeof(is_zero));
|
||||
ARG_CHECK(!is_zero);
|
||||
|
||||
secp256k1_scalar_set_b32(&k[0], &secnonce->data[4], NULL);
|
||||
secp256k1_scalar_set_b32(&k[1], &secnonce->data[36], NULL);
|
||||
secp256k1_ge_from_bytes(pk, &secnonce->data[68]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* If flag is 1, invalidate the secnonce; if flag is 0, leave it.
|
||||
* Constant-time. Flag must be 0 or 1. */
|
||||
static void secp256k1_musig_secnonce_invalidate(const secp256k1_context* ctx, secp256k1_musig_secnonce *secnonce, int flag) {
|
||||
secp256k1_memczero(secnonce->data, sizeof(secnonce->data), flag);
|
||||
/* The flag argument is usually classified. So, the line above makes the
|
||||
* magic and public key classified. However, we need both to be
|
||||
* declassified. Note that we don't declassify the entire object, because if
|
||||
* flag is 0, then k[0] and k[1] have not been zeroed. */
|
||||
secp256k1_declassify(ctx, secnonce->data, sizeof(secp256k1_musig_secnonce_magic));
|
||||
secp256k1_declassify(ctx, &secnonce->data[68], 64);
|
||||
}
|
||||
|
||||
static const unsigned char secp256k1_musig_pubnonce_magic[4] = { 0xf5, 0x7a, 0x3d, 0xa0 };
|
||||
|
||||
/* Saves two group elements into a pubnonce. Requires that none of the provided
|
||||
* group elements is infinity. */
|
||||
static void secp256k1_musig_pubnonce_save(secp256k1_musig_pubnonce* nonce, const secp256k1_ge* ges) {
|
||||
int i;
|
||||
memcpy(&nonce->data[0], secp256k1_musig_pubnonce_magic, 4);
|
||||
for (i = 0; i < 2; i++) {
|
||||
secp256k1_ge_to_bytes(nonce->data + 4+64*i, &ges[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Loads two group elements from a pubnonce. Returns 1 unless the nonce wasn't
|
||||
* properly initialized */
|
||||
static int secp256k1_musig_pubnonce_load(const secp256k1_context* ctx, secp256k1_ge* ges, const secp256k1_musig_pubnonce* nonce) {
|
||||
int i;
|
||||
|
||||
ARG_CHECK(secp256k1_memcmp_var(&nonce->data[0], secp256k1_musig_pubnonce_magic, 4) == 0);
|
||||
for (i = 0; i < 2; i++) {
|
||||
secp256k1_ge_from_bytes(&ges[i], nonce->data + 4 + 64*i);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const unsigned char secp256k1_musig_aggnonce_magic[4] = { 0xa8, 0xb7, 0xe4, 0x67 };
|
||||
|
||||
static void secp256k1_musig_aggnonce_save(secp256k1_musig_aggnonce* nonce, const secp256k1_ge* ges) {
|
||||
int i;
|
||||
memcpy(&nonce->data[0], secp256k1_musig_aggnonce_magic, 4);
|
||||
for (i = 0; i < 2; i++) {
|
||||
secp256k1_ge_to_bytes_ext(&nonce->data[4 + 64*i], &ges[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static int secp256k1_musig_aggnonce_load(const secp256k1_context* ctx, secp256k1_ge* ges, const secp256k1_musig_aggnonce* nonce) {
|
||||
int i;
|
||||
|
||||
ARG_CHECK(secp256k1_memcmp_var(&nonce->data[0], secp256k1_musig_aggnonce_magic, 4) == 0);
|
||||
for (i = 0; i < 2; i++) {
|
||||
secp256k1_ge_from_bytes_ext(&ges[i], &nonce->data[4 + 64*i]);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const unsigned char secp256k1_musig_session_cache_magic[4] = { 0x9d, 0xed, 0xe9, 0x17 };
|
||||
|
||||
/* A session consists of
|
||||
* - 4 byte session cache magic
|
||||
* - 1 byte the parity of the final nonce
|
||||
* - 32 byte serialized x-only final nonce
|
||||
* - 32 byte nonce coefficient b
|
||||
* - 32 byte signature challenge hash e
|
||||
* - 32 byte scalar s that is added to the partial signatures of the signers
|
||||
*/
|
||||
static void secp256k1_musig_session_save(secp256k1_musig_session *session, const secp256k1_musig_session_internal *session_i) {
|
||||
unsigned char *ptr = session->data;
|
||||
|
||||
memcpy(ptr, secp256k1_musig_session_cache_magic, 4);
|
||||
ptr += 4;
|
||||
*ptr = session_i->fin_nonce_parity;
|
||||
ptr += 1;
|
||||
memcpy(ptr, session_i->fin_nonce, 32);
|
||||
ptr += 32;
|
||||
secp256k1_scalar_get_b32(ptr, &session_i->noncecoef);
|
||||
ptr += 32;
|
||||
secp256k1_scalar_get_b32(ptr, &session_i->challenge);
|
||||
ptr += 32;
|
||||
secp256k1_scalar_get_b32(ptr, &session_i->s_part);
|
||||
}
|
||||
|
||||
static int secp256k1_musig_session_load(const secp256k1_context* ctx, secp256k1_musig_session_internal *session_i, const secp256k1_musig_session *session) {
|
||||
const unsigned char *ptr = session->data;
|
||||
|
||||
ARG_CHECK(secp256k1_memcmp_var(ptr, secp256k1_musig_session_cache_magic, 4) == 0);
|
||||
ptr += 4;
|
||||
session_i->fin_nonce_parity = *ptr;
|
||||
ptr += 1;
|
||||
memcpy(session_i->fin_nonce, ptr, 32);
|
||||
ptr += 32;
|
||||
secp256k1_scalar_set_b32(&session_i->noncecoef, ptr, NULL);
|
||||
ptr += 32;
|
||||
secp256k1_scalar_set_b32(&session_i->challenge, ptr, NULL);
|
||||
ptr += 32;
|
||||
secp256k1_scalar_set_b32(&session_i->s_part, ptr, NULL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const unsigned char secp256k1_musig_partial_sig_magic[4] = { 0xeb, 0xfb, 0x1a, 0x32 };
|
||||
|
||||
static void secp256k1_musig_partial_sig_save(secp256k1_musig_partial_sig* sig, secp256k1_scalar *s) {
|
||||
memcpy(&sig->data[0], secp256k1_musig_partial_sig_magic, 4);
|
||||
secp256k1_scalar_get_b32(&sig->data[4], s);
|
||||
}
|
||||
|
||||
static int secp256k1_musig_partial_sig_load(const secp256k1_context* ctx, secp256k1_scalar *s, const secp256k1_musig_partial_sig* sig) {
|
||||
int overflow;
|
||||
|
||||
ARG_CHECK(secp256k1_memcmp_var(&sig->data[0], secp256k1_musig_partial_sig_magic, 4) == 0);
|
||||
secp256k1_scalar_set_b32(s, &sig->data[4], &overflow);
|
||||
/* Parsed signatures can not overflow */
|
||||
VERIFY_CHECK(!overflow);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_pubnonce_parse(const secp256k1_context* ctx, secp256k1_musig_pubnonce* nonce, const unsigned char *in66) {
|
||||
secp256k1_ge ges[2];
|
||||
int i;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(nonce != NULL);
|
||||
ARG_CHECK(in66 != NULL);
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
if (!secp256k1_eckey_pubkey_parse(&ges[i], &in66[33*i], 33)) {
|
||||
return 0;
|
||||
}
|
||||
if (!secp256k1_ge_is_in_correct_subgroup(&ges[i])) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
secp256k1_musig_pubnonce_save(nonce, ges);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_pubnonce_serialize(const secp256k1_context* ctx, unsigned char *out66, const secp256k1_musig_pubnonce* nonce) {
|
||||
secp256k1_ge ges[2];
|
||||
int i;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(out66 != NULL);
|
||||
memset(out66, 0, 66);
|
||||
ARG_CHECK(nonce != NULL);
|
||||
|
||||
if (!secp256k1_musig_pubnonce_load(ctx, ges, nonce)) {
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i < 2; i++) {
|
||||
/* serialize must succeed because the point was just loaded */
|
||||
secp256k1_eckey_pubkey_serialize33(&ges[i], &out66[33*i]);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_aggnonce_parse(const secp256k1_context* ctx, secp256k1_musig_aggnonce* nonce, const unsigned char *in66) {
|
||||
secp256k1_ge ges[2];
|
||||
int i;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(nonce != NULL);
|
||||
ARG_CHECK(in66 != NULL);
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
if (!secp256k1_musig_ge_parse_ext(&ges[i], &in66[33*i])) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
secp256k1_musig_aggnonce_save(nonce, ges);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_aggnonce_serialize(const secp256k1_context* ctx, unsigned char *out66, const secp256k1_musig_aggnonce* nonce) {
|
||||
secp256k1_ge ges[2];
|
||||
int i;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(out66 != NULL);
|
||||
memset(out66, 0, 66);
|
||||
ARG_CHECK(nonce != NULL);
|
||||
|
||||
if (!secp256k1_musig_aggnonce_load(ctx, ges, nonce)) {
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i < 2; i++) {
|
||||
secp256k1_musig_ge_serialize_ext(&out66[33*i], &ges[i]);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_partial_sig_parse(const secp256k1_context* ctx, secp256k1_musig_partial_sig* sig, const unsigned char *in32) {
|
||||
secp256k1_scalar tmp;
|
||||
int overflow;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(sig != NULL);
|
||||
ARG_CHECK(in32 != NULL);
|
||||
|
||||
/* Ensure that using the signature will fail if parsing fails (and the user
|
||||
* doesn't check the return value). */
|
||||
memset(sig, 0, sizeof(*sig));
|
||||
|
||||
secp256k1_scalar_set_b32(&tmp, in32, &overflow);
|
||||
if (overflow) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_musig_partial_sig_save(sig, &tmp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_partial_sig_serialize(const secp256k1_context* ctx, unsigned char *out32, const secp256k1_musig_partial_sig* sig) {
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(out32 != NULL);
|
||||
ARG_CHECK(sig != NULL);
|
||||
ARG_CHECK(secp256k1_memcmp_var(&sig->data[0], secp256k1_musig_partial_sig_magic, 4) == 0);
|
||||
|
||||
memcpy(out32, &sig->data[4], 32);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Write optional inputs into the hash */
|
||||
static void secp256k1_nonce_function_musig_helper(const secp256k1_hash_ctx *hash_ctx, secp256k1_sha256 *sha, unsigned int prefix_size, const unsigned char *data, unsigned char len) {
|
||||
unsigned char zero[7] = { 0 };
|
||||
/* The spec requires length prefixes to be between 1 and 8 bytes
|
||||
* (inclusive) */
|
||||
VERIFY_CHECK(prefix_size >= 1 && prefix_size <= 8);
|
||||
/* Since the length of all input data fits in a byte, we can always pad the
|
||||
* length prefix with prefix_size - 1 zero bytes. */
|
||||
secp256k1_sha256_write(hash_ctx, sha, zero, prefix_size - 1);
|
||||
if (data != NULL) {
|
||||
secp256k1_sha256_write(hash_ctx, sha, &len, 1);
|
||||
secp256k1_sha256_write(hash_ctx, sha, data, len);
|
||||
} else {
|
||||
len = 0;
|
||||
secp256k1_sha256_write(hash_ctx, sha, &len, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
|
||||
* SHA256 to SHA256("MuSig/aux")||SHA256("MuSig/aux"). */
|
||||
static void secp256k1_nonce_function_musig_sha256_tagged_aux(secp256k1_sha256 *sha) {
|
||||
static const uint32_t midstate[8] = {
|
||||
0xa19e884bul, 0xf463fe7eul, 0x2f18f9a2ul, 0xbeb0f9fful,
|
||||
0x0f37e8b0ul, 0x06ebd26ful, 0xe3b243d2ul, 0x522fb150ul
|
||||
};
|
||||
secp256k1_sha256_initialize_midstate(sha, 64, midstate);
|
||||
}
|
||||
|
||||
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
|
||||
* SHA256 to SHA256("MuSig/nonce")||SHA256("MuSig/nonce"). */
|
||||
static void secp256k1_nonce_function_musig_sha256_tagged(secp256k1_sha256 *sha) {
|
||||
static const uint32_t midstate[8] = {
|
||||
0x07101b64ul, 0x18003414ul, 0x0391bc43ul, 0x0e6258eeul,
|
||||
0x29d26b72ul, 0x8343937eul, 0xb7a0a4fbul, 0xff568a30ul
|
||||
};
|
||||
secp256k1_sha256_initialize_midstate(sha, 64, midstate);
|
||||
}
|
||||
|
||||
static void secp256k1_nonce_function_musig(const secp256k1_hash_ctx *hash_ctx, secp256k1_scalar *k, const unsigned char *session_secrand, const unsigned char *msg32, const unsigned char *seckey32, const unsigned char *pk33, const unsigned char *agg_pk32, const unsigned char *extra_input32) {
|
||||
secp256k1_sha256 sha;
|
||||
unsigned char rand[32];
|
||||
unsigned char i;
|
||||
unsigned char msg_present;
|
||||
|
||||
if (seckey32 != NULL) {
|
||||
secp256k1_nonce_function_musig_sha256_tagged_aux(&sha);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, session_secrand, 32);
|
||||
secp256k1_sha256_finalize(hash_ctx, &sha, rand);
|
||||
for (i = 0; i < 32; i++) {
|
||||
rand[i] ^= seckey32[i];
|
||||
}
|
||||
} else {
|
||||
memcpy(rand, session_secrand, sizeof(rand));
|
||||
}
|
||||
|
||||
secp256k1_nonce_function_musig_sha256_tagged(&sha);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, rand, sizeof(rand));
|
||||
secp256k1_nonce_function_musig_helper(hash_ctx, &sha, 1, pk33, 33);
|
||||
secp256k1_nonce_function_musig_helper(hash_ctx, &sha, 1, agg_pk32, 32);
|
||||
msg_present = msg32 != NULL;
|
||||
secp256k1_sha256_write(hash_ctx, &sha, &msg_present, 1);
|
||||
if (msg_present) {
|
||||
secp256k1_nonce_function_musig_helper(hash_ctx, &sha, 8, msg32, 32);
|
||||
}
|
||||
secp256k1_nonce_function_musig_helper(hash_ctx, &sha, 4, extra_input32, 32);
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
unsigned char buf[32];
|
||||
secp256k1_sha256 sha_tmp = sha;
|
||||
secp256k1_sha256_write(hash_ctx, &sha_tmp, &i, 1);
|
||||
secp256k1_sha256_finalize(hash_ctx, &sha_tmp, buf);
|
||||
secp256k1_scalar_set_b32(&k[i], buf, NULL);
|
||||
|
||||
/* Attempt to erase secret data */
|
||||
secp256k1_memclear_explicit(buf, sizeof(buf));
|
||||
secp256k1_sha256_clear(&sha_tmp);
|
||||
}
|
||||
secp256k1_memclear_explicit(rand, sizeof(rand));
|
||||
secp256k1_sha256_clear(&sha);
|
||||
}
|
||||
|
||||
static int secp256k1_musig_nonce_gen_internal(const secp256k1_context* ctx, secp256k1_musig_secnonce *secnonce, secp256k1_musig_pubnonce *pubnonce, const unsigned char *input_nonce, const unsigned char *seckey, const secp256k1_pubkey *pubkey, const unsigned char *msg32, const secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *extra_input32) {
|
||||
secp256k1_scalar k[2];
|
||||
secp256k1_ge nonce_pts[2];
|
||||
secp256k1_gej nonce_ptj[2];
|
||||
int i;
|
||||
unsigned char pk_ser[33];
|
||||
unsigned char aggpk_ser[32];
|
||||
unsigned char *aggpk_ser_ptr = NULL;
|
||||
secp256k1_ge pk;
|
||||
int ret = 1;
|
||||
|
||||
ARG_CHECK(pubnonce != NULL);
|
||||
memset(pubnonce, 0, sizeof(*pubnonce));
|
||||
ARG_CHECK(pubkey != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
|
||||
/* Check that the seckey is valid to be able to sign for it later. */
|
||||
if (seckey != NULL) {
|
||||
secp256k1_scalar sk;
|
||||
ret &= secp256k1_scalar_set_b32_seckey(&sk, seckey);
|
||||
secp256k1_scalar_clear(&sk);
|
||||
}
|
||||
|
||||
if (keyagg_cache != NULL) {
|
||||
secp256k1_keyagg_cache_internal cache_i;
|
||||
if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) {
|
||||
return 0;
|
||||
}
|
||||
/* The loaded point cache_i.pk can not be the point at infinity. */
|
||||
secp256k1_fe_get_b32(aggpk_ser, &cache_i.pk.x);
|
||||
aggpk_ser_ptr = aggpk_ser;
|
||||
}
|
||||
if (!secp256k1_pubkey_load(ctx, &pk, pubkey)) {
|
||||
return 0;
|
||||
}
|
||||
/* A pubkey cannot be the point at infinity */
|
||||
secp256k1_eckey_pubkey_serialize33(&pk, pk_ser);
|
||||
|
||||
secp256k1_nonce_function_musig(secp256k1_get_hash_context(ctx), k, input_nonce, msg32, seckey, pk_ser, aggpk_ser_ptr, extra_input32);
|
||||
VERIFY_CHECK(!secp256k1_scalar_is_zero(&k[0]));
|
||||
VERIFY_CHECK(!secp256k1_scalar_is_zero(&k[1]));
|
||||
secp256k1_musig_secnonce_save(secnonce, k, &pk);
|
||||
secp256k1_musig_secnonce_invalidate(ctx, secnonce, !ret);
|
||||
|
||||
/* Compute pubnonce as two gejs */
|
||||
for (i = 0; i < 2; i++) {
|
||||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &nonce_ptj[i], &k[i]);
|
||||
secp256k1_scalar_clear(&k[i]);
|
||||
}
|
||||
|
||||
/* Batch convert to two public ges */
|
||||
secp256k1_ge_set_all_gej(nonce_pts, nonce_ptj, 2);
|
||||
for (i = 0; i < 2; i++) {
|
||||
secp256k1_gej_clear(&nonce_ptj[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
secp256k1_declassify(ctx, &nonce_pts[i], sizeof(nonce_pts[i]));
|
||||
}
|
||||
/* None of the nonce_pts will be infinity because k != 0 with overwhelming
|
||||
* probability */
|
||||
secp256k1_musig_pubnonce_save(pubnonce, nonce_pts);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int secp256k1_musig_nonce_gen(const secp256k1_context* ctx, secp256k1_musig_secnonce *secnonce, secp256k1_musig_pubnonce *pubnonce, unsigned char *session_secrand32, const unsigned char *seckey, const secp256k1_pubkey *pubkey, const unsigned char *msg32, const secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *extra_input32) {
|
||||
int ret = 1;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secnonce != NULL);
|
||||
memset(secnonce, 0, sizeof(*secnonce));
|
||||
ARG_CHECK(session_secrand32 != NULL);
|
||||
|
||||
/* Check in constant time that the session_secrand32 is not 0 as a
|
||||
* defense-in-depth measure that may protect against a faulty RNG. */
|
||||
ret &= !secp256k1_is_zero_array(session_secrand32, 32);
|
||||
|
||||
/* We can declassify because branching on ret is only relevant when this
|
||||
* function called with an invalid session_secrand32 argument */
|
||||
secp256k1_declassify(ctx, &ret, sizeof(ret));
|
||||
if (ret == 0) {
|
||||
secp256k1_musig_secnonce_invalidate(ctx, secnonce, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret &= secp256k1_musig_nonce_gen_internal(ctx, secnonce, pubnonce, session_secrand32, seckey, pubkey, msg32, keyagg_cache, extra_input32);
|
||||
|
||||
/* Set the session_secrand32 buffer to zero to prevent the caller from using
|
||||
* nonce_gen multiple times with the same buffer. */
|
||||
secp256k1_memczero(session_secrand32, 32, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int secp256k1_musig_nonce_gen_counter(const secp256k1_context* ctx, secp256k1_musig_secnonce *secnonce, secp256k1_musig_pubnonce *pubnonce, uint64_t nonrepeating_cnt, const secp256k1_keypair *keypair, const unsigned char *msg32, const secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *extra_input32) {
|
||||
unsigned char buf[32] = { 0 };
|
||||
unsigned char seckey[32];
|
||||
secp256k1_pubkey pubkey;
|
||||
int ret;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secnonce != NULL);
|
||||
memset(secnonce, 0, sizeof(*secnonce));
|
||||
ARG_CHECK(keypair != NULL);
|
||||
|
||||
secp256k1_write_be64(buf, nonrepeating_cnt);
|
||||
/* keypair_sec and keypair_pub do not fail if the arguments are not NULL */
|
||||
ret = secp256k1_keypair_sec(ctx, seckey, keypair);
|
||||
VERIFY_CHECK(ret);
|
||||
ret = secp256k1_keypair_pub(ctx, &pubkey, keypair);
|
||||
VERIFY_CHECK(ret);
|
||||
#ifndef VERIFY
|
||||
(void) ret;
|
||||
#endif
|
||||
|
||||
if (!secp256k1_musig_nonce_gen_internal(ctx, secnonce, pubnonce, buf, seckey, &pubkey, msg32, keyagg_cache, extra_input32)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_memclear_explicit(seckey, sizeof(seckey));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int secp256k1_musig_sum_pubnonces(const secp256k1_context* ctx, secp256k1_gej *summed_pubnonces, const secp256k1_musig_pubnonce * const* pubnonces, size_t n_pubnonces) {
|
||||
size_t i;
|
||||
int j;
|
||||
|
||||
secp256k1_gej_set_infinity(&summed_pubnonces[0]);
|
||||
secp256k1_gej_set_infinity(&summed_pubnonces[1]);
|
||||
|
||||
for (i = 0; i < n_pubnonces; i++) {
|
||||
secp256k1_ge nonce_pts[2];
|
||||
if (!secp256k1_musig_pubnonce_load(ctx, nonce_pts, pubnonces[i])) {
|
||||
return 0;
|
||||
}
|
||||
for (j = 0; j < 2; j++) {
|
||||
secp256k1_gej_add_ge_var(&summed_pubnonces[j], &summed_pubnonces[j], &nonce_pts[j], NULL);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_nonce_agg(const secp256k1_context* ctx, secp256k1_musig_aggnonce *aggnonce, const secp256k1_musig_pubnonce * const* pubnonces, size_t n_pubnonces) {
|
||||
secp256k1_gej aggnonce_ptsj[2];
|
||||
secp256k1_ge aggnonce_pts[2];
|
||||
size_t i;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(aggnonce != NULL);
|
||||
ARG_CHECK(pubnonces != NULL);
|
||||
ARG_CHECK(n_pubnonces > 0);
|
||||
for (i = 0; i < n_pubnonces; i++) {
|
||||
ARG_CHECK(pubnonces[i] != NULL);
|
||||
}
|
||||
|
||||
if (!secp256k1_musig_sum_pubnonces(ctx, aggnonce_ptsj, pubnonces, n_pubnonces)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_ge_set_all_gej_var(aggnonce_pts, aggnonce_ptsj, 2);
|
||||
secp256k1_musig_aggnonce_save(aggnonce, aggnonce_pts);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
|
||||
* SHA256 to SHA256("MuSig/noncecoef")||SHA256("MuSig/noncecoef"). */
|
||||
static void secp256k1_musig_compute_noncehash_sha256_tagged(secp256k1_sha256 *sha) {
|
||||
static const uint32_t midstate[8] = {
|
||||
0x2c7d5a45ul, 0x06bf7e53ul, 0x89be68a6ul, 0x971254c0ul,
|
||||
0x60ac12d2ul, 0x72846dcdul, 0x6c81212ful, 0xde7a2500ul
|
||||
};
|
||||
secp256k1_sha256_initialize_midstate(sha, 64, midstate);
|
||||
}
|
||||
|
||||
/* tagged_hash(aggnonce[0], aggnonce[1], agg_pk, msg) */
|
||||
static void secp256k1_musig_compute_noncehash(const secp256k1_hash_ctx *hash_ctx, unsigned char *noncehash, secp256k1_ge *aggnonce, const unsigned char *agg_pk32, const unsigned char *msg) {
|
||||
unsigned char buf[33];
|
||||
secp256k1_sha256 sha;
|
||||
int i;
|
||||
|
||||
secp256k1_musig_compute_noncehash_sha256_tagged(&sha);
|
||||
for (i = 0; i < 2; i++) {
|
||||
secp256k1_musig_ge_serialize_ext(buf, &aggnonce[i]);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, buf, sizeof(buf));
|
||||
}
|
||||
secp256k1_sha256_write(hash_ctx, &sha, agg_pk32, 32);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, msg, 32);
|
||||
secp256k1_sha256_finalize(hash_ctx, &sha, noncehash);
|
||||
}
|
||||
|
||||
/* out_nonce = nonce_pts[0] + b*nonce_pts[1] */
|
||||
static void secp256k1_effective_nonce(secp256k1_gej *out_nonce, const secp256k1_ge *nonce_pts, const secp256k1_scalar *b) {
|
||||
secp256k1_gej tmp;
|
||||
|
||||
secp256k1_gej_set_ge(&tmp, &nonce_pts[1]);
|
||||
secp256k1_ecmult(out_nonce, &tmp, b, NULL);
|
||||
secp256k1_gej_add_ge_var(out_nonce, out_nonce, &nonce_pts[0], NULL);
|
||||
}
|
||||
|
||||
static void secp256k1_musig_nonce_process_internal(const secp256k1_context *ctx, int *fin_nonce_parity, unsigned char *fin_nonce, secp256k1_scalar *b, secp256k1_ge *aggnonce_pts, const unsigned char *agg_pk32, const unsigned char *msg) {
|
||||
unsigned char noncehash[32];
|
||||
secp256k1_ge fin_nonce_pt;
|
||||
secp256k1_gej fin_nonce_ptj;
|
||||
|
||||
secp256k1_musig_compute_noncehash(secp256k1_get_hash_context(ctx), noncehash, aggnonce_pts, agg_pk32, msg);
|
||||
secp256k1_scalar_set_b32(b, noncehash, NULL);
|
||||
/* fin_nonce = aggnonce_pts[0] + b*aggnonce_pts[1] */
|
||||
secp256k1_effective_nonce(&fin_nonce_ptj, aggnonce_pts, b);
|
||||
secp256k1_ge_set_gej(&fin_nonce_pt, &fin_nonce_ptj);
|
||||
if (secp256k1_ge_is_infinity(&fin_nonce_pt)) {
|
||||
fin_nonce_pt = secp256k1_ge_const_g;
|
||||
}
|
||||
/* fin_nonce_pt is not the point at infinity */
|
||||
secp256k1_fe_normalize_var(&fin_nonce_pt.x);
|
||||
secp256k1_fe_get_b32(fin_nonce, &fin_nonce_pt.x);
|
||||
secp256k1_fe_normalize_var(&fin_nonce_pt.y);
|
||||
*fin_nonce_parity = secp256k1_fe_is_odd(&fin_nonce_pt.y);
|
||||
}
|
||||
|
||||
int secp256k1_musig_nonce_process(const secp256k1_context* ctx, secp256k1_musig_session *session, const secp256k1_musig_aggnonce *aggnonce, const unsigned char *msg32, const secp256k1_musig_keyagg_cache *keyagg_cache) {
|
||||
secp256k1_keyagg_cache_internal cache_i;
|
||||
secp256k1_ge aggnonce_pts[2];
|
||||
unsigned char fin_nonce[32];
|
||||
secp256k1_musig_session_internal session_i;
|
||||
unsigned char agg_pk32[32];
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(session != NULL);
|
||||
ARG_CHECK(aggnonce != NULL);
|
||||
ARG_CHECK(msg32 != NULL);
|
||||
ARG_CHECK(keyagg_cache != NULL);
|
||||
|
||||
if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_fe_get_b32(agg_pk32, &cache_i.pk.x);
|
||||
|
||||
if (!secp256k1_musig_aggnonce_load(ctx, aggnonce_pts, aggnonce)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_musig_nonce_process_internal(ctx, &session_i.fin_nonce_parity, fin_nonce, &session_i.noncecoef, aggnonce_pts, agg_pk32, msg32);
|
||||
secp256k1_schnorrsig_challenge(secp256k1_get_hash_context(ctx), &session_i.challenge, fin_nonce, msg32, 32, agg_pk32);
|
||||
|
||||
/* If there is a tweak then set `challenge` times `tweak` to the `s`-part.*/
|
||||
secp256k1_scalar_set_int(&session_i.s_part, 0);
|
||||
if (!secp256k1_scalar_is_zero(&cache_i.tweak)) {
|
||||
secp256k1_scalar e_tmp;
|
||||
secp256k1_scalar_mul(&e_tmp, &session_i.challenge, &cache_i.tweak);
|
||||
if (secp256k1_fe_is_odd(&cache_i.pk.y)) {
|
||||
secp256k1_scalar_negate(&e_tmp, &e_tmp);
|
||||
}
|
||||
session_i.s_part = e_tmp;
|
||||
}
|
||||
memcpy(session_i.fin_nonce, fin_nonce, sizeof(session_i.fin_nonce));
|
||||
secp256k1_musig_session_save(session, &session_i);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void secp256k1_musig_partial_sign_clear(secp256k1_scalar *sk, secp256k1_scalar *k) {
|
||||
secp256k1_scalar_clear(sk);
|
||||
secp256k1_scalar_clear(&k[0]);
|
||||
secp256k1_scalar_clear(&k[1]);
|
||||
}
|
||||
|
||||
int secp256k1_musig_partial_sign(const secp256k1_context* ctx, secp256k1_musig_partial_sig *partial_sig, secp256k1_musig_secnonce *secnonce, const secp256k1_keypair *keypair, const secp256k1_musig_keyagg_cache *keyagg_cache, const secp256k1_musig_session *session) {
|
||||
secp256k1_scalar sk;
|
||||
secp256k1_ge pk, keypair_pk;
|
||||
secp256k1_scalar k[2];
|
||||
secp256k1_scalar mu, s;
|
||||
secp256k1_keyagg_cache_internal cache_i;
|
||||
secp256k1_musig_session_internal session_i;
|
||||
int ret;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
|
||||
ARG_CHECK(secnonce != NULL);
|
||||
/* Fails if the magic doesn't match */
|
||||
ret = secp256k1_musig_secnonce_load(ctx, k, &pk, secnonce);
|
||||
/* Set nonce to zero to avoid nonce reuse. This will cause subsequent calls
|
||||
* of this function to fail */
|
||||
secp256k1_memzero_explicit(secnonce, sizeof(*secnonce));
|
||||
if (!ret) {
|
||||
secp256k1_musig_partial_sign_clear(&sk, k);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ARG_CHECK(partial_sig != NULL);
|
||||
ARG_CHECK(keypair != NULL);
|
||||
ARG_CHECK(keyagg_cache != NULL);
|
||||
ARG_CHECK(session != NULL);
|
||||
|
||||
if (!secp256k1_keypair_load(ctx, &sk, &keypair_pk, keypair)) {
|
||||
secp256k1_musig_partial_sign_clear(&sk, k);
|
||||
return 0;
|
||||
}
|
||||
ARG_CHECK(secp256k1_fe_equal(&pk.x, &keypair_pk.x)
|
||||
&& secp256k1_fe_equal(&pk.y, &keypair_pk.y));
|
||||
if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) {
|
||||
secp256k1_musig_partial_sign_clear(&sk, k);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Negate sk if secp256k1_fe_is_odd(&cache_i.pk.y)) XOR cache_i.parity_acc.
|
||||
* This corresponds to the line "Let d = g⋅gacc⋅d' mod n" in the
|
||||
* specification. */
|
||||
if ((secp256k1_fe_is_odd(&cache_i.pk.y)
|
||||
!= cache_i.parity_acc)) {
|
||||
secp256k1_scalar_negate(&sk, &sk);
|
||||
}
|
||||
|
||||
/* Multiply KeyAgg coefficient */
|
||||
secp256k1_musig_keyaggcoef(secp256k1_get_hash_context(ctx), &mu, &cache_i, &pk);
|
||||
secp256k1_scalar_mul(&sk, &sk, &mu);
|
||||
|
||||
if (!secp256k1_musig_session_load(ctx, &session_i, session)) {
|
||||
secp256k1_musig_partial_sign_clear(&sk, k);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (session_i.fin_nonce_parity) {
|
||||
secp256k1_scalar_negate(&k[0], &k[0]);
|
||||
secp256k1_scalar_negate(&k[1], &k[1]);
|
||||
}
|
||||
|
||||
/* Sign */
|
||||
secp256k1_scalar_mul(&s, &session_i.challenge, &sk);
|
||||
secp256k1_scalar_mul(&k[1], &session_i.noncecoef, &k[1]);
|
||||
secp256k1_scalar_add(&k[0], &k[0], &k[1]);
|
||||
secp256k1_scalar_add(&s, &s, &k[0]);
|
||||
secp256k1_musig_partial_sig_save(partial_sig, &s);
|
||||
secp256k1_musig_partial_sign_clear(&sk, k);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_partial_sig_verify(const secp256k1_context* ctx, const secp256k1_musig_partial_sig *partial_sig, const secp256k1_musig_pubnonce *pubnonce, const secp256k1_pubkey *pubkey, const secp256k1_musig_keyagg_cache *keyagg_cache, const secp256k1_musig_session *session) {
|
||||
secp256k1_keyagg_cache_internal cache_i;
|
||||
secp256k1_musig_session_internal session_i;
|
||||
secp256k1_scalar mu, e, s;
|
||||
secp256k1_gej pkj;
|
||||
secp256k1_ge nonce_pts[2];
|
||||
secp256k1_gej rj;
|
||||
secp256k1_gej tmp;
|
||||
secp256k1_ge pkp;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(partial_sig != NULL);
|
||||
ARG_CHECK(pubnonce != NULL);
|
||||
ARG_CHECK(pubkey != NULL);
|
||||
ARG_CHECK(keyagg_cache != NULL);
|
||||
ARG_CHECK(session != NULL);
|
||||
|
||||
if (!secp256k1_musig_session_load(ctx, &session_i, session)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!secp256k1_musig_pubnonce_load(ctx, nonce_pts, pubnonce)) {
|
||||
return 0;
|
||||
}
|
||||
/* Compute "effective" nonce rj = nonce_pts[0] + b*nonce_pts[1] */
|
||||
/* TODO: use multiexp to compute -s*G + e*mu*pubkey + nonce_pts[0] + b*nonce_pts[1] */
|
||||
secp256k1_effective_nonce(&rj, nonce_pts, &session_i.noncecoef);
|
||||
|
||||
if (!secp256k1_pubkey_load(ctx, &pkp, pubkey)) {
|
||||
return 0;
|
||||
}
|
||||
if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) {
|
||||
return 0;
|
||||
}
|
||||
/* Multiplying the challenge by the KeyAgg coefficient is equivalent
|
||||
* to multiplying the signer's public key by the coefficient, except
|
||||
* much easier to do. */
|
||||
secp256k1_musig_keyaggcoef(secp256k1_get_hash_context(ctx), &mu, &cache_i, &pkp);
|
||||
secp256k1_scalar_mul(&e, &session_i.challenge, &mu);
|
||||
|
||||
/* Negate e if secp256k1_fe_is_odd(&cache_i.pk.y)) XOR cache_i.parity_acc.
|
||||
* This corresponds to the line "Let g' = g⋅gacc mod n" and the multiplication "g'⋅e"
|
||||
* in the specification. */
|
||||
if (secp256k1_fe_is_odd(&cache_i.pk.y)
|
||||
!= cache_i.parity_acc) {
|
||||
secp256k1_scalar_negate(&e, &e);
|
||||
}
|
||||
|
||||
if (!secp256k1_musig_partial_sig_load(ctx, &s, partial_sig)) {
|
||||
return 0;
|
||||
}
|
||||
/* Compute -s*G + e*pkj + rj (e already includes the keyagg coefficient mu) */
|
||||
secp256k1_scalar_negate(&s, &s);
|
||||
secp256k1_gej_set_ge(&pkj, &pkp);
|
||||
secp256k1_ecmult(&tmp, &pkj, &e, &s);
|
||||
if (session_i.fin_nonce_parity) {
|
||||
secp256k1_gej_neg(&rj, &rj);
|
||||
}
|
||||
secp256k1_gej_add_var(&tmp, &tmp, &rj, NULL);
|
||||
|
||||
return secp256k1_gej_is_infinity(&tmp);
|
||||
}
|
||||
|
||||
int secp256k1_musig_partial_sig_agg(const secp256k1_context* ctx, unsigned char *sig64, const secp256k1_musig_session *session, const secp256k1_musig_partial_sig * const* partial_sigs, size_t n_sigs) {
|
||||
size_t i;
|
||||
secp256k1_musig_session_internal session_i;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(sig64 != NULL);
|
||||
ARG_CHECK(session != NULL);
|
||||
ARG_CHECK(partial_sigs != NULL);
|
||||
ARG_CHECK(n_sigs > 0);
|
||||
for (i = 0; i < n_sigs; i++) {
|
||||
ARG_CHECK(partial_sigs[i] != NULL);
|
||||
}
|
||||
|
||||
if (!secp256k1_musig_session_load(ctx, &session_i, session)) {
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i < n_sigs; i++) {
|
||||
secp256k1_scalar term;
|
||||
if (!secp256k1_musig_partial_sig_load(ctx, &term, partial_sigs[i])) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_scalar_add(&session_i.s_part, &session_i.s_part, &term);
|
||||
}
|
||||
secp256k1_scalar_get_b32(&sig64[32], &session_i.s_part);
|
||||
memcpy(&sig64[0], session_i.fin_nonce, 32);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,346 @@
|
||||
/**
|
||||
* Automatically generated by ./tools/test_vectors_musig2_generate.py.
|
||||
*
|
||||
* The test vectors for the KeySort function are included in this file. They can
|
||||
* be found in src/modules/extrakeys/tests_impl.h. */
|
||||
|
||||
enum MUSIG_ERROR {
|
||||
MUSIG_PUBKEY,
|
||||
MUSIG_TWEAK,
|
||||
MUSIG_PUBNONCE,
|
||||
MUSIG_AGGNONCE,
|
||||
MUSIG_SECNONCE,
|
||||
MUSIG_SIG,
|
||||
MUSIG_SIG_VERIFY,
|
||||
MUSIG_OTHER
|
||||
};
|
||||
|
||||
struct musig_key_agg_valid_test_case {
|
||||
size_t key_indices_len;
|
||||
size_t key_indices[4];
|
||||
unsigned char expected[32];
|
||||
};
|
||||
|
||||
struct musig_key_agg_error_test_case {
|
||||
size_t key_indices_len;
|
||||
size_t key_indices[4];
|
||||
size_t tweak_indices_len;
|
||||
size_t tweak_indices[1];
|
||||
int is_xonly[1];
|
||||
enum MUSIG_ERROR error;
|
||||
};
|
||||
|
||||
struct musig_key_agg_vector {
|
||||
unsigned char pubkeys[7][33];
|
||||
unsigned char tweaks[2][32];
|
||||
struct musig_key_agg_valid_test_case valid_case[4];
|
||||
struct musig_key_agg_error_test_case error_case[5];
|
||||
};
|
||||
|
||||
static const struct musig_key_agg_vector musig_key_agg_vector = {
|
||||
{
|
||||
{ 0x02, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 },
|
||||
{ 0x03, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 },
|
||||
{ 0x02, 0x35, 0x90, 0xA9, 0x4E, 0x76, 0x8F, 0x8E, 0x18, 0x15, 0xC2, 0xF2, 0x4B, 0x4D, 0x80, 0xA8, 0xE3, 0x14, 0x93, 0x16, 0xC3, 0x51, 0x8C, 0xE7, 0xB7, 0xAD, 0x33, 0x83, 0x68, 0xD0, 0x38, 0xCA, 0x66 },
|
||||
{ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05 },
|
||||
{ 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x30 },
|
||||
{ 0x04, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 },
|
||||
{ 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 }
|
||||
},
|
||||
{
|
||||
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 },
|
||||
{ 0x25, 0x2E, 0x4B, 0xD6, 0x74, 0x10, 0xA7, 0x6C, 0xDF, 0x93, 0x3D, 0x30, 0xEA, 0xA1, 0x60, 0x82, 0x14, 0x03, 0x7F, 0x1B, 0x10, 0x5A, 0x01, 0x3E, 0xCC, 0xD3, 0xC5, 0xC1, 0x84, 0xA6, 0x11, 0x0B }
|
||||
},
|
||||
{
|
||||
{ 3, { 0, 1, 2 }, { 0x90, 0x53, 0x9E, 0xED, 0xE5, 0x65, 0xF5, 0xD0, 0x54, 0xF3, 0x2C, 0xC0, 0xC2, 0x20, 0x12, 0x68, 0x89, 0xED, 0x1E, 0x5D, 0x19, 0x3B, 0xAF, 0x15, 0xAE, 0xF3, 0x44, 0xFE, 0x59, 0xD4, 0x61, 0x0C }},
|
||||
{ 3, { 2, 1, 0 }, { 0x62, 0x04, 0xDE, 0x8B, 0x08, 0x34, 0x26, 0xDC, 0x6E, 0xAF, 0x95, 0x02, 0xD2, 0x70, 0x24, 0xD5, 0x3F, 0xC8, 0x26, 0xBF, 0x7D, 0x20, 0x12, 0x14, 0x8A, 0x05, 0x75, 0x43, 0x5D, 0xF5, 0x4B, 0x2B }},
|
||||
{ 3, { 0, 0, 0 }, { 0xB4, 0x36, 0xE3, 0xBA, 0xD6, 0x2B, 0x8C, 0xD4, 0x09, 0x96, 0x9A, 0x22, 0x47, 0x31, 0xC1, 0x93, 0xD0, 0x51, 0x16, 0x2D, 0x8C, 0x5A, 0xE8, 0xB1, 0x09, 0x30, 0x61, 0x27, 0xDA, 0x3A, 0xA9, 0x35 }},
|
||||
{ 4, { 0, 0, 1, 1 }, { 0x69, 0xBC, 0x22, 0xBF, 0xA5, 0xD1, 0x06, 0x30, 0x6E, 0x48, 0xA2, 0x06, 0x79, 0xDE, 0x1D, 0x73, 0x89, 0x38, 0x61, 0x24, 0xD0, 0x75, 0x71, 0xD0, 0xD8, 0x72, 0x68, 0x60, 0x28, 0xC2, 0x6A, 0x3E }},
|
||||
},
|
||||
{
|
||||
{ 2, { 0, 3 }, 0, { 0 }, { 0 }, MUSIG_PUBKEY },
|
||||
{ 2, { 0, 4 }, 0, { 0 }, { 0 }, MUSIG_PUBKEY },
|
||||
{ 2, { 5, 0 }, 0, { 0 }, { 0 }, MUSIG_PUBKEY },
|
||||
{ 2, { 0, 1 }, 1, { 0 }, { 1 }, MUSIG_TWEAK },
|
||||
{ 1, { 6 }, 1, { 1 }, { 0 }, MUSIG_TWEAK },
|
||||
},
|
||||
};
|
||||
|
||||
struct musig_nonce_gen_test_case {
|
||||
unsigned char rand_[32];
|
||||
int has_sk;
|
||||
unsigned char sk[32];
|
||||
unsigned char pk[33];
|
||||
int has_aggpk;
|
||||
unsigned char aggpk[32];
|
||||
int has_msg;
|
||||
unsigned char msg[32];
|
||||
int has_extra_in;
|
||||
unsigned char extra_in[32];
|
||||
unsigned char expected_secnonce[97];
|
||||
unsigned char expected_pubnonce[66];
|
||||
};
|
||||
|
||||
struct musig_nonce_gen_vector {
|
||||
struct musig_nonce_gen_test_case test_case[2];
|
||||
};
|
||||
|
||||
static const struct musig_nonce_gen_vector musig_nonce_gen_vector = {
|
||||
{
|
||||
{ { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, 1 , { 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 }, { 0x02, 0x4D, 0x4B, 0x6C, 0xD1, 0x36, 0x10, 0x32, 0xCA, 0x9B, 0xD2, 0xAE, 0xB9, 0xD9, 0x00, 0xAA, 0x4D, 0x45, 0xD9, 0xEA, 0xD8, 0x0A, 0xC9, 0x42, 0x33, 0x74, 0xC4, 0x51, 0xA7, 0x25, 0x4D, 0x07, 0x66 }, 1 , { 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07 }, 1 , { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, 1 , { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 }, { 0xB1, 0x14, 0xE5, 0x02, 0xBE, 0xAA, 0x4E, 0x30, 0x1D, 0xD0, 0x8A, 0x50, 0x26, 0x41, 0x72, 0xC8, 0x4E, 0x41, 0x65, 0x0E, 0x6C, 0xB7, 0x26, 0xB4, 0x10, 0xC0, 0x69, 0x4D, 0x59, 0xEF, 0xFB, 0x64, 0x95, 0xB5, 0xCA, 0xF2, 0x8D, 0x04, 0x5B, 0x97, 0x3D, 0x63, 0xE3, 0xC9, 0x9A, 0x44, 0xB8, 0x07, 0xBD, 0xE3, 0x75, 0xFD, 0x6C, 0xB3, 0x9E, 0x46, 0xDC, 0x4A, 0x51, 0x17, 0x08, 0xD0, 0xE9, 0xD2, 0x02, 0x4D, 0x4B, 0x6C, 0xD1, 0x36, 0x10, 0x32, 0xCA, 0x9B, 0xD2, 0xAE, 0xB9, 0xD9, 0x00, 0xAA, 0x4D, 0x45, 0xD9, 0xEA, 0xD8, 0x0A, 0xC9, 0x42, 0x33, 0x74, 0xC4, 0x51, 0xA7, 0x25, 0x4D, 0x07, 0x66 }, { 0x02, 0xF7, 0xBE, 0x70, 0x89, 0xE8, 0x37, 0x6E, 0xB3, 0x55, 0x27, 0x23, 0x68, 0x76, 0x6B, 0x17, 0xE8, 0x8E, 0x7D, 0xB7, 0x20, 0x47, 0xD0, 0x5E, 0x56, 0xAA, 0x88, 0x1E, 0xA5, 0x2B, 0x3B, 0x35, 0xDF, 0x02, 0xC2, 0x9C, 0x80, 0x46, 0xFD, 0xD0, 0xDE, 0xD4, 0xC7, 0xE5, 0x58, 0x69, 0x13, 0x72, 0x00, 0xFB, 0xDB, 0xFE, 0x2E, 0xB6, 0x54, 0x26, 0x7B, 0x6D, 0x70, 0x13, 0x60, 0x2C, 0xAE, 0xD3, 0x11, 0x5A } },
|
||||
{ { 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }, 0 , { 0 }, { 0x02, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 }, 0 , { 0 }, 0 , { 0 }, 0 , { 0 }, { 0x89, 0xBD, 0xD7, 0x87, 0xD0, 0x28, 0x4E, 0x5E, 0x4D, 0x5F, 0xC5, 0x72, 0xE4, 0x9E, 0x31, 0x6B, 0xAB, 0x7E, 0x21, 0xE3, 0xB1, 0x83, 0x0D, 0xE3, 0x7D, 0xFE, 0x80, 0x15, 0x6F, 0xA4, 0x1A, 0x6D, 0x0B, 0x17, 0xAE, 0x8D, 0x02, 0x4C, 0x53, 0x67, 0x96, 0x99, 0xA6, 0xFD, 0x79, 0x44, 0xD9, 0xC4, 0xA3, 0x66, 0xB5, 0x14, 0xBA, 0xF4, 0x30, 0x88, 0xE0, 0x70, 0x8B, 0x10, 0x23, 0xDD, 0x28, 0x97, 0x02, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 }, { 0x02, 0xC9, 0x6E, 0x7C, 0xB1, 0xE8, 0xAA, 0x5D, 0xAC, 0x64, 0xD8, 0x72, 0x94, 0x79, 0x14, 0x19, 0x8F, 0x60, 0x7D, 0x90, 0xEC, 0xDE, 0x52, 0x00, 0xDE, 0x52, 0x97, 0x8A, 0xD5, 0xDE, 0xD6, 0x3C, 0x00, 0x02, 0x99, 0xEC, 0x51, 0x17, 0xC2, 0xD2, 0x9E, 0xDE, 0xE8, 0xA2, 0x09, 0x25, 0x87, 0xC3, 0x90, 0x9B, 0xE6, 0x94, 0xD5, 0xCF, 0xF0, 0x66, 0x7D, 0x6C, 0x02, 0xEA, 0x40, 0x59, 0xF7, 0xCD, 0x97, 0x86 } },
|
||||
},
|
||||
};
|
||||
|
||||
struct musig_nonce_agg_test_case {
|
||||
size_t pnonce_indices[2];
|
||||
/* if valid case */
|
||||
unsigned char expected[66];
|
||||
/* if error case */
|
||||
int invalid_nonce_idx;
|
||||
};
|
||||
|
||||
struct musig_nonce_agg_vector {
|
||||
unsigned char pnonces[7][66];
|
||||
struct musig_nonce_agg_test_case valid_case[2];
|
||||
struct musig_nonce_agg_test_case error_case[3];
|
||||
};
|
||||
|
||||
static const struct musig_nonce_agg_vector musig_nonce_agg_vector = {
|
||||
{
|
||||
{ 0x02, 0x01, 0x51, 0xC8, 0x0F, 0x43, 0x56, 0x48, 0xDF, 0x67, 0xA2, 0x2B, 0x74, 0x9C, 0xD7, 0x98, 0xCE, 0x54, 0xE0, 0x32, 0x1D, 0x03, 0x4B, 0x92, 0xB7, 0x09, 0xB5, 0x67, 0xD6, 0x0A, 0x42, 0xE6, 0x66, 0x03, 0xBA, 0x47, 0xFB, 0xC1, 0x83, 0x44, 0x37, 0xB3, 0x21, 0x2E, 0x89, 0xA8, 0x4D, 0x84, 0x25, 0xE7, 0xBF, 0x12, 0xE0, 0x24, 0x5D, 0x98, 0x26, 0x22, 0x68, 0xEB, 0xDC, 0xB3, 0x85, 0xD5, 0x06, 0x41 },
|
||||
{ 0x03, 0xFF, 0x40, 0x6F, 0xFD, 0x8A, 0xDB, 0x9C, 0xD2, 0x98, 0x77, 0xE4, 0x98, 0x50, 0x14, 0xF6, 0x6A, 0x59, 0xF6, 0xCD, 0x01, 0xC0, 0xE8, 0x8C, 0xAA, 0x8E, 0x5F, 0x31, 0x66, 0xB1, 0xF6, 0x76, 0xA6, 0x02, 0x48, 0xC2, 0x64, 0xCD, 0xD5, 0x7D, 0x3C, 0x24, 0xD7, 0x99, 0x90, 0xB0, 0xF8, 0x65, 0x67, 0x4E, 0xB6, 0x2A, 0x0F, 0x90, 0x18, 0x27, 0x7A, 0x95, 0x01, 0x1B, 0x41, 0xBF, 0xC1, 0x93, 0xB8, 0x33 },
|
||||
{ 0x02, 0x01, 0x51, 0xC8, 0x0F, 0x43, 0x56, 0x48, 0xDF, 0x67, 0xA2, 0x2B, 0x74, 0x9C, 0xD7, 0x98, 0xCE, 0x54, 0xE0, 0x32, 0x1D, 0x03, 0x4B, 0x92, 0xB7, 0x09, 0xB5, 0x67, 0xD6, 0x0A, 0x42, 0xE6, 0x66, 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98 },
|
||||
{ 0x03, 0xFF, 0x40, 0x6F, 0xFD, 0x8A, 0xDB, 0x9C, 0xD2, 0x98, 0x77, 0xE4, 0x98, 0x50, 0x14, 0xF6, 0x6A, 0x59, 0xF6, 0xCD, 0x01, 0xC0, 0xE8, 0x8C, 0xAA, 0x8E, 0x5F, 0x31, 0x66, 0xB1, 0xF6, 0x76, 0xA6, 0x03, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98 },
|
||||
{ 0x04, 0xFF, 0x40, 0x6F, 0xFD, 0x8A, 0xDB, 0x9C, 0xD2, 0x98, 0x77, 0xE4, 0x98, 0x50, 0x14, 0xF6, 0x6A, 0x59, 0xF6, 0xCD, 0x01, 0xC0, 0xE8, 0x8C, 0xAA, 0x8E, 0x5F, 0x31, 0x66, 0xB1, 0xF6, 0x76, 0xA6, 0x02, 0x48, 0xC2, 0x64, 0xCD, 0xD5, 0x7D, 0x3C, 0x24, 0xD7, 0x99, 0x90, 0xB0, 0xF8, 0x65, 0x67, 0x4E, 0xB6, 0x2A, 0x0F, 0x90, 0x18, 0x27, 0x7A, 0x95, 0x01, 0x1B, 0x41, 0xBF, 0xC1, 0x93, 0xB8, 0x33 },
|
||||
{ 0x03, 0xFF, 0x40, 0x6F, 0xFD, 0x8A, 0xDB, 0x9C, 0xD2, 0x98, 0x77, 0xE4, 0x98, 0x50, 0x14, 0xF6, 0x6A, 0x59, 0xF6, 0xCD, 0x01, 0xC0, 0xE8, 0x8C, 0xAA, 0x8E, 0x5F, 0x31, 0x66, 0xB1, 0xF6, 0x76, 0xA6, 0x02, 0x48, 0xC2, 0x64, 0xCD, 0xD5, 0x7D, 0x3C, 0x24, 0xD7, 0x99, 0x90, 0xB0, 0xF8, 0x65, 0x67, 0x4E, 0xB6, 0x2A, 0x0F, 0x90, 0x18, 0x27, 0x7A, 0x95, 0x01, 0x1B, 0x41, 0xBF, 0xC1, 0x93, 0xB8, 0x31 },
|
||||
{ 0x03, 0xFF, 0x40, 0x6F, 0xFD, 0x8A, 0xDB, 0x9C, 0xD2, 0x98, 0x77, 0xE4, 0x98, 0x50, 0x14, 0xF6, 0x6A, 0x59, 0xF6, 0xCD, 0x01, 0xC0, 0xE8, 0x8C, 0xAA, 0x8E, 0x5F, 0x31, 0x66, 0xB1, 0xF6, 0x76, 0xA6, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x30 }
|
||||
},
|
||||
{
|
||||
{ { 0, 1 }, { 0x03, 0x5F, 0xE1, 0x87, 0x3B, 0x4F, 0x29, 0x67, 0xF5, 0x2F, 0xEA, 0x4A, 0x06, 0xAD, 0x5A, 0x8E, 0xCC, 0xBE, 0x9D, 0x0F, 0xD7, 0x30, 0x68, 0x01, 0x2C, 0x89, 0x4E, 0x2E, 0x87, 0xCC, 0xB5, 0x80, 0x4B, 0x02, 0x47, 0x25, 0x37, 0x73, 0x45, 0xBD, 0xE0, 0xE9, 0xC3, 0x3A, 0xF3, 0xC4, 0x3C, 0x0A, 0x29, 0xA9, 0x24, 0x9F, 0x2F, 0x29, 0x56, 0xFA, 0x8C, 0xFE, 0xB5, 0x5C, 0x85, 0x73, 0xD0, 0x26, 0x2D, 0xC8 }, 0 },
|
||||
{ { 2, 3 }, { 0x03, 0x5F, 0xE1, 0x87, 0x3B, 0x4F, 0x29, 0x67, 0xF5, 0x2F, 0xEA, 0x4A, 0x06, 0xAD, 0x5A, 0x8E, 0xCC, 0xBE, 0x9D, 0x0F, 0xD7, 0x30, 0x68, 0x01, 0x2C, 0x89, 0x4E, 0x2E, 0x87, 0xCC, 0xB5, 0x80, 0x4B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0 },
|
||||
},
|
||||
{
|
||||
{ { 0, 4 }, { 0 }, 1 },
|
||||
{ { 5, 1 }, { 0 }, 0 },
|
||||
{ { 6, 1 }, { 0 }, 0 },
|
||||
},
|
||||
};
|
||||
|
||||
/* Omit pubnonces in the test vectors because our partial signature verification
|
||||
* implementation is able to accept the aggnonce directly. */
|
||||
struct musig_valid_case {
|
||||
size_t key_indices_len;
|
||||
size_t key_indices[3];
|
||||
size_t aggnonce_index;
|
||||
size_t msg_index;
|
||||
size_t signer_index;
|
||||
unsigned char expected[32];
|
||||
};
|
||||
|
||||
struct musig_sign_error_case {
|
||||
size_t key_indices_len;
|
||||
size_t key_indices[3];
|
||||
size_t aggnonce_index;
|
||||
size_t msg_index;
|
||||
size_t secnonce_index;
|
||||
enum MUSIG_ERROR error;
|
||||
};
|
||||
|
||||
struct musig_verify_fail_error_case {
|
||||
unsigned char sig[32];
|
||||
size_t key_indices_len;
|
||||
size_t key_indices[3];
|
||||
size_t nonce_indices_len;
|
||||
size_t nonce_indices[3];
|
||||
size_t msg_index;
|
||||
size_t signer_index;
|
||||
enum MUSIG_ERROR error;
|
||||
};
|
||||
|
||||
struct musig_sign_verify_vector {
|
||||
unsigned char sk[32];
|
||||
unsigned char pubkeys[4][33];
|
||||
unsigned char secnonces[2][194];
|
||||
unsigned char pubnonces[5][194];
|
||||
unsigned char aggnonces[5][66];
|
||||
unsigned char msgs[1][32];
|
||||
struct musig_valid_case valid_case[4];
|
||||
struct musig_sign_error_case sign_error_case[6];
|
||||
struct musig_verify_fail_error_case verify_fail_case[3];
|
||||
struct musig_verify_fail_error_case verify_error_case[2];
|
||||
};
|
||||
|
||||
static const struct musig_sign_verify_vector musig_sign_verify_vector = {
|
||||
{ 0x7F, 0xB9, 0xE0, 0xE6, 0x87, 0xAD, 0xA1, 0xEE, 0xBF, 0x7E, 0xCF, 0xE2, 0xF2, 0x1E, 0x73, 0xEB, 0xDB, 0x51, 0xA7, 0xD4, 0x50, 0x94, 0x8D, 0xFE, 0x8D, 0x76, 0xD7, 0xF2, 0xD1, 0x00, 0x76, 0x71 },
|
||||
{
|
||||
{ 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 },
|
||||
{ 0x02, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 },
|
||||
{ 0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x61 },
|
||||
{ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07 }
|
||||
},
|
||||
{
|
||||
{ 0x50, 0x8B, 0x81, 0xA6, 0x11, 0xF1, 0x00, 0xA6, 0xB2, 0xB6, 0xB2, 0x96, 0x56, 0x59, 0x08, 0x98, 0xAF, 0x48, 0x8B, 0xCF, 0x2E, 0x1F, 0x55, 0xCF, 0x22, 0xE5, 0xCF, 0xB8, 0x44, 0x21, 0xFE, 0x61, 0xFA, 0x27, 0xFD, 0x49, 0xB1, 0xD5, 0x00, 0x85, 0xB4, 0x81, 0x28, 0x5E, 0x1C, 0xA2, 0x05, 0xD5, 0x5C, 0x82, 0xCC, 0x1B, 0x31, 0xFF, 0x5C, 0xD5, 0x4A, 0x48, 0x98, 0x29, 0x35, 0x59, 0x01, 0xF7, 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 }
|
||||
},
|
||||
{
|
||||
{ 0x03, 0x37, 0xC8, 0x78, 0x21, 0xAF, 0xD5, 0x0A, 0x86, 0x44, 0xD8, 0x20, 0xA8, 0xF3, 0xE0, 0x2E, 0x49, 0x9C, 0x93, 0x18, 0x65, 0xC2, 0x36, 0x0F, 0xB4, 0x3D, 0x0A, 0x0D, 0x20, 0xDA, 0xFE, 0x07, 0xEA, 0x02, 0x87, 0xBF, 0x89, 0x1D, 0x2A, 0x6D, 0xEA, 0xEB, 0xAD, 0xC9, 0x09, 0x35, 0x2A, 0xA9, 0x40, 0x5D, 0x14, 0x28, 0xC1, 0x5F, 0x4B, 0x75, 0xF0, 0x4D, 0xAE, 0x64, 0x2A, 0x95, 0xC2, 0x54, 0x84, 0x80 },
|
||||
{ 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98, 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98 },
|
||||
{ 0x03, 0x2D, 0xE2, 0x66, 0x26, 0x28, 0xC9, 0x0B, 0x03, 0xF5, 0xE7, 0x20, 0x28, 0x4E, 0xB5, 0x2F, 0xF7, 0xD7, 0x1F, 0x42, 0x84, 0xF6, 0x27, 0xB6, 0x8A, 0x85, 0x3D, 0x78, 0xC7, 0x8E, 0x1F, 0xFE, 0x93, 0x03, 0xE4, 0xC5, 0x52, 0x4E, 0x83, 0xFF, 0xE1, 0x49, 0x3B, 0x90, 0x77, 0xCF, 0x1C, 0xA6, 0xBE, 0xB2, 0x09, 0x0C, 0x93, 0xD9, 0x30, 0x32, 0x10, 0x71, 0xAD, 0x40, 0xB2, 0xF4, 0x4E, 0x59, 0x90, 0x46 },
|
||||
{ 0x02, 0x37, 0xC8, 0x78, 0x21, 0xAF, 0xD5, 0x0A, 0x86, 0x44, 0xD8, 0x20, 0xA8, 0xF3, 0xE0, 0x2E, 0x49, 0x9C, 0x93, 0x18, 0x65, 0xC2, 0x36, 0x0F, 0xB4, 0x3D, 0x0A, 0x0D, 0x20, 0xDA, 0xFE, 0x07, 0xEA, 0x03, 0x87, 0xBF, 0x89, 0x1D, 0x2A, 0x6D, 0xEA, 0xEB, 0xAD, 0xC9, 0x09, 0x35, 0x2A, 0xA9, 0x40, 0x5D, 0x14, 0x28, 0xC1, 0x5F, 0x4B, 0x75, 0xF0, 0x4D, 0xAE, 0x64, 0x2A, 0x95, 0xC2, 0x54, 0x84, 0x80 },
|
||||
{ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x02, 0x87, 0xBF, 0x89, 0x1D, 0x2A, 0x6D, 0xEA, 0xEB, 0xAD, 0xC9, 0x09, 0x35, 0x2A, 0xA9, 0x40, 0x5D, 0x14, 0x28, 0xC1, 0x5F, 0x4B, 0x75, 0xF0, 0x4D, 0xAE, 0x64, 0x2A, 0x95, 0xC2, 0x54, 0x84, 0x80 }
|
||||
},
|
||||
{
|
||||
{ 0x02, 0x84, 0x65, 0xFC, 0xF0, 0xBB, 0xDB, 0xCF, 0x44, 0x3A, 0xAB, 0xCC, 0xE5, 0x33, 0xD4, 0x2B, 0x4B, 0x5A, 0x10, 0x96, 0x6A, 0xC0, 0x9A, 0x49, 0x65, 0x5E, 0x8C, 0x42, 0xDA, 0xAB, 0x8F, 0xCD, 0x61, 0x03, 0x74, 0x96, 0xA3, 0xCC, 0x86, 0x92, 0x6D, 0x45, 0x2C, 0xAF, 0xCF, 0xD5, 0x5D, 0x25, 0x97, 0x2C, 0xA1, 0x67, 0x5D, 0x54, 0x93, 0x10, 0xDE, 0x29, 0x6B, 0xFF, 0x42, 0xF7, 0x2E, 0xEE, 0xA8, 0xC9 },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x04, 0x84, 0x65, 0xFC, 0xF0, 0xBB, 0xDB, 0xCF, 0x44, 0x3A, 0xAB, 0xCC, 0xE5, 0x33, 0xD4, 0x2B, 0x4B, 0x5A, 0x10, 0x96, 0x6A, 0xC0, 0x9A, 0x49, 0x65, 0x5E, 0x8C, 0x42, 0xDA, 0xAB, 0x8F, 0xCD, 0x61, 0x03, 0x74, 0x96, 0xA3, 0xCC, 0x86, 0x92, 0x6D, 0x45, 0x2C, 0xAF, 0xCF, 0xD5, 0x5D, 0x25, 0x97, 0x2C, 0xA1, 0x67, 0x5D, 0x54, 0x93, 0x10, 0xDE, 0x29, 0x6B, 0xFF, 0x42, 0xF7, 0x2E, 0xEE, 0xA8, 0xC9 },
|
||||
{ 0x02, 0x84, 0x65, 0xFC, 0xF0, 0xBB, 0xDB, 0xCF, 0x44, 0x3A, 0xAB, 0xCC, 0xE5, 0x33, 0xD4, 0x2B, 0x4B, 0x5A, 0x10, 0x96, 0x6A, 0xC0, 0x9A, 0x49, 0x65, 0x5E, 0x8C, 0x42, 0xDA, 0xAB, 0x8F, 0xCD, 0x61, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09 },
|
||||
{ 0x02, 0x84, 0x65, 0xFC, 0xF0, 0xBB, 0xDB, 0xCF, 0x44, 0x3A, 0xAB, 0xCC, 0xE5, 0x33, 0xD4, 0x2B, 0x4B, 0x5A, 0x10, 0x96, 0x6A, 0xC0, 0x9A, 0x49, 0x65, 0x5E, 0x8C, 0x42, 0xDA, 0xAB, 0x8F, 0xCD, 0x61, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x30 }
|
||||
},
|
||||
{
|
||||
{ 0xF9, 0x54, 0x66, 0xD0, 0x86, 0x77, 0x0E, 0x68, 0x99, 0x64, 0x66, 0x42, 0x19, 0x26, 0x6F, 0xE5, 0xED, 0x21, 0x5C, 0x92, 0xAE, 0x20, 0xBA, 0xB5, 0xC9, 0xD7, 0x9A, 0xDD, 0xDD, 0xF3, 0xC0, 0xCF }
|
||||
},
|
||||
{
|
||||
{ 3, { 0, 1, 2 }, 0, 0, 0, { 0x01, 0x2A, 0xBB, 0xCB, 0x52, 0xB3, 0x01, 0x6A, 0xC0, 0x3A, 0xD8, 0x23, 0x95, 0xA1, 0xA4, 0x15, 0xC4, 0x8B, 0x93, 0xDE, 0xF7, 0x87, 0x18, 0xE6, 0x2A, 0x7A, 0x90, 0x05, 0x2F, 0xE2, 0x24, 0xFB }},
|
||||
{ 3, { 1, 0, 2 }, 0, 0, 1, { 0x9F, 0xF2, 0xF7, 0xAA, 0xA8, 0x56, 0x15, 0x0C, 0xC8, 0x81, 0x92, 0x54, 0x21, 0x8D, 0x3A, 0xDE, 0xEB, 0x05, 0x35, 0x26, 0x90, 0x51, 0x89, 0x77, 0x24, 0xF9, 0xDB, 0x37, 0x89, 0x51, 0x3A, 0x52 }},
|
||||
{ 3, { 1, 2, 0 }, 0, 0, 2, { 0xFA, 0x23, 0xC3, 0x59, 0xF6, 0xFA, 0xC4, 0xE7, 0x79, 0x6B, 0xB9, 0x3B, 0xC9, 0xF0, 0x53, 0x2A, 0x95, 0x46, 0x8C, 0x53, 0x9B, 0xA2, 0x0F, 0xF8, 0x6D, 0x7C, 0x76, 0xED, 0x92, 0x22, 0x79, 0x00 }},
|
||||
{ 2, { 0, 1 }, 1, 0, 0, { 0xAE, 0x38, 0x60, 0x64, 0xB2, 0x61, 0x05, 0x40, 0x47, 0x98, 0xF7, 0x5D, 0xE2, 0xEB, 0x9A, 0xF5, 0xED, 0xA5, 0x38, 0x7B, 0x06, 0x4B, 0x83, 0xD0, 0x49, 0xCB, 0x7C, 0x5E, 0x08, 0x87, 0x95, 0x31 }},
|
||||
},
|
||||
{
|
||||
{ 2, { 1, 2 }, 0, 0, 0, MUSIG_PUBKEY },
|
||||
{ 3, { 1, 0, 3 }, 0, 0, 0, MUSIG_PUBKEY },
|
||||
{ 3, { 1, 2, 0 }, 2, 0, 0, MUSIG_AGGNONCE },
|
||||
{ 3, { 1, 2, 0 }, 3, 0, 0, MUSIG_AGGNONCE },
|
||||
{ 3, { 1, 2, 0 }, 4, 0, 0, MUSIG_AGGNONCE },
|
||||
{ 3, { 0, 1, 2 }, 0, 0, 1, MUSIG_SECNONCE },
|
||||
},
|
||||
{
|
||||
{ { 0xFE, 0xD5, 0x44, 0x34, 0xAD, 0x4C, 0xFE, 0x95, 0x3F, 0xC5, 0x27, 0xDC, 0x6A, 0x5E, 0x5B, 0xE8, 0xF6, 0x23, 0x49, 0x07, 0xB7, 0xC1, 0x87, 0x55, 0x95, 0x57, 0xCE, 0x87, 0xA0, 0x54, 0x1C, 0x46 }, 3, { 0, 1, 2 }, 3, { 0, 1, 2 }, 0, 0, MUSIG_SIG_VERIFY },
|
||||
{ { 0x01, 0x2A, 0xBB, 0xCB, 0x52, 0xB3, 0x01, 0x6A, 0xC0, 0x3A, 0xD8, 0x23, 0x95, 0xA1, 0xA4, 0x15, 0xC4, 0x8B, 0x93, 0xDE, 0xF7, 0x87, 0x18, 0xE6, 0x2A, 0x7A, 0x90, 0x05, 0x2F, 0xE2, 0x24, 0xFB }, 3, { 0, 1, 2 }, 3, { 0, 1, 2 }, 0, 1, MUSIG_SIG_VERIFY },
|
||||
{ { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 }, 3, { 0, 1, 2 }, 3, { 0, 1, 2 }, 0, 0, MUSIG_SIG },
|
||||
},
|
||||
{
|
||||
{ { 0x01, 0x2A, 0xBB, 0xCB, 0x52, 0xB3, 0x01, 0x6A, 0xC0, 0x3A, 0xD8, 0x23, 0x95, 0xA1, 0xA4, 0x15, 0xC4, 0x8B, 0x93, 0xDE, 0xF7, 0x87, 0x18, 0xE6, 0x2A, 0x7A, 0x90, 0x05, 0x2F, 0xE2, 0x24, 0xFB }, 3, { 0, 1, 2 }, 3, { 4, 1, 2 }, 0, 0, MUSIG_PUBNONCE },
|
||||
{ { 0x01, 0x2A, 0xBB, 0xCB, 0x52, 0xB3, 0x01, 0x6A, 0xC0, 0x3A, 0xD8, 0x23, 0x95, 0xA1, 0xA4, 0x15, 0xC4, 0x8B, 0x93, 0xDE, 0xF7, 0x87, 0x18, 0xE6, 0x2A, 0x7A, 0x90, 0x05, 0x2F, 0xE2, 0x24, 0xFB }, 3, { 3, 1, 2 }, 3, { 0, 1, 2 }, 0, 0, MUSIG_PUBKEY },
|
||||
},
|
||||
};
|
||||
|
||||
struct musig_tweak_case {
|
||||
size_t key_indices_len;
|
||||
size_t key_indices[3];
|
||||
size_t nonce_indices_len;
|
||||
size_t nonce_indices[3];
|
||||
size_t tweak_indices_len;
|
||||
size_t tweak_indices[4];
|
||||
int is_xonly[4];
|
||||
size_t signer_index;
|
||||
unsigned char expected[32];
|
||||
};
|
||||
|
||||
struct musig_tweak_vector {
|
||||
unsigned char sk[32];
|
||||
unsigned char secnonce[97];
|
||||
unsigned char aggnonce[66];
|
||||
unsigned char msg[32];
|
||||
unsigned char pubkeys[3][33];
|
||||
unsigned char pubnonces[3][194];
|
||||
unsigned char tweaks[5][32];
|
||||
struct musig_tweak_case valid_case[5];
|
||||
struct musig_tweak_case error_case[1];
|
||||
};
|
||||
|
||||
static const struct musig_tweak_vector musig_tweak_vector = {
|
||||
{ 0x7F, 0xB9, 0xE0, 0xE6, 0x87, 0xAD, 0xA1, 0xEE, 0xBF, 0x7E, 0xCF, 0xE2, 0xF2, 0x1E, 0x73, 0xEB, 0xDB, 0x51, 0xA7, 0xD4, 0x50, 0x94, 0x8D, 0xFE, 0x8D, 0x76, 0xD7, 0xF2, 0xD1, 0x00, 0x76, 0x71 },
|
||||
{ 0x50, 0x8B, 0x81, 0xA6, 0x11, 0xF1, 0x00, 0xA6, 0xB2, 0xB6, 0xB2, 0x96, 0x56, 0x59, 0x08, 0x98, 0xAF, 0x48, 0x8B, 0xCF, 0x2E, 0x1F, 0x55, 0xCF, 0x22, 0xE5, 0xCF, 0xB8, 0x44, 0x21, 0xFE, 0x61, 0xFA, 0x27, 0xFD, 0x49, 0xB1, 0xD5, 0x00, 0x85, 0xB4, 0x81, 0x28, 0x5E, 0x1C, 0xA2, 0x05, 0xD5, 0x5C, 0x82, 0xCC, 0x1B, 0x31, 0xFF, 0x5C, 0xD5, 0x4A, 0x48, 0x98, 0x29, 0x35, 0x59, 0x01, 0xF7, 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 },
|
||||
{ 0x02, 0x84, 0x65, 0xFC, 0xF0, 0xBB, 0xDB, 0xCF, 0x44, 0x3A, 0xAB, 0xCC, 0xE5, 0x33, 0xD4, 0x2B, 0x4B, 0x5A, 0x10, 0x96, 0x6A, 0xC0, 0x9A, 0x49, 0x65, 0x5E, 0x8C, 0x42, 0xDA, 0xAB, 0x8F, 0xCD, 0x61, 0x03, 0x74, 0x96, 0xA3, 0xCC, 0x86, 0x92, 0x6D, 0x45, 0x2C, 0xAF, 0xCF, 0xD5, 0x5D, 0x25, 0x97, 0x2C, 0xA1, 0x67, 0x5D, 0x54, 0x93, 0x10, 0xDE, 0x29, 0x6B, 0xFF, 0x42, 0xF7, 0x2E, 0xEE, 0xA8, 0xC9 },
|
||||
{ 0xF9, 0x54, 0x66, 0xD0, 0x86, 0x77, 0x0E, 0x68, 0x99, 0x64, 0x66, 0x42, 0x19, 0x26, 0x6F, 0xE5, 0xED, 0x21, 0x5C, 0x92, 0xAE, 0x20, 0xBA, 0xB5, 0xC9, 0xD7, 0x9A, 0xDD, 0xDD, 0xF3, 0xC0, 0xCF },
|
||||
{
|
||||
{ 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 },
|
||||
{ 0x02, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 },
|
||||
{ 0x02, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, 0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 }
|
||||
},
|
||||
{
|
||||
{ 0x03, 0x37, 0xC8, 0x78, 0x21, 0xAF, 0xD5, 0x0A, 0x86, 0x44, 0xD8, 0x20, 0xA8, 0xF3, 0xE0, 0x2E, 0x49, 0x9C, 0x93, 0x18, 0x65, 0xC2, 0x36, 0x0F, 0xB4, 0x3D, 0x0A, 0x0D, 0x20, 0xDA, 0xFE, 0x07, 0xEA, 0x02, 0x87, 0xBF, 0x89, 0x1D, 0x2A, 0x6D, 0xEA, 0xEB, 0xAD, 0xC9, 0x09, 0x35, 0x2A, 0xA9, 0x40, 0x5D, 0x14, 0x28, 0xC1, 0x5F, 0x4B, 0x75, 0xF0, 0x4D, 0xAE, 0x64, 0x2A, 0x95, 0xC2, 0x54, 0x84, 0x80 },
|
||||
{ 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98, 0x02, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, 0x98 },
|
||||
{ 0x03, 0x2D, 0xE2, 0x66, 0x26, 0x28, 0xC9, 0x0B, 0x03, 0xF5, 0xE7, 0x20, 0x28, 0x4E, 0xB5, 0x2F, 0xF7, 0xD7, 0x1F, 0x42, 0x84, 0xF6, 0x27, 0xB6, 0x8A, 0x85, 0x3D, 0x78, 0xC7, 0x8E, 0x1F, 0xFE, 0x93, 0x03, 0xE4, 0xC5, 0x52, 0x4E, 0x83, 0xFF, 0xE1, 0x49, 0x3B, 0x90, 0x77, 0xCF, 0x1C, 0xA6, 0xBE, 0xB2, 0x09, 0x0C, 0x93, 0xD9, 0x30, 0x32, 0x10, 0x71, 0xAD, 0x40, 0xB2, 0xF4, 0x4E, 0x59, 0x90, 0x46 }
|
||||
},
|
||||
{
|
||||
{ 0xE8, 0xF7, 0x91, 0xFF, 0x92, 0x25, 0xA2, 0xAF, 0x01, 0x02, 0xAF, 0xFF, 0x4A, 0x9A, 0x72, 0x3D, 0x96, 0x12, 0xA6, 0x82, 0xA2, 0x5E, 0xBE, 0x79, 0x80, 0x2B, 0x26, 0x3C, 0xDF, 0xCD, 0x83, 0xBB },
|
||||
{ 0xAE, 0x2E, 0xA7, 0x97, 0xCC, 0x0F, 0xE7, 0x2A, 0xC5, 0xB9, 0x7B, 0x97, 0xF3, 0xC6, 0x95, 0x7D, 0x7E, 0x41, 0x99, 0xA1, 0x67, 0xA5, 0x8E, 0xB0, 0x8B, 0xCA, 0xFF, 0xDA, 0x70, 0xAC, 0x04, 0x55 },
|
||||
{ 0xF5, 0x2E, 0xCB, 0xC5, 0x65, 0xB3, 0xD8, 0xBE, 0xA2, 0xDF, 0xD5, 0xB7, 0x5A, 0x4F, 0x45, 0x7E, 0x54, 0x36, 0x98, 0x09, 0x32, 0x2E, 0x41, 0x20, 0x83, 0x16, 0x26, 0xF2, 0x90, 0xFA, 0x87, 0xE0 },
|
||||
{ 0x19, 0x69, 0xAD, 0x73, 0xCC, 0x17, 0x7F, 0xA0, 0xB4, 0xFC, 0xED, 0x6D, 0xF1, 0xF7, 0xBF, 0x99, 0x07, 0xE6, 0x65, 0xFD, 0xE9, 0xBA, 0x19, 0x6A, 0x74, 0xFE, 0xD0, 0xA3, 0xCF, 0x5A, 0xEF, 0x9D },
|
||||
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 }
|
||||
},
|
||||
{
|
||||
{ 3, { 1, 2, 0 }, 3, { 1, 2, 0 }, 1, { 0 }, { 1 }, 2, { 0xE2, 0x8A, 0x5C, 0x66, 0xE6, 0x1E, 0x17, 0x8C, 0x2B, 0xA1, 0x9D, 0xB7, 0x7B, 0x6C, 0xF9, 0xF7, 0xE2, 0xF0, 0xF5, 0x6C, 0x17, 0x91, 0x8C, 0xD1, 0x31, 0x35, 0xE6, 0x0C, 0xC8, 0x48, 0xFE, 0x91 }},
|
||||
{ 3, { 1, 2, 0 }, 3, { 1, 2, 0 }, 1, { 0 }, { 0 }, 2, { 0x38, 0xB0, 0x76, 0x77, 0x98, 0x25, 0x2F, 0x21, 0xBF, 0x57, 0x02, 0xC4, 0x80, 0x28, 0xB0, 0x95, 0x42, 0x83, 0x20, 0xF7, 0x3A, 0x4B, 0x14, 0xDB, 0x1E, 0x25, 0xDE, 0x58, 0x54, 0x3D, 0x2D, 0x2D }},
|
||||
{ 3, { 1, 2, 0 }, 3, { 1, 2, 0 }, 2, { 0, 1 }, { 0, 1 }, 2, { 0x40, 0x8A, 0x0A, 0x21, 0xC4, 0xA0, 0xF5, 0xDA, 0xCA, 0xF9, 0x64, 0x6A, 0xD6, 0xEB, 0x6F, 0xEC, 0xD7, 0xF7, 0xA1, 0x1F, 0x03, 0xED, 0x1F, 0x48, 0xDF, 0xFF, 0x21, 0x85, 0xBC, 0x2C, 0x24, 0x08 }},
|
||||
{ 3, { 1, 2, 0 }, 3, { 1, 2, 0 }, 4, { 0, 1, 2, 3 }, { 0, 0, 1, 1 }, 2, { 0x45, 0xAB, 0xD2, 0x06, 0xE6, 0x1E, 0x3D, 0xF2, 0xEC, 0x9E, 0x26, 0x4A, 0x6F, 0xEC, 0x82, 0x92, 0x14, 0x1A, 0x63, 0x3C, 0x28, 0x58, 0x63, 0x88, 0x23, 0x55, 0x41, 0xF9, 0xAD, 0xE7, 0x54, 0x35 }},
|
||||
{ 3, { 1, 2, 0 }, 3, { 1, 2, 0 }, 4, { 0, 1, 2, 3 }, { 1, 0, 1, 0 }, 2, { 0xB2, 0x55, 0xFD, 0xCA, 0xC2, 0x7B, 0x40, 0xC7, 0xCE, 0x78, 0x48, 0xE2, 0xD3, 0xB7, 0xBF, 0x5E, 0xA0, 0xED, 0x75, 0x6D, 0xA8, 0x15, 0x65, 0xAC, 0x80, 0x4C, 0xCC, 0xA3, 0xE1, 0xD5, 0xD2, 0x39 }},
|
||||
},
|
||||
{
|
||||
{ 3, { 1, 2, 0 }, 3, { 1, 2, 0 }, 1, { 4 }, { 0 }, 2, { 0 }},
|
||||
},
|
||||
};
|
||||
|
||||
/* Omit pubnonces in the test vectors because they're only needed for
|
||||
* implementations that do not directly accept an aggnonce. */
|
||||
struct musig_sig_agg_case {
|
||||
size_t key_indices_len;
|
||||
size_t key_indices[2];
|
||||
size_t tweak_indices_len;
|
||||
size_t tweak_indices[3];
|
||||
int is_xonly[3];
|
||||
unsigned char aggnonce[66];
|
||||
size_t psig_indices_len;
|
||||
size_t psig_indices[2];
|
||||
/* if valid case */
|
||||
unsigned char expected[64];
|
||||
/* if error case */
|
||||
int invalid_sig_idx;
|
||||
};
|
||||
|
||||
struct musig_sig_agg_vector {
|
||||
unsigned char pubkeys[4][33];
|
||||
unsigned char tweaks[3][32];
|
||||
unsigned char psigs[9][32];
|
||||
unsigned char msg[32];
|
||||
struct musig_sig_agg_case valid_case[4];
|
||||
struct musig_sig_agg_case error_case[1];
|
||||
};
|
||||
|
||||
static const struct musig_sig_agg_vector musig_sig_agg_vector = {
|
||||
{
|
||||
{ 0x03, 0x93, 0x5F, 0x97, 0x2D, 0xA0, 0x13, 0xF8, 0x0A, 0xE0, 0x11, 0x89, 0x0F, 0xA8, 0x9B, 0x67, 0xA2, 0x7B, 0x7B, 0xE6, 0xCC, 0xB2, 0x4D, 0x32, 0x74, 0xD1, 0x8B, 0x2D, 0x40, 0x67, 0xF2, 0x61, 0xA9 },
|
||||
{ 0x02, 0xD2, 0xDC, 0x6F, 0x5D, 0xF7, 0xC5, 0x6A, 0xCF, 0x38, 0xC7, 0xFA, 0x0A, 0xE7, 0xA7, 0x59, 0xAE, 0x30, 0xE1, 0x9B, 0x37, 0x35, 0x9D, 0xFD, 0xE0, 0x15, 0x87, 0x23, 0x24, 0xC7, 0xEF, 0x6E, 0x05 },
|
||||
{ 0x03, 0xC7, 0xFB, 0x10, 0x1D, 0x97, 0xFF, 0x93, 0x0A, 0xCD, 0x0C, 0x67, 0x60, 0x85, 0x2E, 0xF6, 0x4E, 0x69, 0x08, 0x3D, 0xE0, 0xB0, 0x6A, 0xC6, 0x33, 0x57, 0x24, 0x75, 0x4B, 0xB4, 0xB0, 0x52, 0x2C },
|
||||
{ 0x02, 0x35, 0x24, 0x33, 0xB2, 0x1E, 0x7E, 0x05, 0xD3, 0xB4, 0x52, 0xB8, 0x1C, 0xAE, 0x56, 0x6E, 0x06, 0xD2, 0xE0, 0x03, 0xEC, 0xE1, 0x6D, 0x10, 0x74, 0xAA, 0xBA, 0x42, 0x89, 0xE0, 0xE3, 0xD5, 0x81 }
|
||||
},
|
||||
{
|
||||
{ 0xB5, 0x11, 0xDA, 0x49, 0x21, 0x82, 0xA9, 0x1B, 0x0F, 0xFB, 0x9A, 0x98, 0x02, 0x0D, 0x55, 0xF2, 0x60, 0xAE, 0x86, 0xD7, 0xEC, 0xBD, 0x03, 0x99, 0xC7, 0x38, 0x3D, 0x59, 0xA5, 0xF2, 0xAF, 0x7C },
|
||||
{ 0xA8, 0x15, 0xFE, 0x04, 0x9E, 0xE3, 0xC5, 0xAA, 0xB6, 0x63, 0x10, 0x47, 0x7F, 0xBC, 0x8B, 0xCC, 0xCA, 0xC2, 0xF3, 0x39, 0x5F, 0x59, 0xF9, 0x21, 0xC3, 0x64, 0xAC, 0xD7, 0x8A, 0x2F, 0x48, 0xDC },
|
||||
{ 0x75, 0x44, 0x8A, 0x87, 0x27, 0x4B, 0x05, 0x64, 0x68, 0xB9, 0x77, 0xBE, 0x06, 0xEB, 0x1E, 0x9F, 0x65, 0x75, 0x77, 0xB7, 0x32, 0x0B, 0x0A, 0x33, 0x76, 0xEA, 0x51, 0xFD, 0x42, 0x0D, 0x18, 0xA8 }
|
||||
},
|
||||
{
|
||||
{ 0xB1, 0x5D, 0x2C, 0xD3, 0xC3, 0xD2, 0x2B, 0x04, 0xDA, 0xE4, 0x38, 0xCE, 0x65, 0x3F, 0x6B, 0x4E, 0xCF, 0x04, 0x2F, 0x42, 0xCF, 0xDE, 0xD7, 0xC4, 0x1B, 0x64, 0xAA, 0xF9, 0xB4, 0xAF, 0x53, 0xFB },
|
||||
{ 0x61, 0x93, 0xD6, 0xAC, 0x61, 0xB3, 0x54, 0xE9, 0x10, 0x5B, 0xBD, 0xC8, 0x93, 0x7A, 0x34, 0x54, 0xA6, 0xD7, 0x05, 0xB6, 0xD5, 0x73, 0x22, 0xA5, 0xA4, 0x72, 0xA0, 0x2C, 0xE9, 0x9F, 0xCB, 0x64 },
|
||||
{ 0x9A, 0x87, 0xD3, 0xB7, 0x9E, 0xC6, 0x72, 0x28, 0xCB, 0x97, 0x87, 0x8B, 0x76, 0x04, 0x9B, 0x15, 0xDB, 0xD0, 0x5B, 0x81, 0x58, 0xD1, 0x7B, 0x5B, 0x91, 0x14, 0xD3, 0xC2, 0x26, 0x88, 0x75, 0x05 },
|
||||
{ 0x66, 0xF8, 0x2E, 0xA9, 0x09, 0x23, 0x68, 0x9B, 0x85, 0x5D, 0x36, 0xC6, 0xB7, 0xE0, 0x32, 0xFB, 0x99, 0x70, 0x30, 0x14, 0x81, 0xB9, 0x9E, 0x01, 0xCD, 0xB4, 0xD6, 0xAC, 0x7C, 0x34, 0x7A, 0x15 },
|
||||
{ 0x4F, 0x5A, 0xEE, 0x41, 0x51, 0x08, 0x48, 0xA6, 0x44, 0x7D, 0xCD, 0x1B, 0xBC, 0x78, 0x45, 0x7E, 0xF6, 0x90, 0x24, 0x94, 0x4C, 0x87, 0xF4, 0x02, 0x50, 0xD3, 0xEF, 0x2C, 0x25, 0xD3, 0x3E, 0xFE },
|
||||
{ 0xDD, 0xEF, 0x42, 0x7B, 0xBB, 0x84, 0x7C, 0xC0, 0x27, 0xBE, 0xFF, 0x4E, 0xDB, 0x01, 0x03, 0x81, 0x48, 0x91, 0x78, 0x32, 0x25, 0x3E, 0xBC, 0x35, 0x5F, 0xC3, 0x3F, 0x4A, 0x8E, 0x2F, 0xCC, 0xE4 },
|
||||
{ 0x97, 0xB8, 0x90, 0xA2, 0x6C, 0x98, 0x1D, 0xA8, 0x10, 0x2D, 0x3B, 0xC2, 0x94, 0x15, 0x9D, 0x17, 0x1D, 0x72, 0x81, 0x0F, 0xDF, 0x7C, 0x6A, 0x69, 0x1D, 0xEF, 0x02, 0xF0, 0xF7, 0xAF, 0x3F, 0xDC },
|
||||
{ 0x53, 0xFA, 0x9E, 0x08, 0xBA, 0x52, 0x43, 0xCB, 0xCB, 0x0D, 0x79, 0x7C, 0x5E, 0xE8, 0x3B, 0xC6, 0x72, 0x8E, 0x53, 0x9E, 0xB7, 0x6C, 0x2D, 0x0B, 0xF0, 0xF9, 0x71, 0xEE, 0x4E, 0x90, 0x99, 0x71 },
|
||||
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41 }
|
||||
},
|
||||
{ 0x59, 0x9C, 0x67, 0xEA, 0x41, 0x0D, 0x00, 0x5B, 0x9D, 0xA9, 0x08, 0x17, 0xCF, 0x03, 0xED, 0x3B, 0x1C, 0x86, 0x8E, 0x4D, 0xA4, 0xED, 0xF0, 0x0A, 0x58, 0x80, 0xB0, 0x08, 0x2C, 0x23, 0x78, 0x69 },
|
||||
{
|
||||
{ 2, { 0, 1 }, 0, { 0 }, { 0 }, { 0x03, 0x41, 0x43, 0x27, 0x22, 0xC5, 0xCD, 0x02, 0x68, 0xD8, 0x29, 0xC7, 0x02, 0xCF, 0x0D, 0x1C, 0xBC, 0xE5, 0x70, 0x33, 0xEE, 0xD2, 0x01, 0xFD, 0x33, 0x51, 0x91, 0x38, 0x52, 0x27, 0xC3, 0x21, 0x0C, 0x03, 0xD3, 0x77, 0xF2, 0xD2, 0x58, 0xB6, 0x4A, 0xAD, 0xC0, 0xE1, 0x6F, 0x26, 0x46, 0x23, 0x23, 0xD7, 0x01, 0xD2, 0x86, 0x04, 0x6A, 0x2E, 0xA9, 0x33, 0x65, 0x65, 0x6A, 0xFD, 0x98, 0x75, 0x98, 0x2B }, 2, { 0, 1 }, { 0x04, 0x1D, 0xA2, 0x22, 0x23, 0xCE, 0x65, 0xC9, 0x2C, 0x9A, 0x0D, 0x6C, 0x2C, 0xAC, 0x82, 0x8A, 0xAF, 0x1E, 0xEE, 0x56, 0x30, 0x4F, 0xEC, 0x37, 0x1D, 0xDF, 0x91, 0xEB, 0xB2, 0xB9, 0xEF, 0x09, 0x12, 0xF1, 0x03, 0x80, 0x25, 0x85, 0x7F, 0xED, 0xEB, 0x3F, 0xF6, 0x96, 0xF8, 0xB9, 0x9F, 0xA4, 0xBB, 0x2C, 0x58, 0x12, 0xF6, 0x09, 0x5A, 0x2E, 0x00, 0x04, 0xEC, 0x99, 0xCE, 0x18, 0xDE, 0x1E }, 0 },
|
||||
{ 2, { 0, 2 }, 0, { 0 }, { 0 }, { 0x02, 0x24, 0xAF, 0xD3, 0x6C, 0x90, 0x20, 0x84, 0x05, 0x8B, 0x51, 0xB5, 0xD3, 0x66, 0x76, 0xBB, 0xA4, 0xDC, 0x97, 0xC7, 0x75, 0x87, 0x37, 0x68, 0xE5, 0x88, 0x22, 0xF8, 0x7F, 0xE4, 0x37, 0xD7, 0x92, 0x02, 0x8C, 0xB1, 0x59, 0x29, 0x09, 0x9E, 0xEE, 0x2F, 0x5D, 0xAE, 0x40, 0x4C, 0xD3, 0x93, 0x57, 0x59, 0x1B, 0xA3, 0x2E, 0x9A, 0xF4, 0xE1, 0x62, 0xB8, 0xD3, 0xE7, 0xCB, 0x5E, 0xFE, 0x31, 0xCB, 0x20 }, 2, { 2, 3 }, { 0x10, 0x69, 0xB6, 0x7E, 0xC3, 0xD2, 0xF3, 0xC7, 0xC0, 0x82, 0x91, 0xAC, 0xCB, 0x17, 0xA9, 0xC9, 0xB8, 0xF2, 0x81, 0x9A, 0x52, 0xEB, 0x5D, 0xF8, 0x72, 0x6E, 0x17, 0xE7, 0xD6, 0xB5, 0x2E, 0x9F, 0x01, 0x80, 0x02, 0x60, 0xA7, 0xE9, 0xDA, 0xC4, 0x50, 0xF4, 0xBE, 0x52, 0x2D, 0xE4, 0xCE, 0x12, 0xBA, 0x91, 0xAE, 0xAF, 0x2B, 0x42, 0x79, 0x21, 0x9E, 0xF7, 0x4B, 0xE1, 0xD2, 0x86, 0xAD, 0xD9 }, 0 },
|
||||
{ 2, { 0, 2 }, 1, { 0 }, { 0 }, { 0x02, 0x08, 0xC5, 0xC4, 0x38, 0xC7, 0x10, 0xF4, 0xF9, 0x6A, 0x61, 0xE9, 0xFF, 0x3C, 0x37, 0x75, 0x88, 0x14, 0xB8, 0xC3, 0xAE, 0x12, 0xBF, 0xEA, 0x0E, 0xD2, 0xC8, 0x7F, 0xF6, 0x95, 0x4F, 0xF1, 0x86, 0x02, 0x0B, 0x18, 0x16, 0xEA, 0x10, 0x4B, 0x4F, 0xCA, 0x2D, 0x30, 0x4D, 0x73, 0x3E, 0x0E, 0x19, 0xCE, 0xAD, 0x51, 0x30, 0x3F, 0xF6, 0x42, 0x0B, 0xFD, 0x22, 0x23, 0x35, 0xCA, 0xA4, 0x02, 0x91, 0x6D }, 2, { 4, 5 }, { 0x5C, 0x55, 0x8E, 0x1D, 0xCA, 0xDE, 0x86, 0xDA, 0x0B, 0x2F, 0x02, 0x62, 0x6A, 0x51, 0x2E, 0x30, 0xA2, 0x2C, 0xF5, 0x25, 0x5C, 0xAE, 0xA7, 0xEE, 0x32, 0xC3, 0x8E, 0x9A, 0x71, 0xA0, 0xE9, 0x14, 0x8B, 0xA6, 0xC0, 0xE6, 0xEC, 0x76, 0x83, 0xB6, 0x42, 0x20, 0xF0, 0x29, 0x86, 0x96, 0xF1, 0xB8, 0x78, 0xCD, 0x47, 0xB1, 0x07, 0xB8, 0x1F, 0x71, 0x88, 0x81, 0x2D, 0x59, 0x39, 0x71, 0xE0, 0xCC }, 0 },
|
||||
{ 2, { 0, 3 }, 3, { 0, 1, 2 }, { 1, 0, 1 }, { 0x02, 0xB5, 0xAD, 0x07, 0xAF, 0xCD, 0x99, 0xB6, 0xD9, 0x2C, 0xB4, 0x33, 0xFB, 0xD2, 0xA2, 0x8F, 0xDE, 0xB9, 0x8E, 0xAE, 0x2E, 0xB0, 0x9B, 0x60, 0x14, 0xEF, 0x0F, 0x81, 0x97, 0xCD, 0x58, 0x40, 0x33, 0x02, 0xE8, 0x61, 0x69, 0x10, 0xF9, 0x29, 0x3C, 0xF6, 0x92, 0xC4, 0x9F, 0x35, 0x1D, 0xB8, 0x6B, 0x25, 0xE3, 0x52, 0x90, 0x1F, 0x0E, 0x23, 0x7B, 0xAF, 0xDA, 0x11, 0xF1, 0xC1, 0xCE, 0xF2, 0x9F, 0xFD }, 2, { 6, 7 }, { 0x83, 0x9B, 0x08, 0x82, 0x0B, 0x68, 0x1D, 0xBA, 0x8D, 0xAF, 0x4C, 0xC7, 0xB1, 0x04, 0xE8, 0xF2, 0x63, 0x8F, 0x93, 0x88, 0xF8, 0xD7, 0xA5, 0x55, 0xDC, 0x17, 0xB6, 0xE6, 0x97, 0x1D, 0x74, 0x26, 0xCE, 0x07, 0xBF, 0x6A, 0xB0, 0x1F, 0x1D, 0xB5, 0x0E, 0x4E, 0x33, 0x71, 0x92, 0x95, 0xF4, 0x09, 0x45, 0x72, 0xB7, 0x98, 0x68, 0xE4, 0x40, 0xFB, 0x3D, 0xEF, 0xD3, 0xFA, 0xC1, 0xDB, 0x58, 0x9E }, 0 },
|
||||
},
|
||||
{
|
||||
{ 2, { 0, 3 }, 3, { 0, 1, 2 }, { 1, 0, 1 }, { 0x02, 0xB5, 0xAD, 0x07, 0xAF, 0xCD, 0x99, 0xB6, 0xD9, 0x2C, 0xB4, 0x33, 0xFB, 0xD2, 0xA2, 0x8F, 0xDE, 0xB9, 0x8E, 0xAE, 0x2E, 0xB0, 0x9B, 0x60, 0x14, 0xEF, 0x0F, 0x81, 0x97, 0xCD, 0x58, 0x40, 0x33, 0x02, 0xE8, 0x61, 0x69, 0x10, 0xF9, 0x29, 0x3C, 0xF6, 0x92, 0xC4, 0x9F, 0x35, 0x1D, 0xB8, 0x6B, 0x25, 0xE3, 0x52, 0x90, 0x1F, 0x0E, 0x23, 0x7B, 0xAF, 0xDA, 0x11, 0xF1, 0xC1, 0xCE, 0xF2, 0x9F, 0xFD }, 2, { 7, 8 }, { 0 }, 1 },
|
||||
},
|
||||
};
|
||||
enum { MUSIG_VECTORS_MAX_PUBKEYS = 7 };
|
||||
@@ -0,0 +1,5 @@
|
||||
include_HEADERS += include/secp256k1_recovery.h
|
||||
noinst_HEADERS += src/modules/recovery/main_impl.h
|
||||
noinst_HEADERS += src/modules/recovery/tests_impl.h
|
||||
noinst_HEADERS += src/modules/recovery/tests_exhaustive_impl.h
|
||||
noinst_HEADERS += src/modules/recovery/bench_impl.h
|
||||
@@ -0,0 +1,62 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2014-2015 Pieter Wuille *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_RECOVERY_BENCH_H
|
||||
#define SECP256K1_MODULE_RECOVERY_BENCH_H
|
||||
|
||||
#include "../../../include/secp256k1_recovery.h"
|
||||
|
||||
typedef struct {
|
||||
secp256k1_context *ctx;
|
||||
unsigned char msg[32];
|
||||
unsigned char sig[64];
|
||||
} bench_recover_data;
|
||||
|
||||
static void bench_recover(void* arg, int iters) {
|
||||
int i;
|
||||
bench_recover_data *data = (bench_recover_data*)arg;
|
||||
secp256k1_pubkey pubkey;
|
||||
unsigned char pubkeyc[33];
|
||||
|
||||
for (i = 0; i < iters; i++) {
|
||||
int j;
|
||||
size_t pubkeylen = 33;
|
||||
secp256k1_ecdsa_recoverable_signature sig;
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(data->ctx, &sig, data->sig, i % 2));
|
||||
CHECK(secp256k1_ecdsa_recover(data->ctx, &pubkey, &sig, data->msg));
|
||||
CHECK(secp256k1_ec_pubkey_serialize(data->ctx, pubkeyc, &pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED));
|
||||
for (j = 0; j < 32; j++) {
|
||||
data->sig[j + 32] = data->msg[j]; /* Move former message to S. */
|
||||
data->msg[j] = data->sig[j]; /* Move former R to message. */
|
||||
data->sig[j] = pubkeyc[j + 1]; /* Move recovered pubkey X coordinate to R (which must be a valid X coordinate). */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void bench_recover_setup(void* arg) {
|
||||
int i;
|
||||
bench_recover_data *data = (bench_recover_data*)arg;
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
data->msg[i] = 1 + i;
|
||||
}
|
||||
for (i = 0; i < 64; i++) {
|
||||
data->sig[i] = 65 + i;
|
||||
}
|
||||
}
|
||||
|
||||
static void run_recovery_bench(int iters, int argc, char** argv) {
|
||||
bench_recover_data data;
|
||||
int d = argc == 1;
|
||||
|
||||
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
||||
|
||||
if (d || have_flag(argc, argv, "ecdsa") || have_flag(argc, argv, "recover") || have_flag(argc, argv, "ecdsa_recover")) run_benchmark("ecdsa_recover", bench_recover, bench_recover_setup, NULL, &data, 10, iters);
|
||||
|
||||
secp256k1_context_destroy(data.ctx);
|
||||
}
|
||||
|
||||
#endif /* SECP256K1_MODULE_RECOVERY_BENCH_H */
|
||||
@@ -0,0 +1,159 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2013-2015 Pieter Wuille *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_RECOVERY_MAIN_H
|
||||
#define SECP256K1_MODULE_RECOVERY_MAIN_H
|
||||
|
||||
#include "../../../include/secp256k1_recovery.h"
|
||||
|
||||
static void secp256k1_ecdsa_recoverable_signature_load(const secp256k1_context* ctx, secp256k1_scalar* r, secp256k1_scalar* s, int* recid, const secp256k1_ecdsa_recoverable_signature* sig) {
|
||||
(void)ctx;
|
||||
if (sizeof(secp256k1_scalar) == 32) {
|
||||
/* When the secp256k1_scalar type is exactly 32 byte, use its
|
||||
* representation inside secp256k1_ecdsa_signature, as conversion is very fast.
|
||||
* Note that secp256k1_ecdsa_signature_save must use the same representation. */
|
||||
memcpy(r, &sig->data[0], 32);
|
||||
memcpy(s, &sig->data[32], 32);
|
||||
} else {
|
||||
secp256k1_scalar_set_b32(r, &sig->data[0], NULL);
|
||||
secp256k1_scalar_set_b32(s, &sig->data[32], NULL);
|
||||
}
|
||||
*recid = sig->data[64];
|
||||
}
|
||||
|
||||
static void secp256k1_ecdsa_recoverable_signature_save(secp256k1_ecdsa_recoverable_signature* sig, const secp256k1_scalar* r, const secp256k1_scalar* s, int recid) {
|
||||
if (sizeof(secp256k1_scalar) == 32) {
|
||||
memcpy(&sig->data[0], r, 32);
|
||||
memcpy(&sig->data[32], s, 32);
|
||||
} else {
|
||||
secp256k1_scalar_get_b32(&sig->data[0], r);
|
||||
secp256k1_scalar_get_b32(&sig->data[32], s);
|
||||
}
|
||||
sig->data[64] = recid;
|
||||
}
|
||||
|
||||
int secp256k1_ecdsa_recoverable_signature_parse_compact(const secp256k1_context* ctx, secp256k1_ecdsa_recoverable_signature* sig, const unsigned char *input64, int recid) {
|
||||
secp256k1_scalar r, s;
|
||||
int ret = 1;
|
||||
int overflow = 0;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(sig != NULL);
|
||||
ARG_CHECK(input64 != NULL);
|
||||
ARG_CHECK(recid >= 0 && recid <= 3);
|
||||
|
||||
secp256k1_scalar_set_b32(&r, &input64[0], &overflow);
|
||||
ret &= !overflow;
|
||||
secp256k1_scalar_set_b32(&s, &input64[32], &overflow);
|
||||
ret &= !overflow;
|
||||
if (ret) {
|
||||
secp256k1_ecdsa_recoverable_signature_save(sig, &r, &s, recid);
|
||||
} else {
|
||||
memset(sig, 0, sizeof(*sig));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int secp256k1_ecdsa_recoverable_signature_serialize_compact(const secp256k1_context* ctx, unsigned char *output64, int *recid, const secp256k1_ecdsa_recoverable_signature* sig) {
|
||||
secp256k1_scalar r, s;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(output64 != NULL);
|
||||
ARG_CHECK(sig != NULL);
|
||||
ARG_CHECK(recid != NULL);
|
||||
|
||||
secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, recid, sig);
|
||||
secp256k1_scalar_get_b32(&output64[0], &r);
|
||||
secp256k1_scalar_get_b32(&output64[32], &s);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_ecdsa_recoverable_signature_convert(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const secp256k1_ecdsa_recoverable_signature* sigin) {
|
||||
secp256k1_scalar r, s;
|
||||
int recid;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(sig != NULL);
|
||||
ARG_CHECK(sigin != NULL);
|
||||
|
||||
secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, sigin);
|
||||
secp256k1_ecdsa_signature_save(sig, &r, &s);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int secp256k1_ecdsa_sig_recover(const secp256k1_scalar *sigr, const secp256k1_scalar* sigs, secp256k1_ge *pubkey, const secp256k1_scalar *message, int recid) {
|
||||
unsigned char brx[32];
|
||||
secp256k1_fe fx;
|
||||
secp256k1_ge x;
|
||||
secp256k1_gej xj;
|
||||
secp256k1_scalar rn, u1, u2;
|
||||
secp256k1_gej qj;
|
||||
int r;
|
||||
|
||||
if (secp256k1_scalar_is_zero(sigr) || secp256k1_scalar_is_zero(sigs)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_scalar_get_b32(brx, sigr);
|
||||
r = secp256k1_fe_set_b32_limit(&fx, brx);
|
||||
(void)r;
|
||||
VERIFY_CHECK(r); /* brx comes from a scalar, so is less than the order; certainly less than p */
|
||||
if (recid & 2) {
|
||||
if (secp256k1_fe_cmp_var(&fx, &secp256k1_ecdsa_const_p_minus_order) >= 0) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_fe_add(&fx, &secp256k1_ecdsa_const_order_as_fe);
|
||||
}
|
||||
if (!secp256k1_ge_set_xo_var(&x, &fx, recid & 1)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_gej_set_ge(&xj, &x);
|
||||
secp256k1_scalar_inverse_var(&rn, sigr);
|
||||
secp256k1_scalar_mul(&u1, &rn, message);
|
||||
secp256k1_scalar_negate(&u1, &u1);
|
||||
secp256k1_scalar_mul(&u2, &rn, sigs);
|
||||
secp256k1_ecmult(&qj, &xj, &u2, &u1);
|
||||
secp256k1_ge_set_gej_var(pubkey, &qj);
|
||||
return !secp256k1_gej_is_infinity(&qj);
|
||||
}
|
||||
|
||||
int secp256k1_ecdsa_sign_recoverable(const secp256k1_context* ctx, secp256k1_ecdsa_recoverable_signature *signature, const unsigned char *msghash32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) {
|
||||
secp256k1_scalar r, s;
|
||||
int ret, recid;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
ARG_CHECK(msghash32 != NULL);
|
||||
ARG_CHECK(signature != NULL);
|
||||
ARG_CHECK(seckey != NULL);
|
||||
|
||||
ret = secp256k1_ecdsa_sign_inner(ctx, &r, &s, &recid, msghash32, seckey, noncefp, noncedata);
|
||||
secp256k1_ecdsa_recoverable_signature_save(signature, &r, &s, recid);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int secp256k1_ecdsa_recover(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const secp256k1_ecdsa_recoverable_signature *signature, const unsigned char *msghash32) {
|
||||
secp256k1_ge q;
|
||||
secp256k1_scalar r, s;
|
||||
secp256k1_scalar m;
|
||||
int recid;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(msghash32 != NULL);
|
||||
ARG_CHECK(signature != NULL);
|
||||
ARG_CHECK(pubkey != NULL);
|
||||
|
||||
secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, signature);
|
||||
VERIFY_CHECK(recid >= 0 && recid < 4); /* should have been caught in parse_compact */
|
||||
secp256k1_scalar_set_b32(&m, msghash32, NULL);
|
||||
if (secp256k1_ecdsa_sig_recover(&r, &s, &q, &m, recid)) {
|
||||
secp256k1_pubkey_save(pubkey, &q);
|
||||
return 1;
|
||||
} else {
|
||||
memset(pubkey, 0, sizeof(*pubkey));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* SECP256K1_MODULE_RECOVERY_MAIN_H */
|
||||
@@ -0,0 +1,148 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2016 Andrew Poelstra *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_RECOVERY_EXHAUSTIVE_TESTS_H
|
||||
#define SECP256K1_MODULE_RECOVERY_EXHAUSTIVE_TESTS_H
|
||||
|
||||
#include "main_impl.h"
|
||||
#include "../../../include/secp256k1_recovery.h"
|
||||
|
||||
static void test_exhaustive_recovery_sign(const secp256k1_context *ctx, const secp256k1_ge *group) {
|
||||
int i, j, k;
|
||||
uint64_t iter = 0;
|
||||
|
||||
/* Loop */
|
||||
for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { /* message */
|
||||
for (j = 1; j < EXHAUSTIVE_TEST_ORDER; j++) { /* key */
|
||||
if (skip_section(&iter)) continue;
|
||||
for (k = 1; k < EXHAUSTIVE_TEST_ORDER; k++) { /* nonce */
|
||||
const int starting_k = k;
|
||||
secp256k1_fe r_dot_y_normalized;
|
||||
secp256k1_ecdsa_recoverable_signature rsig;
|
||||
secp256k1_ecdsa_signature sig;
|
||||
secp256k1_scalar sk, msg, r, s, expected_r;
|
||||
unsigned char sk32[32], msg32[32];
|
||||
int expected_recid;
|
||||
int recid;
|
||||
int overflow;
|
||||
secp256k1_scalar_set_int(&msg, i);
|
||||
secp256k1_scalar_set_int(&sk, j);
|
||||
secp256k1_scalar_get_b32(sk32, &sk);
|
||||
secp256k1_scalar_get_b32(msg32, &msg);
|
||||
|
||||
secp256k1_ecdsa_sign_recoverable(ctx, &rsig, msg32, sk32, secp256k1_nonce_function_smallint, &k);
|
||||
|
||||
/* Check directly */
|
||||
secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, &rsig);
|
||||
r_from_k(&expected_r, group, k, &overflow);
|
||||
CHECK(r == expected_r);
|
||||
CHECK((k * s) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER ||
|
||||
(k * (EXHAUSTIVE_TEST_ORDER - s)) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER);
|
||||
/* The recid's second bit is for conveying overflow (R.x value >= group order).
|
||||
* In the actual secp256k1 this is an astronomically unlikely event, but in the
|
||||
* small group used here, it will almost certainly be the case for all points.
|
||||
* Note that this isn't actually useful; full recovery would need to convey
|
||||
* floor(R.x / group_order), but only one bit is used as that is sufficient
|
||||
* in the real group. */
|
||||
expected_recid = overflow ? 2 : 0;
|
||||
r_dot_y_normalized = group[k].y;
|
||||
secp256k1_fe_normalize(&r_dot_y_normalized);
|
||||
/* Also the recovery id is flipped depending if we hit the low-s branch */
|
||||
if ((k * s) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER) {
|
||||
expected_recid |= secp256k1_fe_is_odd(&r_dot_y_normalized);
|
||||
} else {
|
||||
expected_recid |= !secp256k1_fe_is_odd(&r_dot_y_normalized);
|
||||
}
|
||||
CHECK(recid == expected_recid);
|
||||
|
||||
/* Convert to a standard sig then check */
|
||||
secp256k1_ecdsa_recoverable_signature_convert(ctx, &sig, &rsig);
|
||||
secp256k1_ecdsa_signature_load(ctx, &r, &s, &sig);
|
||||
/* Note that we compute expected_r *after* signing -- this is important
|
||||
* because our nonce-computing function function might change k during
|
||||
* signing. */
|
||||
r_from_k(&expected_r, group, k, NULL);
|
||||
CHECK(r == expected_r);
|
||||
CHECK((k * s) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER ||
|
||||
(k * (EXHAUSTIVE_TEST_ORDER - s)) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER);
|
||||
|
||||
/* Overflow means we've tried every possible nonce */
|
||||
if (k < starting_k) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void test_exhaustive_recovery_verify(const secp256k1_context *ctx, const secp256k1_ge *group) {
|
||||
/* This is essentially a copy of test_exhaustive_verify, with recovery added */
|
||||
int s, r, msg, key;
|
||||
uint64_t iter = 0;
|
||||
for (s = 1; s < EXHAUSTIVE_TEST_ORDER; s++) {
|
||||
for (r = 1; r < EXHAUSTIVE_TEST_ORDER; r++) {
|
||||
for (msg = 1; msg < EXHAUSTIVE_TEST_ORDER; msg++) {
|
||||
for (key = 1; key < EXHAUSTIVE_TEST_ORDER; key++) {
|
||||
secp256k1_ge nonconst_ge;
|
||||
secp256k1_ecdsa_recoverable_signature rsig;
|
||||
secp256k1_ecdsa_signature sig;
|
||||
secp256k1_pubkey pk;
|
||||
secp256k1_scalar sk_s, msg_s, r_s, s_s;
|
||||
secp256k1_scalar s_times_k_s, msg_plus_r_times_sk_s;
|
||||
int recid = 0;
|
||||
int k, should_verify;
|
||||
unsigned char msg32[32];
|
||||
|
||||
if (skip_section(&iter)) continue;
|
||||
|
||||
secp256k1_scalar_set_int(&s_s, s);
|
||||
secp256k1_scalar_set_int(&r_s, r);
|
||||
secp256k1_scalar_set_int(&msg_s, msg);
|
||||
secp256k1_scalar_set_int(&sk_s, key);
|
||||
secp256k1_scalar_get_b32(msg32, &msg_s);
|
||||
|
||||
/* Verify by hand */
|
||||
/* Run through every k value that gives us this r and check that *one* works.
|
||||
* Note there could be none, there could be multiple, ECDSA is weird. */
|
||||
should_verify = 0;
|
||||
for (k = 0; k < EXHAUSTIVE_TEST_ORDER; k++) {
|
||||
secp256k1_scalar check_x_s;
|
||||
r_from_k(&check_x_s, group, k, NULL);
|
||||
if (r_s == check_x_s) {
|
||||
secp256k1_scalar_set_int(&s_times_k_s, k);
|
||||
secp256k1_scalar_mul(&s_times_k_s, &s_times_k_s, &s_s);
|
||||
secp256k1_scalar_mul(&msg_plus_r_times_sk_s, &r_s, &sk_s);
|
||||
secp256k1_scalar_add(&msg_plus_r_times_sk_s, &msg_plus_r_times_sk_s, &msg_s);
|
||||
should_verify |= secp256k1_scalar_eq(&s_times_k_s, &msg_plus_r_times_sk_s);
|
||||
}
|
||||
}
|
||||
/* nb we have a "high s" rule */
|
||||
should_verify &= !secp256k1_scalar_is_high(&s_s);
|
||||
|
||||
/* We would like to try recovering the pubkey and checking that it matches,
|
||||
* but pubkey recovery is impossible in the exhaustive tests (the reason
|
||||
* being that there are 12 nonzero r values, 12 nonzero points, and no
|
||||
* overlap between the sets, so there are no valid signatures). */
|
||||
|
||||
/* Verify by converting to a standard signature and calling verify */
|
||||
secp256k1_ecdsa_recoverable_signature_save(&rsig, &r_s, &s_s, recid);
|
||||
secp256k1_ecdsa_recoverable_signature_convert(ctx, &sig, &rsig);
|
||||
memcpy(&nonconst_ge, &group[sk_s], sizeof(nonconst_ge));
|
||||
secp256k1_pubkey_save(&pk, &nonconst_ge);
|
||||
CHECK(should_verify ==
|
||||
secp256k1_ecdsa_verify(ctx, &sig, msg32, &pk));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void test_exhaustive_recovery(const secp256k1_context *ctx, const secp256k1_ge *group) {
|
||||
test_exhaustive_recovery_sign(ctx, group);
|
||||
test_exhaustive_recovery_verify(ctx, group);
|
||||
}
|
||||
|
||||
#endif /* SECP256K1_MODULE_RECOVERY_EXHAUSTIVE_TESTS_H */
|
||||
@@ -0,0 +1,339 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2013-2015 Pieter Wuille *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_RECOVERY_TESTS_H
|
||||
#define SECP256K1_MODULE_RECOVERY_TESTS_H
|
||||
|
||||
#include "../../unit_test.h"
|
||||
|
||||
static int recovery_test_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) {
|
||||
(void) msg32;
|
||||
(void) key32;
|
||||
(void) algo16;
|
||||
(void) data;
|
||||
|
||||
/* On the first run, return 0 to force a second run */
|
||||
if (counter == 0) {
|
||||
memset(nonce32, 0, 32);
|
||||
return 1;
|
||||
}
|
||||
/* On the second run, return an overflow to force a third run */
|
||||
if (counter == 1) {
|
||||
memset(nonce32, 0xff, 32);
|
||||
return 1;
|
||||
}
|
||||
/* On the next run, return a valid nonce, but flip a coin as to whether or not to fail signing. */
|
||||
memset(nonce32, 1, 32);
|
||||
return testrand_bits(1);
|
||||
}
|
||||
|
||||
static void test_ecdsa_recovery_api_internal(void) {
|
||||
/* Setup contexts that just count errors */
|
||||
secp256k1_pubkey pubkey;
|
||||
secp256k1_pubkey recpubkey;
|
||||
secp256k1_ecdsa_signature normal_sig;
|
||||
secp256k1_ecdsa_recoverable_signature recsig;
|
||||
unsigned char privkey[32] = { 1 };
|
||||
unsigned char message[32] = { 2 };
|
||||
int recid = 0;
|
||||
unsigned char sig[74];
|
||||
unsigned char zero_privkey[32] = { 0 };
|
||||
unsigned char over_privkey[32] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
|
||||
/* Construct and verify corresponding public key. */
|
||||
CHECK(secp256k1_ec_seckey_verify(CTX, privkey) == 1);
|
||||
CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, privkey) == 1);
|
||||
|
||||
/* Check bad contexts and NULLs for signing */
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, privkey, NULL, NULL) == 1);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_ecdsa_sign_recoverable(CTX, NULL, message, privkey, NULL, NULL));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_ecdsa_sign_recoverable(CTX, &recsig, NULL, privkey, NULL, NULL));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, NULL, NULL, NULL));
|
||||
CHECK_ILLEGAL(STATIC_CTX, secp256k1_ecdsa_sign_recoverable(STATIC_CTX, &recsig, message, privkey, NULL, NULL));
|
||||
/* This will fail or succeed randomly, and in either case will not ARG_CHECK failure */
|
||||
secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, privkey, recovery_test_nonce_function, NULL);
|
||||
/* These will all fail, but not in ARG_CHECK way */
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, zero_privkey, NULL, NULL) == 0);
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, over_privkey, NULL, NULL) == 0);
|
||||
/* This one will succeed. */
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, privkey, NULL, NULL) == 1);
|
||||
|
||||
/* Check signing with a goofy nonce function */
|
||||
|
||||
/* Check bad contexts and NULLs for recovery */
|
||||
CHECK(secp256k1_ecdsa_recover(CTX, &recpubkey, &recsig, message) == 1);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recover(CTX, NULL, &recsig, message));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recover(CTX, &recpubkey, NULL, message));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recover(CTX, &recpubkey, &recsig, NULL));
|
||||
|
||||
/* Check NULLs for conversion */
|
||||
CHECK(secp256k1_ecdsa_sign(CTX, &normal_sig, message, privkey, NULL, NULL) == 1);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_convert(CTX, NULL, &recsig));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_convert(CTX, &normal_sig, NULL));
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_convert(CTX, &normal_sig, &recsig) == 1);
|
||||
|
||||
/* Check NULLs for de/serialization */
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, privkey, NULL, NULL) == 1);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, NULL, &recid, &recsig));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, NULL, &recsig));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, &recid, NULL));
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, &recid, &recsig) == 1);
|
||||
|
||||
CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, NULL, sig, recid));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, NULL, recid));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, sig, -1));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, sig, 5));
|
||||
/* overflow in signature will not result in calling illegal_callback */
|
||||
memcpy(sig, over_privkey, 32);
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, sig, recid) == 0);
|
||||
}
|
||||
|
||||
static void test_ecdsa_recovery_end_to_end_internal(void) {
|
||||
unsigned char extra[32] = {0x00};
|
||||
unsigned char privkey[32];
|
||||
unsigned char message[32];
|
||||
secp256k1_ecdsa_signature signature[5];
|
||||
secp256k1_ecdsa_recoverable_signature rsignature[5];
|
||||
unsigned char sig[74];
|
||||
secp256k1_pubkey pubkey;
|
||||
secp256k1_pubkey recpubkey;
|
||||
int recid = 0;
|
||||
|
||||
/* Generate a random key and message. */
|
||||
{
|
||||
secp256k1_scalar msg, key;
|
||||
testutil_random_scalar_order_test(&msg);
|
||||
testutil_random_scalar_order_test(&key);
|
||||
secp256k1_scalar_get_b32(privkey, &key);
|
||||
secp256k1_scalar_get_b32(message, &msg);
|
||||
}
|
||||
|
||||
/* Construct and verify corresponding public key. */
|
||||
CHECK(secp256k1_ec_seckey_verify(CTX, privkey) == 1);
|
||||
CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, privkey) == 1);
|
||||
|
||||
/* Serialize/parse compact and verify/recover. */
|
||||
extra[0] = 0;
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &rsignature[0], message, privkey, NULL, NULL) == 1);
|
||||
CHECK(secp256k1_ecdsa_sign(CTX, &signature[0], message, privkey, NULL, NULL) == 1);
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &rsignature[4], message, privkey, NULL, NULL) == 1);
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &rsignature[1], message, privkey, NULL, extra) == 1);
|
||||
extra[31] = 1;
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &rsignature[2], message, privkey, NULL, extra) == 1);
|
||||
extra[31] = 0;
|
||||
extra[0] = 1;
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &rsignature[3], message, privkey, NULL, extra) == 1);
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, &recid, &rsignature[4]) == 1);
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_convert(CTX, &signature[4], &rsignature[4]) == 1);
|
||||
CHECK(secp256k1_memcmp_var(&signature[4], &signature[0], 64) == 0);
|
||||
CHECK(secp256k1_ecdsa_verify(CTX, &signature[4], message, &pubkey) == 1);
|
||||
memset(&rsignature[4], 0, sizeof(rsignature[4]));
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsignature[4], sig, recid) == 1);
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_convert(CTX, &signature[4], &rsignature[4]) == 1);
|
||||
CHECK(secp256k1_ecdsa_verify(CTX, &signature[4], message, &pubkey) == 1);
|
||||
/* Parse compact (with recovery id) and recover. */
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsignature[4], sig, recid) == 1);
|
||||
CHECK(secp256k1_ecdsa_recover(CTX, &recpubkey, &rsignature[4], message) == 1);
|
||||
CHECK(secp256k1_memcmp_var(&pubkey, &recpubkey, sizeof(pubkey)) == 0);
|
||||
/* Serialize/destroy/parse signature and verify again. */
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, &recid, &rsignature[4]) == 1);
|
||||
sig[testrand_bits(6)] += 1 + testrand_int(255);
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsignature[4], sig, recid) == 1);
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_convert(CTX, &signature[4], &rsignature[4]) == 1);
|
||||
CHECK(secp256k1_ecdsa_verify(CTX, &signature[4], message, &pubkey) == 0);
|
||||
/* Recover again */
|
||||
CHECK(secp256k1_ecdsa_recover(CTX, &recpubkey, &rsignature[4], message) == 0 ||
|
||||
secp256k1_memcmp_var(&pubkey, &recpubkey, sizeof(pubkey)) != 0);
|
||||
}
|
||||
|
||||
/* Tests several edge cases. */
|
||||
static void test_ecdsa_recovery_edge_cases(void) {
|
||||
const unsigned char msg32[32] = {
|
||||
'T', 'h', 'i', 's', ' ', 'i', 's', ' ',
|
||||
'a', ' ', 'v', 'e', 'r', 'y', ' ', 's',
|
||||
'e', 'c', 'r', 'e', 't', ' ', 'm', 'e',
|
||||
's', 's', 'a', 'g', 'e', '.', '.', '.'
|
||||
};
|
||||
const unsigned char sig64[64] = {
|
||||
/* Generated by signing the above message with nonce 'This is the nonce we will use...'
|
||||
* and secret key 0 (which is not valid), resulting in recid 1. */
|
||||
0x67, 0xCB, 0x28, 0x5F, 0x9C, 0xD1, 0x94, 0xE8,
|
||||
0x40, 0xD6, 0x29, 0x39, 0x7A, 0xF5, 0x56, 0x96,
|
||||
0x62, 0xFD, 0xE4, 0x46, 0x49, 0x99, 0x59, 0x63,
|
||||
0x17, 0x9A, 0x7D, 0xD1, 0x7B, 0xD2, 0x35, 0x32,
|
||||
0x4B, 0x1B, 0x7D, 0xF3, 0x4C, 0xE1, 0xF6, 0x8E,
|
||||
0x69, 0x4F, 0xF6, 0xF1, 0x1A, 0xC7, 0x51, 0xDD,
|
||||
0x7D, 0xD7, 0x3E, 0x38, 0x7E, 0xE4, 0xFC, 0x86,
|
||||
0x6E, 0x1B, 0xE8, 0xEC, 0xC7, 0xDD, 0x95, 0x57
|
||||
};
|
||||
secp256k1_pubkey pubkey;
|
||||
/* signature (r,s) = (4,4), which can be recovered with all 4 recids. */
|
||||
const unsigned char sigb64[64] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
|
||||
};
|
||||
secp256k1_pubkey pubkeyb;
|
||||
secp256k1_ecdsa_recoverable_signature rsig;
|
||||
secp256k1_ecdsa_signature sig;
|
||||
int recid;
|
||||
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sig64, 0));
|
||||
CHECK(!secp256k1_ecdsa_recover(CTX, &pubkey, &rsig, msg32));
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sig64, 1));
|
||||
CHECK(secp256k1_ecdsa_recover(CTX, &pubkey, &rsig, msg32));
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sig64, 2));
|
||||
CHECK(!secp256k1_ecdsa_recover(CTX, &pubkey, &rsig, msg32));
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sig64, 3));
|
||||
CHECK(!secp256k1_ecdsa_recover(CTX, &pubkey, &rsig, msg32));
|
||||
|
||||
for (recid = 0; recid < 4; recid++) {
|
||||
int i;
|
||||
int recid2;
|
||||
/* (4,4) encoded in DER. */
|
||||
unsigned char sigbder[8] = {0x30, 0x06, 0x02, 0x01, 0x04, 0x02, 0x01, 0x04};
|
||||
unsigned char sigcder_zr[7] = {0x30, 0x05, 0x02, 0x00, 0x02, 0x01, 0x01};
|
||||
unsigned char sigcder_zs[7] = {0x30, 0x05, 0x02, 0x01, 0x01, 0x02, 0x00};
|
||||
unsigned char sigbderalt1[39] = {
|
||||
0x30, 0x25, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x04, 0x02, 0x01, 0x04,
|
||||
};
|
||||
unsigned char sigbderalt2[39] = {
|
||||
0x30, 0x25, 0x02, 0x01, 0x04, 0x02, 0x20, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
|
||||
};
|
||||
unsigned char sigbderalt3[40] = {
|
||||
0x30, 0x26, 0x02, 0x21, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x01, 0x04,
|
||||
};
|
||||
unsigned char sigbderalt4[40] = {
|
||||
0x30, 0x26, 0x02, 0x01, 0x04, 0x02, 0x21, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
|
||||
};
|
||||
/* (order + r,4) encoded in DER. */
|
||||
unsigned char sigbderlong[40] = {
|
||||
0x30, 0x26, 0x02, 0x21, 0x00, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC,
|
||||
0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E,
|
||||
0x8C, 0xD0, 0x36, 0x41, 0x45, 0x02, 0x01, 0x04
|
||||
};
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sigb64, recid) == 1);
|
||||
CHECK(secp256k1_ecdsa_recover(CTX, &pubkeyb, &rsig, msg32) == 1);
|
||||
CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbder, sizeof(sigbder)) == 1);
|
||||
CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyb) == 1);
|
||||
for (recid2 = 0; recid2 < 4; recid2++) {
|
||||
secp256k1_pubkey pubkey2b;
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sigb64, recid2) == 1);
|
||||
CHECK(secp256k1_ecdsa_recover(CTX, &pubkey2b, &rsig, msg32) == 1);
|
||||
/* Verifying with (order + r,4) should always fail. */
|
||||
CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbderlong, sizeof(sigbderlong)) == 1);
|
||||
CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyb) == 0);
|
||||
}
|
||||
/* DER parsing tests. */
|
||||
/* Zero length r/s. */
|
||||
CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigcder_zr, sizeof(sigcder_zr)) == 0);
|
||||
CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigcder_zs, sizeof(sigcder_zs)) == 0);
|
||||
/* Leading zeros. */
|
||||
CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbderalt1, sizeof(sigbderalt1)) == 0);
|
||||
CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbderalt2, sizeof(sigbderalt2)) == 0);
|
||||
CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbderalt3, sizeof(sigbderalt3)) == 0);
|
||||
CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbderalt4, sizeof(sigbderalt4)) == 0);
|
||||
sigbderalt3[4] = 1;
|
||||
CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbderalt3, sizeof(sigbderalt3)) == 1);
|
||||
CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyb) == 0);
|
||||
sigbderalt4[7] = 1;
|
||||
CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbderalt4, sizeof(sigbderalt4)) == 1);
|
||||
CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyb) == 0);
|
||||
/* Damage signature. */
|
||||
sigbder[7]++;
|
||||
CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbder, sizeof(sigbder)) == 1);
|
||||
CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyb) == 0);
|
||||
sigbder[7]--;
|
||||
CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbder, 6) == 0);
|
||||
CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbder, sizeof(sigbder) - 1) == 0);
|
||||
for(i = 0; i < 8; i++) {
|
||||
int c;
|
||||
unsigned char orig = sigbder[i];
|
||||
/*Try every single-byte change.*/
|
||||
for (c = 0; c < 256; c++) {
|
||||
if (c == orig ) {
|
||||
continue;
|
||||
}
|
||||
sigbder[i] = c;
|
||||
CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbder, sizeof(sigbder)) == 0 || secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyb) == 0);
|
||||
}
|
||||
sigbder[i] = orig;
|
||||
}
|
||||
}
|
||||
|
||||
/* Test r/s equal to zero */
|
||||
{
|
||||
/* (1,1) encoded in DER. */
|
||||
unsigned char sigcder[8] = {0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01};
|
||||
unsigned char sigc64[64] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
};
|
||||
secp256k1_pubkey pubkeyc;
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sigc64, 0) == 1);
|
||||
CHECK(secp256k1_ecdsa_recover(CTX, &pubkeyc, &rsig, msg32) == 1);
|
||||
CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigcder, sizeof(sigcder)) == 1);
|
||||
CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyc) == 1);
|
||||
sigcder[4] = 0;
|
||||
sigc64[31] = 0;
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sigc64, 0) == 1);
|
||||
CHECK(secp256k1_ecdsa_recover(CTX, &pubkeyb, &rsig, msg32) == 0);
|
||||
CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigcder, sizeof(sigcder)) == 1);
|
||||
CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyc) == 0);
|
||||
sigcder[4] = 1;
|
||||
sigcder[7] = 0;
|
||||
sigc64[31] = 1;
|
||||
sigc64[63] = 0;
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sigc64, 0) == 1);
|
||||
CHECK(secp256k1_ecdsa_recover(CTX, &pubkeyb, &rsig, msg32) == 0);
|
||||
CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigcder, sizeof(sigcder)) == 1);
|
||||
CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyc) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* --- Test registry --- */
|
||||
REPEAT_TEST(test_ecdsa_recovery_api)
|
||||
REPEAT_TEST_MULT(test_ecdsa_recovery_end_to_end, 64)
|
||||
|
||||
static const struct tf_test_entry tests_recovery[] = {
|
||||
CASE1(test_ecdsa_recovery_api),
|
||||
CASE1(test_ecdsa_recovery_end_to_end),
|
||||
CASE1(test_ecdsa_recovery_edge_cases)
|
||||
};
|
||||
|
||||
#endif /* SECP256K1_MODULE_RECOVERY_TESTS_H */
|
||||
@@ -0,0 +1,5 @@
|
||||
include_HEADERS += include/secp256k1_schnorrsig.h
|
||||
noinst_HEADERS += src/modules/schnorrsig/main_impl.h
|
||||
noinst_HEADERS += src/modules/schnorrsig/tests_impl.h
|
||||
noinst_HEADERS += src/modules/schnorrsig/tests_exhaustive_impl.h
|
||||
noinst_HEADERS += src/modules/schnorrsig/bench_impl.h
|
||||
@@ -0,0 +1,104 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2018-2020 Andrew Poelstra, Jonas Nick *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_SCHNORRSIG_BENCH_H
|
||||
#define SECP256K1_MODULE_SCHNORRSIG_BENCH_H
|
||||
|
||||
#include "../../../include/secp256k1_schnorrsig.h"
|
||||
|
||||
#define MSGLEN 32
|
||||
|
||||
typedef struct {
|
||||
secp256k1_context *ctx;
|
||||
int n;
|
||||
|
||||
const secp256k1_keypair **keypairs;
|
||||
const unsigned char **pk;
|
||||
const unsigned char **sigs;
|
||||
const unsigned char **msgs;
|
||||
} bench_schnorrsig_data;
|
||||
|
||||
static void bench_schnorrsig_sign(void* arg, int iters) {
|
||||
bench_schnorrsig_data *data = (bench_schnorrsig_data *)arg;
|
||||
int i;
|
||||
unsigned char msg[MSGLEN] = {0};
|
||||
unsigned char sig[64];
|
||||
|
||||
for (i = 0; i < iters; i++) {
|
||||
msg[0] = i;
|
||||
msg[1] = i >> 8;
|
||||
CHECK(secp256k1_schnorrsig_sign_custom(data->ctx, sig, msg, MSGLEN, data->keypairs[i], NULL));
|
||||
}
|
||||
}
|
||||
|
||||
static void bench_schnorrsig_verify(void* arg, int iters) {
|
||||
bench_schnorrsig_data *data = (bench_schnorrsig_data *)arg;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < iters; i++) {
|
||||
secp256k1_xonly_pubkey pk;
|
||||
CHECK(secp256k1_xonly_pubkey_parse(data->ctx, &pk, data->pk[i]) == 1);
|
||||
CHECK(secp256k1_schnorrsig_verify(data->ctx, data->sigs[i], data->msgs[i], MSGLEN, &pk));
|
||||
}
|
||||
}
|
||||
|
||||
static void run_schnorrsig_bench(int iters, int argc, char** argv) {
|
||||
int i;
|
||||
bench_schnorrsig_data data;
|
||||
int d = argc == 1;
|
||||
|
||||
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
||||
data.keypairs = malloc(iters * sizeof(secp256k1_keypair *));
|
||||
data.pk = malloc(iters * sizeof(unsigned char *));
|
||||
data.msgs = malloc(iters * sizeof(unsigned char *));
|
||||
data.sigs = malloc(iters * sizeof(unsigned char *));
|
||||
|
||||
CHECK(MSGLEN >= 4);
|
||||
for (i = 0; i < iters; i++) {
|
||||
unsigned char sk[32];
|
||||
unsigned char *msg = malloc(MSGLEN);
|
||||
unsigned char *sig = malloc(64);
|
||||
secp256k1_keypair *keypair = malloc(sizeof(*keypair));
|
||||
unsigned char *pk_char = malloc(32);
|
||||
secp256k1_xonly_pubkey pk;
|
||||
msg[0] = sk[0] = i;
|
||||
msg[1] = sk[1] = i >> 8;
|
||||
msg[2] = sk[2] = i >> 16;
|
||||
msg[3] = sk[3] = i >> 24;
|
||||
memset(&msg[4], 'm', MSGLEN - 4);
|
||||
memset(&sk[4], 's', 28);
|
||||
|
||||
data.keypairs[i] = keypair;
|
||||
data.pk[i] = pk_char;
|
||||
data.msgs[i] = msg;
|
||||
data.sigs[i] = sig;
|
||||
|
||||
CHECK(secp256k1_keypair_create(data.ctx, keypair, sk));
|
||||
CHECK(secp256k1_schnorrsig_sign_custom(data.ctx, sig, msg, MSGLEN, keypair, NULL));
|
||||
CHECK(secp256k1_keypair_xonly_pub(data.ctx, &pk, NULL, keypair));
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(data.ctx, pk_char, &pk) == 1);
|
||||
}
|
||||
|
||||
if (d || have_flag(argc, argv, "schnorrsig") || have_flag(argc, argv, "sign") || have_flag(argc, argv, "schnorrsig_sign")) run_benchmark("schnorrsig_sign", bench_schnorrsig_sign, NULL, NULL, (void *) &data, 10, iters);
|
||||
if (d || have_flag(argc, argv, "schnorrsig") || have_flag(argc, argv, "verify") || have_flag(argc, argv, "schnorrsig_verify")) run_benchmark("schnorrsig_verify", bench_schnorrsig_verify, NULL, NULL, (void *) &data, 10, iters);
|
||||
|
||||
for (i = 0; i < iters; i++) {
|
||||
free((void *)data.keypairs[i]);
|
||||
free((void *)data.pk[i]);
|
||||
free((void *)data.msgs[i]);
|
||||
free((void *)data.sigs[i]);
|
||||
}
|
||||
|
||||
/* Casting to (void *) avoids a stupid warning in MSVC. */
|
||||
free((void *)data.keypairs);
|
||||
free((void *)data.pk);
|
||||
free((void *)data.msgs);
|
||||
free((void *)data.sigs);
|
||||
|
||||
secp256k1_context_destroy(data.ctx);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,263 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2018-2020 Andrew Poelstra, Jonas Nick *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_SCHNORRSIG_MAIN_H
|
||||
#define SECP256K1_MODULE_SCHNORRSIG_MAIN_H
|
||||
|
||||
#include "../../../include/secp256k1.h"
|
||||
#include "../../../include/secp256k1_schnorrsig.h"
|
||||
#include "../../hash.h"
|
||||
|
||||
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
|
||||
* SHA256 to SHA256("BIP0340/nonce")||SHA256("BIP0340/nonce"). */
|
||||
static void secp256k1_nonce_function_bip340_sha256_tagged(secp256k1_sha256 *sha) {
|
||||
static const uint32_t midstate[8] = {
|
||||
0x46615b35ul, 0xf4bfbff7ul, 0x9f8dc671ul, 0x83627ab3ul,
|
||||
0x60217180ul, 0x57358661ul, 0x21a29e54ul, 0x68b07b4cul
|
||||
};
|
||||
secp256k1_sha256_initialize_midstate(sha, 64, midstate);
|
||||
}
|
||||
|
||||
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
|
||||
* SHA256 to SHA256("BIP0340/aux")||SHA256("BIP0340/aux"). */
|
||||
static void secp256k1_nonce_function_bip340_sha256_tagged_aux(secp256k1_sha256 *sha) {
|
||||
static const uint32_t midstate[8] = {
|
||||
0x24dd3219ul, 0x4eba7e70ul, 0xca0fabb9ul, 0x0fa3166dul,
|
||||
0x3afbe4b1ul, 0x4c44df97ul, 0x4aac2739ul, 0x249e850aul
|
||||
};
|
||||
secp256k1_sha256_initialize_midstate(sha, 64, midstate);
|
||||
}
|
||||
|
||||
/* algo argument for nonce_function_bip340 to derive the nonce exactly as stated in BIP-340
|
||||
* by using the correct tagged hash function. */
|
||||
static const unsigned char bip340_algo[] = {'B', 'I', 'P', '0', '3', '4', '0', '/', 'n', 'o', 'n', 'c', 'e'};
|
||||
|
||||
static const unsigned char schnorrsig_extraparams_magic[4] = SECP256K1_SCHNORRSIG_EXTRAPARAMS_MAGIC;
|
||||
|
||||
static int nonce_function_bip340_impl(const secp256k1_hash_ctx *hash_ctx, unsigned char *nonce32, const unsigned char *msg, size_t msglen, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo, size_t algolen, void *data) {
|
||||
secp256k1_sha256 sha;
|
||||
unsigned char masked_key[32];
|
||||
int i;
|
||||
|
||||
if (algo == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (data != NULL) {
|
||||
secp256k1_nonce_function_bip340_sha256_tagged_aux(&sha);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, data, 32);
|
||||
secp256k1_sha256_finalize(hash_ctx, &sha, masked_key);
|
||||
for (i = 0; i < 32; i++) {
|
||||
masked_key[i] ^= key32[i];
|
||||
}
|
||||
} else {
|
||||
/* Precomputed TaggedHash("BIP0340/aux", 0x0000...00); */
|
||||
static const unsigned char ZERO_MASK[32] = {
|
||||
84, 241, 105, 207, 201, 226, 229, 114,
|
||||
116, 128, 68, 31, 144, 186, 37, 196,
|
||||
136, 244, 97, 199, 11, 94, 165, 220,
|
||||
170, 247, 175, 105, 39, 10, 165, 20
|
||||
};
|
||||
for (i = 0; i < 32; i++) {
|
||||
masked_key[i] = key32[i] ^ ZERO_MASK[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* Tag the hash with algo which is important to avoid nonce reuse across
|
||||
* algorithms. If this nonce function is used in BIP-340 signing as defined
|
||||
* in the spec, an optimized tagging implementation is used. */
|
||||
if (algolen == sizeof(bip340_algo)
|
||||
&& secp256k1_memcmp_var(algo, bip340_algo, algolen) == 0) {
|
||||
secp256k1_nonce_function_bip340_sha256_tagged(&sha);
|
||||
} else {
|
||||
secp256k1_sha256_initialize_tagged(hash_ctx, &sha, algo, algolen);
|
||||
}
|
||||
|
||||
/* Hash masked-key||pk||msg using the tagged hash as per the spec */
|
||||
secp256k1_sha256_write(hash_ctx, &sha, masked_key, 32);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, xonly_pk32, 32);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, msg, msglen);
|
||||
secp256k1_sha256_finalize(hash_ctx, &sha, nonce32);
|
||||
secp256k1_sha256_clear(&sha);
|
||||
secp256k1_memclear_explicit(masked_key, sizeof(masked_key));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int nonce_function_bip340(unsigned char *nonce32, const unsigned char *msg, size_t msglen, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo, size_t algolen, void *data) {
|
||||
return nonce_function_bip340_impl(secp256k1_get_hash_context(secp256k1_context_static), nonce32, msg, msglen, key32, xonly_pk32, algo, algolen, data);
|
||||
}
|
||||
|
||||
const secp256k1_nonce_function_hardened secp256k1_nonce_function_bip340 = nonce_function_bip340;
|
||||
|
||||
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
|
||||
* SHA256 to SHA256("BIP0340/challenge")||SHA256("BIP0340/challenge"). */
|
||||
static void secp256k1_schnorrsig_sha256_tagged(secp256k1_sha256 *sha) {
|
||||
static const uint32_t midstate[8] = {
|
||||
0x9cecba11ul, 0x23925381ul, 0x11679112ul, 0xd1627e0ful,
|
||||
0x97c87550ul, 0x003cc765ul, 0x90f61164ul, 0x33e9b66aul
|
||||
};
|
||||
secp256k1_sha256_initialize_midstate(sha, 64, midstate);
|
||||
}
|
||||
|
||||
static void secp256k1_schnorrsig_challenge(const secp256k1_hash_ctx *hash_ctx, secp256k1_scalar* e, const unsigned char *r32, const unsigned char *msg, size_t msglen, const unsigned char *pubkey32)
|
||||
{
|
||||
unsigned char buf[32];
|
||||
secp256k1_sha256 sha;
|
||||
|
||||
/* tagged hash(r.x, pk.x, msg) */
|
||||
secp256k1_schnorrsig_sha256_tagged(&sha);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, r32, 32);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, pubkey32, 32);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, msg, msglen);
|
||||
secp256k1_sha256_finalize(hash_ctx, &sha, buf);
|
||||
/* Set scalar e to the challenge hash modulo the curve order as per
|
||||
* BIP340. */
|
||||
secp256k1_scalar_set_b32(e, buf, NULL);
|
||||
}
|
||||
|
||||
static int secp256k1_schnorrsig_sign_internal(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg, size_t msglen, const secp256k1_keypair *keypair, secp256k1_nonce_function_hardened noncefp, void *ndata) {
|
||||
secp256k1_scalar sk;
|
||||
secp256k1_scalar e;
|
||||
secp256k1_scalar k;
|
||||
secp256k1_gej rj;
|
||||
secp256k1_ge pk;
|
||||
secp256k1_ge r;
|
||||
unsigned char nonce32[32] = { 0 };
|
||||
unsigned char pk_buf[32];
|
||||
unsigned char seckey[32];
|
||||
int ret = 1;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
ARG_CHECK(sig64 != NULL);
|
||||
ARG_CHECK(msg != NULL || msglen == 0);
|
||||
ARG_CHECK(keypair != NULL);
|
||||
|
||||
ret &= secp256k1_keypair_load(ctx, &sk, &pk, keypair);
|
||||
/* Because we are signing for a x-only pubkey, the secret key is negated
|
||||
* before signing if the point corresponding to the secret key does not
|
||||
* have an even Y. */
|
||||
if (secp256k1_fe_is_odd(&pk.y)) {
|
||||
secp256k1_scalar_negate(&sk, &sk);
|
||||
}
|
||||
|
||||
secp256k1_scalar_get_b32(seckey, &sk);
|
||||
secp256k1_fe_get_b32(pk_buf, &pk.x);
|
||||
|
||||
/* Compute nonce */
|
||||
if (noncefp == NULL || noncefp == secp256k1_nonce_function_bip340) {
|
||||
/* Use context-aware nonce function by default */
|
||||
ret &= nonce_function_bip340_impl(secp256k1_get_hash_context(ctx), nonce32, msg, msglen, seckey, pk_buf, bip340_algo, sizeof(bip340_algo), ndata);
|
||||
} else {
|
||||
ret &= !!noncefp(nonce32, msg, msglen, seckey, pk_buf, bip340_algo, sizeof(bip340_algo), ndata);
|
||||
}
|
||||
|
||||
secp256k1_scalar_set_b32(&k, nonce32, NULL);
|
||||
ret &= !secp256k1_scalar_is_zero(&k);
|
||||
secp256k1_scalar_cmov(&k, &secp256k1_scalar_one, !ret);
|
||||
|
||||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &rj, &k);
|
||||
secp256k1_ge_set_gej(&r, &rj);
|
||||
|
||||
/* We declassify r to allow using it as a branch point. This is fine
|
||||
* because r is not a secret. */
|
||||
secp256k1_declassify(ctx, &r, sizeof(r));
|
||||
secp256k1_fe_normalize_var(&r.y);
|
||||
if (secp256k1_fe_is_odd(&r.y)) {
|
||||
secp256k1_scalar_negate(&k, &k);
|
||||
}
|
||||
secp256k1_fe_normalize_var(&r.x);
|
||||
secp256k1_fe_get_b32(&sig64[0], &r.x);
|
||||
|
||||
secp256k1_schnorrsig_challenge(secp256k1_get_hash_context(ctx), &e, &sig64[0], msg, msglen, pk_buf);
|
||||
secp256k1_scalar_mul(&e, &e, &sk);
|
||||
secp256k1_scalar_add(&e, &e, &k);
|
||||
secp256k1_scalar_get_b32(&sig64[32], &e);
|
||||
|
||||
secp256k1_memczero(sig64, 64, !ret);
|
||||
secp256k1_scalar_clear(&k);
|
||||
secp256k1_scalar_clear(&sk);
|
||||
secp256k1_memclear_explicit(seckey, sizeof(seckey));
|
||||
secp256k1_memclear_explicit(nonce32, sizeof(nonce32));
|
||||
secp256k1_gej_clear(&rj);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int secp256k1_schnorrsig_sign32(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const secp256k1_keypair *keypair, const unsigned char *aux_rand32) {
|
||||
/* We cast away const from the passed aux_rand32 argument since we know the default nonce function does not modify it. */
|
||||
return secp256k1_schnorrsig_sign_internal(ctx, sig64, msg32, 32, keypair, secp256k1_nonce_function_bip340, (unsigned char*)aux_rand32);
|
||||
}
|
||||
|
||||
int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const secp256k1_keypair *keypair, const unsigned char *aux_rand32) {
|
||||
return secp256k1_schnorrsig_sign32(ctx, sig64, msg32, keypair, aux_rand32);
|
||||
}
|
||||
|
||||
int secp256k1_schnorrsig_sign_custom(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg, size_t msglen, const secp256k1_keypair *keypair, secp256k1_schnorrsig_extraparams *extraparams) {
|
||||
secp256k1_nonce_function_hardened noncefp = NULL;
|
||||
void *ndata = NULL;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
|
||||
if (extraparams != NULL) {
|
||||
ARG_CHECK(secp256k1_memcmp_var(extraparams->magic,
|
||||
schnorrsig_extraparams_magic,
|
||||
sizeof(extraparams->magic)) == 0);
|
||||
noncefp = extraparams->noncefp;
|
||||
ndata = extraparams->ndata;
|
||||
}
|
||||
return secp256k1_schnorrsig_sign_internal(ctx, sig64, msg, msglen, keypair, noncefp, ndata);
|
||||
}
|
||||
|
||||
int secp256k1_schnorrsig_verify(const secp256k1_context* ctx, const unsigned char *sig64, const unsigned char *msg, size_t msglen, const secp256k1_xonly_pubkey *pubkey) {
|
||||
secp256k1_scalar s;
|
||||
secp256k1_scalar e;
|
||||
secp256k1_gej rj;
|
||||
secp256k1_ge pk;
|
||||
secp256k1_gej pkj;
|
||||
secp256k1_fe rx;
|
||||
secp256k1_ge r;
|
||||
unsigned char buf[32];
|
||||
int overflow;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(sig64 != NULL);
|
||||
ARG_CHECK(msg != NULL || msglen == 0);
|
||||
ARG_CHECK(pubkey != NULL);
|
||||
|
||||
if (!secp256k1_fe_set_b32_limit(&rx, &sig64[0])) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_scalar_set_b32(&s, &sig64[32], &overflow);
|
||||
if (overflow) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!secp256k1_xonly_pubkey_load(ctx, &pk, pubkey)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compute e. */
|
||||
secp256k1_fe_get_b32(buf, &pk.x);
|
||||
secp256k1_schnorrsig_challenge(secp256k1_get_hash_context(ctx), &e, &sig64[0], msg, msglen, buf);
|
||||
|
||||
/* Compute rj = s*G + (-e)*pkj */
|
||||
secp256k1_scalar_negate(&e, &e);
|
||||
secp256k1_gej_set_ge(&pkj, &pk);
|
||||
secp256k1_ecmult(&rj, &pkj, &e, &s);
|
||||
|
||||
secp256k1_ge_set_gej_var(&r, &rj);
|
||||
if (secp256k1_ge_is_infinity(&r)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_fe_normalize_var(&r.y);
|
||||
return !secp256k1_fe_is_odd(&r.y) &&
|
||||
secp256k1_fe_equal(&rx, &r.x);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,214 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2020 Pieter Wuille *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_SCHNORRSIG_TESTS_EXHAUSTIVE_H
|
||||
#define SECP256K1_MODULE_SCHNORRSIG_TESTS_EXHAUSTIVE_H
|
||||
|
||||
#include "../../../include/secp256k1_schnorrsig.h"
|
||||
#include "main_impl.h"
|
||||
|
||||
static const unsigned char invalid_pubkey_bytes[][32] = {
|
||||
/* 0 */
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
},
|
||||
/* 2 */
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2
|
||||
},
|
||||
/* order */
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
((EXHAUSTIVE_TEST_ORDER + 0UL) >> 24) & 0xFF,
|
||||
((EXHAUSTIVE_TEST_ORDER + 0UL) >> 16) & 0xFF,
|
||||
((EXHAUSTIVE_TEST_ORDER + 0UL) >> 8) & 0xFF,
|
||||
(EXHAUSTIVE_TEST_ORDER + 0UL) & 0xFF
|
||||
},
|
||||
/* order + 1 */
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
((EXHAUSTIVE_TEST_ORDER + 1UL) >> 24) & 0xFF,
|
||||
((EXHAUSTIVE_TEST_ORDER + 1UL) >> 16) & 0xFF,
|
||||
((EXHAUSTIVE_TEST_ORDER + 1UL) >> 8) & 0xFF,
|
||||
(EXHAUSTIVE_TEST_ORDER + 1UL) & 0xFF
|
||||
},
|
||||
/* field size */
|
||||
{
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x2F
|
||||
},
|
||||
/* field size + 1 (note that 1 is legal) */
|
||||
{
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x30
|
||||
},
|
||||
/* 2^256 - 1 */
|
||||
{
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
|
||||
}
|
||||
};
|
||||
|
||||
#define NUM_INVALID_KEYS (ARRAY_SIZE(invalid_pubkey_bytes))
|
||||
|
||||
static int secp256k1_hardened_nonce_function_smallint(unsigned char *nonce32, const unsigned char *msg,
|
||||
size_t msglen,
|
||||
const unsigned char *key32, const unsigned char *xonly_pk32,
|
||||
const unsigned char *algo, size_t algolen,
|
||||
void* data) {
|
||||
secp256k1_scalar s;
|
||||
int *idata = data;
|
||||
(void)msg;
|
||||
(void)msglen;
|
||||
(void)key32;
|
||||
(void)xonly_pk32;
|
||||
(void)algo;
|
||||
(void)algolen;
|
||||
secp256k1_scalar_set_int(&s, *idata);
|
||||
secp256k1_scalar_get_b32(nonce32, &s);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void test_exhaustive_schnorrsig_verify(const secp256k1_context *ctx, const secp256k1_xonly_pubkey* pubkeys, unsigned char (*xonly_pubkey_bytes)[32], const int* parities) {
|
||||
int d;
|
||||
uint64_t iter = 0;
|
||||
/* Iterate over the possible public keys to verify against (through their corresponding DL d). */
|
||||
for (d = 1; d <= EXHAUSTIVE_TEST_ORDER / 2; ++d) {
|
||||
int actual_d;
|
||||
unsigned k;
|
||||
unsigned char pk32[32];
|
||||
memcpy(pk32, xonly_pubkey_bytes[d - 1], 32);
|
||||
actual_d = parities[d - 1] ? EXHAUSTIVE_TEST_ORDER - d : d;
|
||||
/* Iterate over the possible valid first 32 bytes in the signature, through their corresponding DL k.
|
||||
Values above EXHAUSTIVE_TEST_ORDER/2 refer to the entries in invalid_pubkey_bytes. */
|
||||
for (k = 1; k <= EXHAUSTIVE_TEST_ORDER / 2 + NUM_INVALID_KEYS; ++k) {
|
||||
unsigned char sig64[64];
|
||||
int actual_k = -1;
|
||||
int e_done[EXHAUSTIVE_TEST_ORDER] = {0};
|
||||
int e_count_done = 0;
|
||||
if (skip_section(&iter)) continue;
|
||||
if (k <= EXHAUSTIVE_TEST_ORDER / 2) {
|
||||
memcpy(sig64, xonly_pubkey_bytes[k - 1], 32);
|
||||
actual_k = parities[k - 1] ? EXHAUSTIVE_TEST_ORDER - k : k;
|
||||
} else {
|
||||
memcpy(sig64, invalid_pubkey_bytes[k - 1 - EXHAUSTIVE_TEST_ORDER / 2], 32);
|
||||
}
|
||||
/* Randomly generate messages until all challenges have been hit. */
|
||||
while (e_count_done < EXHAUSTIVE_TEST_ORDER) {
|
||||
secp256k1_scalar e;
|
||||
unsigned char msg32[32];
|
||||
testrand256(msg32);
|
||||
secp256k1_schnorrsig_challenge(secp256k1_get_hash_context(ctx), &e, sig64, msg32, sizeof(msg32), pk32);
|
||||
/* Only do work if we hit a challenge we haven't tried before. */
|
||||
if (!e_done[e]) {
|
||||
/* Iterate over the possible valid last 32 bytes in the signature.
|
||||
0..order=that s value; order+1=random bytes */
|
||||
int count_valid = 0;
|
||||
unsigned int s;
|
||||
for (s = 0; s <= EXHAUSTIVE_TEST_ORDER + 1; ++s) {
|
||||
int expect_valid, valid;
|
||||
if (s <= EXHAUSTIVE_TEST_ORDER) {
|
||||
memset(sig64 + 32, 0, 32);
|
||||
secp256k1_write_be32(sig64 + 60, s);
|
||||
expect_valid = actual_k != -1 && s != EXHAUSTIVE_TEST_ORDER &&
|
||||
(s == (actual_k + actual_d * e) % EXHAUSTIVE_TEST_ORDER);
|
||||
} else {
|
||||
testrand256(sig64 + 32);
|
||||
expect_valid = 0;
|
||||
}
|
||||
valid = secp256k1_schnorrsig_verify(ctx, sig64, msg32, sizeof(msg32), &pubkeys[d - 1]);
|
||||
CHECK(valid == expect_valid);
|
||||
count_valid += valid;
|
||||
}
|
||||
/* Exactly one s value must verify, unless R is illegal. */
|
||||
CHECK(count_valid == (actual_k != -1));
|
||||
/* Don't retry other messages that result in the same challenge. */
|
||||
e_done[e] = 1;
|
||||
++e_count_done;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void test_exhaustive_schnorrsig_sign(const secp256k1_context *ctx, unsigned char (*xonly_pubkey_bytes)[32], const secp256k1_keypair* keypairs, const int* parities) {
|
||||
int d, k;
|
||||
uint64_t iter = 0;
|
||||
secp256k1_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT;
|
||||
|
||||
/* Loop over keys. */
|
||||
for (d = 1; d < EXHAUSTIVE_TEST_ORDER; ++d) {
|
||||
int actual_d = d;
|
||||
if (parities[d - 1]) actual_d = EXHAUSTIVE_TEST_ORDER - d;
|
||||
/* Loop over nonces. */
|
||||
for (k = 1; k < EXHAUSTIVE_TEST_ORDER; ++k) {
|
||||
int e_done[EXHAUSTIVE_TEST_ORDER] = {0};
|
||||
int e_count_done = 0;
|
||||
unsigned char msg32[32];
|
||||
unsigned char sig64[64];
|
||||
int actual_k = k;
|
||||
if (skip_section(&iter)) continue;
|
||||
extraparams.noncefp = secp256k1_hardened_nonce_function_smallint;
|
||||
extraparams.ndata = &k;
|
||||
if (parities[k - 1]) actual_k = EXHAUSTIVE_TEST_ORDER - k;
|
||||
/* Generate random messages until all challenges have been tried. */
|
||||
while (e_count_done < EXHAUSTIVE_TEST_ORDER) {
|
||||
secp256k1_scalar e;
|
||||
testrand256(msg32);
|
||||
secp256k1_schnorrsig_challenge(secp256k1_get_hash_context(ctx), &e, xonly_pubkey_bytes[k - 1], msg32, sizeof(msg32), xonly_pubkey_bytes[d - 1]);
|
||||
/* Only do work if we hit a challenge we haven't tried before. */
|
||||
if (!e_done[e]) {
|
||||
secp256k1_scalar expected_s = (actual_k + e * actual_d) % EXHAUSTIVE_TEST_ORDER;
|
||||
unsigned char expected_s_bytes[32];
|
||||
secp256k1_scalar_get_b32(expected_s_bytes, &expected_s);
|
||||
/* Invoke the real function to construct a signature. */
|
||||
CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig64, msg32, sizeof(msg32), &keypairs[d - 1], &extraparams));
|
||||
/* The first 32 bytes must match the xonly pubkey for the specified k. */
|
||||
CHECK(secp256k1_memcmp_var(sig64, xonly_pubkey_bytes[k - 1], 32) == 0);
|
||||
/* The last 32 bytes must match the expected s value. */
|
||||
CHECK(secp256k1_memcmp_var(sig64 + 32, expected_s_bytes, 32) == 0);
|
||||
/* Don't retry other messages that result in the same challenge. */
|
||||
e_done[e] = 1;
|
||||
++e_count_done;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void test_exhaustive_schnorrsig(const secp256k1_context *ctx) {
|
||||
secp256k1_keypair keypair[EXHAUSTIVE_TEST_ORDER - 1];
|
||||
secp256k1_xonly_pubkey xonly_pubkey[EXHAUSTIVE_TEST_ORDER - 1];
|
||||
int parity[EXHAUSTIVE_TEST_ORDER - 1];
|
||||
unsigned char xonly_pubkey_bytes[EXHAUSTIVE_TEST_ORDER - 1][32];
|
||||
unsigned i;
|
||||
|
||||
/* Verify that all invalid_pubkey_bytes are actually invalid. */
|
||||
for (i = 0; i < NUM_INVALID_KEYS; ++i) {
|
||||
secp256k1_xonly_pubkey pk;
|
||||
CHECK(!secp256k1_xonly_pubkey_parse(ctx, &pk, invalid_pubkey_bytes[i]));
|
||||
}
|
||||
|
||||
/* Construct keypairs and xonly-pubkeys for the entire group. */
|
||||
for (i = 1; i < EXHAUSTIVE_TEST_ORDER; ++i) {
|
||||
secp256k1_scalar scalar_i;
|
||||
unsigned char buf[32];
|
||||
secp256k1_scalar_set_int(&scalar_i, i);
|
||||
secp256k1_scalar_get_b32(buf, &scalar_i);
|
||||
CHECK(secp256k1_keypair_create(ctx, &keypair[i - 1], buf));
|
||||
CHECK(secp256k1_keypair_xonly_pub(ctx, &xonly_pubkey[i - 1], &parity[i - 1], &keypair[i - 1]));
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(ctx, xonly_pubkey_bytes[i - 1], &xonly_pubkey[i - 1]));
|
||||
}
|
||||
|
||||
test_exhaustive_schnorrsig_sign(ctx, xonly_pubkey_bytes, keypair, parity);
|
||||
test_exhaustive_schnorrsig_verify(ctx, xonly_pubkey, xonly_pubkey_bytes, parity);
|
||||
}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
16457
firmware/kb2040_hidden_signer/src/secp256k1/src/precomputed_ecmult.c
Normal file
16457
firmware/kb2040_hidden_signer/src/secp256k1/src/precomputed_ecmult.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,40 @@
|
||||
/*****************************************************************************************************
|
||||
* Copyright (c) 2013, 2014, 2017, 2021 Pieter Wuille, Andrew Poelstra, Jonas Nick, Russell O'Connor *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php. *
|
||||
*****************************************************************************************************/
|
||||
|
||||
#ifndef SECP256K1_PRECOMPUTED_ECMULT_H
|
||||
#define SECP256K1_PRECOMPUTED_ECMULT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "ecmult.h"
|
||||
#include "group.h"
|
||||
#include "util_local_visibility.h"
|
||||
|
||||
#if defined(EXHAUSTIVE_TEST_ORDER)
|
||||
# if EXHAUSTIVE_TEST_ORDER == 7
|
||||
# define WINDOW_G 3
|
||||
# elif EXHAUSTIVE_TEST_ORDER == 13
|
||||
# define WINDOW_G 4
|
||||
# elif EXHAUSTIVE_TEST_ORDER == 199
|
||||
# define WINDOW_G 8
|
||||
# else
|
||||
# error No known generator for the specified exhaustive test group order.
|
||||
# endif
|
||||
static secp256k1_ge_storage secp256k1_pre_g[ECMULT_TABLE_SIZE(WINDOW_G)];
|
||||
static secp256k1_ge_storage secp256k1_pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G)];
|
||||
#else /* !defined(EXHAUSTIVE_TEST_ORDER) */
|
||||
# define WINDOW_G ECMULT_WINDOW_SIZE
|
||||
SECP256K1_LOCAL_VAR const secp256k1_ge_storage secp256k1_pre_g[ECMULT_TABLE_SIZE(WINDOW_G)];
|
||||
SECP256K1_LOCAL_VAR const secp256k1_ge_storage secp256k1_pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G)];
|
||||
#endif /* defined(EXHAUSTIVE_TEST_ORDER) */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SECP256K1_PRECOMPUTED_ECMULT_H */
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user