Skip to content

Commit 25720e5

Browse files
committed
FEAT: new native ecdsa = Elliptic Curve Digital Signature Algorithm
1 parent 39957a4 commit 25720e5

File tree

2 files changed

+178
-150
lines changed

2 files changed

+178
-150
lines changed

src/core/n-crypt.c

+126-39
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,48 @@ typedef struct {
522522
uint8_t private[32];
523523
} ECC_CTX;
524524

525+
static uECC_Curve get_ecc_curve(REBCNT curve_type) {
526+
uECC_Curve curve = NULL;
527+
switch (curve_type) {
528+
case SYM_SECP256K1:
529+
curve = ECC_curves[4];
530+
if(curve == NULL) {
531+
curve = uECC_secp256k1();
532+
ECC_curves[4] = curve;
533+
}
534+
break;
535+
case SYM_SECP256R1:
536+
curve = ECC_curves[3];
537+
if(curve == NULL) {
538+
curve = uECC_secp256r1();
539+
ECC_curves[3] = curve;
540+
}
541+
break;
542+
case SYM_SECP224R1:
543+
curve = ECC_curves[2];
544+
if(curve == NULL) {
545+
curve = uECC_secp224r1();
546+
ECC_curves[2] = curve;
547+
}
548+
break;
549+
case SYM_SECP192R1:
550+
curve = ECC_curves[1];
551+
if(curve == NULL) {
552+
curve = uECC_secp192r1();
553+
ECC_curves[1] = curve;
554+
}
555+
break;
556+
case SYM_SECP160R1:
557+
curve = ECC_curves[0];
558+
if(curve == NULL) {
559+
curve = uECC_secp160r1();
560+
ECC_curves[0] = curve;
561+
}
562+
break;
563+
}
564+
return curve;
565+
}
566+
525567
/***********************************************************************
526568
**
527569
*/ REBNATIVE(ecdh)
@@ -574,45 +616,8 @@ typedef struct {
574616
SET_HANDLE(val_handle, ecc_ser, SYM_ECDH, HANDLE_SERIES);
575617
}
576618

577-
switch (curve_type) {
578-
case SYM_SECP256K1:
579-
curve = ECC_curves[4];
580-
if(curve == NULL) {
581-
curve = uECC_secp256k1();
582-
ECC_curves[4] = curve;
583-
}
584-
break;
585-
case SYM_SECP256R1:
586-
curve = ECC_curves[3];
587-
if(curve == NULL) {
588-
curve = uECC_secp256r1();
589-
ECC_curves[3] = curve;
590-
}
591-
break;
592-
case SYM_SECP224R1:
593-
curve = ECC_curves[2];
594-
if(curve == NULL) {
595-
curve = uECC_secp224r1();
596-
ECC_curves[2] = curve;
597-
}
598-
break;
599-
case SYM_SECP192R1:
600-
curve = ECC_curves[1];
601-
if(curve == NULL) {
602-
curve = uECC_secp192r1();
603-
ECC_curves[1] = curve;
604-
}
605-
break;
606-
case SYM_SECP160R1:
607-
curve = ECC_curves[0];
608-
if(curve == NULL) {
609-
curve = uECC_secp160r1();
610-
ECC_curves[0] = curve;
611-
}
612-
break;
613-
default:
614-
return R_NONE;
615-
}
619+
curve = get_ecc_curve(curve_type);
620+
if (!curve) return R_NONE;
616621

