ceremonyclient/ec/bls48581/HPKE.go
2023-04-15 00:05:26 -04:00

328 lines
7.8 KiB
Go

/*
* Copyright (c) 2012-2020 MIRACL UK Ltd.
*
* This file is part of MIRACL Core
* (see https://github.com/miracl/core).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* Hybrid Public Key Encryption */
/* Following https://datatracker.ietf.org/doc/draft-irtf-cfrg-hpke/?include_text=1 */
package bls48581
//import "fmt"
import "source.quilibrium.com/quilibrium/ceremonyclient/ec/bls48581/core"
func reverse(X []byte) {
lx := len(X)
for i := 0; i < lx/2; i++ {
ch := X[i]
X[i] = X[lx-i-1]
X[lx-i-1] = ch
}
}
func labeledExtract(SALT []byte, SUITE_ID []byte, label string, IKM []byte) []byte {
rfc := "HPKE-v1"
RFC := []byte(rfc)
LABEL := []byte(label)
var LIKM []byte
for i := 0; i < len(RFC); i++ {
LIKM = append(LIKM, RFC[i])
}
for i := 0; i < len(SUITE_ID); i++ {
LIKM = append(LIKM, SUITE_ID[i])
}
for i := 0; i < len(LABEL); i++ {
LIKM = append(LIKM, LABEL[i])
}
if IKM != nil {
for i := 0; i < len(IKM); i++ {
LIKM = append(LIKM, IKM[i])
}
}
return core.HKDF_Extract(core.MC_SHA2, HASH_TYPE, SALT, LIKM)
}
func labeledExpand(PRK []byte, SUITE_ID []byte, label string, INFO []byte, L int) []byte {
rfc := "HPKE-v1"
RFC := []byte(rfc)
LABEL := []byte(label)
AR := core.InttoBytes(L, 2)
var LINFO []byte
for i := 0; i < len(AR); i++ {
LINFO = append(LINFO, AR[i])
}
for i := 0; i < len(RFC); i++ {
LINFO = append(LINFO, RFC[i])
}
for i := 0; i < len(SUITE_ID); i++ {
LINFO = append(LINFO, SUITE_ID[i])
}
for i := 0; i < len(LABEL); i++ {
LINFO = append(LINFO, LABEL[i])
}
if INFO != nil {
for i := 0; i < len(INFO); i++ {
LINFO = append(LINFO, INFO[i])
}
}
return core.HKDF_Expand(core.MC_SHA2, HASH_TYPE, L, PRK, LINFO)
}
func extractAndExpand(config_id int, DH []byte, context []byte) []byte {
kem := config_id & 255
txt := "KEM"
KEM_ID := core.InttoBytes(kem, 2)
KEM := []byte(txt)
var SUITE_ID []byte
for i := 0; i < len(KEM); i++ {
SUITE_ID = append(SUITE_ID, KEM[i])
}
SUITE_ID = append(SUITE_ID, KEM_ID[0])
SUITE_ID = append(SUITE_ID, KEM_ID[1])
PRK := labeledExtract(nil, SUITE_ID, "eae_prk", DH)
return labeledExpand(PRK, SUITE_ID, "shared_secret", context, HASH_TYPE)
}
func DeriveKeyPair(config_id int, SK []byte, PK []byte, SEED []byte) bool {
counter := 0
kem := config_id & 255
txt := "KEM"
KEM_ID := core.InttoBytes(kem, 2)
KEM := []byte(txt)
var SUITE_ID []byte
for i := 0; i < len(KEM); i++ {
SUITE_ID = append(SUITE_ID, KEM[i])
}
SUITE_ID = append(SUITE_ID, KEM_ID[0])
SUITE_ID = append(SUITE_ID, KEM_ID[1])
PRK := labeledExtract(nil, SUITE_ID, "dkp_prk", SEED)
var S []byte
if kem == 32 || kem == 33 { // RFC7748
S = labeledExpand(PRK, SUITE_ID, "sk", nil, EGS)
reverse(S)
if kem == 32 {
S[EGS-1] &= 248
S[0] &= 127
S[0] |= 64
} else {
S[EGS-1] &= 252
S[0] |= 128
}
} else {
bit_mask := 0xff
if kem == 18 {
bit_mask = 1
}
for i := 0; i < EGS; i++ {
S = append(S, 0)
}
for !ECDH_IN_RANGE(S) && counter < 256 {
var INFO [1]byte
INFO[0] = byte(counter)
S = labeledExpand(PRK, SUITE_ID, "candidate", INFO[:], EGS)
S[0] &= byte(bit_mask)
counter++
}
}
for i := 0; i < EGS; i++ {
SK[i] = S[i]
}
ECDH_KEY_PAIR_GENERATE(nil, SK, PK)
if kem == 32 || kem == 33 {
reverse(PK)
}
if counter < 256 {
return true
}
return false
}
func Encap(config_id int, skE []byte, pkE []byte, pkR []byte) []byte {
DH := make([]byte, EFS)
var kemcontext []byte
kem := config_id & 255
if kem == 32 || kem == 33 {
reverse(pkR)
ECDH_ECPSVDP_DH(skE, pkR, DH[:], 0)
reverse(pkR)
reverse(DH[:])
} else {
ECDH_ECPSVDP_DH(skE, pkR, DH[:], 0)
}
for i := 0; i < len(pkE); i++ {
kemcontext = append(kemcontext, pkE[i])
}
for i := 0; i < len(pkR); i++ {
kemcontext = append(kemcontext, pkR[i])
}
return extractAndExpand(config_id, DH[:], kemcontext)
}
func Decap(config_id int, skR []byte, pkE []byte, pkR []byte) []byte {
DH := make([]byte, EFS)
var kemcontext []byte
kem := config_id & 255
if kem == 32 || kem == 33 {
reverse(pkE)
ECDH_ECPSVDP_DH(skR, pkE, DH[:], 0)
reverse(pkE)
reverse(DH[:])
} else {
ECDH_ECPSVDP_DH(skR, pkE, DH[:], 0)
}
for i := 0; i < len(pkE); i++ {
kemcontext = append(kemcontext, pkE[i])
}
for i := 0; i < len(pkR); i++ {
kemcontext = append(kemcontext, pkR[i])
}
return extractAndExpand(config_id, DH[:], kemcontext)
}
func AuthEncap(config_id int, skE []byte, skS []byte, pkE []byte, pkR []byte, pkS []byte) []byte {
pklen := len(pkE)
DH := make([]byte, EFS)
DH1 := make([]byte, EFS)
kemcontext := make([]byte, 3*pklen)
kem := config_id & 255
if kem == 32 || kem == 33 {
reverse(pkR)
ECDH_ECPSVDP_DH(skE, pkR, DH[:], 0)
ECDH_ECPSVDP_DH(skS, pkR, DH1[:], 0)
reverse(pkR)
reverse(DH[:])
reverse(DH1[:])
} else {
ECDH_ECPSVDP_DH(skE, pkR, DH[:], 0)
ECDH_ECPSVDP_DH(skS, pkR, DH1[:], 0)
}
ZZ := make([]byte, 2*EFS)
for i := 0; i < EFS; i++ {
ZZ[i] = DH[i]
ZZ[EFS+i] = DH1[i]
}
for i := 0; i < pklen; i++ {
kemcontext[i] = pkE[i]
kemcontext[pklen+i] = pkR[i]
kemcontext[2*pklen+i] = pkS[i]
}
return extractAndExpand(config_id, ZZ[:], kemcontext)
}
func AuthDecap(config_id int, skR []byte, pkE []byte, pkR []byte, pkS []byte) []byte {
pklen := len(pkE)
DH := make([]byte, EFS)
DH1 := make([]byte, EFS)
kemcontext := make([]byte, 3*pklen)
kem := config_id & 255
if kem == 32 || kem == 33 {
reverse(pkE)
reverse(pkS)
ECDH_ECPSVDP_DH(skR[:], pkE, DH[:], 0)
ECDH_ECPSVDP_DH(skR[:], pkS, DH1[:], 0)
reverse(pkE)
reverse(pkS)
reverse(DH[:])
reverse(DH1[:])
} else {
ECDH_ECPSVDP_DH(skR[:], pkE, DH[:], 0)
ECDH_ECPSVDP_DH(skR[:], pkS, DH1[:], 0)
}
ZZ := make([]byte, 2*EFS)
for i := 0; i < EFS; i++ {
ZZ[i] = DH[i]
ZZ[EFS+i] = DH1[i]
}
for i := 0; i < pklen; i++ {
kemcontext[i] = pkE[i]
kemcontext[pklen+i] = pkR[i]
kemcontext[2*pklen+i] = pkS[i]
}
return extractAndExpand(config_id, ZZ[:], kemcontext)
}
/*
func printBinary(array []byte) {
for i := 0; i < len(array); i++ {
fmt.Printf("%02x", array[i])
}
fmt.Printf("\n")
}
*/
func KeySchedule(config_id int, mode int, Z []byte, info []byte, psk []byte, pskID []byte) ([]byte, []byte, []byte) {
var context []byte
kem := config_id & 255
kdf := (config_id >> 8) & 3
aead := (config_id >> 10) & 3
txt := "HPKE"
KEM := []byte(txt)
var SUITE_ID []byte
for i := 0; i < len(KEM); i++ {
SUITE_ID = append(SUITE_ID, KEM[i])
}
num := core.InttoBytes(kem, 2)
SUITE_ID = append(SUITE_ID, num[0])
SUITE_ID = append(SUITE_ID, num[1])
num = core.InttoBytes(kdf, 2)
SUITE_ID = append(SUITE_ID, num[0])
SUITE_ID = append(SUITE_ID, num[1])
num = core.InttoBytes(aead, 2)
SUITE_ID = append(SUITE_ID, num[0])
SUITE_ID = append(SUITE_ID, num[1])
ar := core.InttoBytes(mode, 1)
for i := 0; i < len(ar); i++ {
context = append(context, ar[i])
}
H := labeledExtract(nil, SUITE_ID, "psk_id_hash", pskID)
for i := 0; i < HASH_TYPE; i++ {
context = append(context, H[i])
}
H = labeledExtract(nil, SUITE_ID, "info_hash", info)
for i := 0; i < HASH_TYPE; i++ {
context = append(context, H[i])
}
//H=labeledExtract(nil,SUITE_ID,"psk_hash",psk)
//secret:=labeledExtract(H,SUITE_ID,"secret",Z)
secret := labeledExtract(Z, SUITE_ID, "secret", psk)
key := labeledExpand(secret, SUITE_ID, "key", context, AESKEY)
nonce := labeledExpand(secret, SUITE_ID, "base_nonce", context, 12)
exp_secret := labeledExpand(secret, SUITE_ID, "exp", context, HASH_TYPE)
return key, nonce, exp_secret
}