From 2f4912c8fd72788fe61965d94db844a22ebbeca3 Mon Sep 17 00:00:00 2001 From: Kris Kwiatkowski Date: Wed, 22 Aug 2018 13:57:32 +0100 Subject: [PATCH] Init --- msr/include/P751_api.h | 107 ++++++++++++++ msr/lib/libsidh751.a | Bin 0 -> 126588 bytes src/runner.go | 329 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 436 insertions(+) create mode 100644 msr/include/P751_api.h create mode 100644 msr/lib/libsidh751.a create mode 100644 src/runner.go diff --git a/msr/include/P751_api.h b/msr/include/P751_api.h new file mode 100644 index 0000000..fb7b456 --- /dev/null +++ b/msr/include/P751_api.h @@ -0,0 +1,107 @@ +/******************************************************************************************** +* SIDH: an efficient supersingular isogeny cryptography library +* +* Abstract: API header file for P751 +*********************************************************************************************/ + +#ifndef __P751_API_H__ +#define __P751_API_H__ + + +/*********************** Key encapsulation mechanism API ***********************/ + +#define CRYPTO_SECRETKEYBYTES 644 // MSG_BYTES + SECRETKEY_B_BYTES + CRYPTO_PUBLICKEYBYTES bytes +#define CRYPTO_PUBLICKEYBYTES 564 +#define CRYPTO_BYTES 24 +#define CRYPTO_CIPHERTEXTBYTES 596 // CRYPTO_PUBLICKEYBYTES + MSG_BYTES bytes + +// Algorithm name +#define CRYPTO_ALGNAME "SIKEp751" + +// SIKE's key generation +// It produces a private key sk and computes the public key pk. +// Outputs: secret key sk (CRYPTO_SECRETKEYBYTES = 644 bytes) +// public key pk (CRYPTO_PUBLICKEYBYTES = 564 bytes) +int crypto_kem_keypair_SIKEp751(unsigned char *pk, unsigned char *sk); + +// SIKE's encapsulation +// Input: public key pk (CRYPTO_PUBLICKEYBYTES = 564 bytes) +// Outputs: shared secret ss (CRYPTO_BYTES = 24 bytes) +// ciphertext message ct (CRYPTO_CIPHERTEXTBYTES = 596 bytes) +int crypto_kem_enc_SIKEp751(unsigned char *ct, unsigned char *ss, const unsigned char *pk); + +// SIKE's decapsulation +// Input: secret key sk (CRYPTO_SECRETKEYBYTES = 644 bytes) +// ciphertext message ct (CRYPTO_CIPHERTEXTBYTES = 596 bytes) +// Outputs: shared secret ss (CRYPTO_BYTES = 24 bytes) +int crypto_kem_dec_SIKEp751(unsigned char *ss, const unsigned char *ct, const unsigned char *sk); + + +// Encoding of keys for KEM-based isogeny system "SIKEp751" (wire format): +// ---------------------------------------------------------------------- +// Elements over GF(p751) are encoded in 94 octets in little endian format (i.e., the least significant octet is located in the lowest memory address). +// Elements (a+b*i) over GF(p751^2), where a and b are defined over GF(p751), are encoded as {a, b}, with a in the lowest memory portion. +// +// Private keys sk consist of the concatenation of a 32-byte random value, a value in the range [0, 2^378-1] and the public key pk. In the SIKE API, +// private keys are encoded in 644 octets in little endian format. +// Public keys pk consist of 3 elements in GF(p751^2). In the SIKE API, pk is encoded in 564 octets. +// Ciphertexts ct consist of the concatenation of a public key value and a 32-byte value. In the SIKE API, ct is encoded in 564 + 32 = 596 octets. +// Shared keys ss consist of a value of 24 octets. + + +/*********************** Ephemeral key exchange API ***********************/ + +#define SIDH_SECRETKEYBYTES 48 +#define SIDH_PUBLICKEYBYTES 564 +#define SIDH_BYTES 188 + +// 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^372 - 1] to be used as Alice's private key +void random_mod_order_A_SIDHp751(unsigned char* random_digits); + +// Generation of Bob's secret key +// Outputs random value in [0, 2^Floor(Log(2,3^239)) - 1] to be used as Bob's private key +void random_mod_order_B_SIDHp751(unsigned char* random_digits); + +// Alice's ephemeral public key generation +// Input: a private key PrivateKeyA in the range [0, 2^372 - 1], stored in 47 bytes. +// Output: the public key PublicKeyA consisting of 3 GF(p751^2) elements encoded in 564 bytes. +int EphemeralKeyGeneration_A_SIDHp751(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^239)) - 1], stored in 48 bytes. +// The public key consists of 3 GF(p751^2) elements encoded in 564 bytes. +int EphemeralKeyGeneration_B_SIDHp751(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^372 - 1], stored in 47 bytes. +// Bob's PublicKeyB consists of 3 GF(p751^2) elements encoded in 564 bytes. +// Output: a shared secret SharedSecretA that consists of one element in GF(p751^2) encoded in 188 bytes. +int EphemeralSecretAgreement_A_SIDHp751(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^239)) - 1], stored in 48 bytes. +// Alice's PublicKeyA consists of 3 GF(p751^2) elements encoded in 564 bytes. +// Output: a shared secret SharedSecretB that consists of one element in GF(p751^2) encoded in 188 bytes. +int EphemeralSecretAgreement_B_SIDHp751(const unsigned char* PrivateKeyB, const unsigned char* PublicKeyA, unsigned char* SharedSecretB); + + +// Encoding of keys for KEX-based isogeny system "SIDHp751" (wire format): +// ---------------------------------------------------------------------- +// Elements over GF(p751) are encoded in 94 octets in little endian format (i.e., the least significant octet is located in the lowest memory address). +// Elements (a+b*i) over GF(p751^2), where a and b are defined over GF(p751), 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^372-1] and [0, 2^378-1], resp. In the SIDH API, private keys are encoded +// in 48 octets in little endian format. +// Public keys PublicKeyA and PublicKeyB consist of 3 elements in GF(p751^2). In the SIDH API, they are encoded in 564 octets. +// Shared keys SharedSecretA and SharedSecretB consist of one element in GF(p751^2). In the SIDH API, they are encoded in 188 octets. + + +#endif \ No newline at end of file diff --git a/msr/lib/libsidh751.a b/msr/lib/libsidh751.a new file mode 100644 index 0000000000000000000000000000000000000000..c770bee4b69ca125abe5ec48347e256c3b789ecc GIT binary patch literal 126588 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 Q?(bav4)>G)F0KE60g}oL^Z)<= literal 0 HcmV?d00001 diff --git a/src/runner.go b/src/runner.go new file mode 100644 index 0000000..955a6ac --- /dev/null +++ b/src/runner.go @@ -0,0 +1,329 @@ +package main + +/* +#cgo CFLAGS: -I../msr/include +#cgo LDFLAGS: -L../msr/lib -lsidh751 +#include +*/ +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 "unsafe" + +const ( + CSKsz = 644 + GSKsz = 80 // 80 because MSR concatenates public key to the secret key + PKsz = 564 + CTsz = 596 + SSsz = 24 +) + +// Helpers for byte convertion +func convBytesGoToC(goBytes []byte, cBytes []C.uchar) { + for i,v:=range(goBytes) { + cBytes[i] = C.uchar(v) + } +} + +func convBytesCToGo(cBytes []C.uchar, goBytes []byte) { + goBytes=C.GoBytes(unsafe.Pointer(&cBytes[0]), GSKsz) +} + +// Helpers for key generation +func keygenMsr() (*sidh.PublicKey, *sidh.PrivateKey) { + var prvKey = sidh.NewPrivateKey(sidh.FP_751, sidh.KeyVariant_SIKE) + var pubKey = sidh.NewPublicKey(sidh.FP_751, sidh.KeyVariant_SIKE) + var msrPK [PKsz]C.uchar + var msrSK [CSKsz]C.uchar + + if C.crypto_kem_keypair_SIKEp751(&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_751, sidh.KeyVariant_SIKE) + + err := prvKey.Generate(rand.Reader) + if err!=nil { + fmt.Errorf("ERR: Generate private key for CF failed") + } + pubKey, _ := sidh.GeneratePublicKey(prvKey) + return pubKey,prvKey +} + +// MSR keygen +// MSR Encapsulate +// CF Decapsulate +func test_msrK_msrE_cfD() { + var msrCipherText [CTsz]C.uchar + var ss2 [SSsz]C.uchar + var msrSK [CSKsz]C.uchar + + pubKey, prvKey := keygenMsr() + ctext, ss1, err := sike.Encapsulate(rand.Reader, pubKey) + if err != nil { + panic(0) + } + + for i,_:=range(ctext) { + msrCipherText[i] = C.uchar(ctext[i]) + } + + convBytesGoToC(prvKey.Export(), msrSK[:]) + convBytesGoToC(pubKey.Export(), msrSK[80:]) + if C.crypto_kem_dec_SIKEp751(&msrSK[0], &msrCipherText[0], &ss2[0]) != 0 { + panic(0) + } + for _,i:=range(ss2) { + if byte(ss2[i]) != ss1[i] { + fmt.Printf("LEN=%d %X\n", len(ss2), ss2) + // fmt.Printf("LEN=%d %X\n", len(ss1), ss1) + fmt.Println("ERR: shared secrets differ") + break + } + } +} + +// 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[80:]) + if C.crypto_kem_dec_SIKEp751(&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") + break + } + } +} + +// 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[:]) + C.crypto_kem_enc_SIKEp751(&cCT[0], &cSS[0], &cPK[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.Printf("LEN=%d %X\n", len(gSS), gSS) + fmt.Printf("LEN=%d %X\n", len(cSS), cSS) + fmt.Printf("LEN=%d %X\n", len(gCT), gCT) + fmt.Println("ERR: shared secrets differ") + break + } + } +} + +func test_cfK_msrK_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[:]) + C.crypto_kem_enc_SIKEp751(&cCT[0], &cSS[0], &cPK[0]) + + convBytesGoToC(prvKey.Export(), cSK[:]) + convBytesGoToC(pubKey.Export(), cSK[80:]) + C.crypto_kem_dec_SIKEp751(&cSS2[0], &cCT[0], &cSK[0]) + + 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") + break + } + } +} + +// 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[80:]) + if C.crypto_kem_dec_SIKEp751(&cSS[0], &cCT[0], &cSK[0]) != 0 { + panic(0) + } + for i:=0; i