chore: core-rewrite unit tests (#608)

* Add tests for signing, index.

* Add error scenarios.

* Add cert tests, modify previous tests.

* Improve cert tests.

* Add tests for request.

* Fix clippy

* Fix clippy.

* Change requests test style.

* Add attestation unit tests.

* Formatting.

* Clippy.

* make data fixtures optional

---------

Co-authored-by: yuroitaki <>
Co-authored-by: sinu <65924192+sinui0@users.noreply.github.com>
This commit is contained in:
yuroitaki
2024-10-03 22:47:15 +08:00
committed by GitHub
parent 0596a9a245
commit 4d5102b6e1
8 changed files with 847 additions and 3 deletions

View File

@@ -10,9 +10,10 @@ edition = "2021"
[features]
default = []
fixtures = ["dep:hex"]
fixtures = ["dep:hex", "dep:tlsn-data-fixtures"]
[dependencies]
tlsn-data-fixtures = { workspace = true, optional = true }
tlsn-tls-core = { workspace = true, features = ["serde"] }
tlsn-utils = { workspace = true }
@@ -29,6 +30,7 @@ k256 = { workspace = true }
opaque-debug = { workspace = true }
p256 = { workspace = true, features = ["serde"] }
rand = { workspace = true }
rand_core = { workspace = true }
rs_merkle = { workspace = true, features = ["serde"] }
rstest = { workspace = true, optional = true }
serde = { workspace = true }
@@ -41,7 +43,6 @@ webpki-roots = { workspace = true }
[dev-dependencies]
rstest = { workspace = true }
hex = { workspace = true }
rand_core = { workspace = true }
rand_chacha = { workspace = true }
bincode = { workspace = true }
tlsn-data-fixtures = { workspace = true }

View File

@@ -237,3 +237,234 @@ impl std::fmt::Display for AttestationBuilderError {
Ok(())
}
}
#[cfg(test)]
mod test {
use rstest::{fixture, rstest};
use tlsn_data_fixtures::http::{request::GET_WITH_HEADER, response::OK_JSON};
use crate::{
connection::{HandshakeData, HandshakeDataV1_2},
fixtures::{encoder_seed, encoding_provider, ConnectionFixture},
hash::Blake3,
request::RequestConfig,
transcript::{encoding::EncodingTree, Transcript, TranscriptCommitConfigBuilder},
};
use super::*;
fn request_and_connection() -> (Request, ConnectionFixture) {
let provider = CryptoProvider::default();
let transcript = Transcript::new(GET_WITH_HEADER, OK_JSON);
let (sent_len, recv_len) = transcript.len();
// Plaintext encodings which the Prover obtained from GC evaluation
let encodings_provider = encoding_provider(GET_WITH_HEADER, OK_JSON);
// At the end of the TLS connection the Prover holds the:
let ConnectionFixture {
server_name,
server_cert_data,
..
} = ConnectionFixture::tlsnotary(transcript.length());
// Prover specifies the ranges it wants to commit to.
let mut transcript_commitment_builder = TranscriptCommitConfigBuilder::new(&transcript);
transcript_commitment_builder
.commit_sent(&(0..sent_len))
.unwrap()
.commit_recv(&(0..recv_len))
.unwrap();
let transcripts_commitment_config = transcript_commitment_builder.build().unwrap();
// Prover constructs encoding tree.
let encoding_tree = EncodingTree::new(
&Blake3::default(),
transcripts_commitment_config.iter_encoding(),
&encodings_provider,
&transcript.length(),
)
.unwrap();
let request_config = RequestConfig::default();
let mut request_builder = Request::builder(&request_config);
request_builder
.server_name(server_name.clone())
.server_cert_data(server_cert_data)
.transcript(transcript.clone())
.encoding_tree(encoding_tree);
let (request, _) = request_builder.build(&provider).unwrap();
(request, ConnectionFixture::tlsnotary(transcript.length()))
}
#[fixture]
#[once]
fn default_attestation_config() -> AttestationConfig {
AttestationConfig::builder()
.supported_signature_algs([SignatureAlgId::SECP256K1])
.build()
.unwrap()
}
#[fixture]
#[once]
fn crypto_provider() -> CryptoProvider {
let mut provider = CryptoProvider::default();
provider.signer.set_secp256k1(&[42u8; 32]).unwrap();
provider
}
#[rstest]
fn test_attestation_builder_accept_unsupported_signer() {
let (request, _) = request_and_connection();
let attestation_config = AttestationConfig::builder()
.supported_signature_algs([SignatureAlgId::SECP256R1])
.build()
.unwrap();
let err = Attestation::builder(&attestation_config)
.accept_request(request)
.err()
.unwrap();
assert!(err.is_request());
}
#[rstest]
fn test_attestation_builder_accept_unsupported_hasher() {
let (request, _) = request_and_connection();
let attestation_config = AttestationConfig::builder()
.supported_signature_algs([SignatureAlgId::SECP256K1])
.supported_hash_algs([HashAlgId::KECCAK256])
.build()
.unwrap();
let err = Attestation::builder(&attestation_config)
.accept_request(request)
.err()
.unwrap();
assert!(err.is_request());
}
#[rstest]
fn test_attestation_builder_accept_unsupported_encoding_commitment() {
let (request, _) = request_and_connection();
let attestation_config = AttestationConfig::builder()
.supported_signature_algs([SignatureAlgId::SECP256K1])
.supported_fields([
FieldKind::ConnectionInfo,
FieldKind::ServerEphemKey,
FieldKind::ServerIdentityCommitment,
])
.build()
.unwrap();
let err = Attestation::builder(&attestation_config)
.accept_request(request)
.err()
.unwrap();
assert!(err.is_request());
}
#[rstest]
fn test_attestation_builder_sign_missing_signer(
default_attestation_config: &AttestationConfig,
) {
let (request, _) = request_and_connection();
let attestation_builder = Attestation::builder(default_attestation_config)
.accept_request(request.clone())
.unwrap();
let mut provider = CryptoProvider::default();
provider.signer.set_secp256r1(&[42u8; 32]).unwrap();
let err = attestation_builder.build(&provider).err().unwrap();
assert!(matches!(err.kind, ErrorKind::Config));
}
#[rstest]
fn test_attestation_builder_sign_missing_encoding_seed(
default_attestation_config: &AttestationConfig,
crypto_provider: &CryptoProvider,
) {
let (request, connection) = request_and_connection();
let mut attestation_builder = Attestation::builder(default_attestation_config)
.accept_request(request.clone())
.unwrap();
let ConnectionFixture {
connection_info,
server_cert_data,
..
} = connection;
let HandshakeData::V1_2(HandshakeDataV1_2 {
server_ephemeral_key,
..
}) = server_cert_data.handshake.clone();
attestation_builder
.connection_info(connection_info.clone())
.server_ephemeral_key(server_ephemeral_key);
let err = attestation_builder.build(crypto_provider).err().unwrap();
assert!(matches!(err.kind, ErrorKind::Field));
}
#[rstest]
fn test_attestation_builder_sign_missing_server_ephemeral_key(
default_attestation_config: &AttestationConfig,
crypto_provider: &CryptoProvider,
) {
let (request, connection) = request_and_connection();
let mut attestation_builder = Attestation::builder(default_attestation_config)
.accept_request(request.clone())
.unwrap();
let ConnectionFixture {
connection_info, ..
} = connection;
attestation_builder
.connection_info(connection_info.clone())
.encoding_seed(encoder_seed().to_vec());
let err = attestation_builder.build(crypto_provider).err().unwrap();
assert!(matches!(err.kind, ErrorKind::Field));
}
#[rstest]
fn test_attestation_builder_sign_missing_connection_info(
default_attestation_config: &AttestationConfig,
crypto_provider: &CryptoProvider,
) {
let (request, connection) = request_and_connection();
let mut attestation_builder = Attestation::builder(default_attestation_config)
.accept_request(request.clone())
.unwrap();
let ConnectionFixture {
server_cert_data, ..
} = connection;
let HandshakeData::V1_2(HandshakeDataV1_2 {
server_ephemeral_key,
..
}) = server_cert_data.handshake.clone();
attestation_builder
.server_ephemeral_key(server_ephemeral_key)
.encoding_seed(encoder_seed().to_vec());
let err = attestation_builder.build(crypto_provider).err().unwrap();
assert!(matches!(err.kind, ErrorKind::Field));
}
}

