diff --git a/contracts/babylon/src/contract.rs b/contracts/babylon/src/contract.rs index e6ec193e..137de240 100644 --- a/contracts/babylon/src/contract.rs +++ b/contracts/babylon/src/contract.rs @@ -161,7 +161,11 @@ pub fn execute( // TODO: Add events Ok(Response::new()) } - ExecuteMsg::Slashing { fp_btc_pk, block_height, secret_key } => { + ExecuteMsg::Slashing { + fp_btc_pk, + block_height, + secret_key, + } => { // This is an internal routing message from the `btc-staking` contract // Check sender let btc_staking = CONFIG @@ -173,7 +177,8 @@ pub fn execute( } // Send over IBC to the Provider (Babylon) let channel = IBC_CHANNEL.load(deps.storage)?; - let msg = ibc_packet::slashing_msg(&env, &channel, &fp_btc_pk, block_height, &secret_key)?; + let msg = + ibc_packet::slashing_msg(&env, &channel, &fp_btc_pk, block_height, &secret_key)?; // TODO: Add events Ok(Response::new().add_message(msg)) } diff --git a/contracts/babylon/src/ibc.rs b/contracts/babylon/src/ibc.rs index bf98df4a..f3519fc2 100644 --- a/contracts/babylon/src/ibc.rs +++ b/contracts/babylon/src/ibc.rs @@ -141,11 +141,14 @@ pub(crate) mod ibc_packet { use super::*; use crate::state::config::CONFIG; use babylon_apis::ibc_consumer::{consumer_packet_data, ConsumerPacketData}; - use babylon_apis::{btc_staking_api::{ - ActiveBtcDelegation, BtcUndelegationInfo, CovenantAdaptorSignatures, - FinalityProviderDescription, NewFinalityProvider, ProofOfPossessionBtc, SignatureInfo, - UnbondedBtcDelegation, - }, ibc_consumer}; + use babylon_apis::{ + btc_staking_api::{ + ActiveBtcDelegation, BtcUndelegationInfo, CovenantAdaptorSignatures, + FinalityProviderDescription, NewFinalityProvider, ProofOfPossessionBtc, SignatureInfo, + UnbondedBtcDelegation, + }, + ibc_consumer, + }; use babylon_proto::babylon::btcstaking::v1::BtcStakingIbcPacket; use cosmwasm_std::{to_json_binary, Decimal, IbcChannel, IbcMsg, WasmMsg}; use std::str::FromStr; @@ -311,11 +314,13 @@ pub(crate) mod ibc_packet { block_height: u64, secret_key: &[u8], ) -> Result { - let packet = ConsumerPacketData { packet: consumer_packet_data::Packet::Slashing(ibc_consumer::Slashing { - fp_btc_pk: fp_btc_pk.to_vec(), - block_height, - secret_key: secret_key.to_vec(), - }), }; + let packet = ConsumerPacketData { + packet: consumer_packet_data::Packet::Slashing(ibc_consumer::Slashing { + fp_btc_pk: fp_btc_pk.to_vec(), + block_height, + secret_key: secret_key.to_vec(), + }), + }; let msg = IbcMsg::SendPacket { channel_id: channel.endpoint.channel_id.clone(), data: to_json_binary(&packet)?, diff --git a/contracts/babylon/src/msg/contract.rs b/contracts/babylon/src/msg/contract.rs index a007acda..3b721fe9 100644 --- a/contracts/babylon/src/msg/contract.rs +++ b/contracts/babylon/src/msg/contract.rs @@ -1,10 +1,10 @@ -use cosmwasm_schema::{cw_serde, QueryResponses}; -use cosmwasm_std::{Binary, StdError, StdResult}; -use babylon_apis::Bytes; use crate::msg::btc_header::{BtcHeader, BtcHeaderResponse, BtcHeadersResponse}; use crate::msg::cz_header::CzHeaderResponse; use crate::msg::epoch::EpochResponse; use crate::state::config::Config; +use babylon_apis::Bytes; +use cosmwasm_schema::{cw_serde, QueryResponses}; +use cosmwasm_std::{Binary, StdError, StdResult}; const BABYLON_TAG_BYTES: usize = 4; diff --git a/contracts/btc-staking/src/finality.rs b/contracts/btc-staking/src/finality.rs index 634b17f5..f8ee0c1b 100644 --- a/contracts/btc-staking/src/finality.rs +++ b/contracts/btc-staking/src/finality.rs @@ -274,15 +274,15 @@ fn slash_finality_provider( // Extract BTC SK using the evidence let pk = eots::PublicKey::from_hex(fp_btc_pk_hex)?; - let btc_sk = eots::extract( - &pk, - &evidence.pub_rand, - &evidence.canonical_app_hash, - &evidence.canonical_finality_sig, - &evidence.fork_app_hash, - &evidence.fork_finality_sig, - ) - .map_err(|err| ContractError::SecretKeyExtractionError(err.to_string()))?; + let btc_sk = pk + .extract_secret_key( + &evidence.pub_rand, + &evidence.canonical_app_hash, + &evidence.canonical_finality_sig, + &evidence.fork_app_hash, + &evidence.fork_finality_sig, + ) + .map_err(|err| ContractError::SecretKeyExtractionError(err.to_string()))?; // Emit slashing event. // Raises slashing event to babylon over IBC. @@ -1050,15 +1050,16 @@ pub(crate) mod tests { // Assert the slashing event is proper assert_eq!(res.events[0].ty, "slashed_finality_provider".to_string()); // Extract the secret key to compare it - let btc_sk = eots::extract( - &eots::PublicKey::from_hex(&pk_hex).unwrap(), - &pub_rand_one, - &add_finality_signature.block_app_hash, - &finality_signature, - &add_finality_signature_2.block_app_hash, - &add_finality_signature_2.finality_sig, - ) - .unwrap(); + let pk = eots::PublicKey::from_hex(&pk_hex).unwrap(); + let btc_sk = pk + .extract_secret_key( + &pub_rand_one, + &add_finality_signature.block_app_hash, + &finality_signature, + &add_finality_signature_2.block_app_hash, + &add_finality_signature_2.finality_sig, + ) + .unwrap(); assert_eq!( res.messages[0], SubMsg::new(WasmMsg::Execute { diff --git a/packages/apis/src/ibc_consumer.rs b/packages/apis/src/ibc_consumer.rs index cca94bad..b96aa37f 100644 --- a/packages/apis/src/ibc_consumer.rs +++ b/packages/apis/src/ibc_consumer.rs @@ -1,5 +1,5 @@ -use cosmwasm_schema::cw_serde; use crate::Bytes; +use cosmwasm_schema::cw_serde; /// ConsumerPacketData is the message that defines the IBC packets a Consumer can send to Babylon's /// ZoneConcierge module. diff --git a/packages/eots/src/eots.rs b/packages/eots/src/eots.rs index f2405f4c..bc21a8a5 100644 --- a/packages/eots/src/eots.rs +++ b/packages/eots/src/eots.rs @@ -12,120 +12,165 @@ use k256::{ AffinePoint, ProjectivePoint, Scalar, U256, }; use sha2::{Digest, Sha256}; -use std::ops::Mul; +use std::ops::{Deref, Mul}; const CHALLENGE_TAG: &[u8] = b"BIP0340/challenge"; -// adapted from https://github.com/RustCrypto/elliptic-curves/blob/520f67d26be1773bd600d05796cc26d797dd7182/k256/src/schnorr.rs#L181-L187 +// Adapted from https://github.com/RustCrypto/elliptic-curves/blob/520f67d26be1773bd600d05796cc26d797dd7182/k256/src/schnorr.rs#L181-L187 fn tagged_hash(tag: &[u8]) -> Sha256 { let tag_hash = Sha256::digest(tag); let mut digest = Sha256::new(); - // the hash is in sha256d so we need to hash twice + // The hash is in sha256d, so we need to hash twice digest.update(tag_hash); digest.update(tag_hash); digest } -/// SecRand is the type for a secret randomness -/// It is formed as a scalar on the Secp256k1 curve -pub type SecRand = Scalar; - -/// new_sec_rand parses the given bytes into a new secret randomness -/// the given byte slice has to be a 32-byte scalar -/// NOTE: we enforce the secret randomness to correspond to a point -/// with even y-coordinate -pub fn new_sec_rand(r: &[u8]) -> Result { - let array: [u8; 32] = r - .try_into() - .map_err(|_| Error::InvalidInputLength(r.len()))?; - let scalar = - SecRand::from_repr_vartime(array.into()).ok_or(Error::SecretRandomnessParseFailed {})?; - if ProjectivePoint::mul_by_generator(&scalar) - .to_affine() - .y_is_odd() - .into() - { - Ok(-scalar) - } else { - Ok(scalar) +/// `SecRand` is the type for a secret randomness. +/// It is formed as a scalar on the secp256k1 curve +pub struct SecRand { + inner: Scalar, +} + +impl SecRand { + /// `new` parses the given bytes into a new secret randomness. + /// The given byte slice has to be a 32-byte scalar. + /// NOTE: we enforce the secret randomness to correspond to a point + /// with even y-coordinate + pub fn new(r: &[u8]) -> Result { + let array: [u8; 32] = r + .try_into() + .map_err(|_| Error::InvalidInputLength(r.len()))?; + let scalar = + Scalar::from_repr_vartime(array.into()).ok_or(Error::SecretRandomnessParseFailed {})?; + if ProjectivePoint::mul_by_generator(&scalar) + .to_affine() + .y_is_odd() + .into() + { + Ok(Self { inner: -scalar }) + } else { + Ok(Self { inner: scalar }) + } } } -/// PubRand is the type for a public randomness -/// It is formed as a point with even y coord on the Secp256k1 curve -pub type PubRand = ProjectivePoint; - -/// new_pub_rand parses the given bytes into a new public randomness value on the secp256k1 curve. -/// The given byte slice can be: -/// - A 32-byte representation of an x coordinate (the y-coordinate is derived as even). -/// - A 33-byte compressed representation of an x coordinate (the y-coordinate is derived). -/// - A 65-byte uncompressed representation of an x-y coordinate pair (the y-coordinate is _also_ -/// derived). -/// See https://crypto.stackexchange.com/a/108092/119110 for format / prefix details -pub fn new_pub_rand(pr_bytes: &[u8]) -> Result { - // Reject if the input is not 32 (naked), 33 (compressed) or 65 (uncompressed) bytes - let (x_bytes, y_is_odd) = match pr_bytes.len() { - 32 => (pr_bytes, false), // Assume even y-coordinate as even - 33 => { - if pr_bytes[0] != 0x02 && pr_bytes[0] != 0x03 { - return Err(Error::InvalidInputLength(pr_bytes.len())); +impl Deref for SecRand { + type Target = Scalar; + + fn deref(&self) -> &::Target { + &self.inner + } +} + +/// `PubRand` is the type for a public randomness. +/// It is formed as a point on the secp256k1 curve +pub struct PubRand { + inner: ProjectivePoint, +} + +impl PubRand { + /// `new` parses the given bytes into a new public randomness value on the secp256k1 curve. + /// The given byte slice can be: + /// - A 32-byte representation of an x coordinate (the y-coordinate is derived as even). + /// - A 33-byte compressed representation of an x coordinate (the y-coordinate is derived). + /// - A 65-byte uncompressed representation of an x-y coordinate pair (the y-coordinate is _also_ + /// derived). + /// See https://crypto.stackexchange.com/a/108092/119110 for format / prefix details + pub fn new(pr_bytes: &[u8]) -> Result { + // Reject if the input is not 32 (naked), 33 (compressed) or 65 (uncompressed) bytes + let (x_bytes, y_is_odd) = match pr_bytes.len() { + 32 => (pr_bytes, false), // Assume even y-coordinate + 33 => { + if pr_bytes[0] != 0x02 && pr_bytes[0] != 0x03 { + return Err(Error::InvalidInputLength(pr_bytes.len())); + } + (&pr_bytes[1..], pr_bytes[0] == 0x03) // y-coordinate parity } - (&pr_bytes[1..], pr_bytes[0] == 0x03) // y-coordinate parity - } - 65 => { - if pr_bytes[0] != 0x04 { - return Err(Error::InvalidInputLength(pr_bytes.len())); + 65 => { + if pr_bytes[0] != 0x04 { + return Err(Error::InvalidInputLength(pr_bytes.len())); + } + // FIXME: Deserialize y-coordinate directly, instead of deriving it below + (&pr_bytes[1..33], pr_bytes[64] & 0x01 == 0x01) // y-coordinate parity } - // FIXME: Deserialize y-coordinate directly, instead of deriving it below - (&pr_bytes[1..33], pr_bytes[64] & 0x01 == 0x01) // y-coordinate parity + _ => return Err(Error::InvalidInputLength(pr_bytes.len())), + }; + // Convert x_array to a FieldElement + let x = k256::FieldBytes::from_slice(x_bytes); + + // Attempt to derive the corresponding y-coordinate + let ap_option = AffinePoint::decompress(x, Choice::from(y_is_odd as u8)); + if ap_option.is_some().into() { + Ok(Self { + inner: ProjectivePoint::from(ap_option.unwrap()), + }) + } else { + Err(Error::PublicRandomnessParseFailed {}) } - _ => return Err(Error::InvalidInputLength(pr_bytes.len())), - }; - // Convert x_array to a FieldElement - let x = k256::FieldBytes::from_slice(x_bytes); - - // Attempt to derive the corresponding y-coordinate - let ap_option = AffinePoint::decompress(x, Choice::from(y_is_odd as u8)); - if ap_option.is_some().into() { - Ok(ProjectivePoint::from(ap_option.unwrap())) - } else { - Err(Error::PublicRandomnessParseFailed {}) + } + + pub fn to_bytes(&self) -> Vec { + point_to_bytes(&self.inner).to_vec() } } -/// Signature is an extractable one-time signature (EOTS) -/// i.e., s in a Schnorr signature (R, s) -pub type Signature = Scalar; +impl Deref for PubRand { + type Target = ProjectivePoint; -pub fn new_sig(r: &[u8]) -> Result { - let array: [u8; 32] = r - .try_into() - .map_err(|_| Error::InvalidInputLength(r.len()))?; - Signature::from_repr_vartime(array.into()).ok_or(Error::SignatureParseFailed {}) + fn deref(&self) -> &::Target { + &self.inner + } } -/// SecretKey is a secret key, formed as a 32-byte scalar -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct SecretKey { - inner: k256::SecretKey, +impl From for PubRand { + fn from(p: ProjectivePoint) -> Self { + Self { inner: p } + } } -/// PublicKey is a public key, formed as a point with even coordinate -/// on the Secp256k1 curve -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct PublicKey { - inner: k256::PublicKey, +/// `Signature` is an extractable one-time signature (EOTS), i.e., `s` in a Schnorr signature `(R, s)` +pub struct Signature { + inner: Scalar, } -fn point_to_bytes(p: &ProjectivePoint) -> [u8; 32] { - let encoded_p = p.to_encoded_point(false); - // Extract the x-coordinate as bytes - let x_bytes = encoded_p.x().unwrap(); - let x_array: [u8; 32] = x_bytes.as_slice().try_into().unwrap(); // cannot fail - x_array +impl Signature { + /// `new` parses the given bytes into a new signature. + /// The given byte slice has to be a 32-byte scalar + pub fn new(r: &[u8]) -> Result { + let array: [u8; 32] = r + .try_into() + .map_err(|_| Error::InvalidInputLength(r.len()))?; + Ok(Self { + inner: Scalar::from_repr_vartime(array.into()).ok_or(Error::SignatureParseFailed {})?, + }) + } + + pub fn to_bytes(&self) -> Vec { + self.inner.to_bytes().to_vec() + } +} + +impl Deref for Signature { + type Target = Scalar; + + fn deref(&self) -> &::Target { + &self.inner + } +} + +impl From for Signature { + fn from(s: Scalar) -> Self { + Self { inner: s } + } +} + +/// `SecretKey` is a secret key, formed as a 32-byte scalar +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SecretKey { + inner: k256::SecretKey, } -#[allow(clippy::new_without_default)] impl SecretKey { pub fn from_bytes(x: &[u8]) -> Result { let x_array: [u8; 32] = x @@ -158,7 +203,7 @@ impl SecretKey { let x = self.inner.to_nonzero_scalar(); let p = ProjectivePoint::mul_by_generator(&x); let p_bytes = point_to_bytes(&p); - let r = new_sec_rand(sec_rand)?; + let r = SecRand::new(sec_rand)?; let r_point = ProjectivePoint::mul_by_generator(&r); let r_bytes = point_to_bytes(&r_point); let c = >::reduce_bytes( @@ -169,7 +214,7 @@ impl SecretKey { .finalize(), ); - Ok(r + c * *x) + Ok(Signature::from(*r + c * *x)) } /// to_bytes converts the secret key into bytes @@ -178,15 +223,36 @@ impl SecretKey { } } +/// `PublicKey` is a public key, formed as a point on the secp256k1 curve +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct PublicKey { + inner: k256::PublicKey, +} + impl PublicKey { pub fn from_bytes(x_bytes: &[u8]) -> Result { - let x_array: [u8; 32] = x_bytes - .try_into() - .map_err(|_| Error::InvalidInputLength(x_bytes.len()))?; - let x = k256::FieldBytes::from(x_array); + // Reject if the input is not 32 (naked), 33 (compressed) or 65 (uncompressed) bytes + let (x_bytes, y_is_odd) = match x_bytes.len() { + 32 => (x_bytes, false), // Assume even y-coordinate as even + 33 => { + if x_bytes[0] != 0x02 && x_bytes[0] != 0x03 { + return Err(Error::InvalidInputLength(x_bytes.len())); + } + (&x_bytes[1..], x_bytes[0] == 0x03) // y-coordinate parity + } + 65 => { + if x_bytes[0] != 0x04 { + return Err(Error::InvalidInputLength(x_bytes.len())); + } + // FIXME: Deserialize y-coordinate directly, instead of deriving it below + (&x_bytes[1..33], x_bytes[64] & 0x01 == 0x01) // y-coordinate parity + } + _ => return Err(Error::InvalidInputLength(x_bytes.len())), + }; + let x = k256::FieldBytes::from_slice(x_bytes); // Attempt to derive the corresponding y-coordinate - let ap_option = AffinePoint::decompress(&x, Choice::from(0)); + let ap_option = AffinePoint::decompress(x, Choice::from(y_is_odd as u8)); if ap_option.is_some().into() { let pk = k256::PublicKey::from_affine(ap_option.unwrap()) .map_err(|e| Error::EllipticCurveError(e.to_string()))?; @@ -212,10 +278,9 @@ impl PublicKey { let msg_hash: [u8; 32] = msg_hash .try_into() .map_err(|_| Error::InvalidInputLength(msg_hash.len()))?; - let p = self.inner.to_projective(); - let p_bytes = point_to_bytes(&p); - let r = new_pub_rand(pub_rand)?; - let r_bytes = point_to_bytes(&r); + let p_bytes = self.to_bytes(); + let r = PubRand::new(pub_rand)?; + let r_bytes = r.to_bytes(); let c = >::reduce_bytes( &tagged_hash(CHALLENGE_TAG) .chain_update(r_bytes) @@ -224,61 +289,68 @@ impl PublicKey { .finalize(), ); - let s = new_sig(sig)?; - let recovered_r = ProjectivePoint::mul_by_generator(&s) - p.mul(c); + let s = Signature::new(sig)?; + let recovered_r = + ProjectivePoint::mul_by_generator(&*s) - self.inner.to_projective().mul(c); - Ok(recovered_r.eq(&r)) + Ok(recovered_r.eq(&*r)) } -} -/// extract extracts the secret key from the public key, public -/// randomness, and two pairs of message hashes and signatures -pub fn extract( - pk: &PublicKey, - pub_rand: &[u8], - msg1_hash: &[u8], - sig1: &[u8], - msg2_hash: &[u8], - sig2: &[u8], -) -> Result { - if msg1_hash.len() != 32 { - return Err(Error::InvalidInputLength(msg1_hash.len())); - } - if msg2_hash.len() != 32 { - return Err(Error::InvalidInputLength(msg2_hash.len())); + /// `extract_secret_key` extracts the secret key from the public key, public randomness, + /// and two pairs of message hashes and signatures. + pub fn extract_secret_key( + &self, + pub_rand: &[u8], + msg1_hash: &[u8], + sig1: &[u8], + msg2_hash: &[u8], + sig2: &[u8], + ) -> Result { + if msg1_hash.len() != 32 { + return Err(Error::InvalidInputLength(msg1_hash.len())); + } + if msg2_hash.len() != 32 { + return Err(Error::InvalidInputLength(msg2_hash.len())); + } + let p_bytes = self.to_bytes(); + let r = PubRand::new(pub_rand)?; + let r_bytes = r.to_bytes(); + + // calculate e1 - e2 + let e1 = >::reduce_bytes( + &tagged_hash(CHALLENGE_TAG) + .chain_update(r_bytes.clone()) + .chain_update(p_bytes.clone()) + .chain_update(msg1_hash) + .finalize(), + ); + let e2 = >::reduce_bytes( + &tagged_hash(CHALLENGE_TAG) + .chain_update(r_bytes) + .chain_update(p_bytes) + .chain_update(msg2_hash) + .finalize(), + ); + let e_delta = e1 - e2; + + // calculate s1 - s2 + let s1 = Signature::new(sig1)?; + let s2 = Signature::new(sig2)?; + let s_delta = *s1 - *s2; + + // calculate (s1-s2) / (e1 - e2) + let inverted_e_delta = e_delta.invert().unwrap(); + let sk = s_delta * inverted_e_delta; + let sk = k256::SecretKey::new(sk.into()); + Ok(SecretKey { inner: sk }) } - let p = pk.inner.to_projective(); - let p_bytes = point_to_bytes(&p); - let r = new_pub_rand(pub_rand)?; - let r_bytes = point_to_bytes(&r); - - // calculate e1 - e2 - let e1 = >::reduce_bytes( - &tagged_hash(CHALLENGE_TAG) - .chain_update(r_bytes) - .chain_update(p_bytes) - .chain_update(msg1_hash) - .finalize(), - ); - let e2 = >::reduce_bytes( - &tagged_hash(CHALLENGE_TAG) - .chain_update(r_bytes) - .chain_update(p_bytes) - .chain_update(msg2_hash) - .finalize(), - ); - let e_delta = e1 - e2; - - // calculate s1 - s2 - let s1 = new_sig(sig1)?; - let s2 = new_sig(sig2)?; - let s_delta = s1 - s2; - - // calculate (s1-s2) / (e1 - e2) - let inverted_e_delta = e_delta.invert().unwrap(); - let sk = s_delta * inverted_e_delta; - let sk = k256::SecretKey::new(sk.into()); - Ok(SecretKey { inner: sk }) +} + +fn point_to_bytes(p: &ProjectivePoint) -> [u8; 32] { + let encoded_p = p.to_encoded_point(false); + // Extract the x-coordinate as bytes + let x_bytes = encoded_p.x().unwrap(); + x_bytes.as_slice().try_into().unwrap() // cannot fail } #[cfg(test)] @@ -288,12 +360,11 @@ mod tests { use sha2::{Digest, Sha256}; use test_utils::get_eots_testdata; - use k256::elliptic_curve::group::GroupEncoding; use k256::{ProjectivePoint, Scalar}; pub fn rand_gen() -> (SecRand, PubRand) { - let x = new_sec_rand(&Scalar::generate_vartime(&mut thread_rng()).to_bytes()).unwrap(); - let p = ProjectivePoint::mul_by_generator(&x); + let x = SecRand::new(&Scalar::generate_vartime(&mut thread_rng()).to_bytes()).unwrap(); + let p = PubRand::from(ProjectivePoint::mul_by_generator(&*x)); (x, p) } @@ -319,9 +390,9 @@ mod tests { let pk = sk.pubkey(); let (sec_rand, pub_rand) = rand_gen(); let msg_hash = [1u8; 32]; - let sig = sk.sign(&sec_rand.to_bytes(), &msg_hash); + let sig = sk.sign(&sec_rand.to_bytes(), &msg_hash).unwrap(); assert!(pk - .verify(&pub_rand.to_bytes(), &msg_hash, &sig.unwrap().to_bytes()) + .verify(&pub_rand.to_bytes(), &msg_hash, &sig.to_bytes()) .unwrap()); } @@ -335,15 +406,15 @@ mod tests { let sig1 = sk.sign(&sec_rand.to_bytes(), &msg_hash1).unwrap(); let sig2 = sk.sign(&sec_rand.to_bytes(), &msg_hash2).unwrap(); - let extracted_sk = extract( - &pk, - &pub_rand.to_bytes(), - &msg_hash1, - &sig1.to_bytes(), - &msg_hash2, - &sig2.to_bytes(), - ) - .unwrap(); + let extracted_sk = pk + .extract_secret_key( + &pub_rand.to_bytes(), + &msg_hash1, + &sig1.to_bytes(), + &msg_hash2, + &sig2.to_bytes(), + ) + .unwrap(); assert_eq!(sk.pubkey().to_bytes(), extracted_sk.pubkey().to_bytes()); } @@ -358,11 +429,11 @@ mod tests { // convert secret/public randomness to Rust types let sr_slice = hex::decode(testdata.sr).unwrap(); - let sr = new_sec_rand(&sr_slice).unwrap(); + let sr = SecRand::new(&sr_slice).unwrap(); let pr_slice = hex::decode(testdata.pr).unwrap(); let pr_bytes: [u8; 32] = pr_slice.try_into().unwrap(); - let pr = new_pub_rand(&pr_bytes).unwrap(); - assert_eq!(ProjectivePoint::mul_by_generator(&sr), pr); + let pr = PubRand::new(&pr_bytes).unwrap(); + assert_eq!(ProjectivePoint::mul_by_generator(&*sr), *pr); // convert messages let mut hasher = Sha256::new(); @@ -377,9 +448,9 @@ mod tests { // convert signatures let sig1_slice = hex::decode(testdata.sig1).unwrap(); - let sig1 = new_sig(&sig1_slice).unwrap(); + let sig1 = Signature::new(&sig1_slice).unwrap(); let sig2_slice = hex::decode(testdata.sig2).unwrap(); - let sig2 = new_sig(&sig2_slice).unwrap(); + let sig2 = Signature::new(&sig2_slice).unwrap(); // verify signatures assert!(pk @@ -390,15 +461,15 @@ mod tests { .unwrap()); // extract SK - let extracted_sk = extract( - &pk, - &pr.to_bytes(), - &msg1_hash, - &sig1.to_bytes(), - &msg2_hash, - &sig2.to_bytes(), - ) - .unwrap(); + let extracted_sk = pk + .extract_secret_key( + &pr.to_bytes(), + &msg1_hash, + &sig1.to_bytes(), + &msg2_hash, + &sig2.to_bytes(), + ) + .unwrap(); assert_eq!(sk.pubkey().to_bytes(), extracted_sk.pubkey().to_bytes()); } } diff --git a/packages/eots/src/lib.rs b/packages/eots/src/lib.rs index cbe81f8a..c9767d42 100644 --- a/packages/eots/src/lib.rs +++ b/packages/eots/src/lib.rs @@ -1,8 +1,6 @@ pub mod eots; pub mod error; -pub use eots::{ - extract, new_pub_rand, new_sec_rand, new_sig, PubRand, PublicKey, SecRand, SecretKey, Signature, -}; +pub use eots::{PubRand, PublicKey, SecRand, SecretKey, Signature}; pub use error::Error; pub type Result = std::result::Result;