@@ -0,0 +1,107 @@ | |||
/******************************************************************************************** | |||
* SIDH: an efficient supersingular isogeny cryptography library | |||
* | |||
* Abstract: API header file for P503 | |||
*********************************************************************************************/ | |||
#ifndef __P503_API_H__ | |||
#define __P503_API_H__ | |||
/*********************** Key encapsulation mechanism API ***********************/ | |||
#define CRYPTO_SECRETKEYBYTES 434 // MSG_BYTES + SECRETKEY_B_BYTES + CRYPTO_PUBLICKEYBYTES bytes | |||
#define CRYPTO_PUBLICKEYBYTES 378 | |||
#define CRYPTO_BYTES 16 | |||
#define CRYPTO_CIPHERTEXTBYTES 402 // CRYPTO_PUBLICKEYBYTES + MSG_BYTES bytes | |||
// Algorithm name | |||
#define CRYPTO_ALGNAME "SIKEp503" | |||
// SIKE's key generation | |||
// It produces a private key sk and computes the public key pk. | |||
// Outputs: secret key sk (CRYPTO_SECRETKEYBYTES = 434 bytes) | |||
// public key pk (CRYPTO_PUBLICKEYBYTES = 378 bytes) | |||
int crypto_kem_keypair_SIKEp503(unsigned char *pk, unsigned char *sk); | |||
// SIKE's encapsulation | |||
// Input: public key pk (CRYPTO_PUBLICKEYBYTES = 378 bytes) | |||
// Outputs: shared secret ss (CRYPTO_BYTES = 16 bytes) | |||
// ciphertext message ct (CRYPTO_CIPHERTEXTBYTES = 402 bytes) | |||
int crypto_kem_enc_SIKEp503(unsigned char *ct, unsigned char *ss, const unsigned char *pk); | |||
// SIKE's decapsulation | |||
// Input: secret key sk (CRYPTO_SECRETKEYBYTES = 434 bytes) | |||
// ciphertext message ct (CRYPTO_CIPHERTEXTBYTES = 402 bytes) | |||
// Outputs: shared secret ss (CRYPTO_BYTES = 16 bytes) | |||
int crypto_kem_dec_SIKEp503(unsigned char *ss, const unsigned char *ct, const unsigned char *sk); | |||
// Encoding of keys for KEM-based isogeny system "SIKEp503" (wire format): | |||
// ---------------------------------------------------------------------- | |||
// Elements over GF(p503) are encoded in 63 octets in little endian format (i.e., the least significant octet is located in the lowest memory address). | |||
// Elements (a+b*i) over GF(p503^2), where a and b are defined over GF(p503), are encoded as {a, b}, with a in the lowest memory portion. | |||
// | |||
// Private keys sk consist of the concatenation of a 24-byte random value, a value in the range [0, 2^252-1] and the public key pk. In the SIKE API, | |||
// private keys are encoded in 434 octets in little endian format. | |||
// Public keys pk consist of 3 elements in GF(p503^2). In the SIKE API, pk is encoded in 378 octets. | |||
// Ciphertexts ct consist of the concatenation of a public key value and a 24-byte value. In the SIKE API, ct is encoded in 378 + 24 = 402 octets. | |||
// Shared keys ss consist of a value of 16 octets. | |||
/*********************** Ephemeral key exchange API ***********************/ | |||
#define SIDH_SECRETKEYBYTES 32 | |||
#define SIDH_PUBLICKEYBYTES 378 | |||
#define SIDH_BYTES 126 | |||
// SECURITY NOTE: SIDH supports ephemeral Diffie-Hellman key exchange. It is NOT secure to use it with static keys. | |||
// See "On the Security of Supersingular Isogeny Cryptosystems", S.D. Galbraith, C. Petit, B. Shani and Y.B. Ti, in ASIACRYPT 2016, 2016. | |||
// Extended version available at: http://eprint.iacr.org/2016/859 | |||
// Generation of Alice's secret key | |||
// Outputs random value in [0, 2^250 - 1] to be used as Alice's private key | |||
void random_mod_order_A_SIDHp503(unsigned char* random_digits); | |||
// Generation of Bob's secret key | |||
// Outputs random value in [0, 2^Floor(Log(2,3^159)) - 1] to be used as Bob's private key | |||
void random_mod_order_B_SIDHp503(unsigned char* random_digits); | |||
// Alice's ephemeral public key generation | |||
// Input: a private key PrivateKeyA in the range [0, 2^250 - 1], stored in 32 bytes. | |||
// Output: the public key PublicKeyA consisting of 3 GF(p503^2) elements encoded in 378 bytes. | |||
int EphemeralKeyGeneration_A_SIDHp503(const unsigned char* PrivateKeyA, unsigned char* PublicKeyA); | |||
// Bob's ephemeral key-pair generation | |||
// It produces a private key PrivateKeyB and computes the public key PublicKeyB. | |||
// The private key is an integer in the range [0, 2^Floor(Log(2,3^159)) - 1], stored in 32 bytes. | |||
// The public key consists of 3 GF(p503^2) elements encoded in 378 bytes. | |||
int EphemeralKeyGeneration_B_SIDHp503(const unsigned char* PrivateKeyB, unsigned char* PublicKeyB); | |||
// Alice's ephemeral shared secret computation | |||
// It produces a shared secret key SharedSecretA using her secret key PrivateKeyA and Bob's public key PublicKeyB | |||
// Inputs: Alice's PrivateKeyA is an integer in the range [0, 2^250 - 1], stored in 32 bytes. | |||
// Bob's PublicKeyB consists of 3 GF(p503^2) elements encoded in 378 bytes. | |||
// Output: a shared secret SharedSecretA that consists of one element in GF(p503^2) encoded in 126 bytes. | |||
int EphemeralSecretAgreement_A_SIDHp503(const unsigned char* PrivateKeyA, const unsigned char* PublicKeyB, unsigned char* SharedSecretA); | |||
// Bob's ephemeral shared secret computation | |||
// It produces a shared secret key SharedSecretB using his secret key PrivateKeyB and Alice's public key PublicKeyA | |||
// Inputs: Bob's PrivateKeyB is an integer in the range [0, 2^Floor(Log(2,3^159)) - 1], stored in 32 bytes. | |||
// Alice's PublicKeyA consists of 3 GF(p503^2) elements encoded in 378 bytes. | |||
// Output: a shared secret SharedSecretB that consists of one element in GF(p503^2) encoded in 126 bytes. | |||
int EphemeralSecretAgreement_B_SIDHp503(const unsigned char* PrivateKeyB, const unsigned char* PublicKeyA, unsigned char* SharedSecretB); | |||
// Encoding of keys for KEX-based isogeny system "SIDHp503" (wire format): | |||
// ---------------------------------------------------------------------- | |||
// Elements over GF(p503) are encoded in 63 octets in little endian format (i.e., the least significant octet is located in the lowest memory address). | |||
// Elements (a+b*i) over GF(p503^2), where a and b are defined over GF(p503), are encoded as {a, b}, with a in the lowest memory portion. | |||
// | |||
// Private keys PrivateKeyA and PrivateKeyB can have values in the range [0, 2^250-1] and [0, 2^252-1], resp. In the SIDH API, private keys are encoded | |||
// in 32 octets in little endian format. | |||
// Public keys PublicKeyA and PublicKeyB consist of 3 elements in GF(p503^2). In the SIDH API, they are encoded in 378 octets. | |||
// Shared keys SharedSecretA and SharedSecretB consist of one element in GF(p503^2). In the SIDH API, they are encoded in 126 octets. | |||
#endif |
@@ -0,0 +1,365 @@ | |||
package main | |||
/* | |||
#cgo CFLAGS: -I../msr/include | |||
#cgo LDFLAGS: -L../msr/lib/intel -lsidh503 -lsidh751 | |||
#include <P503_api.h> | |||
*/ | |||
import "C" | |||
import "fmt" | |||
import rand "crypto/rand" | |||
import sidh "github.com/cloudflare/p751sidh/sidh" | |||
import sike "github.com/cloudflare/p751sidh/sike" | |||
import "unsafe" | |||
import "runtime" | |||
const ( | |||
GSKsz = 24+32 // 56=(MSG+KeySize). | |||
CSKsz = 434 // 56+public key size, which MSR concatenates with secret key | |||
PKsz = 378 | |||
CTsz = 24+378 | |||
SSsz = 16 | |||
) | |||
func FailNow() { | |||
pc := make([]uintptr, 10) // at least 1 entry needed | |||
runtime.Callers(2, pc) | |||
f := runtime.FuncForPC(pc[0]) | |||
file, line := f.FileLine(pc[0]) | |||
fmt.Printf("%s:%d %s\n", file, line, f.Name()) | |||
panic(0) | |||
} | |||
// Helpers for byte convertion | |||
// ------------------------------ | |||
// cBytes must be initialized to proper size | |||
func convBytesGoToC(goBytes []byte, cBytes []C.uchar) { | |||
for i,v:=range(goBytes) { | |||
cBytes[i] = C.uchar(v) | |||
} | |||
} | |||
// goBytes must be initialized to proper size | |||
func convBytesCToGo(cBytes []C.uchar, goBytes []byte) { | |||
copy(goBytes, C.GoBytes(unsafe.Pointer(&cBytes[0]), C.int(len(cBytes)))) | |||
} | |||
// Helpers for key generation | |||
func keygenMsr() (*sidh.PublicKey, *sidh.PrivateKey) { | |||
var prvKey = sidh.NewPrivateKey(sidh.FP_503, sidh.KeyVariant_SIKE) | |||
var pubKey = sidh.NewPublicKey(sidh.FP_503, sidh.KeyVariant_SIKE) | |||
var msrPK [PKsz]C.uchar | |||
var msrSK [CSKsz]C.uchar | |||
if C.crypto_kem_keypair_SIKEp503(&msrPK[0], &msrSK[0]) != 0 { | |||
panic(0) | |||
} | |||
if prvKey.Import(C.GoBytes(unsafe.Pointer(&msrSK[0]), GSKsz)) != nil { | |||
panic(0) | |||
} | |||
if pubKey.Import(C.GoBytes(unsafe.Pointer(&msrPK[0]), PKsz)) != nil { | |||
panic(0) | |||
} | |||
return pubKey, prvKey | |||
} | |||
func keygenCf() (*sidh.PublicKey, *sidh.PrivateKey) { | |||
var prvKey = sidh.NewPrivateKey(sidh.FP_503, sidh.KeyVariant_SIKE) | |||
err := prvKey.Generate(rand.Reader) | |||
if err!=nil { | |||
fmt.Errorf("ERR: Generate private key for CF failed") | |||
} | |||
return prvKey.GeneratePublicKey(),prvKey | |||
} | |||
// MSR keygen | |||
// CF Encapsulate | |||
// MSR Decapsulate | |||
func test_msrK_cfE_msrD() { | |||
var cCT [CTsz]C.uchar | |||
var cSS [SSsz]C.uchar | |||
var cSK [CSKsz]C.uchar | |||
pubKey, prvKey := keygenMsr() | |||
gCT, gSS, err := sike.Encapsulate(rand.Reader, pubKey) | |||
if err != nil { | |||
panic(0) | |||
} | |||
convBytesGoToC(gCT, cCT[:]) | |||
convBytesGoToC(prvKey.Export(), cSK[:]) | |||
convBytesGoToC(pubKey.Export(), cSK[56:]) | |||
if C.crypto_kem_dec_SIKEp503(&cSS[0], &cCT[0], &cSK[0]) != 0 { | |||
panic(0) | |||
} | |||
for i:=0; i<SSsz; i++ { | |||
if byte(cSS[i]) != gSS[i] { | |||
fmt.Println("ERR: shared secrets differ") | |||
FailNow() | |||
} | |||
} | |||
} | |||
// CF keygen | |||
// CF Encapsulate | |||
// MSR Decapsulate | |||
func test_cfK_cfE_msrD() { | |||
// C variables | |||
var cSS [SSsz]C.uchar | |||
var cCT [CTsz]C.uchar | |||
var cPK [PKsz]C.uchar | |||
var cSK [CSKsz]C.uchar | |||
pubKey, prvKey := keygenCf() | |||
convBytesGoToC(pubKey.Export(), cPK[:]) | |||
gCT, gSS, err := sike.Encapsulate(rand.Reader, pubKey) | |||
if err != nil { | |||
panic("err: SIKE CF encapsulation") | |||
} | |||
convBytesGoToC(gCT[:], cCT[:]) | |||
convBytesGoToC(prvKey.Export(), cSK[:]) | |||
convBytesGoToC(pubKey.Export(), cSK[56:]) | |||
if C.crypto_kem_dec_SIKEp503(&cSS[0], &cCT[0], &cSK[0]) != 0 { | |||
panic("Decapsulation failed") | |||
} | |||
for i,_:=range(gSS) { | |||
if gSS[i] != byte(cSS[i]) { | |||
fmt.Printf("LEN=%d %X\n", len(gSS), gSS) | |||
fmt.Printf("LEN=%d %X\n", len(cSS), cSS) | |||
fmt.Println("ERR: shared secrets differ") | |||
FailNow() | |||
} | |||
} | |||
} | |||
// Check if public key generated with CF is same as the one from MSR | |||
func test_cfK_msrK1() { | |||
// C variables | |||
var cPK [PKsz]C.uchar | |||
var cSK [CSKsz]C.uchar | |||
pubKey, prvKey := keygenCf() | |||
convBytesGoToC(prvKey.Export()[24:], cSK[:]) | |||
if C.EphemeralKeyGeneration_B_SIDHp503(&cSK[0], &cPK[0]) != 0 { | |||
panic(0) | |||
} | |||
gPK := pubKey.Export() | |||
for i,v:=range(gPK) { | |||
if byte(cPK[i]) != v { | |||
fmt.Printf("Public key B differ") | |||
FailNow() | |||
} | |||
} | |||
} | |||
// Check if public key generated with CF is same as the one from MSR | |||
func test_cfK_msrK2() { | |||
pubKeyMsr, prvKey := keygenMsr() | |||
pubKeyCf := prvKey.GeneratePublicKey() | |||
cfPK := pubKeyCf.Export() | |||
msrPK := pubKeyMsr.Export() | |||
for i,v:=range(cfPK) { | |||
if msrPK[i]!= v { | |||
fmt.Printf("Public key B differ") | |||
FailNow() | |||
} | |||
} | |||
} | |||
// CF keygen | |||
// MSR Encapsulate | |||
// CF Decapsulate | |||
func test_cfK_msrE_cfD() { | |||
// C variables | |||
var cSS [SSsz]C.uchar | |||
var cCT [CTsz]C.uchar | |||
var cPK [PKsz]C.uchar | |||
// GO variables | |||
var gCT [CTsz]byte | |||
pubKey, prvKey := keygenCf() | |||
convBytesGoToC(pubKey.Export(), cPK[:]) | |||
if C.crypto_kem_enc_SIKEp503(&cCT[0], &cSS[0], &cPK[0]) != 0 { | |||
panic(0) | |||
} | |||
convBytesCToGo(cCT[:], gCT[:]) | |||
gSS, err := sike.Decapsulate(prvKey, pubKey, gCT[:]) | |||
if err != nil { | |||
panic("Decapsulation failed") | |||
} | |||
for i,_:=range(gSS) { | |||
if gSS[i] != byte(cSS[i]) { | |||
fmt.Println("ERR: shared secrets differ") | |||
FailNow() | |||
} | |||
} | |||
} | |||
func test_cfK_msrE_msrD() { | |||
// C variables | |||
var cSS [SSsz]C.uchar | |||
var cSS2 [SSsz]C.uchar | |||
var cCT [CTsz]C.uchar | |||
var cPK [PKsz]C.uchar | |||
var cSK [CSKsz]C.uchar | |||
// GO variables | |||
pubKey, prvKey := keygenCf() | |||
convBytesGoToC(pubKey.Export(), cPK[:]) | |||
if C.crypto_kem_enc_SIKEp503(&cCT[0], &cSS[0], &cPK[0]) != 0 { | |||
panic(0) | |||
} | |||
convBytesGoToC(prvKey.Export(), cSK[:]) | |||
convBytesGoToC(pubKey.Export(), cSK[56:]) | |||
if C.crypto_kem_dec_SIKEp503(&cSS2[0], &cCT[0], &cSK[0]) != 0 { | |||
panic(0) | |||
} | |||
for i,_:=range(cSS) { | |||
if cSS[i] != cSS2[i] {//gSS[i] != byte(cSS[i]) { | |||
fmt.Println("ERR: shared secrets differ") | |||
FailNow() | |||
} | |||
} | |||
} | |||
// MSR keygen | |||
// MSR Encapsulate | |||
// CF Decapsulate | |||
func test_msrK_msrE_cfD() { | |||
// C variables | |||
var cSS [SSsz]C.uchar | |||
var cCT [CTsz]C.uchar | |||
var cPK [PKsz]C.uchar | |||
var cSK [CSKsz]C.uchar | |||
var gCT [CTsz]byte | |||
// GO variables | |||
pubKey, prvKey := keygenMsr() | |||
convBytesGoToC(prvKey.Export(), cSK[:]) | |||
convBytesGoToC(pubKey.Export(), cSK[56:]) | |||
convBytesGoToC(pubKey.Export(), cPK[:]) | |||
C.crypto_kem_enc_SIKEp503(&cCT[0], &cSS[0], &cPK[0]) | |||
convBytesCToGo(cCT[:], gCT[:]) | |||
gSS, err := sike.Decapsulate(prvKey, pubKey, gCT[:]) | |||
if err!=nil { | |||
panic(0) | |||
} | |||
for i,_:=range(cSS) { | |||
if byte(cSS[i]) != gSS[i] { | |||
fmt.Println("ERR: shared secrets differ") | |||
FailNow() | |||
} | |||
} | |||
} | |||
// MSR keygen | |||
// CF Encapsulate | |||
// CF Decapsulate | |||
func test_msrK_cfE_cfD() { | |||
pubKey, prvKey := keygenMsr() | |||
gCT, gSS1, err := sike.Encapsulate(rand.Reader, pubKey) | |||
if err != nil { | |||
panic("err: SIKE CF encapsulation") | |||
} | |||
gSS2, err := sike.Decapsulate(prvKey, pubKey, gCT) | |||
if err!=nil || len(gSS1) != len(gSS2) { | |||
panic("Decapsulation failed") | |||
} | |||
for i,_:=range(gSS1) { | |||
if gSS1[i] != gSS2[i] { | |||
fmt.Printf("LEN=%d %X\n", len(gSS1), gSS1) | |||
fmt.Printf("LEN=%d %X\n", len(gSS2), gSS2) | |||
fmt.Println("ERR: shared secrets differ") | |||
FailNow() | |||
} | |||
} | |||
} | |||
// For CGO testing really | |||
// ---------------------- | |||
func test_msrK_msrE_msrD() { | |||
// C variables | |||
var cSS [SSsz]C.uchar | |||
var cSS2 [SSsz]C.uchar | |||
var cCT [CTsz]C.uchar | |||
var cPK [PKsz]C.uchar | |||
var cSK [CSKsz]C.uchar | |||
// GO variables | |||
pubKey, prvKey := keygenMsr() | |||
convBytesGoToC(prvKey.Export(), cSK[:]) | |||
convBytesGoToC(pubKey.Export(), cSK[56:]) | |||
convBytesGoToC(pubKey.Export(), cPK[:]) | |||
if C.crypto_kem_enc_SIKEp503(&cCT[0], &cSS[0], &cPK[0]) != 0 {panic(0)} | |||
if C.crypto_kem_dec_SIKEp503(&cSS2[0], &cCT[0], &cSK[0]) != 0 {panic(0)} | |||
for i,_:=range(cSS) { | |||
if cSS[i] != cSS2[i] { | |||
fmt.Printf("LEN=%d %X\n", len(cSS2), cSS2) | |||
fmt.Printf("LEN=%d %X\n", len(cSS), cSS) | |||
fmt.Println("ERR: shared secrets differ") | |||
FailNow() | |||
} | |||
} | |||
} | |||
func debug() { | |||
fmt.Println("MSR+MSR+MSR") | |||
test_msrK_msrE_msrD() | |||
fmt.Println("CF+MSR+CF") | |||
test_cfK_msrE_cfD() | |||
fmt.Println("MSR+CF+MSR") | |||
test_msrK_cfE_msrD() | |||
fmt.Println("MSR+MSR+CF") | |||
test_msrK_msrE_cfD() | |||
fmt.Println("MSR+CF+CF") | |||
test_msrK_cfE_cfD() | |||
fmt.Println("CF+CF+MSR") | |||
test_cfK_cfE_msrD() | |||
fmt.Println("CF+MSR+MSR") | |||
test_cfK_msrE_msrD() | |||
fmt.Println("CF prv Keygen") | |||
test_cfK_msrK1() | |||
fmt.Println("MSR prv Keygen") | |||
test_cfK_msrK2() | |||
} | |||
func doLongTest() { | |||
test_msrK_msrE_cfD() | |||
test_msrK_cfE_msrD() | |||
test_msrK_cfE_cfD() | |||
test_cfK_msrE_cfD() | |||
test_cfK_cfE_msrD() | |||
test_cfK_msrE_msrD() | |||
test_cfK_msrK1() | |||
test_cfK_msrK2() | |||
test_msrK_msrE_msrD() | |||
} | |||
func main() { | |||
debug() | |||
for i:=0; i<1000; i++ { | |||
doLongTest() | |||
} | |||
} | |||
@@ -2,14 +2,14 @@ package main | |||
/* | |||
#cgo CFLAGS: -I../msr/include | |||
#cgo LDFLAGS: -L../msr/lib -lsidh751 | |||
#cgo LDFLAGS: -L../msr/lib/intel -lsidh751 | |||
#include <P751_api.h> | |||
*/ | |||
import "C" | |||
import "fmt" | |||
import rand "crypto/rand" | |||
import sidh "github.com/henrydcase/nobs/dh/sidh" | |||
import sike "github.com/henrydcase/nobs/kem/sike" | |||
import sidh "github.com/cloudflare/p751sidh/sidh" | |||
import sike "github.com/cloudflare/p751sidh/sike" | |||
import "unsafe" | |||
import "runtime" | |||
@@ -74,8 +74,7 @@ func keygenCf() (*sidh.PublicKey, *sidh.PrivateKey) { | |||
if err!=nil { | |||
fmt.Errorf("ERR: Generate private key for CF failed") | |||
} | |||
pubKey, _ := sidh.GeneratePublicKey(prvKey) | |||
return pubKey,prvKey | |||
return prvKey.GeneratePublicKey(),prvKey | |||
} | |||
// MSR keygen | |||
@@ -154,9 +153,8 @@ func test_cfK_msrK1() { | |||
gPK := pubKey.Export() | |||
for i,v:=range(gPK) { | |||
if byte(cPK[i]) != v { | |||
fmt.Printf("PRV =%d %X\n", len(prvKey.Export()), prvKey.Export()) | |||
fmt.Printf("PUB CF =%d %X\n", len(pubKey.Export()), pubKey.Export()) | |||
fmt.Printf("PUB MSR=%d %X\n", len(cPK), cPK) | |||
fmt.Printf("Public key B differ") | |||
FailNow() | |||
} | |||
} | |||
} | |||
@@ -165,16 +163,13 @@ func test_cfK_msrK1() { | |||
// Check if public key generated with CF is same as the one from MSR | |||
func test_cfK_msrK2() { | |||
pubKeyMsr, prvKey := keygenMsr() | |||
pubKeyCf, err := sidh.GeneratePublicKey(prvKey) | |||
if err != nil { | |||
panic(0) | |||
} | |||
pubKeyCf := prvKey.GeneratePublicKey() | |||
cfPK := pubKeyCf.Export() | |||
msrPK := pubKeyMsr.Export() | |||
for i,v:=range(cfPK) { | |||
if msrPK[i]!= v { | |||
fmt.Printf("Keys differ") | |||
fmt.Printf("Public key B differ") | |||
FailNow() | |||
} | |||
} | |||
@@ -235,8 +230,6 @@ func test_cfK_msrE_msrD() { | |||
for i,_:=range(cSS) { | |||
if cSS[i] != cSS2[i] {//gSS[i] != byte(cSS[i]) { | |||
fmt.Printf("LEN=%d %X\n", len(cSS2), cSS2) | |||
fmt.Printf("LEN=%d %X\n", len(cSS), cSS) | |||
fmt.Println("ERR: shared secrets differ") | |||
FailNow() | |||
} | |||
@@ -366,6 +359,7 @@ func doLongTest() { | |||
} | |||
func main() { | |||
debug() | |||
for i:=0; i<1000; i++ { | |||
doLongTest() | |||
} |