Skip to content

Commit 20b947b

Browse files
committed
add verify
1 parent 02c0219 commit 20b947b

File tree

1 file changed

+57
-18
lines changed

1 file changed

+57
-18
lines changed

guest_libs/crypto/src/secp256k1.rs

Lines changed: 57 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use crate::CenoCryptoError;
22
use ceno_keccak::{Hasher, Keccak};
33
use ceno_rt::syscalls::{syscall_secp256k1_add, syscall_secp256k1_double};
44
use k256::{
5-
AffinePoint, EncodedPoint, Scalar, Secp256k1, U256,
5+
AffinePoint, EncodedPoint, FieldBytes, NonZeroScalar, Scalar, Secp256k1, U256,
66
ecdsa::{Error, RecoveryId, Signature, hazmat::bits2field},
77
elliptic_curve::{
88
Curve, Field, FieldBytesEncoding, PrimeField,
@@ -36,7 +36,7 @@ pub fn secp256k1_ecrecover(
3636
let recid = RecoveryId::from_byte(recid).expect("recovery ID is valid");
3737

3838
// recover key
39-
let recovered_key = recover_from_prehash_unchecked(&msg[..], &signature, recid)?;
39+
let recovered_key = recover_from_prehash(&msg[..], &signature, recid)?;
4040

4141
let mut hasher = Keccak::v256();
4242
hasher.update(&recovered_key);
@@ -49,13 +49,14 @@ pub fn secp256k1_ecrecover(
4949

5050
/// Copied from <https://github.com/RustCrypto/signatures/blob/89232d6a962a199fd8211a117db74408353e4383/ecdsa/src/recovery.rs#L278-L316>
5151
/// Modified to use ceno syscalls
52-
fn recover_from_prehash_unchecked(
52+
fn recover_from_prehash(
5353
prehash: &[u8],
5454
signature: &Signature,
5555
recovery_id: RecoveryId,
56-
) -> k256::ecdsa::signature::Result<UntaggedUncompressedPoint> {
56+
) -> Result<UntaggedUncompressedPoint, Error> {
5757
let (r, s) = signature.split_scalars();
58-
let z = <Scalar as Reduce<U256>>::reduce_bytes(&bits2field::<Secp256k1>(prehash)?);
58+
let prehash: FieldBytes = bits2field::<Secp256k1>(prehash)?;
59+
let z = <Scalar as Reduce<U256>>::reduce_bytes(&prehash);
5960

6061
let mut r_bytes = r.to_repr();
6162
if recovery_id.is_x_reduced() {
@@ -98,25 +99,63 @@ fn recover_from_prehash_unchecked(
9899
// Original:
99100
// ProjectivePoint::lincomb(&ProjectivePoint::GENERATOR, &u1, &r_point, &u2)
100101
// Equivalent to: G * u1 + R * u2
101-
let pk_words = match (u1 == Scalar::ZERO, u2 == Scalar::ZERO) {
102-
(true, true) => return Err(Error::new()),
103-
(true, false) => secp256k1_mul(&r_point, u2),
104-
(false, true) => secp256k1_mul(&AffinePoint::GENERATOR, u1),
105-
(false, false) => {
106-
let mut p1 = secp256k1_mul(&AffinePoint::GENERATOR, u1);
107-
let p2 = secp256k1_mul(&r_point, u2);
108-
syscall_secp256k1_add(&mut p1, &p2);
109-
p1
110-
}
111-
};
102+
let pk_words = lincomb(u1, &r_point, u2)?;
103+
104+
let bytes = words_to_untagged_bytes(pk_words);
112105

113-
// FIXME: do we really need to verify the signature again here?
114106
// Original:
115107
// let vk = VerifyingKey::from_affine(pk.to_affine())?;
116108
// // Ensure signature verifies with the recovered key
117109
// vk.verify_prehash(prehash, signature)?;
110+
verify_prehash(&z, (&r, &s), &bytes)?;
111+
112+
Ok(bytes)
113+
}
114+
115+
/// Copied from <https://github.com/RustCrypto/signatures/blob/89232d6a962a199fd8211a117db74408353e4383/ecdsa/src/hazmat.rs#L261-L293>
116+
fn verify_prehash(
117+
z: &Scalar,
118+
(r, s): (&NonZeroScalar, &NonZeroScalar),
119+
bytes: &UntaggedUncompressedPoint,
120+
) -> Result<(), Error> {
121+
let q = EncodedPoint::from_untagged_bytes(bytes.into());
122+
let q = AffinePoint::from_encoded_point(&q)
123+
.into_option()
124+
.ok_or(Error::new())?;
125+
126+
let s_inv = *s.invert_vartime();
127+
let u1 = z * &s_inv;
128+
let u2 = **r * s_inv;
118129

119-
Ok(words_to_untagged_bytes(pk_words))
130+
// Original:
131+
// let x = ProjectivePoint::lincomb(&ProjectivePoint::GENERATOR, &u1, &q, &u2)
132+
// .to_affine()
133+
// .x();
134+
// Equivalent to: G * u1 + q * u2
135+
let p = lincomb(u1, &q, u2)?;
136+
let p_bytes = words_to_untagged_bytes(p);
137+
let x = FieldBytes::from_slice(&p_bytes[..32]);
138+
139+
if **r == <Scalar as Reduce<U256>>::reduce_bytes(&x) {
140+
Ok(())
141+
} else {
142+
Err(Error::new())
143+
}
144+
}
145+
146+
#[inline]
147+
fn lincomb(u1: Scalar, p: &AffinePoint, u2: Scalar) -> Result<[u32; 16], Error> {
148+
Ok(match (u1 == Scalar::ZERO, u2 == Scalar::ZERO) {
149+
(false, false) => {
150+
let mut p1 = secp256k1_mul(&AffinePoint::GENERATOR, u1);
151+
let p2 = secp256k1_mul(&p, u2);
152+
syscall_secp256k1_add(&mut p1, &p2);
153+
p1
154+
}
155+
(true, false) => secp256k1_mul(&p, u2),
156+
(false, true) => secp256k1_mul(&AffinePoint::GENERATOR, u1),
157+
(true, true) => return Err(Error::new()),
158+
})
120159
}
121160

122161
fn secp256k1_mul(point: &AffinePoint, scalar: Scalar) -> [u32; 16] {

0 commit comments

Comments
 (0)