View File

@@ -376,3 +376,291 @@ pub enum CertificateVerificationError {
#[error("invalid server ephemeral key")]
InvalidServerEphemeralKey,
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{fixtures::ConnectionFixture, transcript::Transcript};
use hex::FromHex;
use rstest::*;
use tlsn_data_fixtures::http::{request::GET_WITH_HEADER, response::OK_JSON};
#[fixture]
#[once]
fn crypto_provider() -> CryptoProvider {
CryptoProvider::default()
}
fn tlsnotary() -> ConnectionFixture {
ConnectionFixture::tlsnotary(Transcript::new(GET_WITH_HEADER, OK_JSON).length())
}
fn appliedzkp() -> ConnectionFixture {
ConnectionFixture::appliedzkp(Transcript::new(GET_WITH_HEADER, OK_JSON).length())
}
/// Expect chain verification to succeed.
#[rstest]
#[case::tlsnotary(tlsnotary())]
#[case::appliedzkp(appliedzkp())]
fn test_verify_cert_chain_sucess_ca_implicit(
crypto_provider: &CryptoProvider,
#[case] mut data: ConnectionFixture,
) {
// Remove the CA cert
data.server_cert_data.certs.pop();
assert!(data
.server_cert_data
.verify_with_provider(
crypto_provider,
data.connection_info.time,
data.server_ephemeral_key(),
&ServerName::from(data.server_name.as_ref()),
)
.is_ok());
}
/// Expect chain verification to succeed even when a trusted CA is provided
/// among the intermediate certs. webpki handles such cases properly.
#[rstest]
#[case::tlsnotary(tlsnotary())]
#[case::appliedzkp(appliedzkp())]
fn test_verify_cert_chain_success_ca_explicit(
crypto_provider: &CryptoProvider,
#[case] data: ConnectionFixture,
) {
assert!(data
.server_cert_data
.verify_with_provider(
crypto_provider,
data.connection_info.time,
data.server_ephemeral_key(),
&ServerName::from(data.server_name.as_ref()),
)
.is_ok());
}
/// Expect to fail since the end entity cert was not valid at the time.
#[rstest]
#[case::tlsnotary(tlsnotary())]
#[case::appliedzkp(appliedzkp())]
fn test_verify_cert_chain_fail_bad_time(
crypto_provider: &CryptoProvider,
#[case] data: ConnectionFixture,
) {
// unix time when the cert chain was NOT valid
let bad_time: u64 = 1571465711;
let err = data.server_cert_data.verify_with_provider(
crypto_provider,
bad_time,
data.server_ephemeral_key(),
&ServerName::from(data.server_name.as_ref()),
);
assert!(matches!(
err.unwrap_err(),
CertificateVerificationError::InvalidCert
));
}
/// Expect to fail when no intermediate cert provided.
#[rstest]
#[case::tlsnotary(tlsnotary())]
#[case::appliedzkp(appliedzkp())]
fn test_verify_cert_chain_fail_no_interm_cert(
crypto_provider: &CryptoProvider,
#[case] mut data: ConnectionFixture,
) {
// Remove the CA cert
data.server_cert_data.certs.pop();
// Remove the intermediate cert
data.server_cert_data.certs.pop();
let err = data.server_cert_data.verify_with_provider(
crypto_provider,
data.connection_info.time,
data.server_ephemeral_key(),
&ServerName::from(data.server_name.as_ref()),
);
assert!(matches!(
err.unwrap_err(),
CertificateVerificationError::InvalidCert
));
}
/// Expect to fail when no intermediate cert provided even if a trusted CA
/// cert is provided.
#[rstest]
#[case::tlsnotary(tlsnotary())]
#[case::appliedzkp(appliedzkp())]
fn test_verify_cert_chain_fail_no_interm_cert_with_ca_cert(
crypto_provider: &CryptoProvider,
#[case] mut data: ConnectionFixture,
) {
// Remove the intermediate cert
data.server_cert_data.certs.remove(1);
let err = data.server_cert_data.verify_with_provider(
crypto_provider,
data.connection_info.time,
data.server_ephemeral_key(),
&ServerName::from(data.server_name.as_ref()),
);
assert!(matches!(
err.unwrap_err(),
CertificateVerificationError::InvalidCert
));
}
/// Expect to fail because end-entity cert is wrong.
#[rstest]
#[case::tlsnotary(tlsnotary())]
#[case::appliedzkp(appliedzkp())]
fn test_verify_cert_chain_fail_bad_ee_cert(
crypto_provider: &CryptoProvider,
#[case] mut data: ConnectionFixture,
) {
let ee: &[u8] = include_bytes!("./fixtures/data/unknown/ee.der");
// Change the end entity cert
data.server_cert_data.certs[0] = Certificate(ee.to_vec());
let err = data.server_cert_data.verify_with_provider(
crypto_provider,
data.connection_info.time,
data.server_ephemeral_key(),
&ServerName::from(data.server_name.as_ref()),
);
assert!(matches!(
err.unwrap_err(),
CertificateVerificationError::InvalidCert
));
}
/// Expect sig verification to fail because client_random is wrong.
#[rstest]
#[case::tlsnotary(tlsnotary())]
#[case::appliedzkp(appliedzkp())]
fn test_verify_sig_ke_params_fail_bad_client_random(
crypto_provider: &CryptoProvider,
#[case] mut data: ConnectionFixture,
) {
let HandshakeData::V1_2(HandshakeDataV1_2 { client_random, .. }) =
&mut data.server_cert_data.handshake;
client_random[31] = client_random[31].wrapping_add(1);
let err = data.server_cert_data.verify_with_provider(
crypto_provider,
data.connection_info.time,
data.server_ephemeral_key(),
&ServerName::from(data.server_name.as_ref()),
);
assert!(matches!(
err.unwrap_err(),
CertificateVerificationError::InvalidServerSignature
));
}
/// Expect sig verification to fail because the sig is wrong.
#[rstest]
#[case::tlsnotary(tlsnotary())]
#[case::appliedzkp(appliedzkp())]
fn test_verify_sig_ke_params_fail_bad_sig(
crypto_provider: &CryptoProvider,
#[case] mut data: ConnectionFixture,
) {
data.server_cert_data.sig.sig[31] = data.server_cert_data.sig.sig[31].wrapping_add(1);
let err = data.server_cert_data.verify_with_provider(
crypto_provider,
data.connection_info.time,
data.server_ephemeral_key(),
&ServerName::from(data.server_name.as_ref()),
);
assert!(matches!(
err.unwrap_err(),
CertificateVerificationError::InvalidServerSignature
));
}
/// Expect to fail because the dns name is not in the cert.
#[rstest]
#[case::tlsnotary(tlsnotary())]
#[case::appliedzkp(appliedzkp())]
fn test_check_dns_name_present_in_cert_fail_bad_host(
crypto_provider: &CryptoProvider,
#[case] data: ConnectionFixture,
) {
let bad_name = ServerName::from("badhost.com");
let err = data.server_cert_data.verify_with_provider(
crypto_provider,
data.connection_info.time,
data.server_ephemeral_key(),
&bad_name,
);
assert!(matches!(
err.unwrap_err(),
CertificateVerificationError::InvalidCert
));
}
/// Expect to fail because the ephemeral key provided is wrong.
#[rstest]
#[case::tlsnotary(tlsnotary())]
#[case::appliedzkp(appliedzkp())]
fn test_invalid_ephemeral_key(
crypto_provider: &CryptoProvider,
#[case] data: ConnectionFixture,
) {
let wrong_ephemeral_key = ServerEphemKey {
typ: KeyType::SECP256R1,
key: Vec::<u8>::from_hex(include_bytes!("./fixtures/data/unknown/pubkey")).unwrap(),
};
let err = data.server_cert_data.verify_with_provider(
crypto_provider,
data.connection_info.time,
&wrong_ephemeral_key,
&ServerName::from(data.server_name.as_ref()),
);
assert!(matches!(
err.unwrap_err(),
CertificateVerificationError::InvalidServerEphemeralKey
));
}
/// Expect to fail when no cert provided.
#[rstest]
#[case::tlsnotary(tlsnotary())]
#[case::appliedzkp(appliedzkp())]
fn test_verify_cert_chain_fail_no_cert(
crypto_provider: &CryptoProvider,
#[case] mut data: ConnectionFixture,
) {
// Empty certs
data.server_cert_data.certs = Vec::new();
let err = data.server_cert_data.verify_with_provider(
crypto_provider,
data.connection_info.time,
data.server_ephemeral_key(),
&ServerName::from(data.server_name.as_ref()),
);
assert!(matches!(
err.unwrap_err(),
CertificateVerificationError::MissingCerts
));
}
}

