Skip to content

Commit c3c5f4f

Browse files
committed
Update schnorr_fun to latest BIP340 implementation
- Use new csv test file - Use new hex module from secp25kfun
1 parent 68416e3 commit c3c5f4f

File tree

10 files changed

+98
-208
lines changed

10 files changed

+98
-208
lines changed

schnorr_fun/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ serde = { version = "1.0", default-features = false, optional = true, features =
2121

2222
[dev-dependencies]
2323
rand = { version = "0.7", features = ["wasm-bindgen"] }
24-
hex-literal = "0.2"
2524
lazy_static = "1.4"
2625
bincode = "1.0"
2726
sha2 = "0.9"
27+
secp256kfun = { path = "../secp256kfun", version = "^0.2.5-alpha.0", features = ["alloc"] }
2828

2929

3030
[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies]

schnorr_fun/src/adaptor/encrypted_signature.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use secp256kfun::{marker::*, Point, Scalar};
1111
)]
1212
pub struct EncryptedSignature<S = Public> {
1313
/// The `R` point in the signature
14-
pub R: Point<SquareY, Public>,
14+
pub R: Point<EvenY, Public>,
1515
/// The _one-time encrypted_ `s` value of the signature.
1616
pub s_hat: Scalar<S, Zero>,
1717
/// Whether the decryptor should negate their decryption key prior to decryption.

schnorr_fun/src/adaptor/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ where
105105
.mark::<NonZero>()
106106
.expect("computationally unreachable");
107107

108-
let (R, needs_negation) = R.into_point_with_y_choice::<SquareY>();
108+
let (R, needs_negation) = R.into_point_with_even_y();
109109
// We correct r here but we can't correct the decryption key (y) so we
110110
// store in "needs_negation" whether the decryptor needs to negate their
111111
// key before decrypting it

schnorr_fun/src/schnorr.rs

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ where
105105
challenge_hash: CH::default(),
106106
nonce_gen,
107107
}
108-
.add_protocol_tag("BIP340");
108+
.add_protocol_tag("BIP0340");
109109

110110
if let MessageKind::Plain { tag } = msgkind {
111111
nonce_challenge_bundle = nonce_challenge_bundle.add_application_tag(tag);
@@ -149,7 +149,7 @@ where
149149
public => [X, message]
150150
);
151151

152-
let R = XOnly::<SquareY>::from_scalar_mul(&self.G, &mut r);
152+
let R = XOnly::from_scalar_mul(&self.G, &mut r);
153153
let c = self.challenge(&R, X, message);
154154
let s = s!(r + c * x).mark::<Public>();
155155

