spark_cryptography/utils.rs
1// use k256::{Scalar, elliptic_curve::PrimeField};
2// use num_traits::Num;
3
4// use crate::secp256k1::{CURVE_ORDER, CURVE_RADIX};
5
6// /// Converts a BigInt (shamir_secret_sharing::num_bigint::BigInt) to a k256 Scalar.
7// pub(crate) fn int_to_k256_scalar(value: &BigInt) -> Scalar {
8// // 1) Reduce the entire BigInt modulo the secp256k1 group order.
9// let curve_order =
10// BigInt::from_str_radix(CURVE_ORDER, CURVE_RADIX).expect("invalid curve order constant");
11// let reduced_value = value % &curve_order;
12
13// // 2) Apply zero-padding if the array is less than 32 bytes.
14// let mut be_bytes = reduced_value.to_bytes_be().1;
15// if be_bytes.len() < 32 {
16// // zero-pad if less than 32 bytes
17// let mut padded = vec![0u8; 32];
18// padded[32 - be_bytes.len()..].copy_from_slice(&be_bytes);
19// be_bytes = padded;
20// }
21
22// let mut be_bytes_array = [0u8; 32];
23// be_bytes_array.copy_from_slice(&be_bytes);
24
25// // 3) Use from_be_bytes to get the final Scalar,
26// // which is in [0, n-1].
27// Scalar::from_repr_vartime(be_bytes_array.into())
28// .expect("reduced_value was < n, so this scalar is valid")
29// }
30
31// #[cfg(test)]
32// mod tests {
33// use num_traits::Zero;
34// use rand::Rng;
35
36// use super::*;
37
38// /// Parses the curve order into a BigInt (shamir_secret_sharing::num_bigint::BigInt).
39// fn get_curve_order_as_bigint() -> BigInt {
40// BigInt::from_str_radix(CURVE_ORDER, CURVE_RADIX).expect("invalid curve order constant")
41// }
42
43// #[test]
44// fn test_int_to_scalar_k256_small() {
45// // zero
46// let zero_bigint = BigInt::zero();
47// let zero_scalar = int_to_k256_scalar(&zero_bigint);
48
49// // convert scalar back to BigInt for checking
50// let zero_scalar_bigint = BigInt::from_bytes_be(
51// shamir_secret_sharing::num_bigint::Sign::Plus,
52// &zero_scalar.to_bytes(),
53// );
54
55// // ensure it's indeed zero
56// assert_eq!(zero_scalar_bigint, BigInt::zero());
57
58// // small BigInt, e.g. 123
59// let small = BigInt::from(123u32);
60// let small_scalar = int_to_k256_scalar(&small);
61// let small_scalar_bigint = BigInt::from_bytes_be(
62// shamir_secret_sharing::num_bigint::Sign::Plus,
63// &small_scalar.to_bytes(),
64// );
65// assert_eq!(small, small_scalar_bigint);
66// // also ensure it's < n
67// let curve_order = get_curve_order_as_bigint();
68// assert!(small_scalar_bigint < curve_order);
69// }
70
71// #[test]
72// fn test_int_to_scalar_k256_32_bytes() {
73// // 32 bytes => let's pick a random 256-bit number
74// let mut rng = rand::thread_rng();
75// let mut random_32 = [0u8; 32];
76// rng.fill(&mut random_32);
77
78// let bigint_32 =
79// BigInt::from_bytes_be(shamir_secret_sharing::num_bigint::Sign::Plus, &random_32);
80// let scalar_32 = int_to_k256_scalar(&bigint_32);
81// let scalar_32_bigint = BigInt::from_bytes_be(
82// shamir_secret_sharing::num_bigint::Sign::Plus,
83// &scalar_32.to_bytes(),
84// );
85
86// // Now, scalar_32_bigint should match bigint_32 % n
87// let curve_order = get_curve_order_as_bigint();
88// let expected_mod = &bigint_32 % &curve_order;
89// assert_eq!(scalar_32_bigint, expected_mod);
90// assert!(scalar_32_bigint < curve_order);
91// }
92
93// #[test]
94// fn test_int_to_scalar_k256_oversized() {
95// // create a 48-byte random buffer
96// let mut rng = rand::thread_rng();
97// let mut random_oversized = vec![0u8; 48];
98// rng.fill(&mut random_oversized[..]);
99
100// let bigint_oversized = BigInt::from_bytes_be(
101// shamir_secret_sharing::num_bigint::Sign::Plus,
102// &random_oversized,
103// );
104
105// let scalar_oversized = int_to_k256_scalar(&bigint_oversized);
106// let scalar_oversized_bigint = BigInt::from_bytes_be(
107// shamir_secret_sharing::num_bigint::Sign::Plus,
108// &scalar_oversized.to_bytes(),
109// );
110
111// // The function automatically slices to 32 bytes, then reduces mod n
112// let curve_order = get_curve_order_as_bigint();
113// assert!(scalar_oversized_bigint < curve_order, "result must be < n");
114
115// // Also verify equivalence to forcibly truncated 32 bytes once modded by n
116// // Basically: let truncated = last 32 bytes of random_oversized => big-int => mod n.
117// // But since from_be_bytes also does mod reduction, they should match that mod result.
118// let actual_mod = &bigint_oversized % &curve_order;
119// assert_eq!(scalar_oversized_bigint, actual_mod);
120// }
121
122// #[test]
123// fn test_int_to_scalar_k256_valid_range() {
124// let curve_order = get_curve_order_as_bigint();
125// // Try 10 random inputs
126// for _ in 0..10 {
127// let mut rng = rand::thread_rng();
128// let mut random_64 = vec![0u8; 64];
129// rng.fill(&mut random_64[..]);
130
131// let big_val =
132// BigInt::from_bytes_be(shamir_secret_sharing::num_bigint::Sign::Plus, &random_64);
133// let result_scalar = int_to_k256_scalar(&big_val);
134
135// // check that the result is < n
136// let result_scalar_bigint = BigInt::from_bytes_be(
137// shamir_secret_sharing::num_bigint::Sign::Plus,
138// &result_scalar.to_bytes(),
139// );
140// assert!(result_scalar_bigint < curve_order);
141// }
142// }
143// }