Skip to content

Commit 428130f

Browse files
committed
Add secp-graalvm module and native-image build of schnorr-example
1 parent f9e8cd8 commit 428130f

File tree

6 files changed

+152
-0
lines changed

6 files changed

+152
-0
lines changed

secp-examples-java/build.gradle

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ ext.moduleName = 'org.bitcoinj.secp.examples'
77

88
dependencies {
99
implementation project(':secp-api')
10+
implementation project(':secp-graalvm')
1011
runtimeOnly project(':secp-bouncy')
1112
runtimeOnly project(':secp-ffm')
1213
}
@@ -20,6 +21,7 @@ jar {
2021
inputs.property("moduleName", moduleName)
2122
manifest {
2223
attributes 'Implementation-Title': 'Example secp256k1-jdk Apps',
24+
'Main-Class': application.mainClass,
2325
'Implementation-Version': archiveVersion.get()
2426
}
2527
}
@@ -33,6 +35,11 @@ run {
3335
jvmArgs += '--enable-native-access=org.bitcoinj.secp.ffm'
3436
}
3537

38+
configurations {
39+
nativeToolImplementation.extendsFrom implementation
40+
nativeToolRuntimeOnly.extendsFrom runtimeOnly
41+
}
42+
3643
tasks.register('runEcdsa', JavaExec) {
3744
javaLauncher = javaToolchains.launcherFor {
3845
languageVersion = JavaLanguageVersion.of(javaToolchainVersion)
@@ -42,3 +49,61 @@ tasks.register('runEcdsa', JavaExec) {
4249
mainClass = 'org.bitcoinj.secp.examples.Ecdsa'
4350
jvmArgs += '--enable-native-access=org.bitcoinj.secp.ffm'
4451
}
52+
53+
tasks.register('nativeCompile') {
54+
dependsOn 'nativeCompileSchnorr', 'nativeCompileEcdsa'
55+
}
56+
57+
// Compile a native image using GraalVM's native-image tool
58+
// Graal must be installed at $GRAALVM_HOME
59+
tasks.register('nativeCompileSchnorr', Exec) {
60+
dependsOn jar
61+
workingDir = projectDir
62+
executable = "${System.env.GRAALVM_HOME}/bin/native-image"
63+
args = ['--verbose',
64+
'--no-fallback',
65+
'--module', 'org.bitcoinj.secp.examples/org.bitcoinj.secp.examples.Schnorr',
66+
'--module-path', jar.archiveFile.get(),
67+
'--module-path', "${-> configurations.nativeToolImplementation.asPath}", // Lazy configuration resolution
68+
'--module-path', "${-> configurations.nativeToolRuntimeOnly.asPath}", // Lazy configuration resolution
69+
'--add-modules', 'org.bitcoinj.secp.ffm',
70+
'--enable-native-access=org.bitcoinj.secp.ffm',
71+
'-H:Path=build',
72+
'-H:Name=schnorr-example',
73+
'-H:+ForeignAPISupport',
74+
'-H:+SharedArenaSupport',
75+
'-H:-CheckToolchain',
76+
'--features=org.bitcoinj.secp.graalvmffm.ForeignRegistrationFeature',
77+
'--enable-native-access=ALL-UNNAMED',
78+
'-H:+ReportUnsupportedElementsAtRuntime',
79+
'-H:+ReportExceptionStackTraces'
80+
]
81+
}
82+
83+
// Compile a native image using GraalVM's native-image tool
84+
// Graal must be installed at $GRAALVM_HOME
85+
// THIS IS NOT WORKING YET, THERE'S A PROBLEM AT RUNTIME:
86+
// "Cannot perform downcall with leaf type (long,long,long,long,long)int as it was not registered at compilation time"
87+
tasks.register('nativeCompileEcdsa', Exec) {
88+
dependsOn jar
89+
workingDir = projectDir
90+
executable = "${System.env.GRAALVM_HOME}/bin/native-image"
91+
args = ['--verbose',
92+
'--no-fallback',
93+
'--module', 'org.bitcoinj.secp.examples/org.bitcoinj.secp.examples.Ecdsa',
94+
'--module-path', jar.archiveFile.get(),
95+
'--module-path', "${-> configurations.nativeToolImplementation.asPath}", // Lazy configuration resolution
96+
'--module-path', "${-> configurations.nativeToolRuntimeOnly.asPath}", // Lazy configuration resolution
97+
'--add-modules', 'org.bitcoinj.secp.ffm',
98+
'--enable-native-access=org.bitcoinj.secp.ffm',
99+
'-H:Path=build',
100+
'-H:Name=ecdsa-example',
101+
'-H:+ForeignAPISupport',
102+
'-H:+SharedArenaSupport',
103+
'-H:-CheckToolchain',
104+
'--features=org.bitcoinj.secp.graalvmffm.ForeignRegistrationFeature',
105+
'--enable-native-access=ALL-UNNAMED',
106+
'-H:+ReportUnsupportedElementsAtRuntime',
107+
'-H:+ReportExceptionStackTraces'
108+
]
109+
}

secp-examples-java/src/main/java/module-info.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,6 @@
1616
@org.jspecify.annotations.NullMarked
1717
module org.bitcoinj.secp.examples {
1818
requires org.bitcoinj.secp.api;
19+
requires org.bitcoinj.secp.graalvm;
1920
requires org.jspecify;
2021
}

secp-graalvm/build.gradle

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
plugins {
2+
id 'java-library'
3+
}
4+
5+
ext.moduleName = 'org.bitcoinj.secp.graalvm'
6+
7+
dependencies {
8+
api("org.jspecify:jspecify:1.0.0")
9+
implementation group: 'org.graalvm.sdk', name: 'nativeimage', version: '24.2.2'
10+
}
11+
12+
jar {
13+
inputs.property("moduleName", moduleName)
14+
manifest {
15+
attributes 'Implementation-Title': 'Secp256k1 GraalVM Foreign Registration',
16+
'Automatic-Module-Name': moduleName,
17+
'Implementation-Version': archiveVersion.get()
18+
}
19+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* Copyright 2023-2024 secp256k1-jdk Developers.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
@org.jspecify.annotations.NullMarked
17+
module org.bitcoinj.secp.graalvm {
18+
requires org.graalvm.nativeimage;
19+
requires org.jspecify;
20+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright 2023-2024 secp256k1-jdk Developers.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.bitcoinj.secp.graalvmffm;
17+
18+
import org.graalvm.nativeimage.hosted.Feature;
19+
import org.graalvm.nativeimage.hosted.RuntimeForeignAccess;
20+
21+
import java.lang.foreign.FunctionDescriptor;
22+
import java.lang.foreign.Linker;
23+
24+
import static java.lang.foreign.ValueLayout.*;
25+
26+
/**
27+
* Register secp methods for GraalVM Foreign Access
28+
*/
29+
public class ForeignRegistrationFeature implements Feature {
30+
public void duringSetup(Feature.DuringSetupAccess access) {
31+
RuntimeForeignAccess.registerForDowncall(FunctionDescriptor.ofVoid());
32+
RuntimeForeignAccess.registerForDowncall(FunctionDescriptor.of(JAVA_INT, JAVA_INT, JAVA_INT));
33+
RuntimeForeignAccess.registerForDowncall(FunctionDescriptor.of(JAVA_LONG, JAVA_INT));
34+
RuntimeForeignAccess.registerForDowncall(FunctionDescriptor.of(JAVA_INT, JAVA_INT, JAVA_INT, JAVA_INT));
35+
RuntimeForeignAccess.registerForDowncall(FunctionDescriptor.of(JAVA_INT, JAVA_LONG, JAVA_LONG, JAVA_LONG));
36+
RuntimeForeignAccess.registerForDowncall(FunctionDescriptor.of(JAVA_INT, JAVA_LONG, JAVA_LONG, JAVA_LONG, JAVA_LONG, JAVA_LONG));
37+
RuntimeForeignAccess.registerForDowncall(FunctionDescriptor.of(JAVA_INT, JAVA_LONG, JAVA_LONG, JAVA_LONG, JAVA_LONG, JAVA_LONG, JAVA_LONG));
38+
RuntimeForeignAccess.registerForDowncall(FunctionDescriptor.of(JAVA_INT, JAVA_LONG, JAVA_LONG, JAVA_LONG, JAVA_LONG, JAVA_INT));
39+
RuntimeForeignAccess.registerForDowncall(FunctionDescriptor.of(JAVA_INT, JAVA_LONG, JAVA_LONG));
40+
RuntimeForeignAccess.registerForDowncall(FunctionDescriptor.ofVoid(JAVA_LONG, JAVA_LONG));
41+
RuntimeForeignAccess.registerForDowncall(FunctionDescriptor.ofVoid(JAVA_LONG));
42+
RuntimeForeignAccess.registerForDowncall(FunctionDescriptor.ofVoid(JAVA_INT, JAVA_INT));
43+
RuntimeForeignAccess.registerForDowncall(FunctionDescriptor.of(ADDRESS, JAVA_INT, JAVA_INT), Linker.Option.firstVariadicArg(1));
44+
RuntimeForeignAccess.registerForDowncall(FunctionDescriptor.ofVoid(JAVA_INT), Linker.Option.captureCallState("errno"));
45+
}
46+
}

settings.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ rootProject.name = 'secp256k1-jdk'
33
include 'secp-api' // API interface library
44
include 'secp-bouncy' // Bouncy Castle implementation
55
include 'secp-ffm' // Java Foreign Memory & Function ("Panama") implementation
6+
include 'secp-graalvm' // GraalVM Foreign Function Registration support
67
include 'secp-bitcoinj' // bitcoinj integration utilities and tests (P2TR address generation, etc.)
78
include 'secp-integration-test' // Integration tests of API implementations (ffm and bouncy)
89
include 'secp-examples-java' // Java examples

0 commit comments

Comments
 (0)