@@ -205,18 +205,13 @@ impl<NG, CH: Digest<OutputSize = U32> + Clone, GT> Schnorr<CH, NG, GT> {
205205
/// let message = b"we rolled our own sign!".as_ref().mark::<Public>();
206206
/// let keypair = schnorr.new_keypair(Scalar::random(&mut rand::thread_rng()));
207207
/// let mut r = Scalar::random(&mut rand::thread_rng());
208-
/// let R = XOnly::<SquareY>::from_scalar_mul(schnorr.G(), &mut r);
208+
/// let R = XOnly::from_scalar_mul(schnorr.G(), &mut r);
209209
/// let challenge = schnorr.challenge(&R, keypair.public_key(), message);
210210
/// let s = s!(r + challenge * { keypair.secret_key() });
211211
/// let signature = Signature { R, s };
212212
/// assert!(schnorr.verify(&keypair.verification_key(), message, &signature));
213213
/// ```
214-
pub fn challenge<S: Secrecy>(
215-
&self,
216-
R: &XOnly,
217-
X: &XOnly,
218-
m: Slice<'_, S>,
219-
) -> Scalar<S, Zero> {
214+
pub fn challenge<S: Secrecy>(&self, R: &XOnly, X: &XOnly, m: Slice<'_, S>) -> Scalar<S, Zero> {
220215
let hash = self.nonce_challenge_bundle.challenge_hash.clone();
221216
let challenge = Scalar::from_hash(hash.add(R).add(X).add(&m));
222217
challenge
@@ -243,7 +238,8 @@ impl<NG, CH: Digest<OutputSize = U32> + Clone, GT> Schnorr<CH, NG, GT> {
243238
let X = public_key;
244239
let (R, s) = signature.as_tuple();
245240
let c = self.challenge(R, &X.to_xonly(), message);
246-
g!(s * self.G - c * X) == *R
241+
let R_tmp = g!(s * self.G - c * X).mark::<Normal>();
242+
R_tmp == *R
247243
}
248244

249245
/// _Anticipates_ a Schnorr signature given the nonce `R` that will be used ahead of time.
@@ -252,7 +248,7 @@ impl<NG, CH: Digest<OutputSize = U32> + Clone, GT> Schnorr<CH, NG, GT> {
252248
pub fn anticipate_signature(
253249
&self,
254250
X: &Point<EvenY, impl Secrecy>,
255-
R: &Point<SquareY, impl Secrecy>,
251+
R: &Point<EvenY, impl Secrecy>,
256252
m: Slice<'_, impl Secrecy>,
257253
) -> Point<Jacobian, Public, Zero> {
258254
let c = self.challenge(&R.to_xonly(), &X.to_xonly(), m);

schnorr_fun/src/signature.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ impl Signature<Public> {
8484
/// let random_signature = Signature::random(&mut rand::thread_rng());
8585
pub fn random<R: RngCore + CryptoRng>(rng: &mut R) -> Self {
8686
Signature {
87-
R: XOnly::<SquareY>::random(rng),
87+
R: XOnly::random(rng),
8888
s: Scalar::random(rng).mark::<(Zero, Public)>(),
8989
}
9090
}

schnorr_fun/tests/bip340.rs

Lines changed: 68 additions & 190 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
use hex_literal::hex;
21
use schnorr_fun::{
32
fun::{
3+
hex,
44
marker::*,
55
nonce::{NonceRng, Synthetic},
66
rand_core, Scalar, XOnly,
@@ -9,9 +9,11 @@ use schnorr_fun::{
99
};
1010
use sha2::Sha256;
1111

12-
struct AuxRng([u8; 32]);
12+
static BIP340_CSV: &'static str = include_str!("./test-vectors.csv");
1313

14-
impl rand_core::RngCore for AuxRng {
14+
struct AuxRng<'a>(&'a [u8]);
15+
16+
impl<'a> rand_core::RngCore for AuxRng<'a> {
1517
fn next_u32(&mut self) -> u32 {
1618
rand_core::impls::next_u32_via_fill(self)
1719
}
@@ -26,200 +28,76 @@ impl rand_core::RngCore for AuxRng {
2628
}
2729
}
2830

29-
impl rand_core::CryptoRng for AuxRng {}
31+
impl<'a> rand_core::CryptoRng for AuxRng<'a> {}
3032

31-
impl NonceRng for AuxRng {
33+
impl<'a> NonceRng for AuxRng<'a> {
3234
fn fill_bytes(&self, bytes: &mut [u8]) {
3335
bytes.copy_from_slice(&self.0[..])
3436
}
3537
}
3638

37-
fn signing_test_vector(
38-
secret_key: [u8; 32],
39-
public_key: [u8; 32],
40-
aux_rand: [u8; 32],
41-
message: [u8; 32],
42-
target_sig: [u8; 64],
43-
) {
44-
let nonce_gen = Synthetic::<Sha256, _>::new(AuxRng(aux_rand));
45-
let bip340 = Schnorr::<Sha256, _>::new(nonce_gen, MessageKind::Prehashed);
46-
let secret_key = Scalar::from_bytes_mod_order(secret_key)
47-
.mark::<NonZero>()
48-
.unwrap();
49-
let keypair = bip340.new_keypair(secret_key);
50-
let message = message.as_ref().mark::<Public>();
51-
52-
assert_eq!(keypair.public_key().as_bytes(), &public_key);
53-
let signature = bip340.sign(&keypair, message);
54-
assert_eq!(signature.to_bytes().as_ref(), target_sig.as_ref());
55-
assert!(bip340.verify(&keypair.verification_key(), message, &signature));
56-
}
57-
58-
enum Outcome {
59-
/// The signature was valid
60-
Success,
61-
/// The signature was invalid
62-
Failure,
63-
/// The public key was not on the curve
64-
BadPublicKey,
65-
/// The signature nonce was not on the curve
66-
BadSignatureFormat,
39+
#[test]
40+
fn signing_test_vectors() {
41+
use core::str::FromStr;
42+
43+
let lines: Vec<&str> = BIP340_CSV.split("\n").collect();
44+
45+
for line in &lines[1..5] {
46+
let line: Vec<&str> = line.split(',').collect();
47+
let aux_bytes = hex::decode(line[3]).unwrap();
48+
let fake_rng = AuxRng(&aux_bytes[..]);
49+
let bip340 = Schnorr::<Sha256, _, _>::new(
50+
Synthetic::<Sha256, _>::new(fake_rng),
51+
MessageKind::Prehashed,
52+
);
53+
let secret_key = Scalar::<Secret, NonZero>::from_str(line[1]).unwrap();
54+
let expected_public_key = XOnly::from_str(line[2]).unwrap();
55+
let keypair = bip340.new_keypair(secret_key);
56+
assert_eq!(keypair.public_key(), &expected_public_key);
57+
let message = hex::decode(line[4]).unwrap();
58+
let signature = bip340.sign(&keypair, message.as_slice().mark::<Public>());
59+
let expected_signature = Signature::<Public>::from_str(line[5]).unwrap();
60+
assert_eq!(signature, expected_signature);
61+
}
6762
}
6863

69-
fn verification_test_vector(
70-
public_key: [u8; 32],
71-
message: [u8; 32],
72-
sig: [u8; 64],
73-
expected_outcome: Outcome,
74-
) {
64+
#[test]
65+
fn verification_test_vectors() {
66+
use core::str::FromStr;
7567
let bip340 = Schnorr::<Sha256>::verify_only(MessageKind::Prehashed);
76-
let message = message.as_ref().mark::<Public>();
77-
use Outcome::*;
78-
let public_key = {
79-
let public_key = XOnly::from_bytes(public_key);
80-
match expected_outcome {
81-
BadPublicKey => return assert!(public_key.is_none()),
82-
_ => public_key.unwrap(),
83-
}
84-
};
85-
86-
let signature = {
87-
let signature = Signature::from_bytes(sig);
88-
match expected_outcome {
89-
BadSignatureFormat => return assert!(signature.is_none()),
90-
_ => signature.unwrap(),
91-
}
92-
};
93-
94-
assert_eq!(
95-
bip340.verify(&public_key.into(), message, &signature),
96-
match expected_outcome {
97-
Success => true,
98-
Failure => false,
99-
_ => unreachable!(),
100-
},
101-
)
102-
}
103-
104-
secp256kfun::test_plus_wasm! {
105-
106-
fn bip340_signing_vectors() {
107-
signing_test_vector(
108-
hex!("0000000000000000000000000000000000000000000000000000000000000003"),
109-
hex!("F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9"),
110-
hex!("0000000000000000000000000000000000000000000000000000000000000000"),
111-
hex!("0000000000000000000000000000000000000000000000000000000000000000"),
112-
hex!("067E337AD551B2276EC705E43F0920926A9CE08AC68159F9D258C9BBA412781C9F059FCDF4824F13B3D7C1305316F956704BB3FEA2C26142E18ACD90A90C947E")
113-
);
114-
115-
signing_test_vector(
116-
hex!("B7E151628AED2A6ABF7158809CF4F3C762E7160F38B4DA56A784D9045190CFEF"),
117-
hex!("DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"),
118-
hex!("0000000000000000000000000000000000000000000000000000000000000001"),
119-
hex!("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"),
120-
hex!("0E12B8C520948A776753A96F21ABD7FDC2D7D0C0DDC90851BE17B04E75EF86A47EF0DA46C4DC4D0D1BCB8668C2CE16C54C7C23A6716EDE303AF86774917CF928")
121-
);
122-
123-
signing_test_vector(
124-
hex!("C90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B14E5C9"),
125-
hex!("DD308AFEC5777E13121FA72B9CC1B7CC0139715309B086C960E18FD969774EB8"),
126-
hex!("C87AA53824B4D7AE2EB035A2B5BBBCCC080E76CDC6D1692C4B0B62D798E6D906"),
127-
hex!("7E2D58D8B3BCDF1ABADEC7829054F90DDA9805AAB56C77333024B9D0A508B75C"),
128-
hex!("FC012F9FB8FE00A358F51EF93DCE0DC0C895F6E9A87C6C4905BC820B0C3677616B8737D14E703AF8E16E22E5B8F26227D41E5128F82D86F747244CC289C74D1D")
129-
);
130-
131-
signing_test_vector(
132-
hex!("0B432B2677937381AEF05BB02A66ECD012773062CF3FA2549E44F58ED2401710"),
133-
hex!("25D1DFF95105F5253C4022F628A996AD3A0D95FBF21D468A1B33F8C160D8F517"),
134-
hex!("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"),
135-
hex!("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"),
136-
hex!("FC132D4E426DFF535AEC0FA7083AC5118BC1D5FFFD848ABD8290C23F271CA0DD11AEDCEA3F55DA9BD677FE29C9DDA0CF878BCE43FDE0E313D69D1AF7A5AE8369")
137-
);
138-
}
139-
140-
fn bip340_verification_vectors() {
141-
verification_test_vector(
142-
hex!("D69C3509BB99E412E68B0FE8544E72837DFA30746D8BE2AA65975F29D22DC7B9"),
143-
hex!("4DF3C3F68FCC83B27E9D42C90431A72499F17875C81A599B566C9889B9696703"),
144-
hex!("00000000000000000000003B78CE563F89A0ED9414F5AA28AD0D96D6795F9C630EC50E5363E227ACAC6F542CE1C0B186657E0E0D1A6FFE283A33438DE4738419"),
145-
Outcome::Success,
146-
);
147-
148-
verification_test_vector(
149-
hex!("EEFDEA4CDB677750A420FEE807EACF21EB9898AE79B9768766E4FAA04A2D4A34"),
150-
hex!("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"),
151-
hex!("7036D6BFE1837AE919631039A2CF652A295DFAC9A8BBB0806014B2F48DD7C807941607B563ABBA414287F374A332BA3636DE009EE1EF551A17796B72B68B8A24"),
152-
Outcome::BadPublicKey,
153-
);
154-
155-
verification_test_vector(
156-
hex!("DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"),
157-
hex!("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"),
158-
hex!("F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F995A579DA959FA739FCE39E8BD16FECB5CDCF97060B2C73CDE60E87ABCA1AA5D9"),
159-
Outcome::Failure,
160-
);
161-
162-
verification_test_vector(
163-
hex!("DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"),
164-
hex!("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"),
165-
hex!("F8704654F4687B7365ED32E796DE92761390A3BCC495179BFE073817B7ED32824E76B987F7C1F9A751EF5C343F7645D3CFFC7D570B9A7192EBF1898E1344E3BF"),
166-
Outcome::Failure
167-
);
168-
169-
verification_test_vector(
170-
hex!("DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"),
171-
hex!("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"),
172-
hex!("7036D6BFE1837AE919631039A2CF652A295DFAC9A8BBB0806014B2F48DD7C8076BE9F84A9C5445BEBD780C8B5CCD45C883D0DC47CD594B21A858F31A19AAB71D"),
173-
Outcome::Failure,
174-
);
175-
176-
verification_test_vector(
177-
hex!("DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"),
178-
hex!("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"),
179-
hex!("74556372D3369E8C53E6B84B5D7EE9AE0220EB37A6EA5501EF828FBFBA90A864F6D108D88692535AEEE74170428F4C126A5B6E80D3D965007FF159F46E34B63F"),
180-
Outcome::Failure,
181-
);
182-
183-
verification_test_vector(
184-
hex!("DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"),
185-
hex!("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"),
186-
hex!("00000000000000000000000000000000000000000000000000000000000000009915EE59F07F9DBBAEDC31BFCC9B34AD49DE669CD24773BCED77DDA36D073EC8"),
187-
Outcome::BadSignatureFormat,
188-
);
189-
190-
verification_test_vector(
191-
hex!("DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"),
192-
hex!("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"),
193-
hex!("0000000000000000000000000000000000000000000000000000000000000001C7EC918B2B9CF34071BB54BED7EB4BB6BAB148E9A7E36E6B228F95DFA08B43EC"),
194-
Outcome::Failure,
195-
);
196-
197-
verification_test_vector(
198-
hex!("DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"),
199-
hex!("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"),
200-
hex!("4A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D941607B563ABBA414287F374A332BA3636DE009EE1EF551A17796B72B68B8A24"),
201-
Outcome::BadSignatureFormat,
202-
);
203-
204-
verification_test_vector(
205-
hex!("DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"),
206-
hex!("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"),
207-
hex!("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F941607B563ABBA414287F374A332BA3636DE009EE1EF551A17796B72B68B8A24"),
208-
Outcome::BadSignatureFormat,
209-
);
210-
211-
verification_test_vector(
212-
hex!("DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659"),
213-
hex!("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"),
214-
hex!("7036D6BFE1837AE919631039A2CF652A295DFAC9A8BBB0806014B2F48DD7C807FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"),
215-
Outcome::BadSignatureFormat,
216-
);
217-
218-
verification_test_vector(
219-
hex!("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC30"),
220-
hex!("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89"),
221-
hex!("74556372D3369E8C53E6B84B5D7EE9AE0220EB37A6EA5501EF828FBFBA90A864092EF727796DACA51118BE8FBD70B3EC50536E65DB6F3B3B3FE1049862018B02"),
222-
Outcome::BadPublicKey,
223-
)
224-
}
68+
let lines: Vec<&str> = BIP340_CSV.split("\n").collect();
69+
for line in &lines[5..16] {
70+
let line: Vec<&str> = line.split(',').collect();
71+
72+
let public_key = match XOnly::from_str(line[2]) {
73+
Ok(public_key) => public_key,
74+
Err(e) => {
75+
if line[6] == "TRUE" {
76+
panic!("{:?}", e);
77+
} else {
78+
continue;
79+
}
80+
}
81+
};
82+
let message = hex::decode(line[4]).unwrap();
83+
let signature = match Signature::<Public>::from_str(line[5]) {
84+
Ok(signature) => signature,
85+
Err(e) => {
86+
if line[6] == "TRUE" {
87+
panic!("{:?}", e)
88+
} else {
89+
continue;
90+
}
91+
}
92+
};
93+
94+
println!("{:?}", line);
95+
assert!(
96+
bip340.verify(
97+
&public_key.to_point(),
98+
message.as_slice().mark::<Public>(),
99+
&signature
100+
) == (line[6] == "TRUE")
101+
);
102+
}
225103
}

0 commit comments

Comments
 (0)