Skip to content

Commit d00c33f

Browse files
committed
ed25519: refactor
1 parent 3b3d87d commit d00c33f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+26079
-7922
lines changed

contrib/codegen/gen_wycheproofs.py

+153
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,164 @@ def _gen_ed25519():
9595
print(r"};")
9696

9797

98+
@dataclass
99+
class XDHVerify:
100+
tcId: int
101+
comment: str
102+
shared: bytes
103+
prv: bytes
104+
pub: bytes
105+
ok: bool
106+
107+
def _gen_x25519():
108+
req = requests.get(
109+
"https://raw.githubusercontent.com/google/wycheproof/master/testvectors/x25519_test.json"
110+
)
111+
assert req.status_code == 200
112+
file = req.json()
113+
assert file["algorithm"] == "XDH"
114+
assert file["schema"] == "xdh_comp_schema.json"
115+
verify_tests = []
116+
for group in file["testGroups"]:
117+
if group["type"] != "XdhComp":
118+
print(f"Skipping {group['type']} test", file=sys.stderr)
119+
continue
120+
for test in group["tests"]:
121+
verify_tests.append(
122+
XDHVerify(
123+
tcId=test["tcId"],
124+
comment=test["comment"],
125+
shared=bytes.fromhex(test["shared"]),
126+
prv=bytes.fromhex(test["private"]),
127+
pub=bytes.fromhex(test["public"]),
128+
ok="ZeroSharedSecret" not in set(test["flags"]),
129+
)
130+
)
131+
132+
print("/* Code generated by gen_wycheproofs.py. DO NOT EDIT. */")
133+
print(
134+
f"/* Generated at {datetime.datetime.now(datetime.timezone.utc).isoformat()} */"
135+
)
136+
print(
137+
"""
138+
#include "../fd_ballet_base.h"
139+
140+
struct fd_x25519_verify_wycheproof {
141+
char const * comment;
142+
uchar shared[32];
143+
uchar prv[32];
144+
uchar pub[32];
145+
uint tc_id;
146+
int ok;
147+
};
148+
149+
typedef struct fd_x25519_verify_wycheproof fd_x25519_verify_wycheproof_t;
150+
151+
static fd_x25519_verify_wycheproof_t const x25519_verify_wycheproofs[] = {"""
152+
)
153+
154+
for test in verify_tests:
155+
print(f" {{ .tc_id = {test.tcId},")
156+
print(f' .comment = "{test.comment}",')
157+
print(
158+
r' .shared = "' + "".join([r"\x%02x" % (x) for x in test.shared]) + r'",'
159+
)
160+
print(
161+
r' .prv = "' + "".join([r"\x%02x" % (x) for x in test.prv]) + r'",'
162+
)
163+
print(
164+
r' .pub = "' + "".join([r"\x%02x" % (x) for x in test.pub]) + r'",'
165+
)
166+
print(f" .ok = {1 if test.ok else 0} }},")
167+
168+
print(r" {0}")
169+
print(r"};")
170+
171+
172+
def _gen_cctv_ed25519():
173+
req = requests.get(
174+
"https://raw.githubusercontent.com/C2SP/CCTV/main/ed25519/ed25519vectors.json"
175+
)
176+
assert req.status_code == 200
177+
file = req.json()
178+
verify_tests = []
179+
for test in file:
180+
flags = test["flags"]
181+
if flags:
182+
set_flags = set(flags)
183+
ok = not(flags) or set_flags == set(["low_order_component_A"]) or set_flags == set(["low_order_component_A", "low_order_component_R"])
184+
if "non_canonical_R" in set_flags and "low_order_R" not in set_flags:
185+
raise Exception(test["number"])
186+
else:
187+
ok = True
188+
verify_tests.append(
189+
EddsaVerify(
190+
tcId=test["number"],
191+
comment=test["msg"],
192+
msg=bytes(test["msg"], 'utf-8'),
193+
sig=bytes.fromhex(test["sig"]),
194+
pub=bytes.fromhex(test["key"]),
195+
ok=ok, # we implement dalek verify_strict, so all these should fail
196+
)
197+
)
198+
199+
print("/* Code generated by gen_wycheproofs.py. DO NOT EDIT. */")
200+
print(
201+
f"/* Generated at {datetime.datetime.now(datetime.timezone.utc).isoformat()} */"
202+
)
203+
print(
204+
"""
205+
#include "../fd_ballet_base.h"
206+
207+
struct fd_ed25519_verify_cctv {
208+
char const * comment;
209+
uchar const * msg;
210+
ulong msg_sz;
211+
uchar pub[32];
212+
uchar sig[64];
213+
uint tc_id;
214+
int ok;
215+
};
216+
217+
typedef struct fd_ed25519_verify_cctv fd_ed25519_verify_cctv_t;
218+
219+
static fd_ed25519_verify_cctv_t const ed25519_verify_cctvs[] = {"""
220+
)
221+
222+
for test in verify_tests:
223+
if len(test.sig) != 64:
224+
continue
225+
print(f" {{ .tc_id = {test.tcId},")
226+
print(f' .comment = "{test.comment}",')
227+
print(
228+
r' .msg = (uchar const *)"'
229+
+ "".join([r"\x%02x" % (x) for x in test.msg])
230+
+ r'",'
231+
)
232+
print(f" .msg_sz = {len(test.msg)}UL,")
233+
print(
234+
r' .sig = "' + "".join([r"\x%02x" % (x) for x in test.sig]) + r'",'
235+
)
236+
print(
237+
r' .pub = "' + "".join([r"\x%02x" % (x) for x in test.pub]) + r'",'
238+
)
239+
print(f" .ok = {1 if test.ok else 0} }},")
240+
241+
print(r" {0}")
242+
print(r"};")
243+
98244
def main():
99245
with open("src/ballet/ed25519/test_ed25519_wycheproof.c", "w") as out:
100246
with redirect_stdout(out):
101247
_gen_ed25519()
102248

