1use crypto_bigint::modular::constant_mod::ResidueParams;
4use crypto_bigint::{const_residue, U256};
5use zeroize::{Zeroize, ZeroizeOnDrop};
6
7use crate::crypto::{Random32Bytes, Secp256k1Order};
8use crate::errors::{ArithmeticError, Error};
9
10#[derive(Zeroize, ZeroizeOnDrop)]
14pub struct SecretShare([u8; 32]);
15
16impl From<Random32Bytes> for SecretShare {
17 fn from(value: Random32Bytes) -> Self {
19 Self(value.to_be_bytes())
20 }
21}
22
23impl From<U256> for SecretShare {
24 fn from(value: U256) -> Self {
26 Self(Random32Bytes::from(value).to_be_bytes())
27 }
28}
29
30impl SecretShare {
31 pub fn as_u256(&self) -> U256 {
33 U256::from_be_slice(&self.0)
34 }
35
36 pub fn to_be_bytes(&self) -> [u8; 32] {
38 self.0
39 }
40}
41
42impl TryFrom<&[u8]> for SecretShare {
43 type Error = Error;
44
45 fn try_from(slice: &[u8]) -> Result<Self, Self::Error> {
47 Ok(Self(Random32Bytes::try_from(slice)?.to_be_bytes()))
48 }
49}
50
51#[derive(Clone, Zeroize, ZeroizeOnDrop)]
55pub struct SigningShare([u8; 32]);
56
57impl SigningShare {
58 pub fn generate() -> Self {
60 Self(Random32Bytes::generate().to_be_bytes())
61 }
62
63 pub fn to_be_bytes(&self) -> [u8; 32] {
65 self.0
66 }
67}
68
69impl From<Random32Bytes> for SigningShare {
70 fn from(value: Random32Bytes) -> Self {
72 Self(value.to_be_bytes())
73 }
74}
75
76impl TryFrom<&[u8]> for SigningShare {
77 type Error = Error;
78
79 fn try_from(slice: &[u8]) -> Result<Self, Self::Error> {
81 if slice.len() == 32 {
83 Ok(Self(slice.try_into().map_err(|_| Error::Encoding)?))
84 } else {
85 Err(Error::Encoding)
86 }
87 }
88}
89
90#[derive(Clone, PartialEq, Eq, Zeroize, ZeroizeOnDrop)]
94pub struct SubShare {
95 x: U256,
96 y: U256,
97}
98
99impl SubShare {
100 pub fn new(x: U256, y: U256) -> Result<Self, ArithmeticError> {
102 if x < Secp256k1Order::MODULUS && y < Secp256k1Order::MODULUS {
104 Ok(Self { x, y })
105 } else {
106 Err(ArithmeticError::ModulusOverflow)
107 }
108 }
109
110 pub fn x(&self) -> U256 {
112 self.x
113 }
114
115 pub fn y(&self) -> U256 {
117 self.y
118 }
119
120 pub fn as_tuple(&self) -> (U256, U256) {
122 (self.x, self.y)
123 }
124}
125
126#[derive(Zeroize, ZeroizeOnDrop)]
127pub struct SubShareInterpolator {
128 gradient: U256,
129 intercept: U256,
130}
131
132impl SubShareInterpolator {
133 pub fn new(point_a: &SubShare, point_b: &SubShare) -> Self {
137 let x_1 = point_a.x;
143 let y_1 = point_a.y;
144 let x_2 = point_b.x;
145 let y_2 = point_b.y;
146 let dy = const_residue!(y_1, Secp256k1Order) - const_residue!(y_2, Secp256k1Order);
147 let dx = const_residue!(x_1, Secp256k1Order) - const_residue!(x_2, Secp256k1Order);
148 let gradient = dy * dx.invert().0;
149
150 let intercept_mod =
152 const_residue!(y_1, Secp256k1Order) - (gradient * const_residue!(x_1, Secp256k1Order));
153
154 Self {
155 gradient: gradient.retrieve(),
156 intercept: intercept_mod.retrieve(),
157 }
158 }
159
160 pub fn secret(&self) -> U256 {
162 self.intercept
163 }
164
165 pub fn sub_share(&self, idx: U256) -> Result<SubShare, ArithmeticError> {
167 if idx < Secp256k1Order::MODULUS && U256::ZERO < idx {
171 let gradient = self.gradient;
173 let intercept = self.intercept;
174 let y_coord = (const_residue!(gradient, Secp256k1Order)
175 * const_residue!(idx, Secp256k1Order))
176 + const_residue!(intercept, Secp256k1Order);
177
178 Ok(SubShare {
179 x: idx,
180 y: y_coord.retrieve(),
181 })
182 } else {
183 Err(ArithmeticError::ModulusOverflow)
184 }
185 }
186}
187
188#[cfg(test)]
189mod tests {
190 use super::*;
191
192 #[test]
193 fn sub_share_interpolator_works() {
194 let secret_share = U256::ONE;
197 let sub_share_0 = SubShare::new(U256::ZERO, secret_share).unwrap();
198
199 let sub_share_1 = SubShare::new(U256::ONE, U256::from(2u8)).unwrap();
201
202 let split_sub_share_interpolator = SubShareInterpolator::new(&sub_share_0, &sub_share_1);
204
205 let sub_share_2 = SubShare::new(U256::from(2u8), U256::from(3u8)).unwrap();
207
208 assert_eq!(
210 split_sub_share_interpolator
211 .sub_share(U256::from(2u8))
212 .unwrap()
213 .as_tuple(),
214 sub_share_2.as_tuple()
215 );
216
217 let reconstruct_sub_share_interpolator =
219 SubShareInterpolator::new(&sub_share_1, &sub_share_2);
220
221 assert_eq!(&reconstruct_sub_share_interpolator.secret(), &secret_share);
223 }
224}