mirror of
https://github.com/odin-lang/Odin.git
synced 2026-04-19 21:10:30 +00:00
core/crypto/ecdh: Add secp384r1
This commit is contained in:
@@ -18,6 +18,7 @@ X448_Buf :: [x448.SCALAR_SIZE]byte
|
||||
Curve :: enum {
|
||||
Invalid,
|
||||
SECP256R1,
|
||||
SECP384R1,
|
||||
X25519,
|
||||
X448,
|
||||
}
|
||||
@@ -26,6 +27,7 @@ Curve :: enum {
|
||||
CURVE_NAMES := [Curve]string {
|
||||
.Invalid = "Invalid",
|
||||
.SECP256R1 = "secp256r1",
|
||||
.SECP384R1 = "secp384r1",
|
||||
.X25519 = "X25519",
|
||||
.X448 = "X448",
|
||||
}
|
||||
@@ -34,6 +36,7 @@ CURVE_NAMES := [Curve]string {
|
||||
PRIVATE_KEY_SIZES := [Curve]int {
|
||||
.Invalid = 0,
|
||||
.SECP256R1 = secec.SC_SIZE_P256R1,
|
||||
.SECP384R1 = secec.SC_SIZE_P384R1,
|
||||
.X25519 = x25519.SCALAR_SIZE,
|
||||
.X448 = x448.SCALAR_SIZE,
|
||||
}
|
||||
@@ -42,6 +45,7 @@ PRIVATE_KEY_SIZES := [Curve]int {
|
||||
PUBLIC_KEY_SIZES := [Curve]int {
|
||||
.Invalid = 0,
|
||||
.SECP256R1 = 1 + 2 * secec.FE_SIZE_P256R1,
|
||||
.SECP384R1 = 1 + 2 * secec.FE_SIZE_P384R1,
|
||||
.X25519 = x25519.POINT_SIZE,
|
||||
.X448 = x448.POINT_SIZE,
|
||||
}
|
||||
@@ -50,6 +54,7 @@ PUBLIC_KEY_SIZES := [Curve]int {
|
||||
SHARED_SECRET_SIZES := [Curve]int {
|
||||
.Invalid = 0,
|
||||
.SECP256R1 = secec.FE_SIZE_P256R1,
|
||||
.SECP384R1 = secec.FE_SIZE_P384R1,
|
||||
.X25519 = x25519.POINT_SIZE,
|
||||
.X448 = x448.POINT_SIZE,
|
||||
}
|
||||
@@ -58,6 +63,7 @@ SHARED_SECRET_SIZES := [Curve]int {
|
||||
_PRIV_IMPL_IDS := [Curve]typeid {
|
||||
.Invalid = nil,
|
||||
.SECP256R1 = typeid_of(secec.Scalar_p256r1),
|
||||
.SECP384R1 = typeid_of(secec.Scalar_p384r1),
|
||||
.X25519 = typeid_of(X25519_Buf),
|
||||
.X448 = typeid_of(X448_Buf),
|
||||
}
|
||||
@@ -66,6 +72,7 @@ _PRIV_IMPL_IDS := [Curve]typeid {
|
||||
_PUB_IMPL_IDS := [Curve]typeid {
|
||||
.Invalid = nil,
|
||||
.SECP256R1 = typeid_of(secec.Point_p256r1),
|
||||
.SECP384R1 = typeid_of(secec.Point_p384r1),
|
||||
.X25519 = typeid_of(X25519_Buf),
|
||||
.X448 = typeid_of(X448_Buf),
|
||||
}
|
||||
@@ -77,6 +84,7 @@ Private_Key :: struct {
|
||||
_curve: Curve,
|
||||
_impl: union {
|
||||
secec.Scalar_p256r1,
|
||||
secec.Scalar_p384r1,
|
||||
X25519_Buf,
|
||||
X448_Buf,
|
||||
},
|
||||
@@ -90,6 +98,7 @@ Public_Key :: struct {
|
||||
_curve: Curve,
|
||||
_impl: union {
|
||||
secec.Point_p256r1,
|
||||
secec.Point_p384r1,
|
||||
X25519_Buf,
|
||||
X448_Buf,
|
||||
},
|
||||
@@ -124,6 +133,18 @@ private_key_generate :: proc(priv_key: ^Private_Key, curve: Curve) -> bool {
|
||||
break
|
||||
}
|
||||
}
|
||||
case .SECP384R1:
|
||||
sc := &priv_key._impl.(secec.Scalar_p384r1)
|
||||
|
||||
b: [48]byte = ---
|
||||
defer (mem.zero_explicit(&b, size_of(b)))
|
||||
for {
|
||||
crypto.rand_bytes(b[:])
|
||||
did_reduce := secec.sc_set_bytes(sc, b[:])
|
||||
if !did_reduce && secec.sc_is_zero(sc) == 0 { // Likely
|
||||
break
|
||||
}
|
||||
}
|
||||
case .X25519:
|
||||
sc := &priv_key._impl.(X25519_Buf)
|
||||
crypto.rand_bytes(sc[:])
|
||||
@@ -160,6 +181,17 @@ private_key_set_bytes :: proc(priv_key: ^Private_Key, curve: Curve, b: []byte) -
|
||||
did_reduce := secec.sc_set_bytes(sc, b)
|
||||
is_zero := secec.sc_is_zero(sc) == 1
|
||||
|
||||
// Reject `0` and scalars that are not less than the
|
||||
// curve order.
|
||||
if did_reduce || is_zero {
|
||||
private_key_clear(priv_key)
|
||||
return false
|
||||
}
|
||||
case .SECP384R1:
|
||||
sc := &priv_key._impl.(secec.Scalar_p384r1)
|
||||
did_reduce := secec.sc_set_bytes(sc, b)
|
||||
is_zero := secec.sc_is_zero(sc) == 1
|
||||
|
||||
// Reject `0` and scalars that are not less than the
|
||||
// curve order.
|
||||
if did_reduce || is_zero {
|
||||
@@ -190,6 +222,11 @@ private_key_generate_public :: proc(priv_key: ^Private_Key) {
|
||||
secec.pt_scalar_mul_generator(&pub_key, &sc)
|
||||
secec.pt_rescale(&pub_key, &pub_key)
|
||||
priv_key._pub_key._impl = pub_key
|
||||
case secec.Scalar_p384r1:
|
||||
pub_key: secec.Point_p384r1 = ---
|
||||
secec.pt_scalar_mul_generator(&pub_key, &sc)
|
||||
secec.pt_rescale(&pub_key, &pub_key)
|
||||
priv_key._pub_key._impl = pub_key
|
||||
case X25519_Buf:
|
||||
pub_key: X25519_Buf = ---
|
||||
x25519.scalarmult_basepoint(pub_key[:], sc[:])
|
||||
@@ -214,6 +251,9 @@ private_key_bytes :: proc(priv_key: ^Private_Key, dst: []byte) {
|
||||
case .SECP256R1:
|
||||
sc := &priv_key._impl.(secec.Scalar_p256r1)
|
||||
secec.sc_bytes(dst, sc)
|
||||
case .SECP384R1:
|
||||
sc := &priv_key._impl.(secec.Scalar_p384r1)
|
||||
secec.sc_bytes(dst, sc)
|
||||
case .X25519:
|
||||
sc := &priv_key._impl.(X25519_Buf)
|
||||
copy(dst, sc[:])
|
||||
@@ -236,6 +276,9 @@ private_key_equal :: proc(p, q: ^Private_Key) -> bool {
|
||||
case .SECP256R1:
|
||||
sc_p, sc_q := &p._impl.(secec.Scalar_p256r1), &q._impl.(secec.Scalar_p256r1)
|
||||
return secec.sc_equal(sc_p, sc_q) == 1
|
||||
case .SECP384R1:
|
||||
sc_p, sc_q := &p._impl.(secec.Scalar_p384r1), &q._impl.(secec.Scalar_p384r1)
|
||||
return secec.sc_equal(sc_p, sc_q) == 1
|
||||
case .X25519:
|
||||
b_p, b_q := &p._impl.(X25519_Buf), &q._impl.(X25519_Buf)
|
||||
return crypto.compare_constant_time(b_p[:], b_q[:]) == 1
|
||||
@@ -277,6 +320,16 @@ public_key_set_bytes :: proc(pub_key: ^Public_Key, curve: Curve, b: []byte) -> b
|
||||
if !ok || secec.pt_is_identity(pt) == 1 {
|
||||
return false
|
||||
}
|
||||
case .SECP384R1:
|
||||
if b[0] != secec.SEC_PREFIX_UNCOMPRESSED {
|
||||
return false
|
||||
}
|
||||
|
||||
pt := &pub_key._impl.(secec.Point_p384r1)
|
||||
ok := secec.pt_set_sec_bytes(pt, b)
|
||||
if !ok || secec.pt_is_identity(pt) == 1 {
|
||||
return false
|
||||
}
|
||||
case .X25519:
|
||||
pt := &pub_key._impl.(X25519_Buf)
|
||||
copy(pt[:], b)
|
||||
@@ -313,6 +366,14 @@ public_key_bytes :: proc(pub_key: ^Public_Key, dst: []byte) {
|
||||
dst[0] = secec.SEC_PREFIX_UNCOMPRESSED
|
||||
secec.fe_bytes(dst[1:1+secec.FE_SIZE_P256R1], &pt.x)
|
||||
secec.fe_bytes(dst[1+secec.FE_SIZE_P256R1:], &pt.y)
|
||||
case .SECP384R1:
|
||||
// Invariant: Unless the caller is manually building pub_key
|
||||
// `Z = 1`, so we can skip the rescale.
|
||||
pt := &pub_key._impl.(secec.Point_p384r1)
|
||||
|
||||
dst[0] = secec.SEC_PREFIX_UNCOMPRESSED
|
||||
secec.fe_bytes(dst[1:1+secec.FE_SIZE_P384R1], &pt.x)
|
||||
secec.fe_bytes(dst[1+secec.FE_SIZE_P384R1:], &pt.y)
|
||||
case .X25519:
|
||||
pt := &pub_key._impl.(X25519_Buf)
|
||||
copy(dst, pt[:])
|
||||
@@ -335,6 +396,9 @@ public_key_equal :: proc(p, q: ^Public_Key) -> bool {
|
||||
case .SECP256R1:
|
||||
pt_p, pt_q := &p._impl.(secec.Point_p256r1), &q._impl.(secec.Point_p256r1)
|
||||
return secec.pt_equal(pt_p, pt_q) == 1
|
||||
case .SECP384R1:
|
||||
pt_p, pt_q := &p._impl.(secec.Point_p384r1), &q._impl.(secec.Point_p384r1)
|
||||
return secec.pt_equal(pt_p, pt_q) == 1
|
||||
case .X25519:
|
||||
b_p, b_q := &p._impl.(X25519_Buf), &q._impl.(X25519_Buf)
|
||||
return crypto.compare_constant_time(b_p[:], b_q[:]) == 1
|
||||
@@ -367,6 +431,13 @@ ecdh :: proc(priv_key: ^Private_Key, pub_key: ^Public_Key, dst: []byte) -> bool
|
||||
ss: secec.Point_p256r1
|
||||
defer secec.pt_clear(&ss)
|
||||
|
||||
secec.pt_scalar_mul(&ss, pt, sc)
|
||||
return secec.pt_bytes(dst, nil, &ss)
|
||||
case .SECP384R1:
|
||||
sc, pt := &priv_key._impl.(secec.Scalar_p384r1), &pub_key._impl.(secec.Point_p384r1)
|
||||
ss: secec.Point_p384r1
|
||||
defer secec.pt_clear(&ss)
|
||||
|
||||
secec.pt_scalar_mul(&ss, pt, sc)
|
||||
return secec.pt_bytes(dst, nil, &ss)
|
||||
case .X25519:
|
||||
|
||||
@@ -52,6 +52,19 @@ test_ecdh :: proc(t: ^testing.T) {
|
||||
"04809f04289c64348c01515eb03d5ce7ac1a8cb9498f5caa50197e58d43a86a7aeb29d84e811197f25eba8f5194092cb6ff440e26d4421011372461f579271cda3",
|
||||
"057d636096cb80b67a8c038c890e887d1adfa4195e9b3ce241c8a778c59cda67",
|
||||
},
|
||||
// secp384r1 Test vectors (subset) from NIST CAVP
|
||||
{
|
||||
.SECP384R1,
|
||||
"3cc3122a68f0d95027ad38c067916ba0eb8c38894d22e1b15618b6818a661774ad463b205da88cf699ab4d43c9cf98a1",
|
||||
"04a7c76b970c3b5fe8b05d2838ae04ab47697b9eaf52e764592efda27fe7513272734466b400091adbf2d68c58e0c50066ac68f19f2e1cb879aed43a9969b91a0839c4c38a49749b661efedf243451915ed0905a32b060992b468c64766fc8437a",
|
||||
"5f9d29dc5e31a163060356213669c8ce132e22f57c9a04f40ba7fcead493b457e5621e766c40a2e3d4d6a04b25e533f1",
|
||||
},
|
||||
{
|
||||
.SECP384R1,
|
||||
"92860c21bde06165f8e900c687f8ef0a05d14f290b3f07d8b3a8cc6404366e5d5119cd6d03fb12dc58e89f13df9cd783",
|
||||
"0430f43fcf2b6b00de53f624f1543090681839717d53c7c955d1d69efaf0349b7363acb447240101cbb3af6641ce4b88e025e46c0c54f0162a77efcc27b6ea792002ae2ba82714299c860857a68153ab62e525ec0530d81b5aa15897981e858757",
|
||||
"a23742a2c267d7425fda94b93f93bbcc24791ac51cd8fd501a238d40812f4cbfc59aac9520d758cf789c76300c69d2ff",
|
||||
},
|
||||
}
|
||||
|
||||
for v, _ in test_vectors {
|
||||
|
||||
Reference in New Issue
Block a user