Skip to content

Commit bd83e17

Browse files
committed
Add tests to ensure the feldman stuff works the way we think it does.
These functions cover the operation to split a secret, deserialize the verifier, verify shares and reconstruct the secret.
1 parent 2d594a9 commit bd83e17

File tree

1 file changed

+122
-0
lines changed

1 file changed

+122
-0
lines changed

src/hsm.rs

+122
Original file line numberDiff line numberDiff line change
@@ -811,3 +811,125 @@ pub fn print_password(
811811
print_file.write_all(&[CR, FF])?;
812812
Ok(())
813813
}
814+
815+
#[cfg(test)]
816+
mod tests {
817+
use super::*;
818+
819+
// secret split into the feldman verifier & shares below
820+
const SECRET: &str =
821+
"f259a45c17624b9317d8e292050c46a0f3d7387724b4cd26dd94f8bd3d1c0e1a";
822+
823+
// verifier created and serialized to json by `new_split_wrap`
824+
const VERIFIER: &str = r#"
825+
{
826+
"generator": "036b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
827+
"commitments": [
828+
"02315e9e3cd76d0917ecd60378b75259bbdf2e35a31f46c05a497409d5d89c69dc",
829+
"0250e4e04d42e92bc15eecbe0789f5ac4831abe962df6b1eaed897e4634df702e3",
830+
"02dfc3c60074cb4896163e7e188f8ec93d3bd1e2fd2ed68854c9324e4a56e94cc7"
831+
]
832+
}"#;
833+
834+
// shares dumped to the printer by `new_split_wrap`
835+
const SHARE_ARRAY: [&str; SHARES] = [
836+
"01 b5b7dd6a 8ef8762f 0f266784 be191202 7b8a4b21 72fcb410 f28b2e1a e3669f9c",
837+
"02 042cfd2b 1ede9e78 d7827065 2d8c20ef 1cb43bf1 c722f2e3 a08ac387 b57b18f8",
838+
"03 ddb9039b c714c472 70ecfd33 53657366 51230043 6f56c6a8 cf074e89 ac1fc4d0",
839+
"04 425bf0bf 879ae818 db660def 2fa509f8 e221a80d 765153d1 a2d34dd7 d22d3321",
840+
"05 3215c494 6071096e 16eda298 c24ae4a6 497e28ab 2a41d768 036261f8 2063ae8d",
841+
];
842+
843+
fn secret_bytes() -> [u8; KEY_LEN] {
844+
let mut secret = [0u8; KEY_LEN];
845+
hex::decode_to_slice(SECRET, &mut secret).unwrap();
846+
847+
secret
848+
}
849+
850+
fn deserialize_share(share: &str) -> Result<Share<{ KEY_LEN + 1 }>> {
851+
// filter out whitespace to keep hex::decode happy
852+
let share: String =
853+
share.chars().filter(|c| !c.is_whitespace()).collect();
854+
let share = hex::decode(share)?;
855+
856+
Ok(Share::try_from(&share[..])?)
857+
}
858+
859+
#[test]
860+
fn round_trip() -> Result<()> {
861+
use rand::rngs::ThreadRng;
862+
863+
let secret = secret_bytes();
864+
let secret_key = SecretKey::from_be_bytes(&secret)?;
865+
let nzs = secret_key.to_nonzero_scalar();
866+
867+
let mut rng = ThreadRng::default();
868+
let (shares, verifier) = Feldman::<THRESHOLD, SHARES>::split_secret::<
869+
Scalar,
870+
ProjectivePoint,
871+
ThreadRng,
872+
{ KEY_LEN + 1 },
873+
>(*nzs.as_ref(), None, &mut rng)
874+
.map_err(|e| anyhow::anyhow!("failed to split secret: {}", e))?;
875+
876+
for s in &shares {
877+
assert!(verifier.verify(s));
878+
}
879+
880+
let scalar = Feldman::<THRESHOLD, SHARES>::combine_shares::<
881+
Scalar,
882+
{ KEY_LEN + 1 },
883+
>(&shares)
884+
.map_err(|e| anyhow::anyhow!("failed to combine secret: {}", e))?;
885+
886+
let nzs_dup = NonZeroScalar::from_repr(scalar.to_repr()).unwrap();
887+
let sk_dup = SecretKey::from(nzs_dup);
888+
let new_secret: [u8; KEY_LEN] = sk_dup.to_be_bytes().try_into()?;
889+
890+
assert_eq!(new_secret, secret);
891+
892+
Ok(())
893+
}
894+
895+
// deserialize a verifier & use it to verify the shares in SHARE_ARRAY
896+
#[test]
897+
fn verify_shares() -> Result<()> {
898+
use vsss_rs::FeldmanVerifier;
899+
900+
let verifier: FeldmanVerifier<
901+
Scalar,
902+
ProjectivePoint,
903+
{ KEY_LEN + 1 },
904+
> = serde_json::from_str(VERIFIER)?;
905+
906+
for share in SHARE_ARRAY {
907+
let share = deserialize_share(share)?;
908+
assert!(verifier.verify(&share));
909+
}
910+
911+
Ok(())
912+
}
913+
914+
#[test]
915+
fn recover_secret() -> Result<()> {
916+
let mut shares: Vec<Share<{ KEY_LEN + 1 }>> = Vec::new();
917+
for share in SHARE_ARRAY {
918+
shares.push(deserialize_share(share)?);
919+
}
920+
921+
let scalar = Feldman::<THRESHOLD, SHARES>::combine_shares::<
922+
Scalar,
923+
{ KEY_LEN + 1 },
924+
>(&shares)
925+
.map_err(|e| anyhow::anyhow!("failed to combine secret: {}", e))?;
926+
927+
let nzs_dup = NonZeroScalar::from_repr(scalar.to_repr()).unwrap();
928+
let sk_dup = SecretKey::from(nzs_dup);
929+
let secret: [u8; KEY_LEN] = sk_dup.to_be_bytes().try_into()?;
930+
931+
assert_eq!(secret, secret_bytes());
932+
933+
Ok(())
934+
}
935+
}

0 commit comments

Comments
 (0)