-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Golang cgo bindings and CI tests #4
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
name: Windows Msys2 64bit (msvcrt,ucrt) gcc golang build and test | ||
|
||
on: [push] | ||
|
||
jobs: | ||
windows-build-and-test-golang: | ||
runs-on: ${{ matrix.os }} | ||
strategy: | ||
matrix: | ||
OS: ["windows-2019", "windows-2022"] | ||
CC: ["gcc"] | ||
ENVIRONMENT: ["UCRT64", "MINGW64"] # https://www.msys2.org/docs/environments/ | ||
go-version: ["1.22.x"] | ||
hash: | ||
- sha2 | ||
- shake | ||
- haraka | ||
size: | ||
- 128 | ||
- 192 | ||
- 256 | ||
option: | ||
- s | ||
- f | ||
thash: | ||
- simple | ||
- robust | ||
fail-fast: false | ||
steps: | ||
- uses: actions/checkout@v4 | ||
|
||
- name: Set up Msys2 | ||
uses: msys2/setup-msys2@v2 | ||
with: | ||
msystem: ${{ matrix.ENVIRONMENT }} | ||
install: >- | ||
base-devel | ||
mingw-w64-x86_64-toolchain | ||
mingw-w64-x86_64-pkg-config | ||
mingw-w64-x86_64-gcc | ||
mingw-w64-ucrt-x86_64-gcc | ||
mingw-w64-x86_64-go | ||
mingw-w64-ucrt-x86_64-go | ||
make | ||
git | ||
gcc | ||
|
||
- name: Setup Go ${{ matrix.go-version }} | ||
uses: actions/setup-go@v5 | ||
with: | ||
go-version: ${{ matrix.go-version }} | ||
|
||
- name: Gather runtime environment | ||
shell: msys2 {0} | ||
run: | | ||
echo ${{ matrix.ENVIRONMENT }} | ||
uname -a | ||
bash --version | ||
${{ matrix.CC }} -v | ||
go version | ||
|
||
- name: Build golang | ||
shell: msys2 {0} | ||
run: | | ||
export CGO_ENABLE=1 | ||
export CGO_CFLAGS="-D HASH=${{ matrix.hash }} -D THASH=${{ matrix.thash }} -D PARAMS=sphincs-${{ matrix.hash }}-${{ matrix.size }}${{ matrix.option }}" | ||
go build --tags=sphincs_${{ matrix.hash }}_${{ matrix.size }}${{ matrix.option }} -v ./... | ||
|
||
- name: Golang test | ||
shell: msys2 {0} | ||
run: | | ||
export CGO_ENABLE=1 | ||
export CGO_CFLAGS="-D HASH=${{ matrix.hash }} -D THASH=${{ matrix.thash }} -D PARAMS=sphincs-${{ matrix.hash }}-${{ matrix.size }}${{ matrix.option }}" | ||
go test --tags=sphincs_${{ matrix.hash }}_${{ matrix.size }}${{ matrix.option }} -v ./... |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
name: Tests golang bindings for ref implementation | ||
|
||
on: | ||
- push | ||
- pull_request | ||
|
||
jobs: | ||
build: | ||
runs-on: ${{ matrix.OS }} | ||
strategy: | ||
matrix: | ||
hash: | ||
- sha2 | ||
- shake | ||
- haraka | ||
size: | ||
- 128 | ||
- 192 | ||
- 256 | ||
option: | ||
- s | ||
- f | ||
thash: | ||
- simple | ||
- robust | ||
OS: ["ubuntu-latest", "macos-latest"] | ||
go-version: ["1.20"] | ||
#go-version: ["1.22.x"] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. let's remove this commented code |
||
# later: go-version: ["1.19", "1.20", "1.21.x", "1.22.x"] | ||
fail-fast: false | ||
steps: | ||
- uses: actions/checkout@v4 | ||
|
||
- name: Setup Go ${{ matrix.go-version }} | ||
uses: actions/setup-go@v5 | ||
with: | ||
go-version: ${{ matrix.go-version }} | ||
|
||
- name: Run go test | ||
run: | | ||
export CGO_ENABLE=1 | ||
export CGO_CFLAGS=" -D HASH=${{ matrix.hash }} -D THASH=${{ matrix.thash }} -D PARAMS=sphincs-${{ matrix.hash }}-${{ matrix.size }}${{ matrix.option }}" | ||
go test --tags=sphincs_${{ matrix.hash }}_${{ matrix.size }}${{ matrix.option }} -v ./... | ||
|
||
# vim: set ft=yaml ts=2 sw=2 et : |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
module github.com/katzenpost/sphincsplus | ||
|
||
go 1.20 | ||
|
||
require ( | ||
github.com/davecgh/go-spew v1.1.1 // indirect | ||
github.com/katzenpost/hpqc v0.0.0-20240114190904-bc8bcfcca4ee // indirect | ||
github.com/pmezard/go-difflib v1.0.0 // indirect | ||
github.com/stretchr/objx v0.5.0 // indirect | ||
github.com/stretchr/testify v1.8.4 // indirect | ||
gopkg.in/yaml.v3 v3.0.1 // indirect | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/katzenpost/hpqc v0.0.0-20240114190904-bc8bcfcca4ee h1:MiBBJNXAJkgv7asTOzrL0lbsL+UIFaFlm13boWz4Fxs= | ||
github.com/katzenpost/hpqc v0.0.0-20240114190904-bc8bcfcca4ee/go.mod h1:i2+fQVPYzpv+WoZcN0KQqjQLEc/AgzRYwAFjYC/LiHg= | ||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= | ||
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= | ||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= | ||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | ||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= | ||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= | ||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | ||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
PARAMS = sphincs-haraka-128f | ||
PARAMS ?= sphincs-haraka-128f | ||
THASH = robust | ||
|
||
CC=/usr/bin/gcc | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
// +build PQCgenKAT_sign | ||
|
||
// | ||
// PQCgenKAT_sign.c | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
//go:build cgo && ((linux && amd64) || (darwin && amd64) || (darwin && arm64) || (windows && amd64)) && (sphincs_haraka_128f || sphincs_haraka_128s || sphincs_haraka_192f || sphincs_haraka_192s || sphincs_haraka_256f || sphincs_haraka_256s || sphincs_sha2_128f || sphincs_sha2_128s || sphincs_sha2_192f || sphincs_sha2_192s || sphincs_sha2_256f || sphincs_sha2_256s || sphincs_shake_128f || sphincs_shake_128s || sphincs_shake_192f || sphincs_shake_192s || sphincs_shake_256f || sphincs_shake_256s) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. cool... looks impressive |
||
|
||
package sphincsplus | ||
|
||
//#cgo amd64 LDFLAGS: -L./ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. cool |
||
//#cgo amd64 CFLAGS: -O3 -std=c99 -D CGO=1 | ||
//#cgo darwin/amd64 LDFLAGS: -L./ | ||
//#cgo darwin/amd64 CFLAGS: -O3 -std=c99 -D CGO=1 | ||
//#cgo linux/amd64 LDFLAGS: -L./ -L/usr/lib/x86_64-linux-gnu/ | ||
//#cgo linux/amd64 CFLAGS: -O3 -std=c99 -D CGO=1 | ||
//#include "api.h" | ||
import "C" | ||
import ( | ||
"fmt" | ||
"unsafe" | ||
|
||
"github.com/katzenpost/sphincsplus/ref/params" | ||
) | ||
|
||
var ( | ||
|
||
// PublicKeySize is the size in bytes of the public key. | ||
PublicKeySize int = C.CRYPTO_PUBLICKEYBYTES | ||
|
||
// PrivateKeySize is the size in bytes of the private key. | ||
PrivateKeySize int = C.CRYPTO_SECRETKEYBYTES | ||
|
||
// SignatureSize is the size in bytes of the signature. | ||
SignatureSize int = C.CRYPTO_BYTES | ||
|
||
// SignatureName is the parameterized signature system name | ||
|
||
// Name returns the string naming of the current | ||
// Sphincs+ that this binding is being used with. | ||
SignatureName = params.Name() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd say it's fine if it works... this variable assignment. Sometimes golang programmers will do that inside an init function but i'm not clear on when that's necessary. |
||
|
||
// ErrPublicKeySize indicates the raw data is not the correct size for a public key. | ||
ErrPublicKeySize error = fmt.Errorf("%s: raw public key data size is wrong", Name()) | ||
|
||
// ErrPrivateKeySize indicates the raw data is not the correct size for a private key. | ||
ErrPrivateKeySize error = fmt.Errorf("%s: raw private key data size is wrong", Name()) | ||
) | ||
|
||
func SchemeName() string { | ||
return SignatureName | ||
} | ||
|
||
// NewKeypair generates a new Sphincs+ keypair. | ||
func NewKeypair() (*PrivateKey, *PublicKey) { | ||
privKey := &PrivateKey{ | ||
privateKey: make([]byte, C.CRYPTO_SECRETKEYBYTES), | ||
} | ||
pubKey := &PublicKey{ | ||
publicKey: make([]byte, C.CRYPTO_PUBLICKEYBYTES), | ||
} | ||
C.crypto_sign_keypair((*C.uchar)(unsafe.Pointer(&pubKey.publicKey[0])), | ||
(*C.uchar)(unsafe.Pointer(&privKey.privateKey[0]))) | ||
return privKey, pubKey | ||
} | ||
|
||
// PublicKey is a public Sphincs+ key. | ||
type PublicKey struct { | ||
publicKey []byte | ||
} | ||
|
||
// Verify checks whether the given signature is valid. | ||
func (p *PublicKey) Verify(signature, message []byte) bool { | ||
ret := C.crypto_sign_verify((*C.uchar)(unsafe.Pointer(&signature[0])), | ||
C.size_t(len(signature)), | ||
(*C.uchar)(unsafe.Pointer(&message[0])), | ||
C.size_t(len(message)), | ||
(*C.uchar)(unsafe.Pointer(&p.publicKey[0]))) | ||
if ret == 0 { | ||
return true | ||
} | ||
return false | ||
} | ||
|
||
// Bytes returns the PublicKey as a byte slice. | ||
func (p *PublicKey) Bytes() []byte { | ||
return p.publicKey | ||
} | ||
|
||
// FromBytes loads a PublicKey from the given byte slice. | ||
func (p *PublicKey) FromBytes(data []byte) error { | ||
if len(data) != PublicKeySize { | ||
return ErrPublicKeySize | ||
} | ||
|
||
p.publicKey = data | ||
return nil | ||
} | ||
|
||
// Verify checks whether the given signature is valid. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this may fault? let's remove this commented code section if it's not used. |
||
/* | ||
func (p *PublicKey) Verify(signature, message []byte) bool { | ||
ret := C.crypto_sign_verify((*C.uchar)(unsafe.Pointer(&signature[0])), | ||
C.ulong(len(signature)), | ||
(*C.uchar)(unsafe.Pointer(&message[0])), | ||
C.ulong(len(message)), | ||
(*C.uchar)(unsafe.Pointer(&p.publicKey[0]))) | ||
if ret == 0 { | ||
return true | ||
} | ||
return false | ||
} | ||
*/ | ||
|
||
// PrivateKey is a private Sphincs+ key. | ||
type PrivateKey struct { | ||
privateKey []byte | ||
} | ||
|
||
// Sign signs the given message and returns the signature. | ||
func (p *PrivateKey) Sign(message []byte) []byte { | ||
signature := make([]byte, C.CRYPTO_BYTES) | ||
sigLen := C.size_t(C.CRYPTO_BYTES) | ||
C.crypto_sign_signature((*C.uchar)(unsafe.Pointer(&signature[0])), | ||
&sigLen, | ||
(*C.uchar)(unsafe.Pointer(&message[0])), | ||
(C.size_t)(len(message)), | ||
(*C.uchar)(unsafe.Pointer(&p.privateKey[0]))) | ||
return signature | ||
} | ||
|
||
// Bytes returns the PrivateKey as a byte slice. | ||
func (p *PrivateKey) Bytes() []byte { | ||
return p.privateKey | ||
} | ||
|
||
// FromBytes loads a PrivateKey from the given byte slice. | ||
func (p *PrivateKey) FromBytes(data []byte) error { | ||
if len(data) != PrivateKeySize { | ||
return ErrPrivateKeySize | ||
} | ||
|
||
p.privateKey = data | ||
return nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
//go:build ((linux && amd64) || (darwin && amd64) || (darwin && arm64) || (windows && amd64)) && (sphincs_haraka_128f || sphincs_haraka_128s || sphincs_haraka_192f || sphincs_haraka_192s || sphincs_haraka_256f || sphincs_haraka_256s || sphincs_sha2_128f || sphincs_sha2_128s || sphincs_sha2_192f || sphincs_sha2_192s || sphincs_sha2_256f || sphincs_sha2_256s || sphincs_shake_128f || sphincs_shake_128s || sphincs_shake_192f || sphincs_shake_192s || sphincs_shake_256f || sphincs_shake_256s) | ||
|
||
package sphincsplus | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestSignVerify(t *testing.T) { | ||
t.Parallel() | ||
privKey1, pubKey1 := NewKeypair() | ||
message := []byte("i am a message") | ||
sig1 := privKey1.Sign(message) | ||
require.True(t, pubKey1.Verify(sig1, message)) | ||
|
||
privKey2, pubKey2 := NewKeypair() | ||
require.False(t, pubKey2.Verify(sig1, message)) | ||
|
||
sig2 := privKey2.Sign(message) | ||
require.True(t, pubKey2.Verify(sig2, message)) | ||
require.False(t, pubKey1.Verify(sig2, message)) | ||
|
||
// non-determinism | ||
sig3 := privKey1.Sign(message) | ||
require.NotEqual(t, sig1, sig3) | ||
} | ||
|
||
func TestSerialization(t *testing.T) { | ||
t.Parallel() | ||
privKey1, pubKey1 := NewKeypair() | ||
message := []byte("i am a message") | ||
sig := privKey1.Sign(message) | ||
require.True(t, pubKey1.Verify(sig, message)) | ||
|
||
pubKeyBytes1 := pubKey1.Bytes() | ||
pubKey2 := &PublicKey{} | ||
err := pubKey2.FromBytes(pubKeyBytes1) | ||
require.NoError(t, err) | ||
require.True(t, pubKey2.Verify(sig, message)) | ||
require.False(t, pubKey2.Verify(sig, message[:len(message)-3])) | ||
|
||
privKeyBytes2 := privKey1.Bytes() | ||
privKey2 := &PrivateKey{} | ||
err = privKey2.FromBytes(privKeyBytes2) | ||
require.NoError(t, err) | ||
sig2 := privKey2.Sign(message) | ||
require.True(t, pubKey1.Verify(sig2, message)) | ||
require.True(t, pubKey2.Verify(sig2, message)) | ||
} | ||
|
||
func TestSizes(t *testing.T) { | ||
t.Parallel() | ||
privKey, pubKey := NewKeypair() | ||
message := []byte("i am a message") | ||
sig := privKey.Sign(message) | ||
require.True(t, pubKey.Verify(sig, message)) | ||
|
||
require.Equal(t, PrivateKeySize, len(privKey.Bytes())) | ||
require.Equal(t, PublicKeySize, len(pubKey.Bytes())) | ||
require.Equal(t, SignatureSize, len(sig)) | ||
|
||
t.Logf("SPHINCS+ scheme parameters: %s", SchemeName()) | ||
t.Logf("PrivateKeySize %d", PrivateKeySize) | ||
t.Logf("PublicKeySize %d", PublicKeySize) | ||
t.Logf("SignatureSize %d", SignatureSize) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
now that's a large matrix!