add initial functions
This commit is contained in:
parent
159bd84b37
commit
3376629644
@ -20,7 +20,7 @@ jobs:
|
||||
with:
|
||||
duckdb_version: main
|
||||
ci_tools_version: main
|
||||
extension_name: quack
|
||||
extension_name: secp256k1
|
||||
|
||||
duckdb-stable-build:
|
||||
name: Build extension binaries
|
||||
@ -28,7 +28,7 @@ jobs:
|
||||
with:
|
||||
duckdb_version: v1.3.2
|
||||
ci_tools_version: v1.3.2
|
||||
extension_name: quack
|
||||
extension_name: secp256k1
|
||||
|
||||
code-quality-check:
|
||||
name: Code Quality Check
|
||||
@ -36,5 +36,5 @@ jobs:
|
||||
with:
|
||||
duckdb_version: v1.3.2
|
||||
ci_tools_version: main
|
||||
extension_name: quack
|
||||
extension_name: secp256k1
|
||||
format_checks: 'format;tidy'
|
||||
|
||||
5
.gitmodules
vendored
5
.gitmodules
vendored
@ -5,4 +5,7 @@
|
||||
[submodule "extension-ci-tools"]
|
||||
path = extension-ci-tools
|
||||
url = https://github.com/duckdb/extension-ci-tools
|
||||
branch = main
|
||||
branch = main
|
||||
[submodule "secp256k1"]
|
||||
path = secp256k1
|
||||
url = git@github.com:bitcoin-core/secp256k1.git
|
||||
|
||||
@ -1,28 +1,33 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
# Set extension name here
|
||||
set(TARGET_NAME quack)
|
||||
|
||||
# DuckDB's extension distribution supports vcpkg. As such, dependencies can be added in ./vcpkg.json and then
|
||||
# used in cmake with find_package. Feel free to remove or replace with other dependencies.
|
||||
# Note that it should also be removed from vcpkg.json to prevent needlessly installing it..
|
||||
find_package(OpenSSL REQUIRED)
|
||||
set(TARGET_NAME secp256k1)
|
||||
|
||||
set(EXTENSION_NAME ${TARGET_NAME}_extension)
|
||||
set(LOADABLE_EXTENSION_NAME ${TARGET_NAME}_loadable_extension)
|
||||
|
||||
project(${TARGET_NAME})
|
||||
include_directories(src/include)
|
||||
include_directories(secp256k1/include)
|
||||
|
||||
set(EXTENSION_SOURCES src/quack_extension.cpp)
|
||||
# Include secp256k1 source directly to avoid export issues
|
||||
set(EXTENSION_SOURCES
|
||||
src/secp256k1_extension.cpp
|
||||
secp256k1/src/secp256k1.c
|
||||
secp256k1/src/precomputed_ecmult.c
|
||||
secp256k1/src/precomputed_ecmult_gen.c
|
||||
)
|
||||
|
||||
# Add necessary preprocessor definitions for secp256k1
|
||||
add_definitions(-DECMULT_WINDOW_SIZE=15)
|
||||
add_definitions(-DECMULT_GEN_PRECISION_BITS=4)
|
||||
add_definitions(-DUSE_FIELD_10X26)
|
||||
add_definitions(-DUSE_SCALAR_8X32)
|
||||
add_definitions(-DENABLE_MODULE_ECDH)
|
||||
|
||||
build_static_extension(${TARGET_NAME} ${EXTENSION_SOURCES})
|
||||
build_loadable_extension(${TARGET_NAME} " " ${EXTENSION_SOURCES})
|
||||
|
||||
# Link OpenSSL in both the static library as the loadable extension
|
||||
target_link_libraries(${EXTENSION_NAME} OpenSSL::SSL OpenSSL::Crypto)
|
||||
target_link_libraries(${LOADABLE_EXTENSION_NAME} OpenSSL::SSL OpenSSL::Crypto)
|
||||
|
||||
install(
|
||||
TARGETS ${EXTENSION_NAME}
|
||||
EXPORT "${DUCKDB_EXPORT_SET}"
|
||||
|
||||
2
Makefile
2
Makefile
@ -1,7 +1,7 @@
|
||||
PROJ_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
|
||||
|
||||
# Configuration of extension
|
||||
EXT_NAME=quack
|
||||
EXT_NAME=secp256k1
|
||||
EXT_CONFIG=${PROJ_DIR}extension_config.cmake
|
||||
|
||||
# Include the Makefile from extension-ci-tools
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
# Quack
|
||||
# DuckDB secp256k1 Extension
|
||||
|
||||
This repository is based on https://github.com/duckdb/extension-template, check it out if you want to build and ship your own DuckDB extension.
|
||||
|
||||
---
|
||||
|
||||
This extension, Quack, allow you to ... <extension_goal>.
|
||||
This extension provides secp256k1 cryptographic functions for DuckDB, allowing elliptic curve operations directly in SQL queries.
|
||||
|
||||
|
||||
## Building
|
||||
@ -26,24 +26,26 @@ The main binaries that will be built are:
|
||||
```sh
|
||||
./build/release/duckdb
|
||||
./build/release/test/unittest
|
||||
./build/release/extension/quack/quack.duckdb_extension
|
||||
./build/release/extension/secp256k1/secp256k1.duckdb_extension
|
||||
```
|
||||
- `duckdb` is the binary for the duckdb shell with the extension code automatically loaded.
|
||||
- `unittest` is the test runner of duckdb. Again, the extension is already linked into the binary.
|
||||
- `quack.duckdb_extension` is the loadable binary as it would be distributed.
|
||||
- `secp256k1.duckdb_extension` is the loadable binary as it would be distributed.
|
||||
|
||||
## Running the extension
|
||||
To run the extension code, simply start the shell with `./build/release/duckdb`.
|
||||
|
||||
Now we can use the features from the extension directly in DuckDB. The template contains a single scalar function `quack()` that takes a string arguments and returns a string:
|
||||
Now we can use the secp256k1 cryptographic functions directly in DuckDB. The extension provides functions like `secp256k1_ec_pubkey_combine()` for combining elliptic curve public keys:
|
||||
```
|
||||
D select quack('Jane') as result;
|
||||
┌───────────────┐
|
||||
│ result │
|
||||
│ varchar │
|
||||
├───────────────┤
|
||||
│ Quack Jane 🐥 │
|
||||
└───────────────┘
|
||||
D SELECT secp256k1_ec_pubkey_combine(
|
||||
from_hex('0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798'),
|
||||
from_hex('02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5')
|
||||
) IS NOT NULL as combined_successfully;
|
||||
┌─────────────────────┐
|
||||
│ combined_successfully │
|
||||
├─────────────────────┤
|
||||
│ true │
|
||||
└─────────────────────┘
|
||||
```
|
||||
|
||||
## Running the tests
|
||||
@ -81,6 +83,6 @@ DuckDB. To specify a specific version, you can pass the version instead.
|
||||
|
||||
After running these steps, you can install and load your extension using the regular INSTALL/LOAD commands in DuckDB:
|
||||
```sql
|
||||
INSTALL quack
|
||||
LOAD quack
|
||||
INSTALL secp256k1
|
||||
LOAD secp256k1
|
||||
```
|
||||
|
||||
@ -46,15 +46,18 @@ GEN=ninja make
|
||||
## Running the extension
|
||||
To run the extension code, simply start the shell with `./build/release/duckdb`. This shell will have the extension pre-loaded.
|
||||
|
||||
Now we can use the features from the extension directly in DuckDB. The template contains a single scalar function `quack()` that takes a string arguments and returns a string:
|
||||
Now we can use the features from the extension directly in DuckDB. This extension contains the secp256k1 cryptographic functions, including `secp256k1_ec_pubkey_combine()` that combines multiple public keys:
|
||||
```
|
||||
D select quack('Jane') as result;
|
||||
┌───────────────┐
|
||||
│ result │
|
||||
│ varchar │
|
||||
├───────────────┤
|
||||
│ Quack Jane 🐥 │
|
||||
└───────────────┘
|
||||
D LOAD 'secp256k1';
|
||||
D SELECT secp256k1_ec_pubkey_combine(
|
||||
from_hex('0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798'),
|
||||
from_hex('02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5')
|
||||
) IS NOT NULL as combined_successfully;
|
||||
┌─────────────────────┐
|
||||
│ combined_successfully │
|
||||
├─────────────────────┤
|
||||
│ true │
|
||||
└─────────────────────┘
|
||||
```
|
||||
|
||||
## Running the tests
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
# This file is included by DuckDB's build system. It specifies which extension to load
|
||||
|
||||
# Extension from this repo
|
||||
duckdb_extension_load(quack
|
||||
duckdb_extension_load(secp256k1
|
||||
SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}
|
||||
LOAD_TESTS
|
||||
)
|
||||
|
||||
1
secp256k1
Submodule
1
secp256k1
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit e523e4f90e1b1c0fba49cd8a08016e1a8dff9232
|
||||
@ -4,11 +4,11 @@
|
||||
|
||||
namespace duckdb {
|
||||
|
||||
class QuackExtension : public Extension {
|
||||
class Secp256k1Extension : public Extension {
|
||||
public:
|
||||
void Load(DuckDB &db) override;
|
||||
std::string Name() override;
|
||||
std::string Version() const override;
|
||||
};
|
||||
|
||||
} // namespace duckdb
|
||||
} // namespace duckdb
|
||||
@ -1,73 +0,0 @@
|
||||
#define DUCKDB_EXTENSION_MAIN
|
||||
|
||||
#include "quack_extension.hpp"
|
||||
#include "duckdb.hpp"
|
||||
#include "duckdb/common/exception.hpp"
|
||||
#include "duckdb/common/string_util.hpp"
|
||||
#include "duckdb/function/scalar_function.hpp"
|
||||
#include "duckdb/main/extension_util.hpp"
|
||||
#include <duckdb/parser/parsed_data/create_scalar_function_info.hpp>
|
||||
|
||||
// OpenSSL linked through vcpkg
|
||||
#include <openssl/opensslv.h>
|
||||
|
||||
namespace duckdb {
|
||||
|
||||
inline void QuackScalarFun(DataChunk &args, ExpressionState &state, Vector &result) {
|
||||
auto &name_vector = args.data[0];
|
||||
UnaryExecutor::Execute<string_t, string_t>(name_vector, result, args.size(), [&](string_t name) {
|
||||
return StringVector::AddString(result, "Quack " + name.GetString() + " 🐥");
|
||||
});
|
||||
}
|
||||
|
||||
inline void QuackOpenSSLVersionScalarFun(DataChunk &args, ExpressionState &state, Vector &result) {
|
||||
auto &name_vector = args.data[0];
|
||||
UnaryExecutor::Execute<string_t, string_t>(name_vector, result, args.size(), [&](string_t name) {
|
||||
return StringVector::AddString(result, "Quack " + name.GetString() + ", my linked OpenSSL version is " +
|
||||
OPENSSL_VERSION_TEXT);
|
||||
});
|
||||
}
|
||||
|
||||
static void LoadInternal(DatabaseInstance &instance) {
|
||||
// Register a scalar function
|
||||
auto quack_scalar_function = ScalarFunction("quack", {LogicalType::VARCHAR}, LogicalType::VARCHAR, QuackScalarFun);
|
||||
ExtensionUtil::RegisterFunction(instance, quack_scalar_function);
|
||||
|
||||
// Register another scalar function
|
||||
auto quack_openssl_version_scalar_function = ScalarFunction("quack_openssl_version", {LogicalType::VARCHAR},
|
||||
LogicalType::VARCHAR, QuackOpenSSLVersionScalarFun);
|
||||
ExtensionUtil::RegisterFunction(instance, quack_openssl_version_scalar_function);
|
||||
}
|
||||
|
||||
void QuackExtension::Load(DuckDB &db) {
|
||||
LoadInternal(*db.instance);
|
||||
}
|
||||
std::string QuackExtension::Name() {
|
||||
return "quack";
|
||||
}
|
||||
|
||||
std::string QuackExtension::Version() const {
|
||||
#ifdef EXT_VERSION_QUACK
|
||||
return EXT_VERSION_QUACK;
|
||||
#else
|
||||
return "";
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace duckdb
|
||||
|
||||
extern "C" {
|
||||
|
||||
DUCKDB_EXTENSION_API void quack_init(duckdb::DatabaseInstance &db) {
|
||||
duckdb::DuckDB db_wrapper(db);
|
||||
db_wrapper.LoadExtension<duckdb::QuackExtension>();
|
||||
}
|
||||
|
||||
DUCKDB_EXTENSION_API const char *quack_version() {
|
||||
return duckdb::DuckDB::LibraryVersion();
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef DUCKDB_EXTENSION_MAIN
|
||||
#error DUCKDB_EXTENSION_MAIN not defined
|
||||
#endif
|
||||
231
src/secp256k1_extension.cpp
Normal file
231
src/secp256k1_extension.cpp
Normal file
@ -0,0 +1,231 @@
|
||||
#define DUCKDB_EXTENSION_MAIN
|
||||
|
||||
#include "secp256k1_extension.hpp"
|
||||
#include "duckdb.hpp"
|
||||
#include "duckdb/common/exception.hpp"
|
||||
#include "duckdb/common/string_util.hpp"
|
||||
#include "duckdb/function/scalar_function.hpp"
|
||||
#include "duckdb/main/extension_util.hpp"
|
||||
#include <duckdb/parser/parsed_data/create_scalar_function_info.hpp>
|
||||
|
||||
// secp256k1 library
|
||||
#include "secp256k1.h"
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <cstring>
|
||||
|
||||
namespace duckdb {
|
||||
|
||||
// Global secp256k1 context for verification operations
|
||||
static secp256k1_context* secp256k1_ctx = nullptr;
|
||||
|
||||
// Helper function to initialize secp256k1 context
|
||||
static secp256k1_context* GetSecp256k1Context() {
|
||||
if (!secp256k1_ctx) {
|
||||
secp256k1_ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
||||
if (!secp256k1_ctx) {
|
||||
throw InternalException("Failed to create secp256k1 context");
|
||||
}
|
||||
}
|
||||
return secp256k1_ctx;
|
||||
}
|
||||
|
||||
// Function to combine public keys using secp256k1_ec_pubkey_combine
|
||||
inline void Secp256k1EcPubkeyCombineScalarFun(DataChunk &args, ExpressionState &state, Vector &result) {
|
||||
// Get the secp256k1 context
|
||||
secp256k1_context *ctx = GetSecp256k1Context();
|
||||
|
||||
// The function takes a variable number of BLOB arguments (each 33 bytes for compressed pubkeys)
|
||||
D_ASSERT(args.ColumnCount() >= 1);
|
||||
|
||||
// Get number of rows to process
|
||||
idx_t count = args.size();
|
||||
|
||||
// Process each row
|
||||
for (idx_t i = 0; i < count; i++) {
|
||||
std::vector<secp256k1_pubkey> parsed_pubkeys;
|
||||
std::vector<const secp256k1_pubkey*> pubkey_ptrs;
|
||||
|
||||
bool all_valid = true;
|
||||
|
||||
// Parse all input public keys for this row
|
||||
for (idx_t col = 0; col < args.ColumnCount(); col++) {
|
||||
auto &input_vector = args.data[col];
|
||||
|
||||
// Check if this column value is NULL
|
||||
if (FlatVector::IsNull(input_vector, i)) {
|
||||
all_valid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// Get the blob data
|
||||
auto blob_data = FlatVector::GetData<string_t>(input_vector)[i];
|
||||
|
||||
// Validate that the blob is exactly 33 bytes (compressed pubkey format)
|
||||
if (blob_data.GetSize() != 33) {
|
||||
all_valid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// Parse the public key
|
||||
secp256k1_pubkey pubkey;
|
||||
const unsigned char *input_data = reinterpret_cast<const unsigned char*>(blob_data.GetDataUnsafe());
|
||||
|
||||
if (secp256k1_ec_pubkey_parse(ctx, &pubkey, input_data, 33) != 1) {
|
||||
all_valid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
parsed_pubkeys.push_back(pubkey);
|
||||
}
|
||||
|
||||
if (!all_valid || parsed_pubkeys.empty()) {
|
||||
// Set result to NULL for this row
|
||||
FlatVector::SetNull(result, i, true);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create array of pointers for secp256k1_ec_pubkey_combine
|
||||
for (const auto& pk : parsed_pubkeys) {
|
||||
pubkey_ptrs.push_back(&pk);
|
||||
}
|
||||
|
||||
// Combine the public keys
|
||||
secp256k1_pubkey combined_pubkey;
|
||||
if (secp256k1_ec_pubkey_combine(ctx, &combined_pubkey, pubkey_ptrs.data(), pubkey_ptrs.size()) != 1) {
|
||||
// Set result to NULL for this row if combination failed
|
||||
FlatVector::SetNull(result, i, true);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Serialize the combined public key back to compressed format (33 bytes)
|
||||
unsigned char output[33];
|
||||
size_t output_len = 33;
|
||||
|
||||
if (secp256k1_ec_pubkey_serialize(ctx, output, &output_len, &combined_pubkey, SECP256K1_EC_COMPRESSED) != 1) {
|
||||
// Set result to NULL for this row if serialization failed
|
||||
FlatVector::SetNull(result, i, true);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create the result blob
|
||||
string_t result_blob = StringVector::AddStringOrBlob(result, (const char*)output, 33);
|
||||
FlatVector::GetData<string_t>(result)[i] = result_blob;
|
||||
}
|
||||
}
|
||||
|
||||
// Function to concatenate a 32-byte blob with a 4-byte integer in little-endian format
|
||||
inline void CreateOutpointScalarFun(DataChunk &args, ExpressionState &state, Vector &result) {
|
||||
D_ASSERT(args.ColumnCount() == 2);
|
||||
|
||||
auto &blob_vector = args.data[0];
|
||||
auto &int_vector = args.data[1];
|
||||
|
||||
// Get number of rows to process
|
||||
idx_t count = args.size();
|
||||
|
||||
// Process each row
|
||||
for (idx_t i = 0; i < count; i++) {
|
||||
// Check if either input is NULL
|
||||
if (FlatVector::IsNull(blob_vector, i) || FlatVector::IsNull(int_vector, i)) {
|
||||
FlatVector::SetNull(result, i, true);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the blob data
|
||||
auto blob_data = FlatVector::GetData<string_t>(blob_vector)[i];
|
||||
|
||||
// Validate that the blob is exactly 32 bytes
|
||||
if (blob_data.GetSize() != 32) {
|
||||
FlatVector::SetNull(result, i, true);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the integer value
|
||||
auto int_value = FlatVector::GetData<int32_t>(int_vector)[i];
|
||||
|
||||
// Create output buffer (32 bytes + 4 bytes = 36 bytes)
|
||||
unsigned char output[36];
|
||||
|
||||
// Copy the 32-byte blob
|
||||
memcpy(output, blob_data.GetDataUnsafe(), 32);
|
||||
|
||||
// Append the 4-byte integer in little-endian format
|
||||
output[32] = (unsigned char)(int_value & 0xFF);
|
||||
output[33] = (unsigned char)((int_value >> 8) & 0xFF);
|
||||
output[34] = (unsigned char)((int_value >> 16) & 0xFF);
|
||||
output[35] = (unsigned char)((int_value >> 24) & 0xFF);
|
||||
|
||||
// Create the result blob
|
||||
string_t result_blob = StringVector::AddStringOrBlob(result, (const char*)output, 36);
|
||||
FlatVector::GetData<string_t>(result)[i] = result_blob;
|
||||
}
|
||||
}
|
||||
|
||||
static void LoadInternal(DatabaseInstance &instance) {
|
||||
// Register the secp256k1_ec_pubkey_combine function that accepts variable arguments
|
||||
ScalarFunctionSet secp256k1_ec_pubkey_combine_function_set("secp256k1_ec_pubkey_combine");
|
||||
|
||||
// Add overloads for different numbers of arguments (2-10 public keys)
|
||||
for (idx_t num_args = 2; num_args <= 10; num_args++) {
|
||||
vector<LogicalType> arg_types;
|
||||
for (idx_t i = 0; i < num_args; i++) {
|
||||
arg_types.push_back(LogicalType::BLOB);
|
||||
}
|
||||
|
||||
secp256k1_ec_pubkey_combine_function_set.AddFunction(ScalarFunction(
|
||||
arg_types, LogicalType::BLOB, Secp256k1EcPubkeyCombineScalarFun
|
||||
));
|
||||
}
|
||||
|
||||
ExtensionUtil::RegisterFunction(instance, secp256k1_ec_pubkey_combine_function_set);
|
||||
|
||||
// Register the create_outpoint function
|
||||
auto create_outpoint_function = ScalarFunction("create_outpoint",
|
||||
{LogicalType::BLOB, LogicalType::INTEGER}, LogicalType::BLOB, CreateOutpointScalarFun);
|
||||
ExtensionUtil::RegisterFunction(instance, create_outpoint_function);
|
||||
}
|
||||
|
||||
void Secp256k1Extension::Load(DuckDB &db) {
|
||||
LoadInternal(*db.instance);
|
||||
}
|
||||
|
||||
std::string Secp256k1Extension::Name() {
|
||||
return "secp256k1";
|
||||
}
|
||||
|
||||
std::string Secp256k1Extension::Version() const {
|
||||
#ifdef EXT_VERSION_SECP256K1
|
||||
return EXT_VERSION_SECP256K1;
|
||||
#else
|
||||
return "";
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace duckdb
|
||||
|
||||
extern "C" {
|
||||
|
||||
DUCKDB_EXTENSION_API void secp256k1_init(duckdb::DatabaseInstance &db) {
|
||||
duckdb::DuckDB db_wrapper(db);
|
||||
db_wrapper.LoadExtension<duckdb::Secp256k1Extension>();
|
||||
}
|
||||
|
||||
DUCKDB_EXTENSION_API const char *secp256k1_version() {
|
||||
return duckdb::DuckDB::LibraryVersion();
|
||||
}
|
||||
|
||||
// Cleanup function to destroy the secp256k1 context
|
||||
DUCKDB_EXTENSION_API void secp256k1_cleanup() {
|
||||
if (duckdb::secp256k1_ctx) {
|
||||
secp256k1_context_destroy(duckdb::secp256k1_ctx);
|
||||
duckdb::secp256k1_ctx = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#ifndef DUCKDB_EXTENSION_MAIN
|
||||
#error DUCKDB_EXTENSION_MAIN not defined
|
||||
#endif
|
||||
@ -1,5 +1,5 @@
|
||||
# Testing this extension
|
||||
This directory contains all the tests for this extension. The `sql` directory holds tests that are written as [SQLLogicTests](https://duckdb.org/dev/sqllogictest/intro.html). DuckDB aims to have most its tests in this format as SQL statements, so for the quack extension, this should probably be the goal too.
|
||||
This directory contains all the tests for this extension. The `sql` directory holds tests that are written as [SQLLogicTests](https://duckdb.org/dev/sqllogictest/intro.html). DuckDB aims to have most its tests in this format as SQL statements, so for the secp256k1 extension, this should probably be the goal too.
|
||||
|
||||
The root makefile contains targets to build and run all of these tests. To run the SQLLogicTests:
|
||||
```bash
|
||||
|
||||
@ -1,23 +0,0 @@
|
||||
# name: test/sql/quack.test
|
||||
# description: test quack extension
|
||||
# group: [sql]
|
||||
|
||||
# Before we load the extension, this will fail
|
||||
statement error
|
||||
SELECT quack('Sam');
|
||||
----
|
||||
Catalog Error: Scalar Function with name quack does not exist!
|
||||
|
||||
# Require statement will ensure this test is run with this extension loaded
|
||||
require quack
|
||||
|
||||
# Confirm the extension works
|
||||
query I
|
||||
SELECT quack('Sam');
|
||||
----
|
||||
Quack Sam 🐥
|
||||
|
||||
query I
|
||||
SELECT quack_openssl_version('Michael') ILIKE 'Quack Michael, my linked OpenSSL version is OpenSSL%';
|
||||
----
|
||||
true
|
||||
104
test/sql/secp256k1.test
Normal file
104
test/sql/secp256k1.test
Normal file
@ -0,0 +1,104 @@
|
||||
# name: test/sql/secp256k1.test
|
||||
# description: test secp256k1 extension
|
||||
# group: [sql]
|
||||
|
||||
# Before we load the extension, this will fail
|
||||
statement error
|
||||
SELECT secp256k1_ec_pubkey_combine(from_hex('0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798'), from_hex('02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5'));
|
||||
----
|
||||
Catalog Error: Scalar Function with name secp256k1_ec_pubkey_combine does not exist!
|
||||
|
||||
# Require statement will ensure this test is run with this extension loaded
|
||||
require secp256k1
|
||||
|
||||
# Test combining two valid compressed public keys
|
||||
# Using secp256k1 generator point (0279be...) and another valid compressed pubkey
|
||||
query I
|
||||
SELECT secp256k1_ec_pubkey_combine(
|
||||
from_hex('0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798'),
|
||||
from_hex('02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5')
|
||||
) IS NOT NULL;
|
||||
----
|
||||
true
|
||||
|
||||
# Test combining three public keys
|
||||
query I
|
||||
SELECT secp256k1_ec_pubkey_combine(
|
||||
from_hex('0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798'),
|
||||
from_hex('02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5'),
|
||||
from_hex('03774ae7f858a9411e5ef4246b70c65aac5649980be5c17891bbec17895da008cb')
|
||||
) IS NOT NULL;
|
||||
----
|
||||
true
|
||||
|
||||
# Test with NULL input (should return NULL)
|
||||
query I
|
||||
SELECT secp256k1_ec_pubkey_combine(NULL, from_hex('0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798'));
|
||||
----
|
||||
NULL
|
||||
|
||||
# Test with invalid length input (should return NULL)
|
||||
query I
|
||||
SELECT secp256k1_ec_pubkey_combine(from_hex('0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f817'), from_hex('0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798'));
|
||||
----
|
||||
NULL
|
||||
|
||||
# Test with invalid public key data (should return NULL)
|
||||
query I
|
||||
SELECT secp256k1_ec_pubkey_combine(from_hex('0000000000000000000000000000000000000000000000000000000000000000000'), from_hex('0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798'));
|
||||
----
|
||||
NULL
|
||||
|
||||
# Test create_outpoint function with 32-byte blob and integer
|
||||
query I
|
||||
SELECT octet_length(create_outpoint(
|
||||
from_hex('0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'),
|
||||
1
|
||||
));
|
||||
----
|
||||
36
|
||||
|
||||
# Test create_outpoint with zero integer (little-endian encoding)
|
||||
query I
|
||||
SELECT create_outpoint(
|
||||
from_hex('0000000000000000000000000000000000000000000000000000000000000000'),
|
||||
0
|
||||
) = from_hex('000000000000000000000000000000000000000000000000000000000000000000000000');
|
||||
----
|
||||
true
|
||||
|
||||
# Test create_outpoint with integer 1 (little-endian encoding)
|
||||
query I
|
||||
SELECT create_outpoint(
|
||||
from_hex('0000000000000000000000000000000000000000000000000000000000000000'),
|
||||
1
|
||||
) = from_hex('000000000000000000000000000000000000000000000000000000000000000001000000');
|
||||
----
|
||||
true
|
||||
|
||||
# Test create_outpoint with integer 256 (little-endian encoding)
|
||||
query I
|
||||
SELECT create_outpoint(
|
||||
from_hex('0000000000000000000000000000000000000000000000000000000000000000'),
|
||||
256
|
||||
) = from_hex('000000000000000000000000000000000000000000000000000000000000000000010000');
|
||||
----
|
||||
true
|
||||
|
||||
# Test create_outpoint with NULL blob (should return NULL)
|
||||
query I
|
||||
SELECT create_outpoint(NULL, 1);
|
||||
----
|
||||
NULL
|
||||
|
||||
# Test create_outpoint with NULL integer (should return NULL)
|
||||
query I
|
||||
SELECT create_outpoint(from_hex('0000000000000000000000000000000000000000000000000000000000000000'), NULL);
|
||||
----
|
||||
NULL
|
||||
|
||||
# Test create_outpoint with wrong blob length (should return NULL)
|
||||
query I
|
||||
SELECT create_outpoint(from_hex('00000000000000000000000000000000000000000000000000000000000000'), 1);
|
||||
----
|
||||
NULL
|
||||
10
vcpkg.json
10
vcpkg.json
@ -1,10 +0,0 @@
|
||||
{
|
||||
"dependencies": [
|
||||
"openssl"
|
||||
],
|
||||
"vcpkg-configuration": {
|
||||
"overlay-ports": [
|
||||
"./extension-ci-tools/vcpkg_ports"
|
||||
]
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user