View File

@@ -83,7 +83,7 @@ impl ConnectionFixture {
Certificate(include_bytes!("fixtures/data/appliedzkp.org/ca.der").to_vec()),
],
sig: ServerSignature {
scheme: SignatureScheme::RSA_PKCS1_SHA256,
scheme: SignatureScheme::ECDSA_NISTP256_SHA256,
sig: Vec::<u8>::from_hex(include_bytes!(
"fixtures/data/appliedzkp.org/signature"
))
@@ -109,6 +109,15 @@ impl ConnectionFixture {
},
}
}
/// Returns the server_ephemeral_key fixture.
pub fn server_ephemeral_key(&self) -> &ServerEphemKey {
let HandshakeData::V1_2(HandshakeDataV1_2 {
server_ephemeral_key,
..
}) = &self.server_cert_data.handshake;
server_ephemeral_key
}
}
/// Returns an encoding provider fixture.

View File

@@ -0,0 +1 @@
14e1f634ecfee5bd4f987f8c571146cb2acb432e400b2fabcbd8ed77f6ef08bd5496cd51d449ce131efd74a24d07b01c38ec794d22d3d43b2b05b907e72797534e

View File

@@ -104,3 +104,74 @@ impl From<Vec<PlaintextHashSecret>> for Index<PlaintextHashSecret> {
})
}
}
#[cfg(test)]
mod test {
use utils::range::RangeSet;
use super::*;
#[derive(PartialEq, Debug, Clone)]
struct Stub {
field_index: FieldId,
index: Idx,
}
impl From<Vec<Stub>> for Index<Stub> {
fn from(items: Vec<Stub>) -> Self {
Self::new(items, |item: &Stub| (&item.field_index, &item.index))
}
}
fn stubs() -> Vec<Stub> {
vec![
Stub {
field_index: FieldId(1),
index: Idx::new(RangeSet::from([0..1, 18..21])),
},
Stub {
field_index: FieldId(2),
index: Idx::new(RangeSet::from([1..5, 8..11])),
},
]
}
#[test]
fn test_successful_retrieval() {
let stub_a_index = Idx::new(RangeSet::from([0..4, 7..10]));
let stub_b_field_index = FieldId(8);
let stubs = vec![
Stub {
field_index: FieldId(1),
index: stub_a_index.clone(),
},
Stub {
field_index: stub_b_field_index,
index: Idx::new(RangeSet::from([1..5, 8..11])),
},
];
let stubs_index: Index<Stub> = stubs.clone().into();
assert_eq!(
stubs_index.get_by_field_id(&stub_b_field_index),
Some(&stubs[1])
);
assert_eq!(
stubs_index.get_by_transcript_idx(&stub_a_index),
Some(&stubs[0])
);
}
#[test]
fn test_failed_retrieval() {
let stubs = stubs();
let stubs_index: Index<Stub> = stubs.clone().into();
let wrong_index = Idx::new(RangeSet::from([0..3, 4..5]));
let wrong_field_index = FieldId(200);
assert_eq!(stubs_index.get_by_field_id(&wrong_field_index), None);
assert_eq!(stubs_index.get_by_transcript_idx(&wrong_index), None);
}
}