249+
with open("src/ballet/ed25519/test_x25519_wycheproof.c", "w") as out:
250+
with redirect_stdout(out):
251+
_gen_x25519()
252+
253+
with open("src/ballet/ed25519/test_ed25519_cctv.c", "w") as out:
254+
with redirect_stdout(out):
255+
_gen_cctv_ed25519()
103256

104257
if __name__ == "__main__":
105258
root = Path(__file__).parents[2]
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[package]
2+
name = "dalek_target"
3+
version = "0.1.0"
4+
edition = "2021"
5+
publish = false
6+
7+
[lib]
8+
crate-type = ["cdylib"]
9+
10+
[dependencies]
11+
ed25519-dalek = "=1.0.1"

contrib/ed25519/dalek_target/Makefile

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
RUSTFLAGS:=
2+
RUSTFLAGS+=-Cpasses=sancov-module
3+
RUSTFLAGS+=-Cllvm-args=-sanitizer-coverage-inline-8bit-counters
4+
RUSTFLAGS+=-Cllvm-args=-sanitizer-coverage-level=4
5+
RUSTFLAGS+=-Cllvm-args=-sanitizer-coverage-pc-table
6+
RUSTFLAGS+=-Clink-dead-code
7+
RUSTFLAGS+=-Cforce-frame-pointers=yes
8+
9+
RUST_VERSION:=1.76.0
10+
11+
CARGO?=cargo
12+
13+
.PHONY: clean build
14+
15+
build:
16+
RUSTFLAGS="$(RUSTFLAGS)" $(CARGO) +$(RUST_VERSION) build --target x86_64-unknown-linux-gnu --release
17+
18+
clean:
19+
$(CARGO) clean
+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
use ed25519_dalek::{Keypair, PublicKey, SecretKey, Signature, Signer};
2+
use std::ffi::c_int;
3+
4+
#[no_mangle]
5+
pub extern "C" fn ed25519_dalek_sign(
6+
sig: *mut u8,
7+
msg: *const u8,
8+
sz: u64,
9+
public_key: *const u8,
10+
private_key: *const u8,
11+
) -> c_int {
12+
let secret = match SecretKey::from_bytes(unsafe {
13+
std::slice::from_raw_parts(private_key, 32)
14+
.try_into()
15+
.unwrap()
16+
}) {
17+
Ok(sk) => sk,
18+
Err(_) => return -1,
19+
};
20+
21+
let public = match PublicKey::from_bytes(unsafe {
22+
std::slice::from_raw_parts(public_key, 32)
23+
.try_into()
24+
.unwrap()
25+
}) {
26+
Ok(pk) => pk,
27+
Err(_) => return -1,
28+
};
29+
30+
let keypair = Keypair {
31+
secret: secret,
32+
public: public,
33+
};
34+
35+
let signature = keypair.sign(unsafe { std::slice::from_raw_parts(msg, sz as usize) });
36+
37+
unsafe {
38+
std::ptr::copy_nonoverlapping(&signature.to_bytes() as *const u8, sig, 64);
39+
}
40+
return 0; // success
41+
}
42+
43+
#[no_mangle]
44+
pub extern "C" fn ed25519_dalek_verify(
45+
msg: *const u8,
46+
sz: u64,
47+
sig: *const u8,
48+
public_key: *const u8,
49+
) -> c_int {
50+
let signature = match Signature::from_bytes(unsafe {
51+
std::slice::from_raw_parts(sig, 64)
52+
.try_into()
53+
.unwrap()
54+
}) {
55+
Ok(s) => s,
56+
Err(_) => return -1,
57+
};
58+
59+
let public = match PublicKey::from_bytes(unsafe {
60+
std::slice::from_raw_parts(public_key, 32)
61+
.try_into()
62+
.unwrap()
63+
}) {
64+
Ok(pk) => pk,
65+
Err(_) => return -1,
66+
};
67+
68+
let ok = public
69+
.verify_strict(
70+
unsafe { std::slice::from_raw_parts(msg, sz as usize) },
71+
&signature,
72+
)
73+
.is_ok();
74+
75+
return if ok { 0 } else { -1 };
76+
}

