efficient_sm2/ec/
signing.rs

1// Copyright 2020 Yao Pengfei.
2//
3// Permission to use, copy, modify, and/or distribute this software for any
4// purpose with or without fee is hereby granted, provided that the above
5// copyright notice and this permission notice appear in all copies.
6//
7// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
8// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
10// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14
15use crate::ec::verification::Signature;
16use crate::elem::{
17    elem_reduced_to_scalar, elem_to_unencoded, scalar_add, scalar_inv_to_mont, scalar_mul,
18    scalar_sub, scalar_to_unencoded, Elem, Scalar, R,
19};
20use crate::err::KeyRejectedError;
21use crate::jacobian::exchange::affine_from_jacobian;
22use crate::key::private::create_private_key;
23use crate::key::public::PublicKey;
24use crate::limb::{LIMB_LENGTH, ONE};
25use crate::norop::parse_big_endian;
26use crate::rand::{DefaultRand, SecureRandom};
27use crate::sm2p256::{base_point_mul, scalar_to_mont};
28use core::marker::PhantomData;
29
30#[derive(Clone)]
31pub struct KeyPair {
32    d: Scalar<R>, // *R*
33    pk: PublicKey,
34}
35
36impl KeyPair {
37    pub fn new(private_key: &[u8]) -> Result<Self, KeyRejectedError> {
38        let mut key_limb = [0; LIMB_LENGTH];
39        parse_big_endian(&mut key_limb, private_key)?;
40        let d = Scalar {
41            limbs: scalar_to_mont(&key_limb),
42            m: PhantomData,
43        };
44        let pk = PublicKey::public_from_private(&d)?;
45        Ok(KeyPair { d, pk })
46    }
47
48    pub fn public_key(&self) -> PublicKey {
49        self.pk
50    }
51
52    pub fn sign(&self, message: &[u8]) -> Result<Signature, KeyRejectedError> {
53        let ctx = libsm::sm2::signature::SigCtx::new();
54        let pk_point = ctx
55            .load_pubkey(self.pk.bytes_less_safe())
56            .map_err(|e| KeyRejectedError::LibSmError(format!("{e}")))?;
57        let digest = ctx
58            .hash("1234567812345678", &pk_point, message)
59            .map_err(|e| KeyRejectedError::LibSmError(format!("{e}")))?;
60
61        self.sign_digest(&mut DefaultRand(rand::thread_rng()), &digest)
62    }
63
64    pub fn sign_with_seed(
65        &self,
66        rng: &mut dyn SecureRandom,
67        message: &[u8],
68    ) -> Result<Signature, KeyRejectedError> {
69        let ctx = libsm::sm2::signature::SigCtx::new();
70        let pk_point = ctx
71            .load_pubkey(self.pk.bytes_less_safe())
72            .map_err(|e| KeyRejectedError::LibSmError(format!("{e}")))?;
73        let digest = ctx
74            .hash("1234567812345678", &pk_point, message)
75            .map_err(|e| KeyRejectedError::LibSmError(format!("{e}")))?;
76
77        self.sign_digest(rng, &digest)
78    }
79
80    pub fn sign_digest(
81        &self,
82        rng: &mut dyn SecureRandom,
83        digest: &[u8],
84    ) -> Result<Signature, KeyRejectedError> {
85        for _ in 0..100 {
86            #[allow(unused_variables)]
87            let rk = create_private_key(rng)?;
88
89            // todo, the repo in wip state, keep this for testing basic
90            // algorithm correctness
91            #[cfg(test)]
92            let rk = Scalar {
93                limbs: [
94                    0xb9670787642a68de,
95                    0x3b4a6247824f5d33,
96                    0xa280f245f9e93c7f,
97                    0x94a1bbb14b906a61,
98                ],
99                m: PhantomData,
100            };
101
102            let rq = base_point_mul(&rk.limbs);
103
104            let r = {
105                let (x, _) = affine_from_jacobian(&rq)?;
106                let x = elem_to_unencoded(&x);
107                elem_reduced_to_scalar(&x)
108            };
109            if r.is_zero() {
110                continue;
111            }
112
113            let mut dl = [0; LIMB_LENGTH];
114            parse_big_endian(&mut dl, digest)?;
115            let edl = Elem {
116                limbs: dl,
117                m: PhantomData,
118            };
119            let e = elem_reduced_to_scalar(&edl);
120
121            static SCALAR_ONE: Scalar = Scalar {
122                limbs: ONE,
123                m: PhantomData,
124            };
125
126            let r = scalar_add(&r, &e);
127
128            let da_ue = scalar_to_unencoded(&self.d);
129            let left = scalar_inv_to_mont(&scalar_add(&da_ue, &SCALAR_ONE));
130            let dr = scalar_mul(&self.d, &r);
131            let right = scalar_sub(&rk, &dr);
132            let s = scalar_mul(&left, &right);
133
134            // todo, the repo in wip state, keep this for testing basic
135            // algorithm correctness
136            #[cfg(test)]
137            {
138                assert_eq!(
139                    r.limbs,
140                    [
141                        0x36bbb9347abf074f,
142                        0x25b0f810baf864c4,
143                        0x1b87443325f3afd4,
144                        0xd6297b17c1cdf71a
145                    ]
146                );
147                assert_eq!(
148                    s.limbs,
149                    [
150                        0xb4075ea90353bfe1,
151                        0xe827e9a226326c4e,
152                        0xd768d0b8cf81bc40,
153                        0xde7692f608e19f41
154                    ]
155                );
156            }
157
158            return Ok(Signature::from_scalars(r, s));
159        }
160        Err(KeyRejectedError::SignDigestFailed)
161    }
162}
163
164#[cfg(test)]
165mod tests {
166    use super::*;
167
168    #[test]
169    fn sign_verify_test() {
170        let test_word = hex::decode("5905238877c77421f73e43ee3da6f2d9e2ccad5fc942dcec0cbd25482935faaf416983fe165b1a045ee2bcd2e6dca3bdf46c4310a7461f9a37960ca672d3feb5473e253605fb1ddfd28065b53cb5858a8ad28175bf9bd386a5e471ea7a65c17cc934a9d791e91491eb3754d03799790fe2d308d16146d5c9b0d0debd97d79ce8").unwrap();
171        let private_key =
172            hex::decode("b8aa2a5bd9a9cf448984a247e63cb3878859d02b886e1bc63cd5c6dd46a744ab")
173                .unwrap();
174        let key_pair = KeyPair::new(&private_key).unwrap();
175
176        let sig = key_pair.sign(&test_word).unwrap();
177
178        println!(
179            "pk: {}, r: {}, s: {}",
180            hex::encode(key_pair.pk.bytes_less_safe()),
181            hex::encode(&sig.r()),
182            hex::encode(&sig.s())
183        );
184
185        sig.verify(&key_pair.public_key(), &test_word).unwrap()
186    }
187
188    #[test]
189    fn free_input_verify() {
190        let msg = b"hello world";
191
192        let pk = PublicKey::new(
193            &hex::decode("B0E4E03D589C97375BBD6EA49483DD976FB88BBB0C07C72827CD8808B5794D5E")
194                .unwrap(),
195            &hex::decode("2881721E8D9BF56E81FC1E0C325F4FFC052E67FC3A31510D66E7B8749B93B636")
196                .unwrap(),
197        );
198
199        let sig = Signature::new(
200            &hex::decode("45FACCE4BDE9B8A34D43E6060210928802878DDD86A6EAE2938313A165F9F100")
201                .unwrap(),
202            &hex::decode("D9656DA4EC90FB2EFA399C0ECC6301882CA3301925281C58C2E29D9FD6F9C221")
203                .unwrap(),
204        )
205        .unwrap();
206
207        assert!(sig.verify(&pk, msg).is_ok());
208
209        let pk = PublicKey::from_slice(
210            &hex::decode("B0E4E03D589C97375BBD6EA49483DD976FB88BBB0C07C72827CD8808B5794D5E2881721E8D9BF56E81FC1E0C325F4FFC052E67FC3A31510D66E7B8749B93B636")
211                .unwrap(),
212        );
213
214        assert!(sig.verify(&pk, msg).is_ok());
215
216        let sig = Signature::from_slice(
217            &hex::decode("45FACCE4BDE9B8A34D43E6060210928802878DDD86A6EAE2938313A165F9F100D9656DA4EC90FB2EFA399C0ECC6301882CA3301925281C58C2E29D9FD6F9C221")
218                .unwrap(),
219        ).unwrap();
220
221        assert!(sig.verify(&pk, msg).is_ok());
222    }
223}
224
225#[cfg(feature = "internal_benches")]
226mod sign_bench {
227    use super::*;
228    use rand::prelude::ThreadRng;
229    use rand::Rng;
230
231    extern crate test;
232
233    #[bench]
234    fn es_sign_bench(bench: &mut test::Bencher) {
235        pub struct EgRand(ThreadRng);
236
237        impl SecureRandom for EgRand {
238            fn fill(&mut self, dest: &mut [u8]) {
239                self.0.fill(dest)
240            }
241        }
242
243        let test_word = hex::decode("5905238877c77421f73e43ee3da6f2d9e2ccad5fc942dcec0cbd25482935faaf416983fe165b1a045ee2bcd2e6dca3bdf46c4310a7461f9a37960ca672d3feb5473e253605fb1ddfd28065b53cb5858a8ad28175bf9bd386a5e471ea7a65c17cc934a9d791e91491eb3754d03799790fe2d308d16146d5c9b0d0debd97d79ce8").unwrap();
244        let mut rng = EgRand(rand::thread_rng());
245
246        let private_key =
247            hex::decode("b8aa2a5bd9a9cf448984a247e63cb3878859d02b886e1bc63cd5c6dd46a744ab")
248                .unwrap();
249
250        let key_pair = KeyPair::new(&private_key).unwrap();
251
252        bench.iter(|| {
253            let _ = key_pair.sign_with_seed(&mut rng, &test_word).unwrap();
254        });
255    }
256
257    #[bench]
258    fn libsm_sign_bench(bench: &mut test::Bencher) {
259        let test_word = b"hello world";
260        let ctx = libsm::sm2::signature::SigCtx::new();
261        let (pk, sk) = ctx.new_keypair().unwrap();
262
263        bench.iter(|| {
264            let _ = ctx.sign(test_word, &sk, &pk);
265        });
266    }
267
268    #[bench]
269    fn es_sign_without_sm3_bench(bench: &mut test::Bencher) {
270        pub struct EgRand(ThreadRng);
271
272        impl SecureRandom for EgRand {
273            fn fill(&mut self, dest: &mut [u8]) {
274                self.0.fill(dest)
275            }
276        }
277
278        let test_word = hex::decode("5905238877c77421f73e43ee3da6f2d9e2ccad5fc942dcec0cbd25482935faaf416983fe165b1a045ee2bcd2e6dca3bdf46c4310a7461f9a37960ca672d3feb5473e253605fb1ddfd28065b53cb5858a8ad28175bf9bd386a5e471ea7a65c17cc934a9d791e91491eb3754d03799790fe2d308d16146d5c9b0d0debd97d79ce8").unwrap();
279        let mut rng = EgRand(rand::thread_rng());
280
281        let private_key =
282            hex::decode("b8aa2a5bd9a9cf448984a247e63cb3878859d02b886e1bc63cd5c6dd46a744ab")
283                .unwrap();
284        let key_pair = KeyPair::new(&private_key).unwrap();
285
286        let ctx = libsm::sm2::signature::SigCtx::new();
287        let pk_point = ctx
288            .load_pubkey(key_pair.pk.bytes_less_safe())
289            .map_err(|e| KeyRejectedError::LibSmError(format!("{e}")))
290            .unwrap();
291        let digest = ctx
292            .hash("1234567812345678", &pk_point, &test_word)
293            .map_err(|e| KeyRejectedError::LibSmError(format!("{e}")))
294            .unwrap();
295
296        bench.iter(|| {
297            let _ = key_pair.sign_digest(&mut rng, &digest).unwrap();
298        });
299    }
300
301    #[bench]
302    fn libsm_sign_without_sm3_bench(bench: &mut test::Bencher) {
303        let test_word = b"hello world";
304        let ctx = libsm::sm2::signature::SigCtx::new();
305        let (pk, sk) = ctx.new_keypair().unwrap();
306        let digest = ctx.hash("1234567812345678", &pk, test_word).unwrap();
307
308        bench.iter(|| {
309            let _ = ctx.sign_raw(&digest, &sk);
310        });
311    }
312
313    #[bench]
314    fn es_verify_bench(bench: &mut test::Bencher) {
315        pub struct EgRand(ThreadRng);
316
317        impl SecureRandom for EgRand {
318            fn fill(&mut self, dest: &mut [u8]) {
319                self.0.fill(dest)
320            }
321        }
322
323        let test_word = hex::decode("5905238877c77421f73e43ee3da6f2d9e2ccad5fc942dcec0cbd25482935faaf416983fe165b1a045ee2bcd2e6dca3bdf46c4310a7461f9a37960ca672d3feb5473e253605fb1ddfd28065b53cb5858a8ad28175bf9bd386a5e471ea7a65c17cc934a9d791e91491eb3754d03799790fe2d308d16146d5c9b0d0debd97d79ce8").unwrap();
324        let mut rng = EgRand(rand::thread_rng());
325
326        let private_key =
327            hex::decode("b8aa2a5bd9a9cf448984a247e63cb3878859d02b886e1bc63cd5c6dd46a744ab")
328                .unwrap();
329        let key_pair = KeyPair::new(&private_key).unwrap();
330        let sig = key_pair.sign_with_seed(&mut rng, &test_word).unwrap();
331        let pk = key_pair.public_key();
332
333        bench.iter(|| {
334            let _ = sig.verify(&pk, &test_word).unwrap();
335        });
336    }
337
338    #[bench]
339    fn libsm_verify_bench(bench: &mut test::Bencher) {
340        let test_word = b"hello world";
341        let ctx = libsm::sm2::signature::SigCtx::new();
342        let (pk, sk) = ctx.new_keypair().unwrap();
343        let sig = ctx.sign(test_word, &sk, &pk).unwrap();
344
345        bench.iter(|| {
346            let _ = ctx.verify(test_word, &pk, &sig);
347        });
348    }
349}