View File

@@ -87,3 +87,171 @@ impl Request {
#[derive(Debug, thiserror::Error)]
#[error("inconsistent attestation: {0}")]
pub struct InconsistentAttestation(String);
#[cfg(test)]
mod test {
use super::*;
use crate::{
attestation::{Attestation, AttestationConfig},
connection::{HandshakeData, HandshakeDataV1_2, ServerCertOpening, TranscriptLength},
fixtures::{encoder_seed, encoding_provider, ConnectionFixture},
hash::{Blake3, Hash, HashAlgId},
signing::SignatureAlgId,
transcript::{encoding::EncodingTree, Transcript, TranscriptCommitConfigBuilder},
CryptoProvider,
};
use tlsn_data_fixtures::http::{request::GET_WITH_HEADER, response::OK_JSON};
fn attestation(payload: (Request, ConnectionFixture)) -> Attestation {
let (request, connection) = payload;
let ConnectionFixture {
connection_info,
server_cert_data,
..
} = connection;
let HandshakeData::V1_2(HandshakeDataV1_2 {
server_ephemeral_key,
..
}) = server_cert_data.handshake.clone();
let mut provider = CryptoProvider::default();
provider.signer.set_secp256k1(&[42u8; 32]).unwrap();
let attestation_config = AttestationConfig::builder()
.supported_signature_algs([SignatureAlgId::SECP256K1])
.build()
.unwrap();
let mut attestation_builder = Attestation::builder(&attestation_config)
.accept_request(request.clone())
.unwrap();
attestation_builder
.connection_info(connection_info.clone())
.server_ephemeral_key(server_ephemeral_key)
.encoding_seed(encoder_seed().to_vec());
attestation_builder.build(&provider).unwrap()
}
fn request_and_connection() -> (Request, ConnectionFixture) {
let provider = CryptoProvider::default();
let transcript = Transcript::new(GET_WITH_HEADER, OK_JSON);
let (sent_len, recv_len) = transcript.len();
// Plaintext encodings which the Prover obtained from GC evaluation
let encodings_provider = encoding_provider(GET_WITH_HEADER, OK_JSON);
// At the end of the TLS connection the Prover holds the:
let ConnectionFixture {
server_name,
server_cert_data,
..
} = ConnectionFixture::tlsnotary(transcript.length());
// Prover specifies the ranges it wants to commit to.
let mut transcript_commitment_builder = TranscriptCommitConfigBuilder::new(&transcript);
transcript_commitment_builder
.commit_sent(&(0..sent_len))
.unwrap()
.commit_recv(&(0..recv_len))
.unwrap();
let transcripts_commitment_config = transcript_commitment_builder.build().unwrap();
// Prover constructs encoding tree.
let encoding_tree = EncodingTree::new(
&Blake3::default(),
transcripts_commitment_config.iter_encoding(),
&encodings_provider,
&transcript.length(),
)
.unwrap();
let request_config = RequestConfig::default();
let mut request_builder = Request::builder(&request_config);
request_builder
.server_name(server_name.clone())
.server_cert_data(server_cert_data)
.transcript(transcript.clone())
.encoding_tree(encoding_tree);
let (request, _) = request_builder.build(&provider).unwrap();
(request, ConnectionFixture::tlsnotary(transcript.length()))
}
#[test]
fn test_success() {
let (request, connection) = request_and_connection();
let attestation = attestation((request.clone(), connection));
assert!(request.validate(&attestation).is_ok())
}
#[test]
fn test_wrong_signature_alg() {
let (mut request, connection) = request_and_connection();
let attestation = attestation((request.clone(), connection));
request.signature_alg = SignatureAlgId::SECP256R1;
let res = request.validate(&attestation);
assert!(res.is_err());
}
#[test]
fn test_wrong_hash_alg() {
let (mut request, connection) = request_and_connection();
let attestation = attestation((request.clone(), connection));
request.hash_alg = HashAlgId::SHA256;
let res = request.validate(&attestation);
assert!(res.is_err())
}
#[test]
fn test_wrong_server_commitment() {
let (mut request, connection) = request_and_connection();
let attestation = attestation((request.clone(), connection));
let ConnectionFixture {
server_cert_data, ..
} = ConnectionFixture::appliedzkp(TranscriptLength {
sent: 100,
received: 100,
});
let opening = ServerCertOpening::new(server_cert_data);
let crypto_provider = CryptoProvider::default();
request.server_cert_commitment =
opening.commit(crypto_provider.hash.get(&HashAlgId::BLAKE3).unwrap());
let res = request.validate(&attestation);
assert!(res.is_err())
}
#[test]
fn test_wrong_encoding_commitment_root() {
let (mut request, connection) = request_and_connection();
let attestation = attestation((request.clone(), connection));
request.encoding_commitment_root = Some(TypedHash {
alg: HashAlgId::BLAKE3,
value: Hash::default(),
});
let res = request.validate(&attestation);
assert!(res.is_err())
}
}

View File

@@ -372,3 +372,78 @@ mod secp256r1 {
}
pub use secp256r1::{Secp256r1Signer, Secp256r1Verifier};
#[cfg(test)]
mod test {
use super::*;
use rand_core::OsRng;
use rstest::{fixture, rstest};
#[fixture]
#[once]
fn secp256k1_signer() -> Secp256k1Signer {
let signing_key = k256::ecdsa::SigningKey::random(&mut OsRng);
Secp256k1Signer::new(&signing_key.to_bytes()).unwrap()
}
#[fixture]
#[once]
fn secp256r1_signer() -> Secp256r1Signer {
let signing_key = p256::ecdsa::SigningKey::random(&mut OsRng);
Secp256r1Signer::new(&signing_key.to_bytes()).unwrap()
}
#[rstest]
fn test_secp256k1_success(secp256k1_signer: &Secp256k1Signer) {
assert_eq!(secp256k1_signer.alg_id(), SignatureAlgId::SECP256K1);
let msg = "test payload";
let signature = secp256k1_signer.sign(msg.as_bytes()).unwrap();
let verifying_key = secp256k1_signer.verifying_key();
let verifier = Secp256k1Verifier {};
assert_eq!(verifier.alg_id(), SignatureAlgId::SECP256K1);
let result = verifier.verify(&verifying_key, msg.as_bytes(), &signature.data);
assert!(result.is_ok());
}
#[rstest]
fn test_secp256r1_success(secp256r1_signer: &Secp256r1Signer) {
assert_eq!(secp256r1_signer.alg_id(), SignatureAlgId::SECP256R1);
let msg = "test payload";
let signature = secp256r1_signer.sign(msg.as_bytes()).unwrap();
let verifying_key = secp256r1_signer.verifying_key();
let verifier = Secp256r1Verifier {};
assert_eq!(verifier.alg_id(), SignatureAlgId::SECP256R1);
let result = verifier.verify(&verifying_key, msg.as_bytes(), &signature.data);
assert!(result.is_ok());
}
#[rstest]
#[case::wrong_signer(&secp256r1_signer(), false, false)]
#[case::corrupted_signature(&secp256k1_signer(), true, false)]
#[case::wrong_signature(&secp256k1_signer(), false, true)]
fn test_failure(
#[case] signer: &dyn Signer,
#[case] corrupted_signature: bool,
#[case] wrong_signature: bool,
) {
let msg = "test payload";
let mut signature = signer.sign(msg.as_bytes()).unwrap();
let verifying_key = signer.verifying_key();
if corrupted_signature {
signature.data.push(0);
}
if wrong_signature {
signature = signer.sign("different payload".as_bytes()).unwrap();
}
let verifier = Secp256k1Verifier {};
let result = verifier.verify(&verifying_key, msg.as_bytes(), &signature.data);
assert!(result.is_err());
}
}