diff --git a/config/extra/with-arm.mk b/config/extra/with-arm.mk index 88c87e770b..2fd39c3e40 100644 --- a/config/extra/with-arm.mk +++ b/config/extra/with-arm.mk @@ -29,6 +29,7 @@ else # CROSS=0 include config/extra/with-ucontext.mk include config/extra/with-secp256k1.mk +include config/extra/with-blst.mk include config/extra/with-zstd.mk include config/extra/with-lz4.mk include config/extra/with-openssl.mk diff --git a/config/extra/with-blst.mk b/config/extra/with-blst.mk new file mode 100644 index 0000000000..f64a091cd6 --- /dev/null +++ b/config/extra/with-blst.mk @@ -0,0 +1,7 @@ +ifneq (,$(wildcard $(OPT)/lib/libblst.a)) +FD_HAS_BLST:=1 +CFLAGS+=-DFD_HAS_BLST=1 +LDFLAGS+=$(OPT)/lib/libblst.a +else +$(warning "blst not installed, skipping") +endif diff --git a/config/extra/with-x86-64.mk b/config/extra/with-x86-64.mk index 072b8fb280..6346fe68ff 100644 --- a/config/extra/with-x86-64.mk +++ b/config/extra/with-x86-64.mk @@ -15,6 +15,7 @@ endif include config/extra/with-ucontext.mk include config/extra/with-secp256k1.mk include config/extra/with-s2nbignum.mk +include config/extra/with-blst.mk include config/extra/with-zstd.mk include config/extra/with-lz4.mk include config/extra/with-openssl.mk diff --git a/src/ballet/bls/Local.mk b/src/ballet/bls/Local.mk new file mode 100644 index 0000000000..97d5312f4a --- /dev/null +++ b/src/ballet/bls/Local.mk @@ -0,0 +1,13 @@ +ifdef FD_HAS_BLST + +$(call add-hdrs,fd_bls12_381.h) +$(call add-objs,fd_bls12_381,fd_ballet) +$(call make-unit-test,test_bls12_381,test_bls12_381,fd_ballet fd_util,$(BLST_LIBS)) + +$(call run-unit-test,test_bls12_381) + +else + +$(warning bls12_381 disabled due to lack of libblst) + +endif diff --git a/src/ballet/bls/fd_bls12_381.c b/src/ballet/bls/fd_bls12_381.c new file mode 100644 index 0000000000..186011da22 --- /dev/null +++ b/src/ballet/bls/fd_bls12_381.c @@ -0,0 +1,21 @@ +#include "fd_bls12_381.h" + +#include + +int +fd_bls12_381_g1_add_syscall( uchar rr[48], + uchar const pp[48], + uchar const qq[48] ) { + blst_p1_affine pa[1], qa[1]; + blst_p1 p[1], r[1]; + if( FD_UNLIKELY( blst_p1_uncompress( pa, pp )!=BLST_SUCCESS ) ) { + return -1; + } + if( FD_UNLIKELY( blst_p1_uncompress( qa, qq )!=BLST_SUCCESS ) ) { + return -1; + } + blst_p1_from_affine( p, pa ); + blst_p1_add_or_double_affine( r, p, qa ); + blst_p1_compress( rr, r ); + return 0; +} diff --git a/src/ballet/bls/fd_bls12_381.h b/src/ballet/bls/fd_bls12_381.h new file mode 100644 index 0000000000..606017a854 --- /dev/null +++ b/src/ballet/bls/fd_bls12_381.h @@ -0,0 +1,15 @@ +#ifndef HEADER_fd_src_ballet_bls_fd_bls12_381_h +#define HEADER_fd_src_ballet_bls_fd_bls12_381_h + +#include "../fd_ballet_base.h" + +FD_PROTOTYPES_BEGIN + +int +fd_bls12_381_g1_add_syscall( uchar r[48], + uchar const p[48], + uchar const q[48] ); + +FD_PROTOTYPES_END + +#endif /* HEADER_fd_src_ballet_bls_fd_bls12_381_h */ diff --git a/src/ballet/bls/test_bls12_381.c b/src/ballet/bls/test_bls12_381.c new file mode 100644 index 0000000000..1fc4b83864 --- /dev/null +++ b/src/ballet/bls/test_bls12_381.c @@ -0,0 +1,44 @@ +#include "../fd_ballet.h" +#include "fd_bls12_381.h" +#include "../hex/fd_hex.h" + +void +log_bench( char const * descr, + ulong iter, + long dt ) { + float khz = 1e6f *(float)iter/(float)dt; + float tau = (float)dt /(float)iter; + FD_LOG_NOTICE(( "%-31s %11.3fK/s/core %10.3f ns/call", descr, (double)khz, (double)tau )); +} + +static void +test_add( FD_FN_UNUSED fd_rng_t * rng ) { + // test correctness + // + uchar re[48] = { 0 }; + uchar r[48] = { 0 }; + uchar p[48] = { 0 }; + uchar q[48] = { 0 }; + + fd_hex_decode( p, "97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb", 48 ); + fd_hex_decode( q, "97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb", 48 ); + fd_hex_decode( re, "a572cbea904d67468808c8eb50a9450c9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e", 48 ); + + FD_TEST( fd_bls12_381_g1_add_syscall( r, p, q )==0 ); + FD_TEST( fd_memeq( r, re, 48 ) ); +} + +/**********************************************************************/ + +int +main( int argc, + char ** argv ) { + fd_boot( &argc, &argv ); + fd_rng_t _rng[1]; fd_rng_t * rng = fd_rng_join( fd_rng_new( _rng, 0U, 0UL ) ); + + test_add ( rng ); + + FD_LOG_NOTICE(( "pass" )); + fd_halt(); + return 0; +} diff --git a/src/flamenco/vm/Local.mk b/src/flamenco/vm/Local.mk index a06440a742..d4fc8c5634 100644 --- a/src/flamenco/vm/Local.mk +++ b/src/flamenco/vm/Local.mk @@ -1,6 +1,7 @@ ifdef FD_HAS_INT128 ifdef FD_HAS_HOSTED ifdef FD_HAS_SECP256K1 +ifdef FD_HAS_BLST $(call add-hdrs,fd_vm_base.h fd_vm.h fd_vm_private.h) # FIXME: PRIVATE TEMPORARILY HERE DUE TO SOME MESSINESS IN FD_VM_SYSCALL.H $(call add-objs,fd_vm fd_vm_interp fd_vm_disasm fd_vm_trace,fd_flamenco) @@ -8,10 +9,10 @@ $(call add-objs,fd_vm fd_vm_interp fd_vm_disasm fd_vm_trace,fd_flamenco) $(call add-hdrs,test_vm_util.h) $(call add-objs,test_vm_util,fd_flamenco) -$(call make-bin,fd_vm_tool,fd_vm_tool,fd_flamenco fd_funk fd_ballet fd_util fd_disco,$(SECP256K1_LIBS)) +$(call make-bin,fd_vm_tool,fd_vm_tool,fd_flamenco fd_funk fd_ballet fd_util fd_disco,$(SECP256K1_LIBS) $(BLST_LIBS)) # Unfortunately, the get_sysvar syscall handler depends on the funk database -$(call make-unit-test,test_vm_interp,test_vm_interp,fd_flamenco fd_funk fd_ballet fd_util fd_disco,$(SECP256K1_LIBS)) +$(call make-unit-test,test_vm_interp,test_vm_interp,fd_flamenco fd_funk fd_ballet fd_util fd_disco,$(SECP256K1_LIBS) $(BLST_LIBS)) $(call make-unit-test,test_vm_base,test_vm_base,fd_flamenco fd_ballet fd_util) @@ -22,4 +23,5 @@ $(call run-unit-test,test_vm_base) $(call run-unit-test,test_vm_interp) endif endif +endif endif \ No newline at end of file diff --git a/src/flamenco/vm/syscall/Local.mk b/src/flamenco/vm/syscall/Local.mk index 5058a4cd09..b3f0d9543d 100644 --- a/src/flamenco/vm/syscall/Local.mk +++ b/src/flamenco/vm/syscall/Local.mk @@ -1,6 +1,7 @@ ifdef FD_HAS_INT128 ifdef FD_HAS_HOSTED ifdef FD_HAS_SECP256K1 +ifdef FD_HAS_BLST $(call add-hdrs,fd_vm_syscall.h fd_vm_syscall_macros.h fd_vm_cpi.h) $(call add-objs,fd_vm_syscall fd_vm_syscall_cpi fd_vm_syscall_hash fd_vm_syscall_crypto fd_vm_syscall_curve fd_vm_syscall_pda fd_vm_syscall_runtime fd_vm_syscall_util,fd_flamenco) @@ -14,3 +15,4 @@ $(call run-unit-test,test_vm_syscall_curve) endif endif endif +endif diff --git a/src/flamenco/vm/syscall/fd_vm_syscall.h b/src/flamenco/vm/syscall/fd_vm_syscall.h index e011d982dc..dc39297dd6 100644 --- a/src/flamenco/vm/syscall/fd_vm_syscall.h +++ b/src/flamenco/vm/syscall/fd_vm_syscall.h @@ -831,17 +831,20 @@ FD_VM_SYSCALL_DECL( sol_secp256k1_recover ); #define FD_VM_SYSCALL_SOL_CURVE_CURVE25519_EDWARDS ( 0UL) /* ed25519 */ #define FD_VM_SYSCALL_SOL_CURVE_CURVE25519_RISTRETTO ( 1UL) /* ristretto255 */ +#define FD_VM_SYSCALL_SOL_CURVE_BLS12_381 ( 2UL) /* bls12-381 */ /* FD_VM_SYSCALL_SOL_CURVE_{...} specifies the curve operation */ #define FD_VM_SYSCALL_SOL_CURVE_ADD ( 0UL) /* add */ #define FD_VM_SYSCALL_SOL_CURVE_SUB ( 1UL) /* add inverse */ #define FD_VM_SYSCALL_SOL_CURVE_MUL ( 2UL) /* scalar mul */ +#define FD_VM_SYSCALL_SOL_CURVE_HASH ( 3UL) /* hash to point */ -/* FD_VM_SYSCALL_SOL_CURVE_CURVE25519_{...}_SZ specifies the size of inputs/outputs. */ +/* FD_VM_SYSCALL_SOL_CURVE_{...}_SZ specifies the size of inputs/outputs. */ #define FD_VM_SYSCALL_SOL_CURVE_CURVE25519_POINT_SZ (32UL) /* point (compressed) */ #define FD_VM_SYSCALL_SOL_CURVE_CURVE25519_SCALAR_SZ (32UL) /* scalar */ +#define FD_VM_SYSCALL_SOL_CURVE_BLS12_381_POINT_SZ (48UL) /* point (compressed) */ /* syscall(aa2607ca) sol_curve_validate_point diff --git a/src/flamenco/vm/syscall/fd_vm_syscall_curve.c b/src/flamenco/vm/syscall/fd_vm_syscall_curve.c index 767df72f7c..50d098f018 100644 --- a/src/flamenco/vm/syscall/fd_vm_syscall_curve.c +++ b/src/flamenco/vm/syscall/fd_vm_syscall_curve.c @@ -2,6 +2,7 @@ #include "../../../ballet/ed25519/fd_curve25519.h" #include "../../../ballet/ed25519/fd_ristretto255.h" +#include "../../../ballet/bls/fd_bls12_381.h" int fd_vm_syscall_sol_curve_validate_point( /**/ void * _vm, @@ -69,8 +70,10 @@ fd_vm_syscall_sol_curve_group_op( void * _vm, #define MATCH_ID_OP(crv_id,grp_op) ((crv_id << 4) | grp_op) #define EDWARDS FD_VM_SYSCALL_SOL_CURVE_CURVE25519_EDWARDS #define RISTRETTO FD_VM_SYSCALL_SOL_CURVE_CURVE25519_RISTRETTO +#define BLS FD_VM_SYSCALL_SOL_CURVE_BLS12_381 ulong cost = 0UL; + ulong input_sz = 32UL; switch( curve_id ) { case EDWARDS: @@ -113,6 +116,19 @@ fd_vm_syscall_sol_curve_group_op( void * _vm, } break; + case BLS: + switch( group_op ) { + + case FD_VM_SYSCALL_SOL_CURVE_ADD: + cost = FD_VM_CURVE25519_RISTRETTO_ADD_COST; //FIXME + input_sz = FD_VM_SYSCALL_SOL_CURVE_BLS12_381_POINT_SZ; + break; + + default: + goto invalid_error; + } + break; + default: goto invalid_error; } @@ -122,10 +138,9 @@ fd_vm_syscall_sol_curve_group_op( void * _vm, /* https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L949-L958 */ - /* Note: left_input_addr is a point for add, sub, BUT it's a scalar for mul. - However, from a memory mapping perspective it's always 32 bytes, so we unify the code. */ - uchar const * inputL = FD_VM_MEM_HADDR_LD( vm, left_input_addr, FD_VM_ALIGN_RUST_POD_U8_ARRAY, 32UL ); - uchar const * inputR = FD_VM_MEM_HADDR_LD( vm, right_input_addr, FD_VM_ALIGN_RUST_POD_U8_ARRAY, FD_VM_SYSCALL_SOL_CURVE_CURVE25519_POINT_SZ ); + /* Note: left_input_addr is a point for add, sub, BUT it's a scalar for mul. */ + uchar const * inputL = FD_VM_MEM_HADDR_LD( vm, left_input_addr, FD_VM_ALIGN_RUST_POD_U8_ARRAY, input_sz ); + uchar const * inputR = FD_VM_MEM_HADDR_LD( vm, right_input_addr, FD_VM_ALIGN_RUST_POD_U8_ARRAY, input_sz ); switch( MATCH_ID_OP( curve_id, group_op ) ) { @@ -225,6 +240,16 @@ fd_vm_syscall_sol_curve_group_op( void * _vm, break; } + /* BLS12-381 */ + case MATCH_ID_OP( BLS, FD_VM_SYSCALL_SOL_CURVE_ADD ): { + uchar * result = FD_VM_MEM_HADDR_ST( vm, result_point_addr, FD_VM_ALIGN_RUST_POD_U8_ARRAY, FD_VM_SYSCALL_SOL_CURVE_BLS12_381_POINT_SZ ); + /* Compute add */ + if( FD_LIKELY( fd_bls12_381_g1_add_syscall( result, inputL, inputR )==0 ) ) { + ret = 0UL; /* success */ + } + break; + } + default: /* COV: this can never happen because of the previous switch */ return FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE; /* SyscallError::InvalidAttribute */ @@ -236,6 +261,7 @@ fd_vm_syscall_sol_curve_group_op( void * _vm, #undef MATCH_ID_OP #undef EDWARDS #undef RISTRETTO +#undef BLS invalid_error: /* https://github.com/anza-xyz/agave/blob/5b3390b99a6e7665439c623062c1a1dda2803524/programs/bpf_loader/src/syscalls/mod.rs#L1135-L1156 */ diff --git a/src/flamenco/vm/syscall/test_vm_syscall_curve.c b/src/flamenco/vm/syscall/test_vm_syscall_curve.c index 684e1975b9..5acdb3d2ee 100644 --- a/src/flamenco/vm/syscall/test_vm_syscall_curve.c +++ b/src/flamenco/vm/syscall/test_vm_syscall_curve.c @@ -1,5 +1,6 @@ #include "fd_vm_syscall.h" #include "../test_vm_util.h" +#include "../../../ballet/hex/fd_hex.h" static inline void set_memory_region( uchar * mem, ulong sz ) { for( ulong i=0UL; iheap[0], points, 96 ); + + in0_vaddr = FD_VM_MEM_MAP_HEAP_REGION_START; + in1_vaddr = FD_VM_MEM_MAP_HEAP_REGION_START + 48UL; + result_point_vaddr = FD_VM_MEM_MAP_HEAP_REGION_START + 96UL; + expected_result_host_ptr = _expected; + + FD_TEST( test_fd_vm_syscall_sol_curve_group_op( + "fd_vm_syscall_sol_curve_group_op: bls12-381, add", + vm, + FD_VM_SYSCALL_SOL_CURVE_BLS12_381, + FD_VM_SYSCALL_SOL_CURVE_ADD, + in0_vaddr, + in1_vaddr, + result_point_vaddr, + 0UL, // ret_code + FD_VM_SUCCESS, // syscall_ret + expected_result_host_ptr + ) ); + } + fd_vm_delete ( fd_vm_leave ( vm ) ); fd_sha256_delete( fd_sha256_leave( sha ) ); fd_rng_delete ( fd_rng_leave ( rng ) );