Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
build/
.DS_Store
.idea/
.venv
18 changes: 15 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
cmake_minimum_required(VERSION 3.16)
project(mpt-crypto C CXX)

# --- Find Dependencies ---
# --- 1. Global Architecture Detection ---
include(CheckTypeSize)
check_type_size("unsigned __int128" HAVE_INT128_T)

if (HAVE_INT128_T OR CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64" OR CMAKE_SYSTEM_PROCESSOR MATCHES "arm64"
OR CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64")
message(STATUS "Build: Detected 64-bit system. Enforcing 64-bit arithmetic globally.")
add_compile_definitions(USE_SCALAR_4X64 USE_FIELD_5X52 HAVE___INT128)
else ()
message(STATUS "Build: Detected 32-bit system. Enforcing generic arithmetic globally.")
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The architecture detection enables USE_SCALAR_4X64 and defines HAVE___INT128 whenever the CPU looks 64-bit, even if CheckTypeSize("unsigned __int128") fails. On toolchains without unsigned __int128 (e.g., MSVC x64), this can force the 4x64 backend and HAVE___INT128, likely breaking compilation or producing incorrect scalar math. Suggest gating USE_SCALAR_4X64/HAVE___INT128 strictly on HAVE_INT128_T (and otherwise fall back to USE_SCALAR_8X32), or adding a separate, verified MSVC-compatible 64-bit path.

Suggested change
if (HAVE_INT128_T OR CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64" OR CMAKE_SYSTEM_PROCESSOR MATCHES "arm64"
OR CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64")
message(STATUS "Build: Detected 64-bit system. Enforcing 64-bit arithmetic globally.")
add_compile_definitions(USE_SCALAR_4X64 USE_FIELD_5X52 HAVE___INT128)
else ()
message(STATUS "Build: Detected 32-bit system. Enforcing generic arithmetic globally.")
if (HAVE_INT128_T)
message(STATUS "Build: Detected compiler support for unsigned __int128. Enforcing 64-bit arithmetic backend.")
add_compile_definitions(USE_SCALAR_4X64 USE_FIELD_5X52 HAVE___INT128)
else ()
message(STATUS "Build: No unsigned __int128 support detected. Using generic 32-bit arithmetic backend.")

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've updated CMakeLists.txt to use the definitions that actually exist in the source.

add_compile_definitions(USE_SCALAR_8X32 USE_FIELD_10X26)
endif ()

# --- Find Dependencies (Maintainer's Way) ---
find_package(OpenSSL REQUIRED)
find_package(secp256k1 REQUIRED)

Expand All @@ -22,8 +35,7 @@ add_library(mpt-crypto
target_include_directories(mpt-crypto PUBLIC include)

# --- Set Compile Definitions ---
target_compile_definitions(mpt-crypto PRIVATE USE_SCALAR_8X32 USE_FIELD_10X26 ECMULT_WINDOW_SIZE=15
ECMULT_GEN_PREC_BITS=4)
target_compile_definitions(mpt-crypto PRIVATE ECMULT_WINDOW_SIZE=15 ECMULT_GEN_PREC_BITS=4)

# --- Link Dependencies ---
target_link_libraries(mpt-crypto PUBLIC secp256k1::secp256k1 PUBLIC OpenSSL::Crypto)
Expand Down
9 changes: 1 addition & 8 deletions src/mpt_scalar.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,8 @@
#include <string.h>
#include <openssl/crypto.h>

/* 1. Backend Configuration Definitions */
#ifndef USE_SCALAR_8X32
#define USE_SCALAR_8X32
#endif
#ifndef USE_FIELD_10X26
#define USE_FIELD_10X26
#endif

/* 2. Include low-level utilities first.
/* Include low-level utilities first.
On ARM64/Apple Silicon, the scalar math depends on 128-bit
integer helpers defined in these headers. */
#include <private/util.h>
Expand Down
107 changes: 0 additions & 107 deletions tests/test_bulletproof.c

This file was deleted.

107 changes: 35 additions & 72 deletions tests/test_bulletproof_agg.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <time.h>
#include <openssl/rand.h>
#include <secp256k1.h>
Expand All @@ -15,45 +15,14 @@
/* ---- Benchmark parameters ---- */
#define VERIFY_RUNS 5

/* ---- Prototypes ---- */
int secp256k1_bulletproof_prove_agg(
const secp256k1_context* ctx,
unsigned char* proof_out,
size_t* proof_len,
const uint64_t* values,
const unsigned char* blindings_flat,
size_t m,
const secp256k1_pubkey* pk_base,
const unsigned char* context_id
);

int secp256k1_bulletproof_verify_agg(
const secp256k1_context* ctx,
const secp256k1_pubkey* G_vec,
const secp256k1_pubkey* H_vec,
const unsigned char* proof,
size_t proof_len,
const secp256k1_pubkey* commitment_C_vec,
size_t m,
const secp256k1_pubkey* pk_base,
const unsigned char* context_id
);

int secp256k1_bulletproof_create_commitment(
const secp256k1_context* ctx,
secp256k1_pubkey* commitment_C,
uint64_t value,
const unsigned char* blinding_factor,
const secp256k1_pubkey* pk_base
);

extern int secp256k1_mpt_get_generator_vector(
const secp256k1_context* ctx,
secp256k1_pubkey* vec,
size_t n,
const unsigned char* label,
size_t label_len
);
/* --- Macro: Persistent Assertion --- */
#define EXPECT(cond, msg) do { \
if (!(cond)) { \
fprintf(stderr, "CRITICAL FAILURE: %s\nFile: %s, Line: %d\nCode: %s\n", \
msg, __FILE__, __LINE__, #cond); \
exit(EXIT_FAILURE); \
} \
} while(0)

/* ---- Helpers ---- */

Expand All @@ -67,7 +36,10 @@ static void random_scalar(
unsigned char out[32]
) {
do {
RAND_bytes(out, 32);
if (RAND_bytes(out, 32) != 1) {
fprintf(stderr, "RAND_bytes failed\n");
exit(1);
}
} while (!secp256k1_ec_seckey_verify(ctx, out));
}

Expand All @@ -78,50 +50,42 @@ int main(void) {
/* ---- Context ---- */
secp256k1_context* ctx =
secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
EXPECT(ctx != NULL, "Failed to create context");

/* ---- Values ---- */
uint64_t values[M] = { 5000, 123456 };
unsigned char blindings[M][32];
secp256k1_pubkey commitments[M];

/**
* CONTEXT BINDING:
* In the production system, this ID is derived deterministically:
* TransactionContextID := H(TxType || Account || MPTokenIssuanceID || ...)
* * See [Spec Section 3.3.1] for the derivation rules.
* * For this library unit test, random bytes suffice to verify that the
* proof binds correctly to *whatever* context ID is provided.
*/
/* ---- Context Binding ---- */
unsigned char context_id[32];
RAND_bytes(context_id, 32);

EXPECT(RAND_bytes(context_id, 32) == 1, "Failed to generate context_id");

secp256k1_pubkey pk_base;
/* Use the standard H generator from the library */
assert(secp256k1_mpt_get_h_generator(ctx, &pk_base));

/* Use the standard H generator from the library */
EXPECT(secp256k1_mpt_get_h_generator(ctx, &pk_base), "Failed to get H generator");

/* ---- Commitments ---- */
for (size_t i = 0; i < M; i++) {
random_scalar(ctx, blindings[i]);
assert(secp256k1_bulletproof_create_commitment(
EXPECT(secp256k1_bulletproof_create_commitment(
ctx,
&commitments[i],
values[i],
blindings[i],
&pk_base));
&pk_base), "Failed to create commitment");
}

/* ---- Generator vectors ---- */
const size_t n = BP_TOTAL_BITS(M);
secp256k1_pubkey* G_vec = malloc(n * sizeof(secp256k1_pubkey));
secp256k1_pubkey* H_vec = malloc(n * sizeof(secp256k1_pubkey));
assert(G_vec && H_vec);
EXPECT(G_vec && H_vec, "Malloc failed");

assert(secp256k1_mpt_get_generator_vector(
ctx, G_vec, n, (const unsigned char*)"G", 1));
assert(secp256k1_mpt_get_generator_vector(
ctx, H_vec, n, (const unsigned char*)"H", 1));
EXPECT(secp256k1_mpt_get_generator_vector(
ctx, G_vec, n, (const unsigned char*)"G", 1), "Failed to get G vector");
EXPECT(secp256k1_mpt_get_generator_vector(
ctx, H_vec, n, (const unsigned char*)"H", 1), "Failed to get H vector");

/* ---- Prove (timed) ---- */
unsigned char proof[4096];
Expand All @@ -132,15 +96,16 @@ int main(void) {
struct timespec t_p_start, t_p_end;
clock_gettime(CLOCK_MONOTONIC, &t_p_start);

assert(secp256k1_bulletproof_prove_agg(
/* Note: We cast the 2D array 'blindings' to flat pointer */
EXPECT(secp256k1_bulletproof_prove_agg(
ctx,
proof,
&proof_len,
values,
(const unsigned char*)blindings,
M,
&pk_base,
context_id));
context_id), "Proving failed");

clock_gettime(CLOCK_MONOTONIC, &t_p_end);

Expand All @@ -167,10 +132,7 @@ int main(void) {

clock_gettime(CLOCK_MONOTONIC, &t_v_end);

if (!ok) {
printf("FAILED\n");
return 1;
}
EXPECT(ok, "Verification failed (single run)");

printf("PASSED\n");
printf("[BENCH] Verification time (single): %.3f ms\n",
Expand All @@ -196,7 +158,7 @@ int main(void) {

clock_gettime(CLOCK_MONOTONIC, &te);

assert(ok);
EXPECT(ok, "Verification failed during benchmark");
total_ms += elapsed_ms(ts, te);
}

Expand All @@ -212,12 +174,13 @@ int main(void) {
unsigned char bad_blinding[32];
random_scalar(ctx, bad_blinding);

assert(secp256k1_bulletproof_create_commitment(
/* Create a fake commitment to (value + 1) to break the sum */
EXPECT(secp256k1_bulletproof_create_commitment(
ctx,
&bad_commitments[1],
values[1] + 1,
bad_blinding,
&pk_base));
&pk_base), "Failed to create bad commitment");

ok = secp256k1_bulletproof_verify_agg(
ctx,
Expand All @@ -231,8 +194,8 @@ int main(void) {
context_id);

if (ok) {
printf("FAILED (accepted invalid proof)\n");
return 1;
fprintf(stderr, "FAILED: Accepted invalid proof!\n");
exit(EXIT_FAILURE);
}

printf("PASSED (rejected invalid proof)\n");
Expand Down
Loading
Loading