/* * 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. */ /* ECDH/ECIES/ECDSA API Functions */ package bls48581 //import "fmt" import "source.quilibrium.com/quilibrium/ceremonyclient/ec/bls48581/core" const INVALID_PUBLIC_KEY int = -2 const ERROR int = -3 //const INVALID int = -4 const EFS int = int(MODBYTES) const EGS int = int(MODBYTES) // Transform a point multiplier to RFC7748 form func RFC7748(r *BIG) { lg := 0 t := NewBIGint(1) c := CURVE_Cof_I for c != 1 { lg++ c /= 2 } n := uint(8*EGS - lg + 1) r.mod2m(n) t.shl(n) r.add(t) c = r.lastbits(lg) r.dec(c) } /* return true if S is in ranger 0 < S < order , else return false */ func ECDH_IN_RANGE(S []byte) bool { r := NewBIGints(CURVE_Order) s := FromBytes(S) if s.iszilch() { return false } if Comp(s, r) >= 0 { return false } return true } /* Calculate a public/private EC GF(p) key pair W,S where W=S.G mod EC(p), * where S is the secret key and W is the public key * and G is fixed generator. * If RNG is NULL then the private key is provided externally in S * otherwise it is generated randomly internally */ func ECDH_KEY_PAIR_GENERATE(RNG *core.RAND, S []byte, W []byte) int { res := 0 var s *BIG var G *ECP G = ECP_generator() r := NewBIGints(CURVE_Order) if RNG == nil { s = FromBytes(S) } else { if CURVETYPE != WEIERSTRASS { s = Random(RNG) // from random bytes } else { s = Randomnum(r, RNG) // Removes biases } } if CURVETYPE != WEIERSTRASS { RFC7748(s) // For Montgomery or Edwards, apply RFC7748 transformation } s.ToBytes(S) WP := G.clmul(s, r) WP.ToBytes(W, false) // To use point compression on public keys, change to true return res } /* validate public key */ func ECDH_PUBLIC_KEY_VALIDATE(W []byte) int { WP := ECP_fromBytes(W) res := 0 r := NewBIGints(CURVE_Order) if WP.Is_infinity() { res = INVALID_PUBLIC_KEY } if res == 0 { q := NewBIGints(Modulus) nb := q.nbits() k := NewBIGint(1) k.shl(uint((nb + 4) / 2)) k.add(q) k.div(r) for k.parity() == 0 { k.shr(1) WP.dbl() } if !k.isunity() { WP = WP.mul(k) } if WP.Is_infinity() { res = INVALID_PUBLIC_KEY } } return res } /* IEEE-1363 Diffie-Hellman online calculation Z=S.WD */ // type = 0 is just x coordinate output // type = 1 for standard compressed output // type = 2 for standard uncompress output 04|x|y func ECDH_ECPSVDP_DH(S []byte, WD []byte, Z []byte, typ int) int { res := 0 s := FromBytes(S) W := ECP_fromBytes(WD) if W.Is_infinity() { res = ERROR } if res == 0 { r := NewBIGints(CURVE_Order) W = W.clmul(s, r) if W.Is_infinity() { res = ERROR } else { if CURVETYPE != MONTGOMERY { if typ > 0 { if typ == 1 { W.ToBytes(Z, true) } else { W.ToBytes(Z, false) } } else { W.GetX().ToBytes(Z) } return res } else { W.GetX().ToBytes(Z) } } } return res } /* IEEE ECDSA Signature, C and D are signature on F using private key S */ func ECDH_ECPSP_DSA(sha int, RNG *core.RAND, S []byte, F []byte, C []byte, D []byte) int { var T [EGS]byte B := core.GPhashit(core.MC_SHA2, sha, EGS, 0, F, -1, nil) G := ECP_generator() r := NewBIGints(CURVE_Order) s := FromBytes(S) f := FromBytes(B[:]) c := NewBIGint(0) d := NewBIGint(0) V := NewECP() for d.iszilch() { u := Randomnum(r, RNG) w := Randomnum(r, RNG) /* IMPORTANT - side channel masking to protect invmodp() */ V.Copy(G) V = V.clmul(u, r) vx := V.GetX() c.copy(vx) c.Mod(r) if c.iszilch() { continue } u.copy(Modmul(u, w, r)) u.Invmodp(r) d.copy(Modmul(s, c, r)) d.copy(Modadd(d, f, r)) d.copy(Modmul(d, w, r)) d.copy(Modmul(u, d, r)) } c.ToBytes(T[:]) for i := 0; i < EGS; i++ { C[i] = T[i] } d.ToBytes(T[:]) for i := 0; i < EGS; i++ { D[i] = T[i] } return 0 } /* IEEE1363 ECDSA Signature Verification. Signature C and D on F is verified using public key W */ func ECDH_ECPVP_DSA(sha int, W []byte, F []byte, C []byte, D []byte) int { res := 0 B := core.GPhashit(core.MC_SHA2, sha, EGS, 0, F, -1, nil) G := ECP_generator() r := NewBIGints(CURVE_Order) c := FromBytes(C) d := FromBytes(D) f := FromBytes(B[:]) if c.iszilch() || Comp(c, r) >= 0 || d.iszilch() || Comp(d, r) >= 0 { res = ERROR } if res == 0 { d.Invmodp(r) f.copy(Modmul(f, d, r)) h2 := Modmul(c, d, r) WP := ECP_fromBytes(W) if WP.Is_infinity() { res = ERROR } else { P := NewECP() P.Copy(WP) P = P.Mul2(h2, G, f) if P.Is_infinity() { res = ERROR } else { d = P.GetX() d.Mod(r) if Comp(d, c) != 0 { res = ERROR } } } } return res } /* IEEE1363 ECIES encryption. Encryption of plaintext M uses public key W and produces ciphertext V,C,T */ func ECDH_ECIES_ENCRYPT(sha int, P1 []byte, P2 []byte, RNG *core.RAND, W []byte, M []byte, V []byte, T []byte) []byte { var Z [EFS]byte var VZ [3*EFS + 1]byte var K1 [AESKEY]byte var K2 [AESKEY]byte var U [EGS]byte if ECDH_KEY_PAIR_GENERATE(RNG, U[:], V) != 0 { return nil } if ECDH_ECPSVDP_DH(U[:], W, Z[:], 0) != 0 { return nil } for i := 0; i < 2*EFS+1; i++ { VZ[i] = V[i] } for i := 0; i < EFS; i++ { VZ[2*EFS+1+i] = Z[i] } K := core.KDF2(core.MC_SHA2, sha, VZ[:], P1, 2*AESKEY) for i := 0; i < AESKEY; i++ { K1[i] = K[i] K2[i] = K[AESKEY+i] } C := core.AES_CBC_IV0_ENCRYPT(K1[:], M) L2 := core.InttoBytes(len(P2), 8) var AC []byte for i := 0; i < len(C); i++ { AC = append(AC, C[i]) } for i := 0; i < len(P2); i++ { AC = append(AC, P2[i]) } for i := 0; i < 8; i++ { AC = append(AC, L2[i]) } core.HMAC(core.MC_SHA2, sha, T, len(T), K2[:], AC) return C } /* constant time n-byte compare */ func ncomp(T1 []byte, T2 []byte, n int) bool { res := 0 for i := 0; i < n; i++ { res |= int(T1[i] ^ T2[i]) } if res == 0 { return true } return false } /* IEEE1363 ECIES decryption. Decryption of ciphertext V,C,T using private key U outputs plaintext M */ func ECDH_ECIES_DECRYPT(sha int, P1 []byte, P2 []byte, V []byte, C []byte, T []byte, U []byte) []byte { var Z [EFS]byte var VZ [3*EFS + 1]byte var K1 [AESKEY]byte var K2 [AESKEY]byte var TAG []byte = T[:] if ECDH_ECPSVDP_DH(U, V, Z[:], 0) != 0 { return nil } for i := 0; i < 2*EFS+1; i++ { VZ[i] = V[i] } for i := 0; i < EFS; i++ { VZ[2*EFS+1+i] = Z[i] } K := core.KDF2(core.MC_SHA2, sha, VZ[:], P1, 2*AESKEY) for i := 0; i < AESKEY; i++ { K1[i] = K[i] K2[i] = K[AESKEY+i] } M := core.AES_CBC_IV0_DECRYPT(K1[:], C) if M == nil { return nil } L2 := core.InttoBytes(len(P2), 8) var AC []byte for i := 0; i < len(C); i++ { AC = append(AC, C[i]) } for i := 0; i < len(P2); i++ { AC = append(AC, P2[i]) } for i := 0; i < 8; i++ { AC = append(AC, L2[i]) } core.HMAC(core.MC_SHA2, sha, TAG, len(TAG), K2[:], AC) if !ncomp(T, TAG, len(T)) { return nil } return M }