diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0a3cde0e..4d799e5b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -4,7 +4,7 @@ on: branches: - master pull_request: - types: [opened, repoened, synchronize] + types: [opened, reopened, synchronize] jobs: test: @@ -17,7 +17,7 @@ jobs: - u32_backend toolchain: - stable - - 1.51.0 + - 1.65 name: test steps: - name: Checkout sources @@ -87,7 +87,7 @@ jobs: matrix: toolchain: - stable - - 1.51.0 + - 1.65 name: test simple_login command-line example steps: - name: install expect @@ -111,7 +111,7 @@ jobs: matrix: toolchain: - stable - - 1.51.0 + - 1.65 name: test digital_locker command-line example steps: - name: install expect diff --git a/Cargo.toml b/Cargo.toml index 4c498239..68388a18 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,23 +1,23 @@ [package] -name = "opaque-ke" -version = "1.2.0" -repository = "https://github.com/novifinancial/opaque-ke" -keywords = ["cryptography", "crypto", "opaque", "passwords", "authentication"] +authors = ["Kevin Lewi ", "François Garillot "] categories = ["no-std"] description = "An implementation of the OPAQUE password-authenticated key exchange protocol" -authors = ["Kevin Lewi ", "François Garillot "] +edition = "2021" +keywords = ["cryptography", "crypto", "opaque", "passwords", "authentication"] license = "MIT" -edition = "2018" +name = "opaque-ke" readme = "README.md" -resolver = "2" +repository = "https://github.com/novifinancial/opaque-ke" +rust-version = "1.65" +version = "1.2.0" [features] +bench = [] default = ["u64_backend"] slow-hash = ["scrypt"] std = ["curve25519-dalek/std", "getrandom", "rand/std", "rand/std_rng"] -bench = [] -u64_backend = ["curve25519-dalek/u64_backend"] u32_backend = ["curve25519-dalek/u32_backend"] +u64_backend = ["curve25519-dalek/u64_backend"] [dependencies] constant_time_eq = "0.1" @@ -44,12 +44,12 @@ criterion = "0.3" hex = "0.4" lazy_static = "1" opaque-ke = { path = "", default-features = false, features = ["std"] } -serde_json = "1" -sha2 = "0.9" proptest = "1" rustyline = "8" +serde_json = "1" +sha2 = "0.9" [[bench]] -name = "oprf" harness = false +name = "oprf" required-features = ["bench"] diff --git a/README.md b/README.md index b0f5be9d..03160ab1 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ opaque-ke = "1" ### Minimum Supported Rust Version -Rust **1.51** or higher. +Rust **1.65** or higher. Resources --------- diff --git a/examples/digital_locker.rs b/examples/digital_locker.rs index 4a2fe4f1..3fc94188 100644 --- a/examples/digital_locker.rs +++ b/examples/digital_locker.rs @@ -155,7 +155,7 @@ fn open_locker( let server_login_start_result = ServerLogin::start( &mut server_rng, password_file, - &server_kp.private(), + server_kp.private(), CredentialRequest::deserialize(&credential_request_bytes[..]).unwrap(), ServerLoginStartParameters::default(), ) diff --git a/examples/simple_login.rs b/examples/simple_login.rs index b291e02a..c12d64e7 100644 --- a/examples/simple_login.rs +++ b/examples/simple_login.rs @@ -108,7 +108,7 @@ fn account_login( let server_login_start_result = ServerLogin::start( &mut server_rng, password_file, - &server_kp.private(), + server_kp.private(), CredentialRequest::deserialize(&credential_request_bytes[..]).unwrap(), ServerLoginStartParameters::default(), ) diff --git a/src/key_exchange/tripledh.rs b/src/key_exchange/tripledh.rs index 58495215..28675268 100644 --- a/src/key_exchange/tripledh.rs +++ b/src/key_exchange/tripledh.rs @@ -89,12 +89,12 @@ impl KeyExchange for TripleDH { let mut transcript_hasher = D::new() .chain(STR_3DH) - .chain(&serialize(&id_u, 2)?) + .chain(serialize(&id_u, 2)?) .chain(&serialized_credential_request[..]) - .chain(&serialize(&id_s, 2)?) + .chain(serialize(&id_s, 2)?) .chain(&l2_bytes[..]) .chain(&server_nonce[..]) - .chain(&server_e_kp.public().to_arr()); + .chain(server_e_kp.public().to_arr()); let (session_key, km2, ke2, km3) = derive_3dh_keys::( TripleDHComponents { @@ -157,11 +157,11 @@ impl KeyExchange for TripleDH { ) -> Result<(Vec, Vec, Self::KE3Message), ProtocolError> { let mut transcript_hasher = D::new() .chain(STR_3DH) - .chain(&serialize(&id_u, 2)?) - .chain(&serialized_credential_request) - .chain(&serialize(&id_s, 2)?) + .chain(serialize(&id_u, 2)?) + .chain(serialized_credential_request) + .chain(serialize(&id_s, 2)?) .chain(&l2_component[..]) - .chain(&ke2_message.to_bytes_without_info_or_mac()); + .chain(ke2_message.to_bytes_without_info_or_mac()); let (session_key, km2, ke2, km3) = derive_3dh_keys::( TripleDHComponents { @@ -187,7 +187,7 @@ impl KeyExchange for TripleDH { )); } - transcript_hasher.update(ke2_message.mac.to_vec()); + transcript_hasher.update(&ke2_message.mac); let mut client_mac = Hmac::::new_from_slice(&km3).map_err(|_| InternalPakeError::HmacError)?; diff --git a/src/lib.rs b/src/lib.rs index a04a725c..f21b8f20 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -759,6 +759,7 @@ mod tests; // Exports +pub use curve25519_dalek; pub use rand; pub use crate::messages::{ diff --git a/src/opaque.rs b/src/opaque.rs index ebd38b3c..e369d7e3 100644 --- a/src/opaque.rs +++ b/src/opaque.rs @@ -41,7 +41,7 @@ impl ClientRegistration { /// Serialization into bytes pub fn serialize(&self) -> Vec { let output: Vec = [ - &self.alpha.to_arr().to_vec(), + &self.alpha.to_arr(), &CS::Group::scalar_as_bytes(&self.token.blind)[..], &self.token.data, ] @@ -217,7 +217,7 @@ impl ClientRegistration { let (envelope, export_key) = Envelope::::seal( rng, &password_derived_key, - &client_static_keypair.private().to_arr().to_vec(), + &client_static_keypair.private().to_arr(), &r2.server_s_pk, optional_ids, )?; diff --git a/src/oprf.rs b/src/oprf.rs index 3b6522d2..8b1ecb89 100644 --- a/src/oprf.rs +++ b/src/oprf.rs @@ -67,7 +67,7 @@ fn finalize_after_unblind( let finalize_dst = [STR_VOPRF_FINALIZE, &G::get_context_string(MODE_BASE)?].concat(); let hash_input = [ serialize(input, 2)?, - serialize(&unblinded_element.to_arr().to_vec(), 2)?, + serialize(&unblinded_element.to_arr(), 2)?, serialize(&finalize_dst, 2)?, ] .concat(); @@ -130,7 +130,7 @@ mod tests { RistrettoPoint::from_scalar_slice(GenericArray::from_slice(&oprf_key[..])).unwrap(); let res = point * scalar; - finalize_after_unblind::(&input, res).unwrap() + finalize_after_unblind::(input, res).unwrap() } #[test] @@ -146,7 +146,7 @@ mod tests { let beta = evaluate::(alpha, &oprf_key); let res = finalize::(&token.data, &token.blind, beta).unwrap(); - let res2 = prf(&input[..], &oprf_key.as_bytes()); + let res2 = prf(&input[..], oprf_key.as_bytes()); assert_eq!(res, res2); } diff --git a/src/serialization/mod.rs b/src/serialization/mod.rs index 035059dc..5769e982 100644 --- a/src/serialization/mod.rs +++ b/src/serialization/mod.rs @@ -16,7 +16,7 @@ pub(crate) fn i2osp(input: usize, length: usize) -> Result, PakeError> { } if length <= sizeof_usize { - return Ok((&input.to_be_bytes()[sizeof_usize - length..]).to_vec()); + return Ok(input.to_be_bytes()[sizeof_usize - length..].to_vec()); } let mut output = alloc::vec![0u8; length]; diff --git a/src/serialization/tests.rs b/src/serialization/tests.rs index 0477420e..076e8823 100644 --- a/src/serialization/tests.rs +++ b/src/serialization/tests.rs @@ -136,7 +136,7 @@ fn registration_response_roundtrip() { let mut input = Vec::new(); input.extend_from_slice(beta_bytes.as_slice()); - input.extend_from_slice(&pubkey_bytes.as_slice()); + input.extend_from_slice(pubkey_bytes.as_slice()); let r2 = RegistrationResponse::::deserialize(input.as_slice()).unwrap(); let r2_bytes = r2.serialize(); @@ -200,7 +200,7 @@ fn credential_request_roundtrip() { let ke1m: Vec = [ &client_nonce[..], - &serialize(&info.to_vec(), 2).unwrap(), + &serialize(info.as_ref(), 2).unwrap(), &client_e_kp.public(), ] .concat(); @@ -261,7 +261,7 @@ fn credential_response_roundtrip() { let ke2m: Vec = [ &server_nonce[..], &server_e_kp.public(), - &serialize(&e_info.to_vec(), 2).unwrap(), + &serialize(e_info.as_ref(), 2).unwrap(), &mac[..], ] .concat(); @@ -270,7 +270,7 @@ fn credential_response_roundtrip() { let mut input = Vec::new(); input.extend_from_slice(pt_bytes.as_slice()); - input.extend_from_slice(&pubkey_bytes.as_slice()); + input.extend_from_slice(pubkey_bytes.as_slice()); input.extend_from_slice(&serialized_envelope); input.extend_from_slice(&ke2m[..]); @@ -348,7 +348,7 @@ fn ke1_message_roundtrip() { let ke1m: Vec = [ &client_nonce[..], - &serialize(&info.to_vec(), 2).unwrap(), + &serialize(info.as_ref(), 2).unwrap(), &client_e_kp.public(), ] .concat(); @@ -374,7 +374,7 @@ fn ke2_message_roundtrip() { let ke2m: Vec = [ &server_nonce[..], &server_e_kp.public(), - &serialize(&e_info.to_vec(), 2).unwrap(), + &serialize(e_info.as_ref(), 2).unwrap(), &mac[..], ] .concat(); @@ -410,52 +410,52 @@ fn test_i2osp_os2ip(bytes in vec(any::(), 0..core::mem::size_of::())) #[test] fn test_nocrash_registration_request(bytes in vec(any::(), 0..200)) { - RegistrationRequest::::deserialize(&bytes[..]).map_or(true, |_| true); + let _ =RegistrationRequest::::deserialize(&bytes[..]).map_or(true, |_| true); } #[test] fn test_nocrash_registration_response(bytes in vec(any::(), 0..200)) { - RegistrationResponse::::deserialize(&bytes[..]).map_or(true, |_| true); + let _ =RegistrationResponse::::deserialize(&bytes[..]).map_or(true, |_| true); } #[test] fn test_nocrash_registration_upload(bytes in vec(any::(), 0..200)) { - RegistrationUpload::::deserialize(&bytes[..]).map_or(true, |_| true); + let _ =RegistrationUpload::::deserialize(&bytes[..]).map_or(true, |_| true); } #[test] fn test_nocrash_credential_request(bytes in vec(any::(), 0..500)) { - CredentialRequest::::deserialize(&bytes[..]).map_or(true, |_| true); + let _ =CredentialRequest::::deserialize(&bytes[..]).map_or(true, |_| true); } #[test] fn test_nocrash_credential_response(bytes in vec(any::(), 0..500)) { - CredentialResponse::::deserialize(&bytes[..]).map_or(true, |_| true); + let _ =CredentialResponse::::deserialize(&bytes[..]).map_or(true, |_| true); } #[test] fn test_nocrash_credential_finalization(bytes in vec(any::(), 0..500)) { - CredentialFinalization::::deserialize(&bytes[..]).map_or(true, |_| true); + let _ =CredentialFinalization::::deserialize(&bytes[..]).map_or(true, |_| true); } #[test] fn test_nocrash_client_registration(bytes in vec(any::(), 0..700)) { - ClientRegistration::::deserialize(&bytes[..]).map_or(true, |_| true); + let _ =ClientRegistration::::deserialize(&bytes[..]).map_or(true, |_| true); } #[test] fn test_nocrash_server_registration(bytes in vec(any::(), 0..700)) { - ServerRegistration::::deserialize(&bytes[..]).map_or(true, |_| true); + let _ =ServerRegistration::::deserialize(&bytes[..]).map_or(true, |_| true); } #[test] fn test_nocrash_client_login(bytes in vec(any::(), 0..700)) { - ClientLogin::::deserialize(&bytes[..]).map_or(true, |_| true); + let _ =ClientLogin::::deserialize(&bytes[..]).map_or(true, |_| true); } #[test] fn test_nocrash_server_login(bytes in vec(any::(), 0..700)) { - ServerLogin::::deserialize(&bytes[..]).map_or(true, |_| true); + let _ =ServerLogin::::deserialize(&bytes[..]).map_or(true, |_| true); } } diff --git a/src/tests/full_test.rs b/src/tests/full_test.rs index 8b68035f..d0db8357 100644 --- a/src/tests/full_test.rs +++ b/src/tests/full_test.rs @@ -19,7 +19,6 @@ use generic_array::typenum::Unsigned; #[cfg(feature = "std")] use rand::RngCore; -use alloc::string::ToString; use alloc::vec; use alloc::vec::Vec; use core::slice::from_raw_parts; @@ -112,44 +111,42 @@ static TEST_VECTOR: &str = r#" "#; fn decode(values: &Value, key: &str) -> Option> { - values[key] - .as_str() - .and_then(|s| hex::decode(&s.to_string()).ok()) + values[key].as_str().and_then(|s| hex::decode(s).ok()) } fn populate_test_vectors(values: &Value) -> TestVectorParameters { TestVectorParameters { - client_s_pk: decode(&values, "client_s_pk").unwrap(), - client_s_sk: decode(&values, "client_s_sk").unwrap(), - client_e_pk: decode(&values, "client_e_pk").unwrap(), - client_e_sk: decode(&values, "client_e_sk").unwrap(), - server_s_pk: decode(&values, "server_s_pk").unwrap(), - server_s_sk: decode(&values, "server_s_sk").unwrap(), - server_e_pk: decode(&values, "server_e_pk").unwrap(), - server_e_sk: decode(&values, "server_e_sk").unwrap(), - id_u: decode(&values, "id_u").unwrap(), - id_s: decode(&values, "id_s").unwrap(), - password: decode(&values, "password").unwrap(), - blinding_factor: decode(&values, "blinding_factor").unwrap(), - oprf_key: decode(&values, "oprf_key").unwrap(), - envelope_nonce: decode(&values, "envelope_nonce").unwrap(), - client_nonce: decode(&values, "client_nonce").unwrap(), - server_nonce: decode(&values, "server_nonce").unwrap(), - info1: decode(&values, "info1").unwrap(), - einfo2: decode(&values, "einfo2").unwrap(), - registration_request: decode(&values, "registration_request").unwrap(), - registration_response: decode(&values, "registration_response").unwrap(), - registration_upload: decode(&values, "registration_upload").unwrap(), - credential_request: decode(&values, "credential_request").unwrap(), - credential_response: decode(&values, "credential_response").unwrap(), - credential_finalization: decode(&values, "credential_finalization").unwrap(), - client_registration_state: decode(&values, "client_registration_state").unwrap(), - client_login_state: decode(&values, "client_login_state").unwrap(), - server_registration_state: decode(&values, "server_registration_state").unwrap(), - server_login_state: decode(&values, "server_login_state").unwrap(), - password_file: decode(&values, "password_file").unwrap(), - export_key: decode(&values, "export_key").unwrap(), - session_key: decode(&values, "session_key").unwrap(), + client_s_pk: decode(values, "client_s_pk").unwrap(), + client_s_sk: decode(values, "client_s_sk").unwrap(), + client_e_pk: decode(values, "client_e_pk").unwrap(), + client_e_sk: decode(values, "client_e_sk").unwrap(), + server_s_pk: decode(values, "server_s_pk").unwrap(), + server_s_sk: decode(values, "server_s_sk").unwrap(), + server_e_pk: decode(values, "server_e_pk").unwrap(), + server_e_sk: decode(values, "server_e_sk").unwrap(), + id_u: decode(values, "id_u").unwrap(), + id_s: decode(values, "id_s").unwrap(), + password: decode(values, "password").unwrap(), + blinding_factor: decode(values, "blinding_factor").unwrap(), + oprf_key: decode(values, "oprf_key").unwrap(), + envelope_nonce: decode(values, "envelope_nonce").unwrap(), + client_nonce: decode(values, "client_nonce").unwrap(), + server_nonce: decode(values, "server_nonce").unwrap(), + info1: decode(values, "info1").unwrap(), + einfo2: decode(values, "einfo2").unwrap(), + registration_request: decode(values, "registration_request").unwrap(), + registration_response: decode(values, "registration_response").unwrap(), + registration_upload: decode(values, "registration_upload").unwrap(), + credential_request: decode(values, "credential_request").unwrap(), + credential_response: decode(values, "credential_response").unwrap(), + credential_finalization: decode(values, "credential_finalization").unwrap(), + client_registration_state: decode(values, "client_registration_state").unwrap(), + client_login_state: decode(values, "client_login_state").unwrap(), + server_registration_state: decode(values, "server_registration_state").unwrap(), + server_login_state: decode(values, "server_login_state").unwrap(), + password_file: decode(values, "password_file").unwrap(), + export_key: decode(values, "export_key").unwrap(), + session_key: decode(values, "session_key").unwrap(), } } @@ -516,7 +513,7 @@ fn test_registration_upload() -> Result<(), ProtocolError> { ); assert_eq!( hex::encode(parameters.export_key), - hex::encode(result.export_key.to_vec()) + hex::encode(result.export_key) ); Ok(()) @@ -621,7 +618,7 @@ fn test_credential_finalization() -> Result<(), ProtocolError> { ); assert_eq!( hex::encode(¶meters.server_s_pk), - hex::encode(&client_login_finish_result.server_s_pk.to_arr().to_vec()) + hex::encode(client_login_finish_result.server_s_pk.to_arr()) ); assert_eq!( hex::encode(¶meters.session_key), @@ -652,7 +649,7 @@ fn test_server_login_finish() -> Result<(), ProtocolError> { assert_eq!( hex::encode(parameters.session_key), - hex::encode(&server_login_result.session_key) + hex::encode(server_login_result.session_key) ); Ok(()) @@ -692,7 +689,7 @@ fn test_complete_flow( let server_login_start_result = ServerLogin::::start( &mut server_rng, p_file, - &server_kp.private(), + server_kp.private(), client_login_start_result.message, ServerLoginStartParameters::default(), )?; @@ -709,7 +706,7 @@ fn test_complete_flow( .finish(client_login_finish_result.message)?; assert_eq!( - hex::encode(&server_login_finish_result.session_key), + hex::encode(server_login_finish_result.session_key), hex::encode(&client_login_finish_result.session_key) ); assert_eq!( @@ -912,7 +909,7 @@ fn test_zeroize_server_login_start() -> Result<(), ProtocolError> { let server_login_start_result = ServerLogin::::start( &mut server_rng, p_file, - &server_kp.private(), + server_kp.private(), client_login_start_result.message, ServerLoginStartParameters::default(), )?; @@ -961,7 +958,7 @@ fn test_zeroize_client_login_finish() -> Result<(), ProtocolError> { let server_login_start_result = ServerLogin::::start( &mut server_rng, p_file, - &server_kp.private(), + server_kp.private(), client_login_start_result.message, ServerLoginStartParameters::default(), )?; @@ -1014,7 +1011,7 @@ fn test_zeroize_server_login_finish() -> Result<(), ProtocolError> { let server_login_start_result = ServerLogin::::start( &mut server_rng, p_file, - &server_kp.private(), + server_kp.private(), client_login_start_result.message, ServerLoginStartParameters::default(), )?; @@ -1125,14 +1122,14 @@ fn test_reflected_value_error_login() -> Result<(), ProtocolError> { let server_login_start_result = ServerLogin::::start( &mut server_rng, p_file, - &server_kp.private(), + server_kp.private(), client_login_start_result.message, ServerLoginStartParameters::default(), )?; let reflected_credential_response = server_login_start_result .message - .set_beta_for_testing(alpha.clone()); + .set_beta_for_testing(alpha); let client_login_result = client_login_start_result.state.finish( reflected_credential_response, diff --git a/src/tests/mock_rng.rs b/src/tests/mock_rng.rs index 1d10828e..ff740088 100644 --- a/src/tests/mock_rng.rs +++ b/src/tests/mock_rng.rs @@ -49,7 +49,7 @@ impl RngCore for CycleRng { #[inline] fn fill_bytes(&mut self, dest: &mut [u8]) { let len = min(self.v.len(), dest.len()); - (&mut dest[..len]).copy_from_slice(&self.v[..len]); + dest[..len].copy_from_slice(&self.v[..len]); rotate_left(&mut self.v, len); } diff --git a/src/tests/opaque_test_vectors.rs b/src/tests/opaque_test_vectors.rs index 3fb3ea3c..8d16478d 100644 --- a/src/tests/opaque_test_vectors.rs +++ b/src/tests/opaque_test_vectors.rs @@ -283,20 +283,20 @@ fn rfc_to_json(input: &str) -> String { let mut json = vec![]; for line in input.lines() { // If line contains colon, then - if line.contains(":") { - if json.len() > 0 { + if line.contains(':') { + if !json.is_empty() { // Adding closing quote for previous line, comma, and newline json.push("\",\n".to_string()); } - let mut iter = line.split(":"); + let mut iter = line.split(':'); let key = iter.next().unwrap().split_whitespace().next().unwrap(); let val = iter.next().unwrap().split_whitespace().next().unwrap(); json.push(format!(" \"{}\": \"{}", key, val)); } else { let s = line.trim().to_string(); - if s.len() > 0 { + if !s.is_empty() { json.push(s); } } @@ -306,9 +306,7 @@ fn rfc_to_json(input: &str) -> String { } fn decode(values: &Value, key: &str) -> Option> { - values[key] - .as_str() - .and_then(|s| hex::decode(&s.to_string()).ok()) + values[key].as_str().and_then(|s| hex::decode(s).ok()) } fn populate_test_vectors(values: &Value) -> TestVectorParameters { @@ -431,7 +429,7 @@ fn test_registration_upload() -> Result<(), ProtocolError> { ); assert_eq!( hex::encode(parameters.export_key), - hex::encode(result.export_key.to_vec()) + hex::encode(result.export_key) ); } diff --git a/src/tests/voprf_test_vectors.rs b/src/tests/voprf_test_vectors.rs index e608d435..60ca8a25 100644 --- a/src/tests/voprf_test_vectors.rs +++ b/src/tests/voprf_test_vectors.rs @@ -5,7 +5,6 @@ use crate::tests::mock_rng::CycleRng; use crate::{errors::*, group::Group, oprf}; -use alloc::string::ToString; use alloc::vec::Vec; use curve25519_dalek::ristretto::RistrettoPoint; use generic_array::GenericArray; @@ -23,7 +22,7 @@ struct VOPRFTestVectorParameters { // Taken from https://github.com/cfrg/draft-irtf-cfrg-voprf/blob/master/draft-irtf-cfrg-voprf.md // in base mode -static OPRF_RISTRETTO255_SHA512: &'static [&str] = &[ +static OPRF_RISTRETTO255_SHA512: &[&str] = &[ r#" { "sksm": "758cbac0e1eb4265d80f6e6489d9a74d788f7ddeda67d7fb3c08b08f44bda30a", @@ -47,19 +46,17 @@ static OPRF_RISTRETTO255_SHA512: &'static [&str] = &[ ]; fn decode(values: &Value, key: &str) -> Option> { - values[key] - .as_str() - .and_then(|s| hex::decode(&s.to_string()).ok()) + values[key].as_str().and_then(|s| hex::decode(s).ok()) } fn populate_test_vectors(values: &Value) -> VOPRFTestVectorParameters { VOPRFTestVectorParameters { - sksm: decode(&values, "sksm").unwrap(), - input: decode(&values, "input").unwrap(), - blind: decode(&values, "blind").unwrap(), - blinded_element: decode(&values, "blinded_element").unwrap(), - evaluation_element: decode(&values, "evaluation_element").unwrap(), - output: decode(&values, "output").unwrap(), + sksm: decode(values, "sksm").unwrap(), + input: decode(values, "input").unwrap(), + blind: decode(values, "blind").unwrap(), + blinded_element: decode(values, "blinded_element").unwrap(), + evaluation_element: decode(values, "evaluation_element").unwrap(), + output: decode(values, "output").unwrap(), } }