feat(crypto): key generation, validation, and secret-to-public derivation
Co-Authored-By: Charon <charon@lethean.io>
This commit is contained in:
parent
b759645724
commit
a68926c45c
4 changed files with 111 additions and 0 deletions
|
|
@ -14,4 +14,29 @@ void bridge_fast_hash(const uint8_t *data, size_t len, uint8_t hash[32]) {
|
|||
crypto::cn_fast_hash(data, len, reinterpret_cast<char*>(hash));
|
||||
}
|
||||
|
||||
int cn_generate_keys(uint8_t pub[32], uint8_t sec[32]) {
|
||||
crypto::public_key pk;
|
||||
crypto::secret_key sk;
|
||||
crypto::generate_keys(pk, sk);
|
||||
memcpy(pub, &pk, 32);
|
||||
memcpy(sec, &sk, 32);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cn_secret_to_public(const uint8_t sec[32], uint8_t pub[32]) {
|
||||
crypto::secret_key sk;
|
||||
crypto::public_key pk;
|
||||
memcpy(&sk, sec, 32);
|
||||
bool ok = crypto::secret_key_to_public_key(sk, pk);
|
||||
if (!ok) return 1;
|
||||
memcpy(pub, &pk, 32);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cn_check_key(const uint8_t pub[32]) {
|
||||
crypto::public_key pk;
|
||||
memcpy(&pk, pub, 32);
|
||||
return crypto::check_key(pk) ? 0 : 1;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
|
|
|||
|
|
@ -14,6 +14,11 @@ extern "C" {
|
|||
// ── Hashing ───────────────────────────────────────────────
|
||||
void bridge_fast_hash(const uint8_t *data, size_t len, uint8_t hash[32]);
|
||||
|
||||
// ── Key Operations ────────────────────────────────────────
|
||||
int cn_generate_keys(uint8_t pub[32], uint8_t sec[32]);
|
||||
int cn_secret_to_public(const uint8_t sec[32], uint8_t pub[32]);
|
||||
int cn_check_key(const uint8_t pub[32]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -28,3 +28,41 @@ func TestFastHash_Good_HelloWorld(t *testing.T) {
|
|||
t.Fatal("FastHash returned zero hash")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateKeys_Good_Roundtrip(t *testing.T) {
|
||||
pub, sec, err := crypto.GenerateKeys()
|
||||
if err != nil {
|
||||
t.Fatalf("GenerateKeys: %v", err)
|
||||
}
|
||||
|
||||
if !crypto.CheckKey(pub) {
|
||||
t.Fatal("generated public key failed CheckKey")
|
||||
}
|
||||
|
||||
pub2, err := crypto.SecretToPublic(sec)
|
||||
if err != nil {
|
||||
t.Fatalf("SecretToPublic: %v", err)
|
||||
}
|
||||
if pub != pub2 {
|
||||
t.Fatalf("SecretToPublic mismatch:\n GenerateKeys: %x\n SecretToPublic: %x", pub, pub2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckKey_Bad_Invalid(t *testing.T) {
|
||||
// A random 32-byte value is overwhelmingly unlikely to be a valid curve point.
|
||||
bad := [32]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
|
||||
if crypto.CheckKey(bad) {
|
||||
t.Fatal("0xFF...FF should fail CheckKey")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateKeys_Good_Unique(t *testing.T) {
|
||||
pub1, _, _ := crypto.GenerateKeys()
|
||||
pub2, _, _ := crypto.GenerateKeys()
|
||||
if pub1 == pub2 {
|
||||
t.Fatal("two GenerateKeys calls returned identical public keys")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
43
crypto/keygen.go
Normal file
43
crypto/keygen.go
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
// SPDX-Licence-Identifier: EUPL-1.2
|
||||
|
||||
package crypto
|
||||
|
||||
/*
|
||||
#include "bridge.h"
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// GenerateKeys creates a new random key pair.
|
||||
func GenerateKeys() (pub [32]byte, sec [32]byte, err error) {
|
||||
rc := C.cn_generate_keys(
|
||||
(*C.uint8_t)(unsafe.Pointer(&pub[0])),
|
||||
(*C.uint8_t)(unsafe.Pointer(&sec[0])),
|
||||
)
|
||||
if rc != 0 {
|
||||
err = fmt.Errorf("crypto: generate_keys failed (rc=%d)", rc)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// SecretToPublic derives the public key from a secret key.
|
||||
func SecretToPublic(sec [32]byte) ([32]byte, error) {
|
||||
var pub [32]byte
|
||||
rc := C.cn_secret_to_public(
|
||||
(*C.uint8_t)(unsafe.Pointer(&sec[0])),
|
||||
(*C.uint8_t)(unsafe.Pointer(&pub[0])),
|
||||
)
|
||||
if rc != 0 {
|
||||
return pub, fmt.Errorf("crypto: secret_to_public failed (rc=%d)", rc)
|
||||
}
|
||||
return pub, nil
|
||||
}
|
||||
|
||||
// CheckKey validates that a public key is a valid curve point.
|
||||
func CheckKey(pub [32]byte) bool {
|
||||
return C.cn_check_key((*C.uint8_t)(unsafe.Pointer(&pub[0]))) == 0
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue