mirror of
https://github.com/luxfi/crypto.git
synced 2026-07-27 01:54:50 +00:00
341 lines
8.5 KiB
Go
341 lines
8.5 KiB
Go
//go:build cgo && liboqs
|
|
// +build cgo,liboqs
|
|
|
|
package kem
|
|
|
|
/*
|
|
#cgo CFLAGS: -I/usr/local/include
|
|
#cgo LDFLAGS: -L/usr/local/lib -loqs
|
|
|
|
#include <oqs/oqs.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#define OQS_SUCCESS_VAL OQS_SUCCESS
|
|
|
|
// ML-KEM-768 wrapper functions
|
|
void* mlkem768_new() {
|
|
return OQS_KEM_new(OQS_KEM_alg_ml_kem_768);
|
|
}
|
|
|
|
void mlkem768_free(void* kem) {
|
|
if (kem != NULL) {
|
|
OQS_KEM_free((OQS_KEM*)kem);
|
|
}
|
|
}
|
|
|
|
int mlkem768_keypair(void* kem, uint8_t* public_key, uint8_t* secret_key) {
|
|
if (kem == NULL) return -1;
|
|
return OQS_KEM_keypair((OQS_KEM*)kem, public_key, secret_key);
|
|
}
|
|
|
|
int mlkem768_encaps(void* kem, uint8_t* ciphertext, uint8_t* shared_secret, const uint8_t* public_key) {
|
|
if (kem == NULL) return -1;
|
|
return OQS_KEM_encaps((OQS_KEM*)kem, ciphertext, shared_secret, public_key);
|
|
}
|
|
|
|
int mlkem768_decaps(void* kem, uint8_t* shared_secret, const uint8_t* ciphertext, const uint8_t* secret_key) {
|
|
if (kem == NULL) return -1;
|
|
return OQS_KEM_decaps((OQS_KEM*)kem, shared_secret, ciphertext, secret_key);
|
|
}
|
|
|
|
// ML-KEM-1024 wrapper functions
|
|
void* mlkem1024_new() {
|
|
return OQS_KEM_new(OQS_KEM_alg_ml_kem_1024);
|
|
}
|
|
|
|
void mlkem1024_free(void* kem) {
|
|
if (kem != NULL) {
|
|
OQS_KEM_free((OQS_KEM*)kem);
|
|
}
|
|
}
|
|
|
|
int mlkem1024_keypair(void* kem, uint8_t* public_key, uint8_t* secret_key) {
|
|
if (kem == NULL) return -1;
|
|
return OQS_KEM_keypair((OQS_KEM*)kem, public_key, secret_key);
|
|
}
|
|
|
|
int mlkem1024_encaps(void* kem, uint8_t* ciphertext, uint8_t* shared_secret, const uint8_t* public_key) {
|
|
if (kem == NULL) return -1;
|
|
return OQS_KEM_encaps((OQS_KEM*)kem, ciphertext, shared_secret, public_key);
|
|
}
|
|
|
|
int mlkem1024_decaps(void* kem, uint8_t* shared_secret, const uint8_t* ciphertext, const uint8_t* secret_key) {
|
|
if (kem == NULL) return -1;
|
|
return OQS_KEM_decaps((OQS_KEM*)kem, shared_secret, ciphertext, secret_key);
|
|
}
|
|
*/
|
|
import "C"
|
|
import (
|
|
"errors"
|
|
"runtime"
|
|
"unsafe"
|
|
)
|
|
|
|
// MLKEM768CGO implements ML-KEM-768 using liboqs via CGO
|
|
type MLKEM768CGO struct {
|
|
kem unsafe.Pointer
|
|
}
|
|
|
|
// NewMLKEM768CGO creates a new ML-KEM-768 instance using liboqs
|
|
func NewMLKEM768CGO() (*MLKEM768CGO, error) {
|
|
kem := C.mlkem768_new()
|
|
if kem == nil {
|
|
return nil, errors.New("failed to create ML-KEM-768 instance")
|
|
}
|
|
|
|
m := &MLKEM768CGO{kem: kem}
|
|
runtime.SetFinalizer(m, (*MLKEM768CGO).cleanup)
|
|
return m, nil
|
|
}
|
|
|
|
// cleanup frees the C resources
|
|
func (m *MLKEM768CGO) cleanup() {
|
|
if m.kem != nil {
|
|
C.mlkem768_free(m.kem)
|
|
m.kem = nil
|
|
}
|
|
}
|
|
|
|
// GenerateKeyPair generates a new ML-KEM-768 key pair using liboqs
|
|
func (m *MLKEM768CGO) GenerateKeyPair() (PublicKey, PrivateKey, error) {
|
|
if m.kem == nil {
|
|
return nil, nil, errors.New("KEM instance not initialized")
|
|
}
|
|
|
|
pk := &MLKEM768PublicKey{
|
|
data: make([]byte, mlkem768PublicKeySize),
|
|
}
|
|
sk := &MLKEM768PrivateKey{
|
|
data: make([]byte, mlkem768PrivateKeySize),
|
|
pk: pk,
|
|
}
|
|
|
|
ret := C.mlkem768_keypair(
|
|
m.kem,
|
|
(*C.uint8_t)(unsafe.Pointer(&pk.data[0])),
|
|
(*C.uint8_t)(unsafe.Pointer(&sk.data[0])),
|
|
)
|
|
|
|
if ret != C.OQS_SUCCESS_VAL {
|
|
return nil, nil, errors.New("ML-KEM-768 key generation failed")
|
|
}
|
|
|
|
return pk, sk, nil
|
|
}
|
|
|
|
// Encapsulate generates a shared secret and ciphertext using liboqs
|
|
func (m *MLKEM768CGO) Encapsulate(pk PublicKey) ([]byte, []byte, error) {
|
|
if m.kem == nil {
|
|
return nil, nil, errors.New("KEM instance not initialized")
|
|
}
|
|
|
|
mlkemPK, ok := pk.(*MLKEM768PublicKey)
|
|
if !ok {
|
|
return nil, nil, errors.New("invalid public key type")
|
|
}
|
|
|
|
ciphertext := make([]byte, mlkem768CiphertextSize)
|
|
sharedSecret := make([]byte, mlkem768SharedSecretSize)
|
|
|
|
ret := C.mlkem768_encaps(
|
|
m.kem,
|
|
(*C.uint8_t)(unsafe.Pointer(&ciphertext[0])),
|
|
(*C.uint8_t)(unsafe.Pointer(&sharedSecret[0])),
|
|
(*C.uint8_t)(unsafe.Pointer(&mlkemPK.data[0])),
|
|
)
|
|
|
|
if ret != C.OQS_SUCCESS_VAL {
|
|
return nil, nil, errors.New("ML-KEM-768 encapsulation failed")
|
|
}
|
|
|
|
return ciphertext, sharedSecret, nil
|
|
}
|
|
|
|
// Decapsulate recovers the shared secret from ciphertext using liboqs
|
|
func (m *MLKEM768CGO) Decapsulate(sk PrivateKey, ciphertext []byte) ([]byte, error) {
|
|
if m.kem == nil {
|
|
return nil, errors.New("KEM instance not initialized")
|
|
}
|
|
|
|
mlkemSK, ok := sk.(*MLKEM768PrivateKey)
|
|
if !ok {
|
|
return nil, errors.New("invalid private key type")
|
|
}
|
|
|
|
if len(ciphertext) != mlkem768CiphertextSize {
|
|
return nil, errors.New("invalid ciphertext size")
|
|
}
|
|
|
|
sharedSecret := make([]byte, mlkem768SharedSecretSize)
|
|
|
|
ret := C.mlkem768_decaps(
|
|
m.kem,
|
|
(*C.uint8_t)(unsafe.Pointer(&sharedSecret[0])),
|
|
(*C.uint8_t)(unsafe.Pointer(&ciphertext[0])),
|
|
(*C.uint8_t)(unsafe.Pointer(&mlkemSK.data[0])),
|
|
)
|
|
|
|
if ret != C.OQS_SUCCESS_VAL {
|
|
return nil, errors.New("ML-KEM-768 decapsulation failed")
|
|
}
|
|
|
|
return sharedSecret, nil
|
|
}
|
|
|
|
// PublicKeySize returns the size of public keys
|
|
func (m *MLKEM768CGO) PublicKeySize() int {
|
|
return mlkem768PublicKeySize
|
|
}
|
|
|
|
// PrivateKeySize returns the size of private keys
|
|
func (m *MLKEM768CGO) PrivateKeySize() int {
|
|
return mlkem768PrivateKeySize
|
|
}
|
|
|
|
// CiphertextSize returns the size of ciphertexts
|
|
func (m *MLKEM768CGO) CiphertextSize() int {
|
|
return mlkem768CiphertextSize
|
|
}
|
|
|
|
// SharedSecretSize returns the size of shared secrets
|
|
func (m *MLKEM768CGO) SharedSecretSize() int {
|
|
return mlkem768SharedSecretSize
|
|
}
|
|
|
|
// MLKEM1024CGO implements ML-KEM-1024 using liboqs via CGO
|
|
type MLKEM1024CGO struct {
|
|
kem unsafe.Pointer
|
|
}
|
|
|
|
// NewMLKEM1024CGO creates a new ML-KEM-1024 instance using liboqs
|
|
func NewMLKEM1024CGO() (*MLKEM1024CGO, error) {
|
|
kem := C.mlkem1024_new()
|
|
if kem == nil {
|
|
return nil, errors.New("failed to create ML-KEM-1024 instance")
|
|
}
|
|
|
|
m := &MLKEM1024CGO{kem: kem}
|
|
runtime.SetFinalizer(m, (*MLKEM1024CGO).cleanup)
|
|
return m, nil
|
|
}
|
|
|
|
// cleanup frees the C resources
|
|
func (m *MLKEM1024CGO) cleanup() {
|
|
if m.kem != nil {
|
|
C.mlkem1024_free(m.kem)
|
|
m.kem = nil
|
|
}
|
|
}
|
|
|
|
// GenerateKeyPair generates a new ML-KEM-1024 key pair using liboqs
|
|
func (m *MLKEM1024CGO) GenerateKeyPair() (PublicKey, PrivateKey, error) {
|
|
if m.kem == nil {
|
|
return nil, nil, errors.New("KEM instance not initialized")
|
|
}
|
|
|
|
pk := &MLKEM1024PublicKey{
|
|
data: make([]byte, mlkem1024PublicKeySize),
|
|
}
|
|
sk := &MLKEM1024PrivateKey{
|
|
data: make([]byte, mlkem1024PrivateKeySize),
|
|
pk: pk,
|
|
}
|
|
|
|
ret := C.mlkem1024_keypair(
|
|
m.kem,
|
|
(*C.uint8_t)(unsafe.Pointer(&pk.data[0])),
|
|
(*C.uint8_t)(unsafe.Pointer(&sk.data[0])),
|
|
)
|
|
|
|
if ret != C.OQS_SUCCESS_VAL {
|
|
return nil, nil, errors.New("ML-KEM-1024 key generation failed")
|
|
}
|
|
|
|
return pk, sk, nil
|
|
}
|
|
|
|
// Encapsulate generates a shared secret and ciphertext using liboqs
|
|
func (m *MLKEM1024CGO) Encapsulate(pk PublicKey) ([]byte, []byte, error) {
|
|
if m.kem == nil {
|
|
return nil, nil, errors.New("KEM instance not initialized")
|
|
}
|
|
|
|
mlkemPK, ok := pk.(*MLKEM1024PublicKey)
|
|
if !ok {
|
|
return nil, nil, errors.New("invalid public key type")
|
|
}
|
|
|
|
ciphertext := make([]byte, mlkem1024CiphertextSize)
|
|
sharedSecret := make([]byte, mlkem1024SharedSecretSize)
|
|
|
|
ret := C.mlkem1024_encaps(
|
|
m.kem,
|
|
(*C.uint8_t)(unsafe.Pointer(&ciphertext[0])),
|
|
(*C.uint8_t)(unsafe.Pointer(&sharedSecret[0])),
|
|
(*C.uint8_t)(unsafe.Pointer(&mlkemPK.data[0])),
|
|
)
|
|
|
|
if ret != C.OQS_SUCCESS_VAL {
|
|
return nil, nil, errors.New("ML-KEM-1024 encapsulation failed")
|
|
}
|
|
|
|
return ciphertext, sharedSecret, nil
|
|
}
|
|
|
|
// Decapsulate recovers the shared secret from ciphertext using liboqs
|
|
func (m *MLKEM1024CGO) Decapsulate(sk PrivateKey, ciphertext []byte) ([]byte, error) {
|
|
if m.kem == nil {
|
|
return nil, errors.New("KEM instance not initialized")
|
|
}
|
|
|
|
mlkemSK, ok := sk.(*MLKEM1024PrivateKey)
|
|
if !ok {
|
|
return nil, errors.New("invalid private key type")
|
|
}
|
|
|
|
if len(ciphertext) != mlkem1024CiphertextSize {
|
|
return nil, errors.New("invalid ciphertext size")
|
|
}
|
|
|
|
sharedSecret := make([]byte, mlkem1024SharedSecretSize)
|
|
|
|
ret := C.mlkem1024_decaps(
|
|
m.kem,
|
|
(*C.uint8_t)(unsafe.Pointer(&sharedSecret[0])),
|
|
(*C.uint8_t)(unsafe.Pointer(&ciphertext[0])),
|
|
(*C.uint8_t)(unsafe.Pointer(&mlkemSK.data[0])),
|
|
)
|
|
|
|
if ret != C.OQS_SUCCESS_VAL {
|
|
return nil, errors.New("ML-KEM-1024 decapsulation failed")
|
|
}
|
|
|
|
return sharedSecret, nil
|
|
}
|
|
|
|
// PublicKeySize returns the size of public keys
|
|
func (m *MLKEM1024CGO) PublicKeySize() int {
|
|
return mlkem1024PublicKeySize
|
|
}
|
|
|
|
// PrivateKeySize returns the size of private keys
|
|
func (m *MLKEM1024CGO) PrivateKeySize() int {
|
|
return mlkem1024PrivateKeySize
|
|
}
|
|
|
|
// CiphertextSize returns the size of ciphertexts
|
|
func (m *MLKEM1024CGO) CiphertextSize() int {
|
|
return mlkem1024CiphertextSize
|
|
}
|
|
|
|
// SharedSecretSize returns the size of shared secrets
|
|
func (m *MLKEM1024CGO) SharedSecretSize() int {
|
|
return mlkem1024SharedSecretSize
|
|
}
|
|
|
|
// cgoAvailable returns true when CGO is available
|
|
func cgoAvailable() bool {
|
|
return true
|
|
}
|