frost_bluepallas/
negate.rs1use frost_core::{
4 round1::{Nonce, NonceCommitment, SigningCommitments, SigningNonces},
5 SigningPackage,
6};
7
8use crate::{BluePallas, ChallengeMessage};
9
10pub(crate) trait NegateY {
13 fn negate_y(&self) -> Self;
15}
16
17impl<M> NegateY for SigningNonces<BluePallas<M>>
18where
19 M: ChallengeMessage,
20{
21 fn negate_y(&self) -> Self {
22 let negated_hiding = -self.hiding().to_scalar();
23 let negated_binding = -self.binding().to_scalar();
24 SigningNonces::from_nonces(
25 Nonce::<BluePallas<M>>::from_scalar(negated_hiding),
26 Nonce::<BluePallas<M>>::from_scalar(negated_binding),
27 )
28 }
29}
30
31impl<M> NegateY for SigningCommitments<BluePallas<M>>
33where
34 M: ChallengeMessage,
35{
36 fn negate_y(&self) -> Self {
37 let negated_hiding = -self.hiding().value();
39 let negated_binding = -self.binding().value();
40
41 let negated_hiding_nonce = NoncePallas::<M>::new(negated_hiding);
43 let negated_binding_nonce = NoncePallas::<M>::new(negated_binding);
44
45 SigningCommitments::new(negated_hiding_nonce, negated_binding_nonce)
46 }
47}
48
49type NoncePallas<M> = NonceCommitment<BluePallas<M>>;
50
51impl<M> NegateY for SigningPackage<BluePallas<M>>
53where
54 M: ChallengeMessage,
55{
56 fn negate_y(&self) -> Self {
57 let negated_commitments = self
58 .signing_commitments()
59 .iter()
60 .map(|(id, commitment)| (*id, commitment.negate_y()))
61 .collect();
62 SigningPackage::new(negated_commitments, self.message())
63 }
64}
65
66#[cfg(test)]
67mod tests {
68 use crate::{
69 hasher::hash_to_scalar, BluePallas, ChallengeMessage, PallasGroup, PallasScalarField,
70 };
71
72 use super::*;
73 use alloc::collections::BTreeMap;
74 use ark_ff::UniformRand;
75 use frost_core::{
76 round1::{Nonce, NonceCommitment},
77 Group,
78 };
79 use mina_curves::pasta::ProjectivePallas;
80 use rand_core::OsRng;
81
82 #[derive(Clone, Debug, PartialEq, Eq)]
83 struct TestMessage;
84
85 impl ChallengeMessage for TestMessage {
86 fn challenge(
87 _r: &frost_core::Element<BluePallas<Self>>,
88 _verifying_key: &frost_core::VerifyingKey<BluePallas<Self>>,
89 message: &[u8],
90 ) -> Result<frost_core::Challenge<BluePallas<Self>>, frost_core::Error<BluePallas<Self>>>
91 {
92 Ok(frost_core::Challenge::from_scalar(hash_to_scalar(&[
93 b"test-challenge",
94 message,
95 ])))
96 }
97 }
98
99 type Suite = BluePallas<TestMessage>;
100 type SigningNonces = frost_core::round1::SigningNonces<Suite>;
101 type SigningCommitments = frost_core::round1::SigningCommitments<Suite>;
102 type SigningPackage = frost_core::SigningPackage<Suite>;
103
104 fn commit_to_group(c: &NonceCommitment<Suite>) -> ProjectivePallas {
106 c.value()
107 }
108
109 #[test]
110 fn signing_nonces_negate_y_inverts_scalars() {
111 let mut rng = OsRng;
112 let r1 = <PallasScalarField as frost_core::Field>::Scalar::rand(&mut rng);
114 let r2 = <PallasScalarField as frost_core::Field>::Scalar::rand(&mut rng);
115 let nonces = SigningNonces::from_nonces(
116 Nonce::<Suite>::from_scalar(r1),
117 Nonce::<Suite>::from_scalar(r2),
118 );
119
120 let neg = nonces.negate_y();
121
122 let orig_h = nonces.hiding().to_scalar();
124 let new_h = neg.hiding().to_scalar();
125 assert_eq!(
126 orig_h + new_h,
127 <PallasScalarField as frost_core::Field>::zero()
128 );
129
130 let orig_b = nonces.binding().to_scalar();
132 let new_b = neg.binding().to_scalar();
133 assert_eq!(
134 orig_b + new_b,
135 <PallasScalarField as frost_core::Field>::zero()
136 );
137 }
138
139 #[test]
140 fn signing_commitments_negate_y_inverts_group_elements() {
141 let g = PallasGroup::generator();
143 let g_ser = PallasGroup::serialize(&g).unwrap();
144 let comm = NonceCommitment::<Suite>::deserialize(&g_ser).unwrap();
145
146 let commitments = SigningCommitments::new(comm, comm);
147 let neg = commitments.negate_y();
148
149 let orig_h = commit_to_group(commitments.hiding());
151 let new_h = commit_to_group(neg.hiding());
152 assert_eq!(new_h, -orig_h);
153
154 let orig_b = commit_to_group(commitments.binding());
156 let new_b = commit_to_group(neg.binding());
157 assert_eq!(new_b, -orig_b);
158 }
159
160 #[test]
161 fn signing_package_negate_y_inverts_all_commitments_and_preserves_message() {
162 let g = PallasGroup::generator();
164 let g_ser = PallasGroup::serialize(&g).unwrap();
165 let comm = NonceCommitment::<Suite>::deserialize(&g_ser).unwrap();
166 let single = SigningCommitments::new(comm, comm);
167
168 let mut map: BTreeMap<frost_core::Identifier<Suite>, SigningCommitments> = BTreeMap::new();
169 let participant_identifier = frost_core::Identifier::try_from(1u16).unwrap();
170 map.insert(participant_identifier, single);
171 let message = b"hello frost".to_vec();
172
173 let pkg = SigningPackage::new(map.clone(), message.as_slice());
174 let neg_pkg = pkg.negate_y();
175
176 assert_eq!(neg_pkg.message(), &message[..]);
178
179 for (id, neg_comm) in neg_pkg.signing_commitments() {
181 let orig = &map[id];
182 let orig_h = commit_to_group(orig.hiding());
183 let new_h = commit_to_group(neg_comm.hiding());
184 assert_eq!(new_h, -orig_h);
185
186 let orig_b = commit_to_group(orig.binding());
187 let new_b = commit_to_group(neg_comm.binding());
188 assert_eq!(new_b, -orig_b);
189 }
190 }
191}