617622
if (ref_init) {
618623
if(!uECC_make_key(ecc->public, ecc->private, curve)) {
@@ -673,6 +678,88 @@ typedef struct {
673678
}
674679

675680

681+
/***********************************************************************
682+
**
683+
*/ REBNATIVE(ecdsa)
684+
/*
685+
// ecdsa: native [
686+
// "Elliptic Curve Digital Signature Algorithm"
687+
// key [handle! binary!] "Keypair to work with, created using ECDH function, or raw binary key (needs /curve)"
688+
// hash [binary!] "Data to sign or verify"
689+
// /sign "Use private key to sign data, returns 64 bytes of signature"
690+
// /verify "Use public key to verify signed data, returns true or false"
691+
// signature [binary!] "Signature (64 bytes)"
692+
// /curve "Used if key is just a binary"
693+
// type [word!] "One of supported curves: [secp256k1 secp256r1 secp224r1 secp192r1 secp160r1]"
694+
// ]
695+
***********************************************************************/
696+
{
697+
REBVAL *val_key = D_ARG(1);
698+
REBVAL *val_hash = D_ARG(2);
699+
REBOOL ref_sign = D_REF(3);
700+
REBOOL ref_verify = D_REF(4);
701+
REBVAL *val_sign = D_ARG(5);
702+
REBOOL ref_curve = D_REF(6);
703+
REBVAL *val_curve = D_ARG(7);
704+
705+
REBSER *ecc_ser = NULL;
706+
REBSER *bin = NULL;
707+
REBYTE *key = NULL;
708+
REBCNT curve_type = 0;
709+
uECC_Curve curve = NULL;
710+
ECC_CTX *ecc = NULL;
711+
712+
if (IS_BINARY(val_key)) {
713+
if (!ref_curve) Trap0(RE_MISSING_ARG);
714+
curve_type = VAL_WORD_CANON(val_curve);
715+
}
716+
else {
717+
if (VAL_HANDLE_TYPE(val_key) != SYM_ECDH || VAL_HANDLE_DATA(val_key) == NULL) {
718+
Trap0(RE_INVALID_HANDLE);
719+
}
720+
ecc_ser = VAL_HANDLE_DATA(val_key);
721+
ecc = (ECC_CTX*)SERIES_DATA(ecc_ser);
722+
curve_type = ecc->curve_type;
723+
}
724+
725+
curve = get_ecc_curve(curve_type);
726+
if (!curve) return R_NONE;
727+
728+
if (ref_sign) {
729+
if (ecc) {
730+
key = ecc->private;
731+
}
732+
else {
733+
if (VAL_LEN(val_key) != 32) return R_NONE;
734+
key = VAL_BIN(val_key);
735+
}
736+
bin = Make_Series((REBCNT)64, (REBCNT)1, FALSE);
737+
if(!uECC_sign(key, VAL_DATA(val_hash), VAL_LEN(val_hash), BIN_DATA(bin), curve)) {
738+
return R_NONE;
739+
}
740+
SET_BINARY(D_RET, bin);
741+
VAL_TAIL(D_RET) = 64;
742+
return R_RET;
743+
}
744+
745+
if (ref_verify) {
746+
if (ecc) {
747+
key = ecc->public;
748+
}
749+
else {
750+
if (VAL_LEN(val_key) != 64) return R_FALSE;
751+
key = VAL_BIN(val_key);
752+
}
753+
if(VAL_LEN(val_sign) == 64 && uECC_verify(key, VAL_DATA(val_hash), VAL_LEN(val_hash), VAL_DATA(val_sign), curve)) {
754+
return R_TRUE;
755+
}
756+
else {
757+
return R_FALSE;
758+
}
759+
}
760+
}
761+
762+
676763
/***********************************************************************
677764
**
678765
*/ REBNATIVE(chacha20)

src/tests/units/dh-test.r3

+52-111
Original file line numberDiff line numberDiff line change
@@ -81,118 +81,59 @@ C79E915C3277361FBFA587C6DC06FEDE0B7E57FEC0B68F96B3AD651D54264357
8181

8282

8383
===start-group=== "Elliptic-curve Diffie-Hellman key exchange"
84+
curves: [secp256k1 secp256r1 secp224r1 secp192r1 secp160r1]
85+
foreach ecurve curves [
86+
--test-- rejoin ["ECDH (" ecurve ") keys usage"]
87+
88+
;- Boban and Alice both init key with same curve
89+
--assert handle? k-Alice: ecdh/init none ecurve
90+
--assert handle? k-Boban: ecdh/init none ecurve
91+
--assert ecurve = ecdh/curve k-Alice
92+
--assert ecurve = ecdh/curve k-Boban
93+
;- ... exports and exchange public parts of it
94+
--assert binary? pub-Alice: ecdh/public k-Alice
95+
--assert binary? pub-Boban: ecdh/public k-Boban
96+
;- ... and use them to compute shared secret.
97+
--assert binary? secret-Alice: ecdh/secret k-Alice pub-Boban
98+
--assert binary? secret-Boban: ecdh/secret k-Boban pub-Alice
99+
;- These keys should be same on both sides
100+
--assert secret-Alice = secret-Boban
101+
;- Once done with the exchange, the ECDH key must be released!
102+
--assert handle? ecdh/release k-Alice
103+
--assert none? ecdh/public k-Alice
104+
105+
;- re-initialization...
106+
--assert handle? ecdh/init k-Alice ecurve ;- using existing key for a new init
107+
--assert binary? pub-Alice: ecdh/public k-Alice
108+
;- /release may be used with /secret
109+
--assert binary? secret-Alice: ecdh/secret/release k-Alice pub-Boban
110+
--assert binary? secret-Boban: ecdh/secret/release k-Boban pub-Alice
111+
--assert secret-Alice = secret-Boban
112+
113+
--test-- rejoin ["ECDSA (" ecurve ") signing"]
114+
115+
;- Alice generates her key-pair
116+
k-Alice: ecdh/init none ecurve
117+
;- wants to sign some data:
118+
data: {Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it.}
119+
;- computes its hash:
120+
hash: checksum/method data 'sha256
121+
;- and use ECDSA to sign it using her private key
122+
signature: ecdsa/sign k-Alice hash
123+
--assert binary? signature
124+
--assert 64 = length? signature
125+
;- can verify if it really works:
126+
--assert ecdsa/verify k-Alice hash signature
127+
128+
;- than Alice may send the data with signature, used curve and public key to Boban
129+
pub-Alice: ecdh/public k-Alice
130+
;- Boban can verify, that the data are really from Alice
131+
--assert ecdsa/verify/curve pub-Alice hash signature ecurve
132+
133+
]
134+
135+
84136

85-
--test-- "ECDH (secp256k1) keys usage"
86-
87-
ecurve: 'secp256k1
88-
;- Boban and Alice both init key with same curve
89-
--assert handle? k-Alice: ecdh/init none ecurve
90-
--assert handle? k-Boban: ecdh/init none ecurve
91-
--assert ecurve = ecdh/curve k-Alice
92-
--assert ecurve = ecdh/curve k-Boban
93-
;- ... exports and exchange public parts of it
94-
--assert binary? pub-Alice: ecdh/public k-Alice
95-
--assert binary? pub-Boban: ecdh/public k-Boban
96-
;- ... and use them to compute shared secret.
97-
--assert binary? secret-Alice: ecdh/secret k-Alice pub-Boban
98-
--assert binary? secret-Boban: ecdh/secret k-Boban pub-Alice
99-
;- These keys should be same on both sides
100-
--assert secret-Alice = secret-Boban
101-
;- Once done with the exchange, the ECDH key must be released!
102-
--assert handle? ecdh/release k-Alice
103-
--assert handle? ecdh/release k-Boban
104-
--assert none? ecdh/public k-Alice
105-
106-
--test-- "ECDH (secp256r1) keys usage"
107-
108-
ecurve: 'secp256r1
109-
;- Boban and Alice both init key with same curve
110-
--assert handle? k-Alice: ecdh/init none ecurve
111-
--assert handle? k-Boban: ecdh/init none ecurve
112-
--assert ecurve = ecdh/curve k-Alice
113-
--assert ecurve = ecdh/curve k-Boban
114-
;- ... exports and exchange public parts of it
115-
--assert binary? pub-Alice: ecdh/public k-Alice
116-
--assert binary? pub-Boban: ecdh/public k-Boban
117-
;- ... and use them to compute shared secret.
118-
--assert binary? secret-Alice: ecdh/secret k-Alice pub-Boban
119-
--assert binary? secret-Boban: ecdh/secret k-Boban pub-Alice
120-
;- These keys should be same on both sides
121-
--assert secret-Alice = secret-Boban
122-
;- Once done with the exchange, the ECDH key must be released!
123-
--assert handle? ecdh/release k-Alice
124-
--assert handle? ecdh/release k-Boban
125-
--assert none? ecdh/public k-Alice
126-
127-
--test-- "ECDH (secp224r1) keys usage"
128-
129-
ecurve: 'secp224r1
130-
;- Boban and Alice both init key with same curve
131-
--assert handle? k-Alice: ecdh/init none ecurve
132-
--assert handle? k-Boban: ecdh/init none ecurve
133-
--assert ecurve = ecdh/curve k-Alice
134-
--assert ecurve = ecdh/curve k-Boban
135-
;- ... exports and exchange public parts of it
136-
--assert binary? pub-Alice: ecdh/public k-Alice
137-
--assert binary? pub-Boban: ecdh/public k-Boban
138-
;- ... and use them to compute shared secret.
139-
--assert binary? secret-Alice: ecdh/secret k-Alice pub-Boban
140-
--assert binary? secret-Boban: ecdh/secret k-Boban pub-Alice
141-
;- These keys should be same on both sides
142-
--assert secret-Alice = secret-Boban
143-
;- Once done with the exchange, the ECDH key must be released!
144-
--assert handle? ecdh/release k-Alice
145-
--assert handle? ecdh/release k-Boban
146-
--assert none? ecdh/public k-Alice
147-
148-
--test-- "ECDH (secp192r1) keys usage"
149-
150-
ecurve: 'secp192r1
151-
;- Boban and Alice both init key with same curve
152-
--assert handle? k-Alice: ecdh/init none ecurve
153-
--assert handle? k-Boban: ecdh/init none ecurve
154-
--assert ecurve = ecdh/curve k-Alice
155-
--assert ecurve = ecdh/curve k-Boban
156-
;- ... exports and exchange public parts of it
157-
--assert binary? pub-Alice: ecdh/public k-Alice
158-
--assert binary? pub-Boban: ecdh/public k-Boban
159-
;- ... and use them to compute shared secret.
160-
--assert binary? secret-Alice: ecdh/secret k-Alice pub-Boban
161-
--assert binary? secret-Boban: ecdh/secret k-Boban pub-Alice
162-
;- These keys should be same on both sides
163-
--assert secret-Alice = secret-Boban
164-
;- Once done with the exchange, the ECDH key must be released!
165-
--assert handle? ecdh/release k-Alice
166-
--assert handle? ecdh/release k-Boban
167-
--assert none? ecdh/public k-Alice
168-
169-
--test-- "ECDH (secp160r1) keys usage"
170-
171-
ecurve: 'secp160r1
172-
;- Boban and Alice both init key with same curve
173-
--assert handle? k-Alice: ecdh/init none ecurve
174-
--assert handle? k-Boban: ecdh/init none ecurve
175-
--assert ecurve = ecdh/curve k-Alice
176-
--assert ecurve = ecdh/curve k-Boban
177-
;- ... exports and exchange public parts of it
178-
--assert binary? pub-Alice: ecdh/public k-Alice
179-
--assert binary? pub-Boban: ecdh/public k-Boban
180-
;- ... and use them to compute shared secret.
181-
--assert binary? secret-Alice: ecdh/secret k-Alice pub-Boban
182-
--assert binary? secret-Boban: ecdh/secret k-Boban pub-Alice
183-
;- These keys should be same on both sides
184-
--assert secret-Alice = secret-Boban
185-
;- Once done with the exchange, the ECDH key must be released!
186-
--assert handle? ecdh/release k-Alice
187-
--assert none? ecdh/public k-Alice
188-
189-
--test-- "ECDH key re-initialization"
190-
--assert handle? ecdh/init k-Alice ecurve ;- using existing key for a new init
191-
--assert binary? pub-Alice: ecdh/public k-Alice
192-
;- /release may be used with /secret
193-
--assert binary? secret-Alice: ecdh/secret/release k-Alice pub-Boban
194-
--assert binary? secret-Boban: ecdh/secret/release k-Boban pub-Alice
195-
--assert secret-Alice = secret-Boban
196137

197138
===end-group===
198139

0 commit comments

Comments
 (0)