use subtle::ConstantTimeEq;
use crate::crypto::{
canon, CanonEcPoint, CanonEcPointRef, CanonEcScalar, Crypto, CryptoSensitive, Digest, EcPoint,
EcScalar, Hash, HashRef, HmacHash, HmacHashRef, Kdf, PbKdf, AEAD_CANON_KEY_LEN,
EC_CANON_POINT_LEN, EC_CANON_SCALAR_LEN, EC_POINT_ZEROED, EC_SCALAR_ZEROED, HASH_LEN,
HASH_ZEROED, HMAC_HASH_LEN, HMAC_HASH_ZEROED, UINT320_CANON_LEN,
};
use crate::error::{Error, ErrorCode};
use crate::sc::SCStatusCodes;
use crate::utils::init::{init, Init};
pub const SPAKE2P_ITERATION_COUNT: u32 = 2000;
pub const SPAKE2P_KE_LEN: usize = 16;
pub const SPAKE2P_W_LEN: usize = UINT320_CANON_LEN * 2;
pub const SPAKE2P_VERIFIER_PASSWORD_LEN: usize = 4;
pub const SPAKE2P_VERIFIER_STR_LEN: usize = EC_CANON_SCALAR_LEN + EC_CANON_POINT_LEN;
pub const SPAKE2P_VERIFIER_SALT_LEN: usize = 32;
pub const SPAKE2P_VERIFIER_SALT_MIN_LEN: usize = 16;
pub const SPAKE2P_RANDOM_LEN: usize = 32;
pub const SPAKE2P_SESSION_KEYS_LEN: usize = AEAD_CANON_KEY_LEN * 3;
canon!(SPAKE2P_KE_LEN, SPAKE2P_KE_ZEROED, Spake2pKe, Spake2pKeRef);
canon!(SPAKE2P_W_LEN, SPAKE2P_W_ZEROED, Spake2pW, Spake2pWRef);
canon!(
SPAKE2P_VERIFIER_PASSWORD_LEN,
SPAKE2P_VERIFIER_PASSWORD_ZEROED,
Spake2pVerifierPassword,
Spake2pVerifierPasswordRef
);
canon!(
SPAKE2P_VERIFIER_STR_LEN,
SPAKE2P_VERIFIER_STR_ZEROED,
Spake2pVerifierStr,
Spake2pVerifierStrRef
);
canon!(
SPAKE2P_VERIFIER_SALT_LEN,
SPAKE2P_VERIFIER_SALT_ZEROED,
Spake2pVerifierSalt,
Spake2pVerifierSaltRef
);
canon!(
SPAKE2P_RANDOM_LEN,
SPAKE2P_RANDOM_ZEROED,
Spake2pRandom,
Spake2pRandomRef
);
canon!(
SPAKE2P_SESSION_KEYS_LEN,
SPAKE2P_SESSION_KEYS_ZEROED,
Spake2pSessionKeys,
Spake2pSessionKeysRef
);
#[derive(Debug, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Spake2pVerifierData {
pub password: Option<Spake2pVerifierPassword>,
pub verifier: Spake2pVerifierStr,
pub salt: Spake2pVerifierSalt,
pub salt_len: u8,
pub count: u32,
}
impl Spake2pVerifierData {
pub fn init_with_pw<'a>(
password: Spake2pVerifierPasswordRef<'a>,
salt: &'a [u8],
) -> impl Init<Self> + 'a {
Self::init_empty().chain(move |this| {
this.configure_pw(password, salt);
Ok(())
})
}
pub fn init<'a>(
verifier: Spake2pVerifierStrRef<'a>,
salt: &'a [u8],
count: u32,
) -> impl Init<Self> + 'a {
Self::init_empty().chain(move |this| {
this.configure_verifier(verifier, salt, count);
Ok(())
})
}
fn init_empty() -> impl Init<Self> {
init!(Self {
password: None,
verifier <- Spake2pVerifierStr::init(),
salt <- Spake2pVerifierSalt::init(),
salt_len: SPAKE2P_VERIFIER_SALT_LEN as u8,
count: SPAKE2P_ITERATION_COUNT,
})
}
fn configure_pw(&mut self, password: Spake2pVerifierPasswordRef<'_>, salt: &[u8]) {
self.password = Some(password.into());
self.set_salt(salt);
self.verifier.zeroize();
self.count = SPAKE2P_ITERATION_COUNT;
}
fn configure_verifier(&mut self, verifier: Spake2pVerifierStrRef<'_>, salt: &[u8], count: u32) {
self.password = None;
self.set_salt(salt);
self.verifier.load(verifier);
self.count = count;
}
fn set_salt(&mut self, salt: &[u8]) {
debug_assert!(
(SPAKE2P_VERIFIER_SALT_MIN_LEN..=SPAKE2P_VERIFIER_SALT_LEN).contains(&salt.len()),
"PASE salt out of range: {} not in {}..={}",
salt.len(),
SPAKE2P_VERIFIER_SALT_MIN_LEN,
SPAKE2P_VERIFIER_SALT_LEN
);
let n = salt.len().min(SPAKE2P_VERIFIER_SALT_LEN);
let storage = self.salt.access_mut();
storage.fill(0);
storage[..n].copy_from_slice(&salt[..n]);
self.salt_len = n as u8;
}
pub fn salt_bytes(&self) -> &[u8] {
&self.salt.access()[..self.salt_len as usize]
}
}
pub struct ProverContext {
w0: CanonEcScalar,
w1: CanonEcScalar,
xy: CanonEcScalar,
}
pub struct Spake2P {
local_sessid: u16,
peer_sessid: u16,
context_hash: Hash,
ke: Spake2pKe,
ca: HmacHash,
cb: HmacHash,
}
impl Spake2P {
pub const SPAKE2P_KEY_CONFIRM_INFO: &[u8] = b"ConfirmationKeys";
const SPAKE2P_CONTEXT_PREFIX: &[u8] = b"CHIP PAKE V1 Commissioning";
const MATTER_M_BIN: CanonEcPointRef<'static> = CanonEcPointRef::new(&[
0x04, 0x88, 0x6e, 0x2f, 0x97, 0xac, 0xe4, 0x6e, 0x55, 0xba, 0x9d, 0xd7, 0x24, 0x25, 0x79,
0xf2, 0x99, 0x3b, 0x64, 0xe1, 0x6e, 0xf3, 0xdc, 0xab, 0x95, 0xaf, 0xd4, 0x97, 0x33, 0x3d,
0x8f, 0xa1, 0x2f, 0x5f, 0xf3, 0x55, 0x16, 0x3e, 0x43, 0xce, 0x22, 0x4e, 0x0b, 0x0e, 0x65,
0xff, 0x02, 0xac, 0x8e, 0x5c, 0x7b, 0xe0, 0x94, 0x19, 0xc7, 0x85, 0xe0, 0xca, 0x54, 0x7d,
0x55, 0xa1, 0x2e, 0x2d, 0x20,
]);
const MATTER_N_BIN: CanonEcPointRef<'static> = CanonEcPointRef::new(&[
0x04, 0xd8, 0xbb, 0xd6, 0xc6, 0x39, 0xc6, 0x29, 0x37, 0xb0, 0x4d, 0x99, 0x7f, 0x38, 0xc3,
0x77, 0x07, 0x19, 0xc6, 0x29, 0xd7, 0x01, 0x4d, 0x49, 0xa2, 0x4b, 0x4f, 0x98, 0xba, 0xa1,
0x29, 0x2b, 0x49, 0x07, 0xd6, 0x0a, 0xa6, 0xbf, 0xad, 0xe4, 0x50, 0x08, 0xa6, 0x36, 0x33,
0x7f, 0x51, 0x68, 0xc6, 0x4d, 0x9b, 0xd3, 0x60, 0x34, 0x80, 0x8c, 0xd5, 0x64, 0x49, 0x0b,
0x1e, 0x65, 0x6e, 0xdb, 0xe7,
]);
pub const fn new() -> Self {
Self {
local_sessid: 0,
peer_sessid: 0,
context_hash: HASH_ZEROED,
ke: Spake2pKe::new(),
ca: HMAC_HASH_ZEROED,
cb: HMAC_HASH_ZEROED,
}
}
pub fn init() -> impl Init<Self> {
init!(Self {
local_sessid: 0,
peer_sessid: 0,
context_hash <- Hash::init(),
ke <- Spake2pKe::init(),
ca <- HmacHash::init(),
cb <- HmacHash::init(),
})
}
pub fn start_context<'a, C: Crypto>(
&mut self,
crypto: &'a C,
local_sessid: u16,
peer_sessid: u16,
request: &[u8],
) -> Result<C::Hash<'a>, Error> {
self.local_sessid = local_sessid;
self.peer_sessid = peer_sessid;
let mut context = crypto.hash()?;
context.update(Self::SPAKE2P_CONTEXT_PREFIX)?;
context.update(request)?;
Ok(context)
}
pub fn finish_context<'a, C: Crypto>(
&mut self,
mut context: C::Hash<'a>,
response: &[u8],
) -> Result<(), Error> {
context.update(response)?;
context.finish(&mut self.context_hash)
}
pub fn setup_verifier<C: Crypto>(
&mut self,
crypto: C,
verifier: &Spake2pVerifierData,
a_pt: CanonEcPointRef<'_>,
b_pt_out: &mut CanonEcPoint,
cb_out: &mut HmacHash,
) -> Result<(), Error> {
if !crypto.ec_point(a_pt)?.is_valid_pubkey()? {
error!("SPAKE2+: invalid prover public share (pA)");
Err(ErrorCode::InvalidData)?;
}
let (w0, l_pt) = if let Some(pw) = verifier.password.as_ref().map(|pw| pw.reference()) {
let mut w0s_w1s = Spake2pW::new();
Self::compute_w0s_w1s(
&crypto,
pw,
verifier.count,
verifier.salt_bytes(),
&mut w0s_w1s,
)?;
let (w0s, w1s) = w0s_w1s
.reference()
.split::<UINT320_CANON_LEN, UINT320_CANON_LEN>();
let w0 = crypto.ec_scalar_mod_p(w0s)?;
let w1 = crypto.ec_scalar_mod_p(w1s)?;
let l_pt = crypto.ec_generator_point()?.mul(&w1)?;
(w0, l_pt)
} else {
let (w0, l_pt) = verifier
.verifier
.reference()
.split::<EC_CANON_SCALAR_LEN, EC_CANON_POINT_LEN>();
(crypto.ec_scalar(w0)?, crypto.ec_point(l_pt)?)
};
let n_pt = crypto.ec_point(Self::MATTER_N_BIN)?;
let (b_pt, xy) = Self::compute_b_pt_xy(&crypto, &n_pt, &w0)?;
b_pt.write_canon(b_pt_out)?;
let mut tt_hash = HASH_ZEROED;
Self::compute_verifier_tt_hash(
&crypto,
self.context_hash.reference(),
&w0,
&l_pt,
&crypto.ec_point(Self::MATTER_M_BIN)?,
a_pt,
b_pt_out.reference(),
&xy,
&mut tt_hash,
)?;
Self::compute_ke_ca_cb(
&crypto,
tt_hash.reference(),
a_pt,
b_pt,
&mut self.ke,
&mut self.ca,
&mut self.cb,
)?;
cb_out.load(self.cb.reference());
Ok(())
}
pub fn verify(
&mut self,
ca: HmacHashRef<'_>,
) -> Result<(u16, u16, Spake2pKeRef<'_>), SCStatusCodes> {
if ca.access().ct_eq(self.ca.access()).unwrap_u8() == 1 {
Ok((self.local_sessid, self.peer_sessid, self.ke.reference()))
} else {
Err(SCStatusCodes::InvalidParameter)
}
}
pub fn ke(&self) -> Spake2pKeRef<'_> {
self.ke.reference()
}
pub fn setup_prover<C: Crypto>(
&mut self,
crypto: C,
password: Spake2pVerifierPasswordRef<'_>,
salt: &[u8],
iterations: u32,
a_pt_out: &mut CanonEcPoint,
) -> Result<ProverContext, Error> {
let mut w0s_w1s = Spake2pW::new();
Self::compute_w0s_w1s(&crypto, password, iterations, salt, &mut w0s_w1s)?;
let (w0s, w1s) = w0s_w1s
.reference()
.split::<UINT320_CANON_LEN, UINT320_CANON_LEN>();
let w0 = crypto.ec_scalar_mod_p(w0s)?;
let w1 = crypto.ec_scalar_mod_p(w1s)?;
let m_pt = crypto.ec_point(Self::MATTER_M_BIN)?;
let (a_pt, xy) = Self::compute_a_pt_xy(&crypto, &m_pt, &w0)?;
a_pt.write_canon(a_pt_out)?;
let mut w0_out = EC_SCALAR_ZEROED;
let mut w1_out = EC_SCALAR_ZEROED;
let mut xy_out = EC_SCALAR_ZEROED;
w0.write_canon(&mut w0_out)?;
w1.write_canon(&mut w1_out)?;
xy.write_canon(&mut xy_out)?;
Ok(ProverContext {
w0: w0_out,
w1: w1_out,
xy: xy_out,
})
}
pub fn complete_prover<C: Crypto>(
&mut self,
crypto: C,
ctx: &ProverContext,
a_pt: CanonEcPointRef<'_>,
b_pt: CanonEcPointRef<'_>,
cb: HmacHashRef<'_>,
ca_out: &mut HmacHash,
) -> Result<(), SCStatusCodes> {
let w0 = crypto
.ec_scalar(ctx.w0.reference())
.map_err(|_| SCStatusCodes::InvalidParameter)?;
let w1 = crypto
.ec_scalar(ctx.w1.reference())
.map_err(|_| SCStatusCodes::InvalidParameter)?;
let xy = crypto
.ec_scalar(ctx.xy.reference())
.map_err(|_| SCStatusCodes::InvalidParameter)?;
let n_pt = crypto
.ec_point(Self::MATTER_N_BIN)
.map_err(|_| SCStatusCodes::InvalidParameter)?;
let mut tt_hash = HASH_ZEROED;
Self::compute_prover_tt_hash(
&crypto,
self.context_hash.reference(),
&w0,
&w1,
&n_pt,
a_pt,
b_pt,
&xy,
&mut tt_hash,
)
.map_err(|_| SCStatusCodes::InvalidParameter)?;
let b_pt_ec = crypto
.ec_point(b_pt)
.map_err(|_| SCStatusCodes::InvalidParameter)?;
if !b_pt_ec
.is_valid_pubkey()
.map_err(|_| SCStatusCodes::InvalidParameter)?
{
error!("SPAKE2+: invalid verifier public share (pB)");
return Err(SCStatusCodes::InvalidParameter);
}
Self::compute_ke_ca_cb(
&crypto,
tt_hash.reference(),
a_pt,
b_pt_ec,
&mut self.ke,
&mut self.ca,
&mut self.cb,
)
.map_err(|_| SCStatusCodes::InvalidParameter)?;
if cb.access().ct_eq(self.cb.access()).unwrap_u8() != 1 {
return Err(SCStatusCodes::InvalidParameter);
}
ca_out.load(self.ca.reference());
Ok(())
}
fn compute_b_pt_xy<'a, C: Crypto>(
crypto: &'a C,
n_pt: &C::EcPoint<'a>,
w0: &C::EcScalar<'a>,
) -> Result<(C::EcPoint<'a>, C::EcScalar<'a>), Error> {
let xy = crypto.generate_ec_scalar()?;
let b_pt = crypto.ec_generator_point()?.add_mul(&xy, n_pt, w0)?;
Ok((b_pt, xy))
}
fn compute_a_pt_xy<'a, C: Crypto>(
crypto: &'a C,
m_pt: &C::EcPoint<'a>,
w0: &C::EcScalar<'a>,
) -> Result<(C::EcPoint<'a>, C::EcScalar<'a>), Error> {
let xy = crypto.generate_ec_scalar()?;
let a_pt = crypto.ec_generator_point()?.add_mul(&xy, m_pt, w0)?;
Ok((a_pt, xy))
}
#[allow(clippy::too_many_arguments)]
fn compute_verifier_tt_hash<'a, C: Crypto>(
crypto: &'a C,
context: HashRef<'_>,
w0: &C::EcScalar<'a>,
l_pt: &C::EcPoint<'a>,
m_pt: &C::EcPoint<'a>,
a_pt_canon: CanonEcPointRef<'_>,
b_pt_canon: CanonEcPointRef<'_>,
xy: &C::EcScalar<'a>,
tt_hash_out: &mut Hash,
) -> Result<(), Error> {
let mut tt = crypto.hash()?;
let mut add_to_tt = |data: &[u8]| {
tt.update(&(data.len() as u64).to_le_bytes())?;
if !data.is_empty() {
tt.update(data)?;
}
Ok::<_, Error>(())
};
let mut pt_out = EC_POINT_ZEROED;
let mut sc_out = EC_SCALAR_ZEROED;
add_to_tt(context.access())?;
add_to_tt(&[])?;
add_to_tt(&[])?;
add_to_tt(Self::MATTER_M_BIN.access())?;
add_to_tt(Self::MATTER_N_BIN.access())?;
add_to_tt(a_pt_canon.access())?;
add_to_tt(b_pt_canon.access())?;
let a_pt = crypto.ec_point(a_pt_canon)?;
let (z_pt, v_pt) = Self::compute_zv_verifier(crypto, w0, l_pt, m_pt, &a_pt, xy)?;
z_pt.write_canon(&mut pt_out)?;
add_to_tt(pt_out.access())?;
v_pt.write_canon(&mut pt_out)?;
add_to_tt(pt_out.access())?;
w0.write_canon(&mut sc_out)?;
add_to_tt(sc_out.access())?;
tt.finish(tt_hash_out)?;
Ok(())
}
#[allow(clippy::too_many_arguments)]
fn compute_prover_tt_hash<'a, C: Crypto>(
crypto: &'a C,
context: HashRef<'_>,
w0: &C::EcScalar<'a>,
w1: &C::EcScalar<'a>,
n_pt: &C::EcPoint<'a>,
a_pt_canon: CanonEcPointRef<'_>,
b_pt_canon: CanonEcPointRef<'_>,
xy: &C::EcScalar<'a>,
tt_hash_out: &mut Hash,
) -> Result<(), Error> {
let mut tt = crypto.hash()?;
let mut add_to_tt = |data: &[u8]| {
tt.update(&(data.len() as u64).to_le_bytes())?;
if !data.is_empty() {
tt.update(data)?;
}
Ok::<_, Error>(())
};
let mut pt_out = EC_POINT_ZEROED;
let mut sc_out = EC_SCALAR_ZEROED;
add_to_tt(context.access())?;
add_to_tt(&[])?;
add_to_tt(&[])?;
add_to_tt(Self::MATTER_M_BIN.access())?;
add_to_tt(Self::MATTER_N_BIN.access())?;
add_to_tt(a_pt_canon.access())?;
add_to_tt(b_pt_canon.access())?;
let b_pt = crypto.ec_point(b_pt_canon)?;
let (z_pt, v_pt) = Self::compute_zv_prover(crypto, w0, w1, n_pt, &b_pt, xy)?;
z_pt.write_canon(&mut pt_out)?;
add_to_tt(pt_out.access())?;
v_pt.write_canon(&mut pt_out)?;
add_to_tt(pt_out.access())?;
w0.write_canon(&mut sc_out)?;
add_to_tt(sc_out.access())?;
tt.finish(tt_hash_out)?;
Ok(())
}
fn compute_ke_ca_cb<'a, C: Crypto>(
crypto: &'a C,
tt_hash: HashRef<'_>,
a_pt_canon: CanonEcPointRef<'_>,
b_pt: C::EcPoint<'a>,
ke_out: &mut Spake2pKe,
ca_out: &mut HmacHash,
cb_out: &mut HmacHash,
) -> Result<(), Error> {
let ka_ke = tt_hash;
let (ka, ke_internal) = ka_ke.split::<{ HASH_LEN / 2 }, { HASH_LEN / 2 }>();
ke_out.load(ke_internal);
let mut kca_kcb = CryptoSensitive::<{ HMAC_HASH_LEN }>::new();
crypto
.kdf()
.unwrap()
.expand(&[], ka, Self::SPAKE2P_KEY_CONFIRM_INFO, &mut kca_kcb)?;
let (kca, kcb) = kca_kcb.reference().split::<16, 16>();
let mut pt_out = EC_POINT_ZEROED;
let mut mac = crypto.hmac(kca)?;
b_pt.write_canon(&mut pt_out)?;
mac.update(pt_out.access())?;
mac.finish(ca_out)?;
let mut mac = crypto.hmac(kcb)?;
mac.update(a_pt_canon.access())?;
mac.finish(cb_out)?;
Ok(())
}
fn compute_zv_verifier<'a, C: Crypto>(
_crypto: &'a C,
w0: &C::EcScalar<'a>,
l_pt: &C::EcPoint<'a>,
m_pt: &C::EcPoint<'a>,
x_pt: &C::EcPoint<'a>,
y: &C::EcScalar<'a>,
) -> Result<(C::EcPoint<'a>, C::EcPoint<'a>), Error> {
let z_pt = x_pt.add_mul(y, &m_pt.neg()?, &y.mul(w0)?)?;
let v_pt = l_pt.mul(y)?;
Ok((z_pt, v_pt))
}
fn compute_zv_prover<'a, C: Crypto>(
_crypto: &'a C,
w0: &C::EcScalar<'a>,
w1: &C::EcScalar<'a>,
n_pt: &C::EcPoint<'a>,
y_pt: &C::EcPoint<'a>,
x: &C::EcScalar<'a>,
) -> Result<(C::EcPoint<'a>, C::EcPoint<'a>), Error> {
let n_pt_neg = n_pt.neg()?;
let z_pt = y_pt.add_mul(x, &n_pt_neg, &x.mul(w0)?)?;
let v_pt = y_pt.add_mul(w1, &n_pt_neg, &w1.mul(w0)?)?;
Ok((z_pt, v_pt))
}
fn compute_w0s_w1s<C: Crypto>(
crypto: C,
pw: Spake2pVerifierPasswordRef<'_>,
iter: u32,
salt: &[u8],
w0w1s: &mut Spake2pW,
) -> Result<(), Error> {
crypto.pbkdf()?.derive(pw, iter as usize, salt, w0w1s)
}
}
#[cfg(test)]
mod tests {
use crate::crypto::{
test_only_crypto, CanonEcScalarRef, Crypto, Digest, HmacHashRef, HASH_ZEROED,
};
use super::*;
#[test]
fn test_x() {
for t in RFC_T {
let crypto = test_only_crypto();
let m_pt = unwrap!(crypto.ec_point(Spake2P::MATTER_M_BIN));
let x = unwrap!(crypto.ec_scalar(t.x));
let w0 = unwrap!(crypto.ec_scalar(t.w0));
let gen_pt = unwrap!(crypto.ec_generator_point());
let result_pt = unwrap!(gen_pt.add_mul(&x, &m_pt, &w0));
let mut point = EC_POINT_ZEROED;
unwrap!(result_pt.write_canon(&mut point));
assert_eq!(t.x_pt.access(), point.access());
}
}
#[test]
fn test_y() {
for t in RFC_T {
let crypto = test_only_crypto();
let n_pt = unwrap!(crypto.ec_point(Spake2P::MATTER_N_BIN));
let y = unwrap!(crypto.ec_scalar(t.y));
let w0 = unwrap!(crypto.ec_scalar(t.w0));
let gen_pt = unwrap!(crypto.ec_generator_point());
let result_pt = unwrap!(gen_pt.add_mul(&y, &n_pt, &w0));
let mut point = EC_POINT_ZEROED;
unwrap!(result_pt.write_canon(&mut point));
assert_eq!(t.y_pt.access(), point.access());
}
}
#[test]
fn test_zv_prover() {
for t in RFC_T {
let crypto = test_only_crypto();
let n_pt = unwrap!(crypto.ec_point(Spake2P::MATTER_N_BIN));
let x = unwrap!(crypto.ec_scalar(t.x));
let y_pt = unwrap!(crypto.ec_point(t.y_pt));
let w0 = unwrap!(crypto.ec_scalar(t.w0));
let w1 = unwrap!(crypto.ec_scalar(t.w1));
let (z_pt, v_pt) = unwrap!(Spake2P::compute_zv_prover(
&crypto, &w0, &w1, &n_pt, &y_pt, &x
));
let mut point = EC_POINT_ZEROED;
unwrap!(z_pt.write_canon(&mut point));
assert_eq!(t.z_pt.access(), point.access());
unwrap!(v_pt.write_canon(&mut point));
assert_eq!(t.v_pt.access(), point.access());
}
}
#[test]
fn test_zv_verifier() {
for t in RFC_T {
let crypto = test_only_crypto();
let m_pt = unwrap!(crypto.ec_point(Spake2P::MATTER_M_BIN));
let x = unwrap!(crypto.ec_point(t.x_pt));
let y = unwrap!(crypto.ec_scalar(t.y));
let w0 = unwrap!(crypto.ec_scalar(t.w0));
let l_pt = unwrap!(crypto.ec_point(t.l_pt));
let (z_pt, v_pt) = unwrap!(Spake2P::compute_zv_verifier(
&crypto, &w0, &l_pt, &m_pt, &x, &y
));
let mut point = EC_POINT_ZEROED;
unwrap!(z_pt.write_canon(&mut point));
assert_eq!(t.z_pt.access(), point.access());
unwrap!(v_pt.write_canon(&mut point));
assert_eq!(t.v_pt.access(), point.access());
}
}
#[test]
fn test_pbkdf2() {
const SALT: &[u8; 16] = &[
0x4, 0xa1, 0xd2, 0xc6, 0x11, 0xf0, 0xbd, 0x36, 0x78, 0x67, 0x79, 0x7b, 0xfe, 0x82,
0x36, 0x00,
];
let mut w0s_w1s = Spake2pW::new();
unwrap!(Spake2P::compute_w0s_w1s(
test_only_crypto(),
(&123456_u32.to_le_bytes()).into(),
2000,
SALT,
&mut w0s_w1s,
));
assert_eq!(
w0s_w1s.access(),
&[
0xc7, 0x89, 0x33, 0x9c, 0xc5, 0xeb, 0xbc, 0xf6, 0xdf, 0x04, 0xa9, 0x11, 0x11, 0x06,
0x4c, 0x15, 0xac, 0x5a, 0xea, 0x67, 0x69, 0x9f, 0x32, 0x62, 0xcf, 0xc6, 0xe9, 0x19,
0xe8, 0xa4, 0x0b, 0xb3, 0x42, 0xe8, 0xc6, 0x8e, 0xa9, 0x9a, 0x73, 0xe2, 0x59, 0xd1,
0x17, 0xd8, 0xed, 0xcb, 0x72, 0x8c, 0xbf, 0x3b, 0xa9, 0x88, 0x02, 0xd8, 0x45, 0x4b,
0xd0, 0x2d, 0xe5, 0xe4, 0x1c, 0xc3, 0xd7, 0x00, 0x03, 0x3c, 0x86, 0x20, 0x9a, 0x42,
0x5f, 0x55, 0x96, 0x3b, 0x9f, 0x6f, 0x79, 0xef, 0xcb, 0x37,
]
)
}
#[test]
fn test_compute_ke_ca_cb() {
let crypto = test_only_crypto();
for t in RFC_T {
let mut ke = Spake2pKe::new();
let mut ca = HmacHash::new();
let mut cb = HmacHash::new();
let mut tt_hash = HASH_ZEROED;
let mut hasher = unwrap!(crypto.hash());
unwrap!(hasher.update(&t.tt[..t.tt_len]));
unwrap!(hasher.finish(&mut tt_hash));
unwrap!(Spake2P::compute_ke_ca_cb(
&crypto,
tt_hash.reference(),
t.x_pt,
crypto.ec_point(t.y_pt).unwrap(),
&mut ke,
&mut ca,
&mut cb,
));
assert_eq!(ke.access(), t.ke.access());
assert_eq!(ca.access(), t.ca.access());
assert_eq!(cb.access(), t.cb.access());
}
}
#[test]
fn test_prover_verifier_roundtrip() {
let password: u32 = 123456;
let password_bytes = password.to_le_bytes();
let password_ref = Spake2pVerifierPasswordRef::new(&password_bytes);
let salt: [u8; 32] = [
0x4, 0xa1, 0xd2, 0xc6, 0x11, 0xf0, 0xbd, 0x36, 0x78, 0x67, 0x79, 0x7b, 0xfe, 0x82,
0x36, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc,
0xdd, 0xee, 0xff, 0x00,
];
let iterations = 2000u32;
let mut prover = Spake2P::new();
prover.local_sessid = 1;
prover.peer_sessid = 2;
let mut a_pt = CanonEcPoint::new();
let prover_ctx = unwrap!(prover.setup_prover(
test_only_crypto(),
password_ref,
&salt,
iterations,
&mut a_pt
));
let mut verifier = Spake2P::new();
verifier.local_sessid = 2;
verifier.peer_sessid = 1;
let mut verifier_data = Spake2pVerifierData {
password: Some(password_ref.into()),
verifier: Spake2pVerifierStr::new(),
salt: Spake2pVerifierSalt::new(),
salt_len: SPAKE2P_VERIFIER_SALT_LEN as u8,
count: iterations,
};
verifier_data.salt.load(Spake2pVerifierSaltRef::new(&salt));
let mut b_pt = CanonEcPoint::new();
let mut cb_from_verifier = HmacHash::new();
unwrap!(verifier.setup_verifier(
test_only_crypto(),
&verifier_data,
a_pt.reference(),
&mut b_pt,
&mut cb_from_verifier
));
let mut ca_from_prover = HmacHash::new();
unwrap!(prover.complete_prover(
test_only_crypto(),
&prover_ctx,
a_pt.reference(),
b_pt.reference(),
cb_from_verifier.reference(),
&mut ca_from_prover
));
let (_, _, v_ke) = unwrap!(verifier.verify(ca_from_prover.reference()));
assert_eq!(
prover.ke().access(),
v_ke.access(),
"Prover and verifier should derive the same Ke"
);
}
#[test]
fn test_ec_point_is_valid_pubkey() {
use crate::crypto::EcPoint;
let crypto = test_only_crypto();
let valid = unwrap!(crypto.ec_point(RFC_T[0].x_pt));
assert!(unwrap!(valid.is_valid_pubkey()));
let mut bad = EC_POINT_ZEROED;
bad.access_mut().copy_from_slice(RFC_T[0].x_pt.access());
let last = bad.access().len() - 1;
bad.access_mut()[last] ^= 0x01;
let rejected = match crypto.ec_point(bad.reference()) {
Err(_) => true,
Ok(pt) => !unwrap!(pt.is_valid_pubkey()),
};
assert!(rejected, "an off-curve point must not pass validation");
}
#[test]
fn test_setup_verifier_rejects_invalid_pa() {
let password: u32 = 123456;
let password_bytes = password.to_le_bytes();
let password_ref = Spake2pVerifierPasswordRef::new(&password_bytes);
let salt = [0x42u8; 32];
let iterations = 2000u32;
let mut verifier = Spake2P::new();
let mut verifier_data = Spake2pVerifierData {
password: Some(password_ref.into()),
verifier: Spake2pVerifierStr::new(),
salt: Spake2pVerifierSalt::new(),
salt_len: SPAKE2P_VERIFIER_SALT_LEN as u8,
count: iterations,
};
verifier_data.salt.load(Spake2pVerifierSaltRef::new(&salt));
let mut bad_a = EC_POINT_ZEROED;
bad_a.access_mut().copy_from_slice(RFC_T[0].x_pt.access());
let last = bad_a.access().len() - 1;
bad_a.access_mut()[last] ^= 0x01;
let mut b_pt = CanonEcPoint::new();
let mut cb = HmacHash::new();
let result = verifier.setup_verifier(
test_only_crypto(),
&verifier_data,
bad_a.reference(),
&mut b_pt,
&mut cb,
);
assert!(
result.is_err(),
"setup_verifier must reject an invalid prover share pA"
);
}
#[test]
fn test_complete_prover_wrong_password() {
let password: u32 = 123456;
let password_bytes = password.to_le_bytes();
let password_ref = Spake2pVerifierPasswordRef::new(&password_bytes);
let salt: [u8; 32] = [
0x4, 0xa1, 0xd2, 0xc6, 0x11, 0xf0, 0xbd, 0x36, 0x78, 0x67, 0x79, 0x7b, 0xfe, 0x82,
0x36, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc,
0xdd, 0xee, 0xff, 0x00,
];
let iterations = 2000u32;
let mut prover = Spake2P::new();
prover.local_sessid = 1;
prover.peer_sessid = 2;
let mut a_pt = CanonEcPoint::new();
let prover_ctx = unwrap!(prover.setup_prover(
test_only_crypto(),
password_ref,
&salt,
iterations,
&mut a_pt
));
let wrong_password: u32 = 999999;
let wrong_password_bytes = wrong_password.to_le_bytes();
let wrong_password_ref = Spake2pVerifierPasswordRef::new(&wrong_password_bytes);
let mut verifier = Spake2P::new();
verifier.local_sessid = 2;
verifier.peer_sessid = 1;
let mut verifier_data = Spake2pVerifierData {
password: Some(wrong_password_ref.into()),
verifier: Spake2pVerifierStr::new(),
salt: Spake2pVerifierSalt::new(),
salt_len: SPAKE2P_VERIFIER_SALT_LEN as u8,
count: iterations,
};
verifier_data.salt.load(Spake2pVerifierSaltRef::new(&salt));
let mut b_pt = CanonEcPoint::new();
let mut cb_from_verifier = HmacHash::new();
unwrap!(verifier.setup_verifier(
test_only_crypto(),
&verifier_data,
a_pt.reference(),
&mut b_pt,
&mut cb_from_verifier
));
let mut ca_from_prover = HmacHash::new();
let result = prover.complete_prover(
test_only_crypto(),
&prover_ctx,
a_pt.reference(),
b_pt.reference(),
cb_from_verifier.reference(),
&mut ca_from_prover,
);
assert!(
result.is_err(),
"complete_prover should fail with mismatched password"
);
assert_eq!(result.unwrap_err(), SCStatusCodes::InvalidParameter);
}
pub struct RFCTestVector<'a> {
pub w0: CanonEcScalarRef<'a>,
pub w1: CanonEcScalarRef<'a>,
pub x: CanonEcScalarRef<'a>,
pub y: CanonEcScalarRef<'a>,
pub x_pt: CanonEcPointRef<'a>,
pub y_pt: CanonEcPointRef<'a>,
pub z_pt: CanonEcPointRef<'a>,
pub v_pt: CanonEcPointRef<'a>,
pub l_pt: CanonEcPointRef<'a>,
pub ca: HmacHashRef<'a>,
pub cb: HmacHashRef<'a>,
pub ke: Spake2pKeRef<'a>,
pub tt: &'a [u8; 547],
pub tt_len: usize,
}
pub const RFC_T: [RFCTestVector; 4] = [
RFCTestVector {
w0: CanonEcScalarRef::new(&[
0xe6, 0x88, 0x7c, 0xf9, 0xbd, 0xfb, 0x75, 0x79, 0xc6, 0x9b, 0xf4, 0x79, 0x28, 0xa8,
0x45, 0x14, 0xb5, 0xe3, 0x55, 0xac, 0x03, 0x48, 0x63, 0xf7, 0xff, 0xaf, 0x43, 0x90,
0xe6, 0x7d, 0x79, 0x8c,
]),
w1: CanonEcScalarRef::new(&[
0x24, 0xb5, 0xae, 0x4a, 0xbd, 0xa8, 0x68, 0xec, 0x93, 0x36, 0xff, 0xc3, 0xb7, 0x8e,
0xe3, 0x1c, 0x57, 0x55, 0xbe, 0xf1, 0x75, 0x92, 0x27, 0xef, 0x53, 0x72, 0xca, 0x13,
0x9b, 0x94, 0xe5, 0x12,
]),
x: CanonEcScalarRef::new(&[
0x8b, 0x0f, 0x3f, 0x38, 0x39, 0x05, 0xcf, 0x3a, 0x3b, 0xb9, 0x55, 0xef, 0x8f, 0xb6,
0x2e, 0x24, 0x84, 0x9d, 0xd3, 0x49, 0xa0, 0x5c, 0xa7, 0x9a, 0xaf, 0xb1, 0x80, 0x41,
0xd3, 0x0c, 0xbd, 0xb6,
]),
x_pt: CanonEcPointRef::new(&[
0x04, 0xaf, 0x09, 0x98, 0x7a, 0x59, 0x3d, 0x3b, 0xac, 0x86, 0x94, 0xb1, 0x23, 0x83,
0x94, 0x22, 0xc3, 0xcc, 0x87, 0xe3, 0x7d, 0x6b, 0x41, 0xc1, 0xd6, 0x30, 0xf0, 0x00,
0xdd, 0x64, 0x98, 0x0e, 0x53, 0x7a, 0xe7, 0x04, 0xbc, 0xed, 0xe0, 0x4e, 0xa3, 0xbe,
0xc9, 0xb7, 0x47, 0x5b, 0x32, 0xfa, 0x2c, 0xa3, 0xb6, 0x84, 0xbe, 0x14, 0xd1, 0x16,
0x45, 0xe3, 0x8e, 0xa6, 0x60, 0x9e, 0xb3, 0x9e, 0x7e,
]),
y: CanonEcScalarRef::new(&[
0x2e, 0x08, 0x95, 0xb0, 0xe7, 0x63, 0xd6, 0xd5, 0xa9, 0x56, 0x44, 0x33, 0xe6, 0x4a,
0xc3, 0xca, 0xc7, 0x4f, 0xf8, 0x97, 0xf6, 0xc3, 0x44, 0x52, 0x47, 0xba, 0x1b, 0xab,
0x40, 0x08, 0x2a, 0x91,
]),
y_pt: CanonEcPointRef::new(&[
0x04, 0x41, 0x75, 0x92, 0x62, 0x0a, 0xeb, 0xf9, 0xfd, 0x20, 0x36, 0x16, 0xbb, 0xb9,
0xf1, 0x21, 0xb7, 0x30, 0xc2, 0x58, 0xb2, 0x86, 0xf8, 0x90, 0xc5, 0xf1, 0x9f, 0xea,
0x83, 0x3a, 0x9c, 0x90, 0x0c, 0xbe, 0x90, 0x57, 0xbc, 0x54, 0x9a, 0x3e, 0x19, 0x97,
0x5b, 0xe9, 0x92, 0x7f, 0x0e, 0x76, 0x14, 0xf0, 0x8d, 0x1f, 0x0a, 0x10, 0x8e, 0xed,
0xe5, 0xfd, 0x7e, 0xb5, 0x62, 0x45, 0x84, 0xa4, 0xf4,
]),
z_pt: CanonEcPointRef::new(&[
0x04, 0x71, 0xa3, 0x52, 0x82, 0xd2, 0x02, 0x6f, 0x36, 0xbf, 0x3c, 0xeb, 0x38, 0xfc,
0xf8, 0x7e, 0x31, 0x12, 0xa4, 0x45, 0x2f, 0x46, 0xe9, 0xf7, 0xb4, 0x7f, 0xd7, 0x69,
0xcf, 0xb5, 0x70, 0x14, 0x5b, 0x62, 0x58, 0x9c, 0x76, 0xb7, 0xaa, 0x1e, 0xb6, 0x08,
0x0a, 0x83, 0x2e, 0x53, 0x32, 0xc3, 0x68, 0x98, 0x42, 0x69, 0x12, 0xe2, 0x9c, 0x40,
0xef, 0x9e, 0x9c, 0x74, 0x2e, 0xee, 0x82, 0xbf, 0x30,
]),
v_pt: CanonEcPointRef::new(&[
0x04, 0x67, 0x18, 0x98, 0x1b, 0xf1, 0x5b, 0xc4, 0xdb, 0x53, 0x8f, 0xc1, 0xf1, 0xc1,
0xd0, 0x58, 0xcb, 0x0e, 0xec, 0xec, 0xf1, 0xdb, 0xe1, 0xb1, 0xea, 0x08, 0xa4, 0xe2,
0x52, 0x75, 0xd3, 0x82, 0xe8, 0x2b, 0x34, 0x8c, 0x81, 0x31, 0xd8, 0xed, 0x66, 0x9d,
0x16, 0x9c, 0x2e, 0x03, 0xa8, 0x58, 0xdb, 0x7c, 0xf6, 0xca, 0x28, 0x53, 0xa4, 0x07,
0x12, 0x51, 0xa3, 0x9f, 0xbe, 0x8c, 0xfc, 0x39, 0xbc,
]),
l_pt: CanonEcPointRef::new(&[
0x04, 0x95, 0x64, 0x5c, 0xfb, 0x74, 0xdf, 0x6e, 0x58, 0xf9, 0x74, 0x8b, 0xb8, 0x3a,
0x86, 0x62, 0x0b, 0xab, 0x7c, 0x82, 0xe1, 0x07, 0xf5, 0x7d, 0x68, 0x70, 0xda, 0x8c,
0xbc, 0xb2, 0xff, 0x9f, 0x70, 0x63, 0xa1, 0x4b, 0x64, 0x02, 0xc6, 0x2f, 0x99, 0xaf,
0xcb, 0x97, 0x06, 0xa4, 0xd1, 0xa1, 0x43, 0x27, 0x32, 0x59, 0xfe, 0x76, 0xf1, 0xc6,
0x05, 0xa3, 0x63, 0x97, 0x45, 0xa9, 0x21, 0x54, 0xb9,
]),
ca: HmacHashRef::new(&[
0xd4, 0x37, 0x6f, 0x2d, 0xa9, 0xc7, 0x22, 0x26, 0xdd, 0x15, 0x1b, 0x77, 0xc2, 0x91,
0x90, 0x71, 0x15, 0x5f, 0xc2, 0x2a, 0x20, 0x68, 0xd9, 0x0b, 0x5f, 0xaa, 0x6c, 0x78,
0xc1, 0x1e, 0x77, 0xdd,
]),
cb: HmacHashRef::new(&[
0x06, 0x60, 0xa6, 0x80, 0x66, 0x3e, 0x8c, 0x56, 0x95, 0x95, 0x6f, 0xb2, 0x2d, 0xff,
0x29, 0x8b, 0x1d, 0x07, 0xa5, 0x26, 0xcf, 0x3c, 0xc5, 0x91, 0xad, 0xfe, 0xcd, 0x1f,
0x6e, 0xf6, 0xe0, 0x2e,
]),
ke: Spake2pKeRef::new(&[
0x80, 0x1d, 0xb2, 0x97, 0x65, 0x48, 0x16, 0xeb, 0x4f, 0x02, 0x86, 0x81, 0x29, 0xb9,
0xdc, 0x89,
]),
tt: &[
0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x50, 0x41, 0x4b, 0x45, 0x32,
0x2b, 0x2d, 0x50, 0x32, 0x35, 0x36, 0x2d, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x2d,
0x48, 0x4b, 0x44, 0x46, 0x20, 0x64, 0x72, 0x61, 0x66, 0x74, 0x2d, 0x30, 0x31, 0x06,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x06,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x88, 0x6e, 0x2f, 0x97, 0xac, 0xe4,
0x6e, 0x55, 0xba, 0x9d, 0xd7, 0x24, 0x25, 0x79, 0xf2, 0x99, 0x3b, 0x64, 0xe1, 0x6e,
0xf3, 0xdc, 0xab, 0x95, 0xaf, 0xd4, 0x97, 0x33, 0x3d, 0x8f, 0xa1, 0x2f, 0x5f, 0xf3,
0x55, 0x16, 0x3e, 0x43, 0xce, 0x22, 0x4e, 0x0b, 0x0e, 0x65, 0xff, 0x02, 0xac, 0x8e,
0x5c, 0x7b, 0xe0, 0x94, 0x19, 0xc7, 0x85, 0xe0, 0xca, 0x54, 0x7d, 0x55, 0xa1, 0x2e,
0x2d, 0x20, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xd8, 0xbb, 0xd6,
0xc6, 0x39, 0xc6, 0x29, 0x37, 0xb0, 0x4d, 0x99, 0x7f, 0x38, 0xc3, 0x77, 0x07, 0x19,
0xc6, 0x29, 0xd7, 0x01, 0x4d, 0x49, 0xa2, 0x4b, 0x4f, 0x98, 0xba, 0xa1, 0x29, 0x2b,
0x49, 0x07, 0xd6, 0x0a, 0xa6, 0xbf, 0xad, 0xe4, 0x50, 0x08, 0xa6, 0x36, 0x33, 0x7f,
0x51, 0x68, 0xc6, 0x4d, 0x9b, 0xd3, 0x60, 0x34, 0x80, 0x8c, 0xd5, 0x64, 0x49, 0x0b,
0x1e, 0x65, 0x6e, 0xdb, 0xe7, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
0xaf, 0x09, 0x98, 0x7a, 0x59, 0x3d, 0x3b, 0xac, 0x86, 0x94, 0xb1, 0x23, 0x83, 0x94,
0x22, 0xc3, 0xcc, 0x87, 0xe3, 0x7d, 0x6b, 0x41, 0xc1, 0xd6, 0x30, 0xf0, 0x00, 0xdd,
0x64, 0x98, 0x0e, 0x53, 0x7a, 0xe7, 0x04, 0xbc, 0xed, 0xe0, 0x4e, 0xa3, 0xbe, 0xc9,
0xb7, 0x47, 0x5b, 0x32, 0xfa, 0x2c, 0xa3, 0xb6, 0x84, 0xbe, 0x14, 0xd1, 0x16, 0x45,
0xe3, 0x8e, 0xa6, 0x60, 0x9e, 0xb3, 0x9e, 0x7e, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x04, 0x41, 0x75, 0x92, 0x62, 0x0a, 0xeb, 0xf9, 0xfd, 0x20, 0x36, 0x16,
0xbb, 0xb9, 0xf1, 0x21, 0xb7, 0x30, 0xc2, 0x58, 0xb2, 0x86, 0xf8, 0x90, 0xc5, 0xf1,
0x9f, 0xea, 0x83, 0x3a, 0x9c, 0x90, 0x0c, 0xbe, 0x90, 0x57, 0xbc, 0x54, 0x9a, 0x3e,
0x19, 0x97, 0x5b, 0xe9, 0x92, 0x7f, 0x0e, 0x76, 0x14, 0xf0, 0x8d, 0x1f, 0x0a, 0x10,
0x8e, 0xed, 0xe5, 0xfd, 0x7e, 0xb5, 0x62, 0x45, 0x84, 0xa4, 0xf4, 0x41, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x71, 0xa3, 0x52, 0x82, 0xd2, 0x02, 0x6f, 0x36,
0xbf, 0x3c, 0xeb, 0x38, 0xfc, 0xf8, 0x7e, 0x31, 0x12, 0xa4, 0x45, 0x2f, 0x46, 0xe9,
0xf7, 0xb4, 0x7f, 0xd7, 0x69, 0xcf, 0xb5, 0x70, 0x14, 0x5b, 0x62, 0x58, 0x9c, 0x76,
0xb7, 0xaa, 0x1e, 0xb6, 0x08, 0x0a, 0x83, 0x2e, 0x53, 0x32, 0xc3, 0x68, 0x98, 0x42,
0x69, 0x12, 0xe2, 0x9c, 0x40, 0xef, 0x9e, 0x9c, 0x74, 0x2e, 0xee, 0x82, 0xbf, 0x30,
0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x67, 0x18, 0x98, 0x1b, 0xf1,
0x5b, 0xc4, 0xdb, 0x53, 0x8f, 0xc1, 0xf1, 0xc1, 0xd0, 0x58, 0xcb, 0x0e, 0xec, 0xec,
0xf1, 0xdb, 0xe1, 0xb1, 0xea, 0x08, 0xa4, 0xe2, 0x52, 0x75, 0xd3, 0x82, 0xe8, 0x2b,
0x34, 0x8c, 0x81, 0x31, 0xd8, 0xed, 0x66, 0x9d, 0x16, 0x9c, 0x2e, 0x03, 0xa8, 0x58,
0xdb, 0x7c, 0xf6, 0xca, 0x28, 0x53, 0xa4, 0x07, 0x12, 0x51, 0xa3, 0x9f, 0xbe, 0x8c,
0xfc, 0x39, 0xbc, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0x88, 0x7c,
0xf9, 0xbd, 0xfb, 0x75, 0x79, 0xc6, 0x9b, 0xf4, 0x79, 0x28, 0xa8, 0x45, 0x14, 0xb5,
0xe3, 0x55, 0xac, 0x03, 0x48, 0x63, 0xf7, 0xff, 0xaf, 0x43, 0x90, 0xe6, 0x7d, 0x79,
0x8c,
],
tt_len: 547,
},
RFCTestVector {
w0: CanonEcScalarRef::new(&[
0xe6, 0x88, 0x7c, 0xf9, 0xbd, 0xfb, 0x75, 0x79, 0xc6, 0x9b, 0xf4, 0x79, 0x28, 0xa8,
0x45, 0x14, 0xb5, 0xe3, 0x55, 0xac, 0x03, 0x48, 0x63, 0xf7, 0xff, 0xaf, 0x43, 0x90,
0xe6, 0x7d, 0x79, 0x8c,
]),
w1: CanonEcScalarRef::new(&[
0x24, 0xb5, 0xae, 0x4a, 0xbd, 0xa8, 0x68, 0xec, 0x93, 0x36, 0xff, 0xc3, 0xb7, 0x8e,
0xe3, 0x1c, 0x57, 0x55, 0xbe, 0xf1, 0x75, 0x92, 0x27, 0xef, 0x53, 0x72, 0xca, 0x13,
0x9b, 0x94, 0xe5, 0x12,
]),
x: CanonEcScalarRef::new(&[
0xec, 0x82, 0xd9, 0x25, 0x83, 0x37, 0xf6, 0x12, 0x39, 0xc9, 0xcd, 0x68, 0xe8, 0xe5,
0x32, 0xa3, 0xa6, 0xb8, 0x3d, 0x12, 0xd2, 0xb1, 0xca, 0x5d, 0x54, 0x3f, 0x44, 0xde,
0xf1, 0x7d, 0xfb, 0x8d,
]),
x_pt: CanonEcPointRef::new(&[
0x04, 0x23, 0x07, 0x79, 0x96, 0x08, 0x24, 0x07, 0x6d, 0x36, 0x66, 0xa7, 0x41, 0x8e,
0x4d, 0x43, 0x3e, 0x2f, 0xa1, 0x5b, 0x06, 0x17, 0x6e, 0xab, 0xdd, 0x57, 0x2f, 0x43,
0xa3, 0x2e, 0xcc, 0x79, 0xa1, 0x92, 0xb2, 0x43, 0xd2, 0x62, 0x43, 0x10, 0xa7, 0x35,
0x62, 0x73, 0xb8, 0x6e, 0x5f, 0xd9, 0xbd, 0x62, 0x7d, 0x3a, 0xde, 0x76, 0x2b, 0xae,
0xff, 0x1a, 0x32, 0x0d, 0x4a, 0xd7, 0xa4, 0xe4, 0x7f,
]),
y: CanonEcScalarRef::new(&[
0xea, 0xc3, 0xf7, 0xde, 0x4b, 0x19, 0x8d, 0x5f, 0xe2, 0x5c, 0x44, 0x3c, 0x0c, 0xd4,
0x96, 0x38, 0x07, 0xad, 0xd7, 0x67, 0x81, 0x5d, 0xd0, 0x2a, 0x6f, 0x01, 0x33, 0xb4,
0xbc, 0x2c, 0x9e, 0xb0,
]),
y_pt: CanonEcPointRef::new(&[
0x04, 0x45, 0x58, 0x64, 0x2e, 0x71, 0xb6, 0x16, 0xb2, 0x48, 0xc9, 0x58, 0x3b, 0xd6,
0xd7, 0xaa, 0x1b, 0x39, 0x52, 0xc6, 0xdf, 0x6a, 0x9f, 0x74, 0x92, 0xa0, 0x60, 0x35,
0xca, 0x5d, 0x92, 0x52, 0x2d, 0x84, 0x44, 0x3d, 0xe7, 0xaa, 0x20, 0xa5, 0x93, 0x80,
0xfa, 0x4d, 0xe6, 0xb7, 0x43, 0x8d, 0x92, 0x5d, 0xbf, 0xb7, 0xf1, 0xcf, 0xe6, 0x0d,
0x79, 0xac, 0xf9, 0x61, 0xee, 0x33, 0x98, 0x8c, 0x7d,
]),
z_pt: CanonEcPointRef::new(&[
0x04, 0xb4, 0xe8, 0x77, 0x0f, 0x19, 0xf5, 0x8d, 0xdf, 0x83, 0xf9, 0x22, 0x0c, 0x3a,
0x93, 0x05, 0x79, 0x26, 0x65, 0xe0, 0xc6, 0x09, 0x89, 0xe6, 0xee, 0x9d, 0x7f, 0xa4,
0x49, 0xc7, 0x75, 0xd6, 0x39, 0x5f, 0x6f, 0x25, 0xf3, 0x07, 0xe3, 0x90, 0x3a, 0xc0,
0x45, 0xa0, 0x13, 0xfb, 0xb5, 0xa6, 0x76, 0xe8, 0x72, 0xa6, 0xab, 0xfc, 0xf4, 0xd7,
0xbb, 0x5a, 0xac, 0x69, 0xef, 0xd6, 0x14, 0x0e, 0xed,
]),
v_pt: CanonEcPointRef::new(&[
0x04, 0x14, 0x1d, 0xb8, 0x3b, 0xc7, 0xd9, 0x6f, 0x41, 0xb6, 0x36, 0x62, 0x2e, 0x7a,
0x5c, 0x55, 0x2a, 0xd8, 0x32, 0x11, 0xff, 0x55, 0x31, 0x9a, 0xc2, 0x5e, 0xd0, 0xa0,
0x9f, 0x08, 0x18, 0xbd, 0x94, 0x2e, 0x81, 0x50, 0x31, 0x9b, 0xfb, 0xfa, 0x68, 0x61,
0x83, 0x80, 0x6d, 0xc6, 0x19, 0x11, 0x18, 0x3f, 0x6a, 0x0f, 0x59, 0x56, 0x15, 0x60,
0x23, 0xd9, 0x6e, 0x0f, 0x93, 0xd2, 0x75, 0xbf, 0x50,
]),
l_pt: CanonEcPointRef::new(&[
0x04, 0x95, 0x64, 0x5c, 0xfb, 0x74, 0xdf, 0x6e, 0x58, 0xf9, 0x74, 0x8b, 0xb8, 0x3a,
0x86, 0x62, 0x0b, 0xab, 0x7c, 0x82, 0xe1, 0x07, 0xf5, 0x7d, 0x68, 0x70, 0xda, 0x8c,
0xbc, 0xb2, 0xff, 0x9f, 0x70, 0x63, 0xa1, 0x4b, 0x64, 0x02, 0xc6, 0x2f, 0x99, 0xaf,
0xcb, 0x97, 0x06, 0xa4, 0xd1, 0xa1, 0x43, 0x27, 0x32, 0x59, 0xfe, 0x76, 0xf1, 0xc6,
0x05, 0xa3, 0x63, 0x97, 0x45, 0xa9, 0x21, 0x54, 0xb9,
]),
ca: HmacHashRef::new(&[
0xe1, 0xb9, 0x25, 0x88, 0x07, 0xba, 0x47, 0x50, 0xda, 0xe1, 0xd7, 0xf3, 0xc3, 0xc2,
0x94, 0xf1, 0x3d, 0xc4, 0xfa, 0x60, 0xcd, 0xe3, 0x46, 0xd5, 0xde, 0x7d, 0x20, 0x0e,
0x2f, 0x8f, 0xd3, 0xfc,
]),
cb: HmacHashRef::new(&[
0xb9, 0xc3, 0x9d, 0xfa, 0x49, 0xc4, 0x77, 0x57, 0xde, 0x77, 0x8d, 0x9b, 0xed, 0xea,
0xca, 0x24, 0x48, 0xb9, 0x05, 0xbe, 0x19, 0xa4, 0x3b, 0x94, 0xee, 0x24, 0xb7, 0x70,
0x20, 0x81, 0x35, 0xe3,
]),
ke: Spake2pKeRef::new(&[
0x69, 0x89, 0xd8, 0xf9, 0x17, 0x7e, 0xf7, 0xdf, 0x67, 0xda, 0x43, 0x79, 0x87, 0xf0,
0x72, 0x55,
]),
tt: &[
0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x50, 0x41, 0x4b, 0x45, 0x32,
0x2b, 0x2d, 0x50, 0x32, 0x35, 0x36, 0x2d, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x2d,
0x48, 0x4b, 0x44, 0x46, 0x20, 0x64, 0x72, 0x61, 0x66, 0x74, 0x2d, 0x30, 0x31, 0x06,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x04, 0x88, 0x6e, 0x2f, 0x97, 0xac, 0xe4, 0x6e, 0x55, 0xba, 0x9d, 0xd7, 0x24,
0x25, 0x79, 0xf2, 0x99, 0x3b, 0x64, 0xe1, 0x6e, 0xf3, 0xdc, 0xab, 0x95, 0xaf, 0xd4,
0x97, 0x33, 0x3d, 0x8f, 0xa1, 0x2f, 0x5f, 0xf3, 0x55, 0x16, 0x3e, 0x43, 0xce, 0x22,
0x4e, 0x0b, 0x0e, 0x65, 0xff, 0x02, 0xac, 0x8e, 0x5c, 0x7b, 0xe0, 0x94, 0x19, 0xc7,
0x85, 0xe0, 0xca, 0x54, 0x7d, 0x55, 0xa1, 0x2e, 0x2d, 0x20, 0x41, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x04, 0xd8, 0xbb, 0xd6, 0xc6, 0x39, 0xc6, 0x29, 0x37, 0xb0,
0x4d, 0x99, 0x7f, 0x38, 0xc3, 0x77, 0x07, 0x19, 0xc6, 0x29, 0xd7, 0x01, 0x4d, 0x49,
0xa2, 0x4b, 0x4f, 0x98, 0xba, 0xa1, 0x29, 0x2b, 0x49, 0x07, 0xd6, 0x0a, 0xa6, 0xbf,
0xad, 0xe4, 0x50, 0x08, 0xa6, 0x36, 0x33, 0x7f, 0x51, 0x68, 0xc6, 0x4d, 0x9b, 0xd3,
0x60, 0x34, 0x80, 0x8c, 0xd5, 0x64, 0x49, 0x0b, 0x1e, 0x65, 0x6e, 0xdb, 0xe7, 0x41,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x23, 0x07, 0x79, 0x96, 0x08, 0x24,
0x07, 0x6d, 0x36, 0x66, 0xa7, 0x41, 0x8e, 0x4d, 0x43, 0x3e, 0x2f, 0xa1, 0x5b, 0x06,
0x17, 0x6e, 0xab, 0xdd, 0x57, 0x2f, 0x43, 0xa3, 0x2e, 0xcc, 0x79, 0xa1, 0x92, 0xb2,
0x43, 0xd2, 0x62, 0x43, 0x10, 0xa7, 0x35, 0x62, 0x73, 0xb8, 0x6e, 0x5f, 0xd9, 0xbd,
0x62, 0x7d, 0x3a, 0xde, 0x76, 0x2b, 0xae, 0xff, 0x1a, 0x32, 0x0d, 0x4a, 0xd7, 0xa4,
0xe4, 0x7f, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x45, 0x58, 0x64,
0x2e, 0x71, 0xb6, 0x16, 0xb2, 0x48, 0xc9, 0x58, 0x3b, 0xd6, 0xd7, 0xaa, 0x1b, 0x39,
0x52, 0xc6, 0xdf, 0x6a, 0x9f, 0x74, 0x92, 0xa0, 0x60, 0x35, 0xca, 0x5d, 0x92, 0x52,
0x2d, 0x84, 0x44, 0x3d, 0xe7, 0xaa, 0x20, 0xa5, 0x93, 0x80, 0xfa, 0x4d, 0xe6, 0xb7,
0x43, 0x8d, 0x92, 0x5d, 0xbf, 0xb7, 0xf1, 0xcf, 0xe6, 0x0d, 0x79, 0xac, 0xf9, 0x61,
0xee, 0x33, 0x98, 0x8c, 0x7d, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
0xb4, 0xe8, 0x77, 0x0f, 0x19, 0xf5, 0x8d, 0xdf, 0x83, 0xf9, 0x22, 0x0c, 0x3a, 0x93,
0x05, 0x79, 0x26, 0x65, 0xe0, 0xc6, 0x09, 0x89, 0xe6, 0xee, 0x9d, 0x7f, 0xa4, 0x49,
0xc7, 0x75, 0xd6, 0x39, 0x5f, 0x6f, 0x25, 0xf3, 0x07, 0xe3, 0x90, 0x3a, 0xc0, 0x45,
0xa0, 0x13, 0xfb, 0xb5, 0xa6, 0x76, 0xe8, 0x72, 0xa6, 0xab, 0xfc, 0xf4, 0xd7, 0xbb,
0x5a, 0xac, 0x69, 0xef, 0xd6, 0x14, 0x0e, 0xed, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x04, 0x14, 0x1d, 0xb8, 0x3b, 0xc7, 0xd9, 0x6f, 0x41, 0xb6, 0x36, 0x62,
0x2e, 0x7a, 0x5c, 0x55, 0x2a, 0xd8, 0x32, 0x11, 0xff, 0x55, 0x31, 0x9a, 0xc2, 0x5e,
0xd0, 0xa0, 0x9f, 0x08, 0x18, 0xbd, 0x94, 0x2e, 0x81, 0x50, 0x31, 0x9b, 0xfb, 0xfa,
0x68, 0x61, 0x83, 0x80, 0x6d, 0xc6, 0x19, 0x11, 0x18, 0x3f, 0x6a, 0x0f, 0x59, 0x56,
0x15, 0x60, 0x23, 0xd9, 0x6e, 0x0f, 0x93, 0xd2, 0x75, 0xbf, 0x50, 0x20, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0x88, 0x7c, 0xf9, 0xbd, 0xfb, 0x75, 0x79, 0xc6,
0x9b, 0xf4, 0x79, 0x28, 0xa8, 0x45, 0x14, 0xb5, 0xe3, 0x55, 0xac, 0x03, 0x48, 0x63,
0xf7, 0xff, 0xaf, 0x43, 0x90, 0xe6, 0x7d, 0x79, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00,
],
tt_len: 541,
},
RFCTestVector {
w0: CanonEcScalarRef::new(&[
0xe6, 0x88, 0x7c, 0xf9, 0xbd, 0xfb, 0x75, 0x79, 0xc6, 0x9b, 0xf4, 0x79, 0x28, 0xa8,
0x45, 0x14, 0xb5, 0xe3, 0x55, 0xac, 0x03, 0x48, 0x63, 0xf7, 0xff, 0xaf, 0x43, 0x90,
0xe6, 0x7d, 0x79, 0x8c,
]),
w1: CanonEcScalarRef::new(&[
0x24, 0xb5, 0xae, 0x4a, 0xbd, 0xa8, 0x68, 0xec, 0x93, 0x36, 0xff, 0xc3, 0xb7, 0x8e,
0xe3, 0x1c, 0x57, 0x55, 0xbe, 0xf1, 0x75, 0x92, 0x27, 0xef, 0x53, 0x72, 0xca, 0x13,
0x9b, 0x94, 0xe5, 0x12,
]),
x: CanonEcScalarRef::new(&[
0xba, 0x0f, 0x0f, 0x5b, 0x78, 0xef, 0x23, 0xfd, 0x07, 0x86, 0x8e, 0x46, 0xae, 0xca,
0x63, 0xb5, 0x1f, 0xda, 0x51, 0x9a, 0x34, 0x20, 0x50, 0x1a, 0xcb, 0xe2, 0x3d, 0x53,
0xc2, 0x91, 0x87, 0x48,
]),
x_pt: CanonEcPointRef::new(&[
0x04, 0xc1, 0x4d, 0x28, 0xf4, 0x37, 0x0f, 0xea, 0x20, 0x74, 0x51, 0x06, 0xce, 0xa5,
0x8b, 0xcf, 0xb6, 0x0f, 0x29, 0x49, 0xfa, 0x4e, 0x13, 0x1b, 0x9a, 0xff, 0x5e, 0xa1,
0x3f, 0xd5, 0xaa, 0x79, 0xd5, 0x07, 0xae, 0x1d, 0x22, 0x9e, 0x44, 0x7e, 0x00, 0x0f,
0x15, 0xeb, 0x78, 0xa9, 0xa3, 0x2c, 0x2b, 0x88, 0x65, 0x2e, 0x34, 0x11, 0x64, 0x20,
0x43, 0xc1, 0xb2, 0xb7, 0x99, 0x2c, 0xf2, 0xd4, 0xde,
]),
y: CanonEcScalarRef::new(&[
0x39, 0x39, 0x7f, 0xbe, 0x6d, 0xb4, 0x7e, 0x9f, 0xbd, 0x1a, 0x26, 0x3d, 0x79, 0xf5,
0xd0, 0xaa, 0xa4, 0x4d, 0xf2, 0x6c, 0xe7, 0x55, 0xf7, 0x8e, 0x09, 0x26, 0x44, 0xb4,
0x34, 0x53, 0x3a, 0x42,
]),
y_pt: CanonEcPointRef::new(&[
0x04, 0xd1, 0xbe, 0xe3, 0x12, 0x0f, 0xd8, 0x7e, 0x86, 0xfe, 0x18, 0x9c, 0xb9, 0x52,
0xdc, 0x68, 0x88, 0x23, 0x08, 0x0e, 0x62, 0x52, 0x4d, 0xd2, 0xc0, 0x8d, 0xff, 0xe3,
0xd2, 0x2a, 0x0a, 0x89, 0x86, 0xaa, 0x64, 0xc9, 0xfe, 0x01, 0x91, 0x03, 0x3c, 0xaf,
0xbc, 0x9b, 0xca, 0xef, 0xc8, 0xe2, 0xba, 0x8b, 0xa8, 0x60, 0xcd, 0x12, 0x7a, 0xf9,
0xef, 0xdd, 0x7f, 0x1c, 0x3a, 0x41, 0x92, 0x0f, 0xe8,
]),
z_pt: CanonEcPointRef::new(&[
0x04, 0xaa, 0xc7, 0x1c, 0xf4, 0xc8, 0xdf, 0x81, 0x81, 0xb8, 0x67, 0xc9, 0xec, 0xbe,
0xe9, 0xd0, 0x96, 0x3c, 0xaf, 0x51, 0xf1, 0x53, 0x4a, 0x82, 0x34, 0x29, 0xc2, 0x6f,
0xe5, 0x24, 0x83, 0x13, 0xff, 0xc5, 0xc5, 0xe4, 0x4e, 0xa8, 0x16, 0x21, 0x61, 0xab,
0x6b, 0x3d, 0x73, 0xb8, 0x77, 0x04, 0xa4, 0x58, 0x89, 0xbf, 0x63, 0x43, 0xd9, 0x6f,
0xa9, 0x6c, 0xd1, 0x64, 0x1e, 0xfa, 0x71, 0x60, 0x7c,
]),
v_pt: CanonEcPointRef::new(&[
0x04, 0xc7, 0xc9, 0x50, 0x53, 0x65, 0xf7, 0xce, 0x57, 0x29, 0x3c, 0x92, 0xa3, 0x7f,
0x1b, 0xbd, 0xc6, 0x8e, 0x03, 0x22, 0x90, 0x1e, 0x61, 0xed, 0xef, 0x59, 0xfe, 0xe7,
0x87, 0x6b, 0x17, 0xb0, 0x63, 0xe0, 0xfa, 0x4a, 0x12, 0x6e, 0xae, 0x0a, 0x67, 0x1b,
0x37, 0xf1, 0x46, 0x4c, 0xf1, 0xcc, 0xad, 0x59, 0x1c, 0x33, 0xae, 0x94, 0x4e, 0x3b,
0x1f, 0x31, 0x8d, 0x76, 0xe3, 0x6f, 0xea, 0x99, 0x66,
]),
l_pt: CanonEcPointRef::new(&[
0x04, 0x95, 0x64, 0x5c, 0xfb, 0x74, 0xdf, 0x6e, 0x58, 0xf9, 0x74, 0x8b, 0xb8, 0x3a,
0x86, 0x62, 0x0b, 0xab, 0x7c, 0x82, 0xe1, 0x07, 0xf5, 0x7d, 0x68, 0x70, 0xda, 0x8c,
0xbc, 0xb2, 0xff, 0x9f, 0x70, 0x63, 0xa1, 0x4b, 0x64, 0x02, 0xc6, 0x2f, 0x99, 0xaf,
0xcb, 0x97, 0x06, 0xa4, 0xd1, 0xa1, 0x43, 0x27, 0x32, 0x59, 0xfe, 0x76, 0xf1, 0xc6,
0x05, 0xa3, 0x63, 0x97, 0x45, 0xa9, 0x21, 0x54, 0xb9,
]),
ca: HmacHashRef::new(&[
0xe5, 0x64, 0xc9, 0x3b, 0x30, 0x15, 0xef, 0xb9, 0x46, 0xdc, 0x16, 0xd6, 0x42, 0xbb,
0xe7, 0xd1, 0xc8, 0xda, 0x5b, 0xe1, 0x64, 0xed, 0x9f, 0xc3, 0xba, 0xe4, 0xe0, 0xff,
0x86, 0xe1, 0xbd, 0x3c,
]),
cb: HmacHashRef::new(&[
0x07, 0x2a, 0x94, 0xd9, 0xa5, 0x4e, 0xdc, 0x20, 0x1d, 0x88, 0x91, 0x53, 0x4c, 0x23,
0x17, 0xca, 0xdf, 0x3e, 0xa3, 0x79, 0x28, 0x27, 0xf4, 0x79, 0xe8, 0x73, 0xf9, 0x3e,
0x90, 0xf2, 0x15, 0x52,
]),
ke: Spake2pKeRef::new(&[
0x2e, 0xa4, 0x0e, 0x4b, 0xad, 0xfa, 0x54, 0x52, 0xb5, 0x74, 0x4d, 0xc5, 0x98, 0x3e,
0x99, 0xba,
]),
tt: &[
0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x50, 0x41, 0x4b, 0x45, 0x32,
0x2b, 0x2d, 0x50, 0x32, 0x35, 0x36, 0x2d, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x2d,
0x48, 0x4b, 0x44, 0x46, 0x20, 0x64, 0x72, 0x61, 0x66, 0x74, 0x2d, 0x30, 0x31, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x04, 0x88, 0x6e, 0x2f, 0x97, 0xac, 0xe4, 0x6e, 0x55, 0xba, 0x9d, 0xd7, 0x24,
0x25, 0x79, 0xf2, 0x99, 0x3b, 0x64, 0xe1, 0x6e, 0xf3, 0xdc, 0xab, 0x95, 0xaf, 0xd4,
0x97, 0x33, 0x3d, 0x8f, 0xa1, 0x2f, 0x5f, 0xf3, 0x55, 0x16, 0x3e, 0x43, 0xce, 0x22,
0x4e, 0x0b, 0x0e, 0x65, 0xff, 0x02, 0xac, 0x8e, 0x5c, 0x7b, 0xe0, 0x94, 0x19, 0xc7,
0x85, 0xe0, 0xca, 0x54, 0x7d, 0x55, 0xa1, 0x2e, 0x2d, 0x20, 0x41, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x04, 0xd8, 0xbb, 0xd6, 0xc6, 0x39, 0xc6, 0x29, 0x37, 0xb0,
0x4d, 0x99, 0x7f, 0x38, 0xc3, 0x77, 0x07, 0x19, 0xc6, 0x29, 0xd7, 0x01, 0x4d, 0x49,
0xa2, 0x4b, 0x4f, 0x98, 0xba, 0xa1, 0x29, 0x2b, 0x49, 0x07, 0xd6, 0x0a, 0xa6, 0xbf,
0xad, 0xe4, 0x50, 0x08, 0xa6, 0x36, 0x33, 0x7f, 0x51, 0x68, 0xc6, 0x4d, 0x9b, 0xd3,
0x60, 0x34, 0x80, 0x8c, 0xd5, 0x64, 0x49, 0x0b, 0x1e, 0x65, 0x6e, 0xdb, 0xe7, 0x41,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xc1, 0x4d, 0x28, 0xf4, 0x37, 0x0f,
0xea, 0x20, 0x74, 0x51, 0x06, 0xce, 0xa5, 0x8b, 0xcf, 0xb6, 0x0f, 0x29, 0x49, 0xfa,
0x4e, 0x13, 0x1b, 0x9a, 0xff, 0x5e, 0xa1, 0x3f, 0xd5, 0xaa, 0x79, 0xd5, 0x07, 0xae,
0x1d, 0x22, 0x9e, 0x44, 0x7e, 0x00, 0x0f, 0x15, 0xeb, 0x78, 0xa9, 0xa3, 0x2c, 0x2b,
0x88, 0x65, 0x2e, 0x34, 0x11, 0x64, 0x20, 0x43, 0xc1, 0xb2, 0xb7, 0x99, 0x2c, 0xf2,
0xd4, 0xde, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xd1, 0xbe, 0xe3,
0x12, 0x0f, 0xd8, 0x7e, 0x86, 0xfe, 0x18, 0x9c, 0xb9, 0x52, 0xdc, 0x68, 0x88, 0x23,
0x08, 0x0e, 0x62, 0x52, 0x4d, 0xd2, 0xc0, 0x8d, 0xff, 0xe3, 0xd2, 0x2a, 0x0a, 0x89,
0x86, 0xaa, 0x64, 0xc9, 0xfe, 0x01, 0x91, 0x03, 0x3c, 0xaf, 0xbc, 0x9b, 0xca, 0xef,
0xc8, 0xe2, 0xba, 0x8b, 0xa8, 0x60, 0xcd, 0x12, 0x7a, 0xf9, 0xef, 0xdd, 0x7f, 0x1c,
0x3a, 0x41, 0x92, 0x0f, 0xe8, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
0xaa, 0xc7, 0x1c, 0xf4, 0xc8, 0xdf, 0x81, 0x81, 0xb8, 0x67, 0xc9, 0xec, 0xbe, 0xe9,
0xd0, 0x96, 0x3c, 0xaf, 0x51, 0xf1, 0x53, 0x4a, 0x82, 0x34, 0x29, 0xc2, 0x6f, 0xe5,
0x24, 0x83, 0x13, 0xff, 0xc5, 0xc5, 0xe4, 0x4e, 0xa8, 0x16, 0x21, 0x61, 0xab, 0x6b,
0x3d, 0x73, 0xb8, 0x77, 0x04, 0xa4, 0x58, 0x89, 0xbf, 0x63, 0x43, 0xd9, 0x6f, 0xa9,
0x6c, 0xd1, 0x64, 0x1e, 0xfa, 0x71, 0x60, 0x7c, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x04, 0xc7, 0xc9, 0x50, 0x53, 0x65, 0xf7, 0xce, 0x57, 0x29, 0x3c, 0x92,
0xa3, 0x7f, 0x1b, 0xbd, 0xc6, 0x8e, 0x03, 0x22, 0x90, 0x1e, 0x61, 0xed, 0xef, 0x59,
0xfe, 0xe7, 0x87, 0x6b, 0x17, 0xb0, 0x63, 0xe0, 0xfa, 0x4a, 0x12, 0x6e, 0xae, 0x0a,
0x67, 0x1b, 0x37, 0xf1, 0x46, 0x4c, 0xf1, 0xcc, 0xad, 0x59, 0x1c, 0x33, 0xae, 0x94,
0x4e, 0x3b, 0x1f, 0x31, 0x8d, 0x76, 0xe3, 0x6f, 0xea, 0x99, 0x66, 0x20, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0x88, 0x7c, 0xf9, 0xbd, 0xfb, 0x75, 0x79, 0xc6,
0x9b, 0xf4, 0x79, 0x28, 0xa8, 0x45, 0x14, 0xb5, 0xe3, 0x55, 0xac, 0x03, 0x48, 0x63,
0xf7, 0xff, 0xaf, 0x43, 0x90, 0xe6, 0x7d, 0x79, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00,
],
tt_len: 541,
},
RFCTestVector {
w0: CanonEcScalarRef::new(&[
0xe6, 0x88, 0x7c, 0xf9, 0xbd, 0xfb, 0x75, 0x79, 0xc6, 0x9b, 0xf4, 0x79, 0x28, 0xa8,
0x45, 0x14, 0xb5, 0xe3, 0x55, 0xac, 0x03, 0x48, 0x63, 0xf7, 0xff, 0xaf, 0x43, 0x90,
0xe6, 0x7d, 0x79, 0x8c,
]),
w1: CanonEcScalarRef::new(&[
0x24, 0xb5, 0xae, 0x4a, 0xbd, 0xa8, 0x68, 0xec, 0x93, 0x36, 0xff, 0xc3, 0xb7, 0x8e,
0xe3, 0x1c, 0x57, 0x55, 0xbe, 0xf1, 0x75, 0x92, 0x27, 0xef, 0x53, 0x72, 0xca, 0x13,
0x9b, 0x94, 0xe5, 0x12,
]),
x: CanonEcScalarRef::new(&[
0x5b, 0x47, 0x86, 0x19, 0x80, 0x4f, 0x49, 0x38, 0xd3, 0x61, 0xfb, 0xba, 0x3a, 0x20,
0x64, 0x87, 0x25, 0x22, 0x2f, 0x0a, 0x54, 0xcc, 0x4c, 0x87, 0x61, 0x39, 0xef, 0xe7,
0xd9, 0xa2, 0x17, 0x86,
]),
x_pt: CanonEcPointRef::new(&[
0x04, 0xa6, 0xdb, 0x23, 0xd0, 0x01, 0x72, 0x3f, 0xb0, 0x1f, 0xcf, 0xc9, 0xd0, 0x87,
0x46, 0xc3, 0xc2, 0xa0, 0xa3, 0xfe, 0xff, 0x86, 0x35, 0xd2, 0x9c, 0xad, 0x28, 0x53,
0xe7, 0x35, 0x86, 0x23, 0x42, 0x5c, 0xf3, 0x97, 0x12, 0xe9, 0x28, 0x05, 0x45, 0x61,
0xba, 0x71, 0xe2, 0xdc, 0x11, 0xf3, 0x00, 0xf1, 0x76, 0x0e, 0x71, 0xeb, 0x17, 0x70,
0x21, 0xa8, 0xf8, 0x5e, 0x78, 0x68, 0x90, 0x71, 0xcd,
]),
y: CanonEcScalarRef::new(&[
0x76, 0x67, 0x70, 0xda, 0xd8, 0xc8, 0xee, 0xcb, 0xa9, 0x36, 0x82, 0x3c, 0x0a, 0xed,
0x04, 0x4b, 0x8c, 0x3c, 0x4f, 0x76, 0x55, 0xe8, 0xbe, 0xec, 0x44, 0xa1, 0x5d, 0xcb,
0xca, 0xf7, 0x8e, 0x5e,
]),
y_pt: CanonEcPointRef::new(&[
0x04, 0x39, 0x0d, 0x29, 0xbf, 0x18, 0x5c, 0x3a, 0xbf, 0x99, 0xf1, 0x50, 0xae, 0x7c,
0x13, 0x38, 0x8c, 0x82, 0xb6, 0xbe, 0x0c, 0x07, 0xb1, 0xb8, 0xd9, 0x0d, 0x26, 0x85,
0x3e, 0x84, 0x37, 0x4b, 0xbd, 0xc8, 0x2b, 0xec, 0xdb, 0x97, 0x8c, 0xa3, 0x79, 0x2f,
0x47, 0x24, 0x24, 0x10, 0x6a, 0x25, 0x78, 0x01, 0x27, 0x52, 0xc1, 0x19, 0x38, 0xfc,
0xf6, 0x0a, 0x41, 0xdf, 0x75, 0xff, 0x7c, 0xf9, 0x47,
]),
z_pt: CanonEcPointRef::new(&[
0x04, 0x0a, 0x15, 0x0d, 0x9a, 0x62, 0xf5, 0x14, 0xc9, 0xa1, 0xfe, 0xdd, 0x78, 0x2a,
0x02, 0x40, 0xa3, 0x42, 0x72, 0x10, 0x46, 0xce, 0xfb, 0x11, 0x11, 0xc3, 0xad, 0xb3,
0xbe, 0x89, 0x3c, 0xe9, 0xfc, 0xd2, 0xff, 0xa1, 0x37, 0x92, 0x2f, 0xcf, 0x8a, 0x58,
0x8d, 0x0f, 0x76, 0xba, 0x9c, 0x55, 0xc8, 0x5d, 0xa2, 0xaf, 0x3f, 0x1c, 0x78, 0x9c,
0xa1, 0x79, 0x76, 0x81, 0x03, 0x87, 0xfb, 0x1d, 0x7e,
]),
v_pt: CanonEcPointRef::new(&[
0x04, 0xf8, 0xe2, 0x47, 0xcc, 0x26, 0x3a, 0x18, 0x46, 0x27, 0x2f, 0x5a, 0x3b, 0x61,
0xb6, 0x8a, 0xa6, 0x0a, 0x5a, 0x26, 0x65, 0xd1, 0x0c, 0xd2, 0x2c, 0x89, 0xcd, 0x6b,
0xad, 0x05, 0xdc, 0x0e, 0x5e, 0x65, 0x0f, 0x21, 0xff, 0x01, 0x71, 0x86, 0xcc, 0x92,
0x65, 0x1a, 0x4c, 0xd7, 0xe6, 0x6c, 0xe8, 0x8f, 0x52, 0x92, 0x99, 0xf3, 0x40, 0xea,
0x80, 0xfb, 0x90, 0xa9, 0xba, 0xd0, 0x94, 0xe1, 0xa6,
]),
l_pt: CanonEcPointRef::new(&[
0x04, 0x95, 0x64, 0x5c, 0xfb, 0x74, 0xdf, 0x6e, 0x58, 0xf9, 0x74, 0x8b, 0xb8, 0x3a,
0x86, 0x62, 0x0b, 0xab, 0x7c, 0x82, 0xe1, 0x07, 0xf5, 0x7d, 0x68, 0x70, 0xda, 0x8c,
0xbc, 0xb2, 0xff, 0x9f, 0x70, 0x63, 0xa1, 0x4b, 0x64, 0x02, 0xc6, 0x2f, 0x99, 0xaf,
0xcb, 0x97, 0x06, 0xa4, 0xd1, 0xa1, 0x43, 0x27, 0x32, 0x59, 0xfe, 0x76, 0xf1, 0xc6,
0x05, 0xa3, 0x63, 0x97, 0x45, 0xa9, 0x21, 0x54, 0xb9,
]),
ca: HmacHashRef::new(&[
0x71, 0xd9, 0x41, 0x27, 0x79, 0xb6, 0xc4, 0x5a, 0x2c, 0x61, 0x5c, 0x9d, 0xf3, 0xf1,
0xfd, 0x93, 0xdc, 0x0a, 0xaf, 0x63, 0x10, 0x4d, 0xa8, 0xec, 0xe4, 0xaa, 0x1b, 0x5a,
0x3a, 0x41, 0x5f, 0xea,
]),
cb: HmacHashRef::new(&[
0x09, 0x5d, 0xc0, 0x40, 0x03, 0x55, 0xcc, 0x23, 0x3f, 0xde, 0x74, 0x37, 0x81, 0x18,
0x15, 0xb3, 0xc1, 0x52, 0x4a, 0xae, 0x80, 0xfd, 0x4e, 0x68, 0x10, 0xcf, 0x53, 0x1c,
0xf1, 0x1d, 0x20, 0xe3,
]),
ke: Spake2pKeRef::new(&[
0xea, 0x32, 0x76, 0xd6, 0x83, 0x34, 0x57, 0x60, 0x97, 0xe0, 0x4b, 0x19, 0xee, 0x5a,
0x3a, 0x8b,
]),
tt: &[
0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x50, 0x41, 0x4b, 0x45, 0x32,
0x2b, 0x2d, 0x50, 0x32, 0x35, 0x36, 0x2d, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x2d,
0x48, 0x4b, 0x44, 0x46, 0x20, 0x64, 0x72, 0x61, 0x66, 0x74, 0x2d, 0x30, 0x31, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x88, 0x6e, 0x2f, 0x97,
0xac, 0xe4, 0x6e, 0x55, 0xba, 0x9d, 0xd7, 0x24, 0x25, 0x79, 0xf2, 0x99, 0x3b, 0x64,
0xe1, 0x6e, 0xf3, 0xdc, 0xab, 0x95, 0xaf, 0xd4, 0x97, 0x33, 0x3d, 0x8f, 0xa1, 0x2f,
0x5f, 0xf3, 0x55, 0x16, 0x3e, 0x43, 0xce, 0x22, 0x4e, 0x0b, 0x0e, 0x65, 0xff, 0x02,
0xac, 0x8e, 0x5c, 0x7b, 0xe0, 0x94, 0x19, 0xc7, 0x85, 0xe0, 0xca, 0x54, 0x7d, 0x55,
0xa1, 0x2e, 0x2d, 0x20, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xd8,
0xbb, 0xd6, 0xc6, 0x39, 0xc6, 0x29, 0x37, 0xb0, 0x4d, 0x99, 0x7f, 0x38, 0xc3, 0x77,
0x07, 0x19, 0xc6, 0x29, 0xd7, 0x01, 0x4d, 0x49, 0xa2, 0x4b, 0x4f, 0x98, 0xba, 0xa1,
0x29, 0x2b, 0x49, 0x07, 0xd6, 0x0a, 0xa6, 0xbf, 0xad, 0xe4, 0x50, 0x08, 0xa6, 0x36,
0x33, 0x7f, 0x51, 0x68, 0xc6, 0x4d, 0x9b, 0xd3, 0x60, 0x34, 0x80, 0x8c, 0xd5, 0x64,
0x49, 0x0b, 0x1e, 0x65, 0x6e, 0xdb, 0xe7, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x04, 0xa6, 0xdb, 0x23, 0xd0, 0x01, 0x72, 0x3f, 0xb0, 0x1f, 0xcf, 0xc9, 0xd0,
0x87, 0x46, 0xc3, 0xc2, 0xa0, 0xa3, 0xfe, 0xff, 0x86, 0x35, 0xd2, 0x9c, 0xad, 0x28,
0x53, 0xe7, 0x35, 0x86, 0x23, 0x42, 0x5c, 0xf3, 0x97, 0x12, 0xe9, 0x28, 0x05, 0x45,
0x61, 0xba, 0x71, 0xe2, 0xdc, 0x11, 0xf3, 0x00, 0xf1, 0x76, 0x0e, 0x71, 0xeb, 0x17,
0x70, 0x21, 0xa8, 0xf8, 0x5e, 0x78, 0x68, 0x90, 0x71, 0xcd, 0x41, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x04, 0x39, 0x0d, 0x29, 0xbf, 0x18, 0x5c, 0x3a, 0xbf, 0x99,
0xf1, 0x50, 0xae, 0x7c, 0x13, 0x38, 0x8c, 0x82, 0xb6, 0xbe, 0x0c, 0x07, 0xb1, 0xb8,
0xd9, 0x0d, 0x26, 0x85, 0x3e, 0x84, 0x37, 0x4b, 0xbd, 0xc8, 0x2b, 0xec, 0xdb, 0x97,
0x8c, 0xa3, 0x79, 0x2f, 0x47, 0x24, 0x24, 0x10, 0x6a, 0x25, 0x78, 0x01, 0x27, 0x52,
0xc1, 0x19, 0x38, 0xfc, 0xf6, 0x0a, 0x41, 0xdf, 0x75, 0xff, 0x7c, 0xf9, 0x47, 0x41,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x0a, 0x15, 0x0d, 0x9a, 0x62, 0xf5,
0x14, 0xc9, 0xa1, 0xfe, 0xdd, 0x78, 0x2a, 0x02, 0x40, 0xa3, 0x42, 0x72, 0x10, 0x46,
0xce, 0xfb, 0x11, 0x11, 0xc3, 0xad, 0xb3, 0xbe, 0x89, 0x3c, 0xe9, 0xfc, 0xd2, 0xff,
0xa1, 0x37, 0x92, 0x2f, 0xcf, 0x8a, 0x58, 0x8d, 0x0f, 0x76, 0xba, 0x9c, 0x55, 0xc8,
0x5d, 0xa2, 0xaf, 0x3f, 0x1c, 0x78, 0x9c, 0xa1, 0x79, 0x76, 0x81, 0x03, 0x87, 0xfb,
0x1d, 0x7e, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xf8, 0xe2, 0x47,
0xcc, 0x26, 0x3a, 0x18, 0x46, 0x27, 0x2f, 0x5a, 0x3b, 0x61, 0xb6, 0x8a, 0xa6, 0x0a,
0x5a, 0x26, 0x65, 0xd1, 0x0c, 0xd2, 0x2c, 0x89, 0xcd, 0x6b, 0xad, 0x05, 0xdc, 0x0e,
0x5e, 0x65, 0x0f, 0x21, 0xff, 0x01, 0x71, 0x86, 0xcc, 0x92, 0x65, 0x1a, 0x4c, 0xd7,
0xe6, 0x6c, 0xe8, 0x8f, 0x52, 0x92, 0x99, 0xf3, 0x40, 0xea, 0x80, 0xfb, 0x90, 0xa9,
0xba, 0xd0, 0x94, 0xe1, 0xa6, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6,
0x88, 0x7c, 0xf9, 0xbd, 0xfb, 0x75, 0x79, 0xc6, 0x9b, 0xf4, 0x79, 0x28, 0xa8, 0x45,
0x14, 0xb5, 0xe3, 0x55, 0xac, 0x03, 0x48, 0x63, 0xf7, 0xff, 0xaf, 0x43, 0x90, 0xe6,
0x7d, 0x79, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00,
],
tt_len: 535,
},
];
}