confium_tc_cmp20/
inprocess.rs1use elliptic_curve::sec1::ToSec1Point;
27use p256::AffinePoint;
28
29use confium_tc::Result;
30use confium_tc::inprocess as driver;
31
32use crate::share::Cmp20Share;
33
34#[derive(Debug, Clone)]
37pub struct KeygenOutput {
38 pub shares: Vec<Vec<u8>>,
41 pub public_key: Vec<u8>,
43}
44
45pub fn keygen(threshold: u32, party_count: usize) -> Result<KeygenOutput> {
51 let shares = driver::run_dkg(crate::DKG_SCHEME_NAME, threshold, party_count)?;
52 let first = Cmp20Share::from_bytes(&shares[0])?;
53 let public_key: Vec<u8> = first.public_key.to_sec1_point(true).as_bytes().to_vec();
54 Ok(KeygenOutput { shares, public_key })
55}
56
57pub fn sign(share_blobs: &[Vec<u8>], threshold: u32, message: &[u8]) -> Result<Vec<u8>> {
65 driver::run_sign(crate::SIGN_SCHEME_NAME, share_blobs, threshold, message)
66}
67
68pub fn sign_batch(
84 share_blobs: &[Vec<u8>],
85 threshold: u32,
86 messages: &[&[u8]],
87) -> Result<Vec<Vec<u8>>> {
88 let mut out = Vec::with_capacity(messages.len());
89 for msg in messages {
90 out.push(sign(share_blobs, threshold, msg)?);
91 }
92 Ok(out)
93}
94
95pub fn decode_public_key(bytes: &[u8]) -> Result<AffinePoint> {
98 use elliptic_curve::sec1::FromSec1Point;
99 if bytes.len() != 33 {
100 return Err(crate::error::scheme_error(
101 crate::error::Cmp20ErrorCode::BAD_SHARE,
102 ));
103 }
104 let enc = elliptic_curve::sec1::Sec1Point::<p256::NistP256>::from_bytes(bytes)
105 .map_err(|_| crate::error::scheme_error(crate::error::Cmp20ErrorCode::BAD_SHARE))?;
106 Option::<AffinePoint>::from(AffinePoint::from_sec1_point(&enc))
107 .ok_or_else(|| crate::error::scheme_error(crate::error::Cmp20ErrorCode::BAD_SHARE))
108}
109
110#[cfg(test)]
111mod tests {
112 use super::*;
113 use p256::ecdsa::{Signature, VerifyingKey, signature::Verifier};
114
115 #[test]
116 fn keygen_and_sign_round_trip() {
117 let kg = keygen(2, 3).expect("dkg");
118 assert_eq!(kg.shares.len(), 3);
119 assert_eq!(kg.public_key.len(), 33);
120
121 let sig = sign(&kg.shares[..2], 2, b"hello cmp20").expect("sign");
122 assert_eq!(sig.len(), 64);
123
124 let pk = decode_public_key(&kg.public_key).expect("pk decode");
125 let vk = VerifyingKey::from_affine(pk).expect("vk");
126 let s = Signature::from_slice(&sig).expect("parse sig");
127 vk.verify(b"hello cmp20", &s).expect("verify ok");
128 }
129
130 #[test]
131 fn keygen_below_threshold_sign_errors() {
132 let kg = keygen(3, 5).expect("dkg");
133 let err = sign(&kg.shares[..2], 3, b"msg");
134 assert!(err.is_err());
135 }
136
137 #[test]
138 fn keygen_full_committee_signs_and_verifies() {
139 let kg = keygen(3, 3).expect("dkg");
140 let sig = sign(&kg.shares, 3, b"all-three").expect("sign");
141 let pk = decode_public_key(&kg.public_key).expect("pk decode");
142 let vk = VerifyingKey::from_affine(pk).expect("vk");
143 let s = Signature::from_slice(&sig).expect("parse sig");
144 vk.verify(b"all-three", &s).expect("verify ok");
145 }
146
147 #[test]
148 fn keygen_rejects_corrupt_share_magic() {
149 let kg = keygen(2, 3).expect("dkg");
150 let mut corrupt = kg.shares[0].clone();
151 corrupt[0] = b'X';
152 let err = sign(&[corrupt], 1, b"msg");
153 assert!(err.is_err());
154 }
155
156 #[test]
157 fn sign_batch_produces_one_sig_per_message() {
158 let kg = keygen(2, 3).expect("dkg");
159 let messages: Vec<&[u8]> = vec![b"msg-a", b"msg-b", b"msg-c", b"msg-d"];
160 let sigs = sign_batch(&kg.shares[..2], 2, &messages).expect("batch sign");
161 assert_eq!(sigs.len(), 4);
162 for s in &sigs {
163 assert_eq!(s.len(), 64);
164 }
165 }
166
167 #[test]
168 fn sign_batch_all_verify_under_joint_public_key() {
169 use p256::ecdsa::{Signature, VerifyingKey, signature::Verifier};
170 let kg = keygen(2, 3).expect("dkg");
171 let messages: Vec<&[u8]> = vec![b"a", b"b", b"c"];
172 let sigs = sign_batch(&kg.shares[..2], 2, &messages).expect("batch sign");
173 let pk = decode_public_key(&kg.public_key).expect("pk");
174 let vk = VerifyingKey::from_affine(pk).expect("vk");
175 for (msg, sig) in messages.iter().zip(sigs.iter()) {
176 let s = Signature::from_slice(sig).expect("parse sig");
177 vk.verify(msg, &s).expect("verify");
178 }
179 }
180}