src/ballet/ed25519/Local.mk

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
1-
$(call add-hdrs,fd_ed25519.h fd_x25519.h)
2-
$(call add-objs,fd_ed25519_fe fd_ed25519_ge fd_ed25519_user fd_x25519,fd_ballet)
1+
$(call add-hdrs,fd_ed25519.h fd_x25519.h fd_f25519.h fd_curve25519.h fd_curve25519_scalar.h)
2+
$(call add-objs,fd_f25519 fd_curve25519 fd_curve25519_scalar fd_ed25519_user fd_x25519,fd_ballet)
3+
$(call add-objs,fd_ristretto255,fd_ballet)
34
$(call make-unit-test,test_ed25519,test_ed25519,fd_ballet fd_util)
45
$(call make-unit-test,test_ed25519_signature_malleability,test_ed25519_signature_malleability,fd_ballet fd_util)
56
$(call make-unit-test,test_x25519,test_x25519,fd_ballet fd_util)
7+
$(call make-unit-test,test_ristretto255,test_ristretto255,fd_ballet fd_util)
68
$(call make-fuzz-test,fuzz_ed25519_verify,fuzz_ed25519_verify,fd_ballet fd_util)
79
$(call make-fuzz-test,fuzz_ed25519_sigverify,fuzz_ed25519_sigverify,fd_ballet fd_util)
10+
$(call make-fuzz-test,fuzz_ed25519_sigverify_diff,fuzz_ed25519_sigverify_diff,fd_ballet fd_util)
811

912
$(call run-unit-test,test_ed25519)
1013
$(call run-unit-test,test_ed25519_signature_malleability)
1114
$(call run-unit-test,test_x25519)
15+
$(call run-unit-test,test_ristretto255)
16+
17+
#$(call make-unit-test,fd_curve25519_tables,fd_curve25519_tables,fd_ballet fd_util)

0 commit comments

Comments
 (0)