Skip to content

Commit 9d68c5e

Browse files
authored
Merge pull request #1 from crema-labs/feat/ecdsa-old
Core Implementation
2 parents 2891728 + 7ca3c3f commit 9d68c5e

15 files changed

+644
-31
lines changed

.gitmodules

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[submodule "circuits/aes-circom"]
2+
path = circuits/aes-circom
3+
url = https://github.com/crema-labs/aes-circom.git
4+
5+
6+
[submodule "ecdsa-0xparc"]
7+
path = circuits/ecdsa-0xparc
8+
url = https://github.com/crema-labs/circom-ecdsa.git

.mocharc.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22
"extension": ["ts"],
33
"require": "ts-node/register",
44
"spec": "tests/**/*.test.ts",
5-
"timeout": 100000,
5+
"timeout": 100000000,
66
"exit": true
77
}

circuits/add.circom

-10
This file was deleted.

circuits/aes-circom

Submodule aes-circom added at ec54b9b

circuits/encrypt.circom

+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
pragma circom 2.1.9;
2+
3+
include "./ecdsa-0xparc/circuits/secp256k1.circom";
4+
include "./ecdsa-0xparc/circuits/ecdsa.circom";
5+
include "./hkdf.circom";
6+
include "./hmac.circom";
7+
include "./aes-circom/circuits/ctr.circom";
8+
include "./utils.circom";
9+
10+
template Encrypt(npt,ns1,ns2){
11+
signal input r[32];
12+
signal input x[32];
13+
signal input y[32];
14+
signal input pt[npt];
15+
signal input iv[16];
16+
signal input s1[ns1];
17+
signal input s2[ns2];
18+
19+
signal output pubkey[2][4];
20+
signal output ct[npt];
21+
signal output hmac[32];
22+
23+
component BytesToStrides[3];
24+
for (var i = 0; i < 3; i++) {
25+
BytesToStrides[i] = BytesToStrides();
26+
}
27+
BytesToStrides[0].in <== r;
28+
BytesToStrides[1].in <== x;
29+
BytesToStrides[2].in <== y;
30+
31+
component SK = GenSharedKey();
32+
SK.r <== BytesToStrides[0].out;
33+
SK.px <== BytesToStrides[1].out;
34+
SK.py <== BytesToStrides[2].out;
35+
36+
component KG = KeyGen(ns1);
37+
KG.info <== s1;
38+
KG.key <== SK.out;
39+
40+
component AESCTR = EncryptCTR(npt,4);
41+
AESCTR.plainText <== pt;
42+
AESCTR.iv <== iv;
43+
AESCTR.key <== KG.out[0];
44+
45+
component HMAC = HmacSha256(16+npt+ns2,16);
46+
HMAC.key <== KG.out[1];
47+
for (var i = 0; i < 16; i++) {
48+
HMAC.message[i] <== iv[i];
49+
}
50+
for (var i = 0; i < npt; i++) {
51+
HMAC.message[16+i] <== AESCTR.cipher[i];
52+
}
53+
for (var i = 0; i < ns2; i++) {
54+
HMAC.message[16+npt+i] <== s2[i];
55+
}
56+
57+
component PRIV2PUB = ECDSAPrivToPub(64,4);
58+
PRIV2PUB.privkey <== BytesToStrides[0].out;
59+
60+
pubkey <== PRIV2PUB.pubkey;
61+
ct <== AESCTR.cipher;
62+
hmac <== HMAC.hmac;
63+
64+
// decryption needs pubkey.x | pubkey.y | iv | ct | hmac
65+
}
66+
67+
template GenSharedKey(){
68+
signal input r[4];
69+
signal input px[4];
70+
signal input py[4];
71+
72+
signal output out[32];
73+
74+
component scalarMul = Secp256k1ScalarMult(64,4);
75+
scalarMul.scalar <== r;
76+
scalarMul.point[0] <== px;
77+
scalarMul.point[1] <== py;
78+
79+
80+
component StridesToBytes = StridesToBytes();
81+
StridesToBytes.in <== scalarMul.out[0];
82+
83+
for(var i=0;i<32;i++){
84+
out[i] <== StridesToBytes.out[31-i];
85+
}
86+
}
87+
88+
template KeyGen(ni){
89+
signal input info[ni];
90+
signal input key[32];
91+
92+
signal output out[2][16];
93+
94+
component HKDF = HKDFSha256(0,ni,32,2,16);
95+
96+
HKDF.info <== info;
97+
HKDF.key <== key;
98+
99+
out <== HKDF.out;
100+
}

circuits/hkdf.circom

+97
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
pragma circom 2.1.9;
2+
3+
include "./hmac.circom";
4+
5+
// s : salt length
6+
// i : info length
7+
// k : key length
8+
// m : number of keys to extract
9+
// n : key length
10+
template HKDFSha256(s,i,k,m,n){
11+
signal input salt[s];
12+
signal input info[i];
13+
signal input key[k];
14+
15+
signal output out[m][n];
16+
17+
component extract = Extract(s, k);
18+
extract.salt <== salt;
19+
extract.key <== key;
20+
21+
component expand = Expand(i, 32, m, n);
22+
expand.info <== info;
23+
expand.key <== extract.out;
24+
25+
out <== expand.out;
26+
}
27+
28+
// s : salt length
29+
// k : key length
30+
// out : 32 bytes from sha256 hmac
31+
template Extract(s,k){
32+
signal input salt[s];
33+
signal input key[k];
34+
35+
component hmac = HmacSha256(k,s);
36+
signal output out[32];
37+
38+
hmac.message <== key;
39+
hmac.key <== salt;
40+
41+
out <== hmac.hmac;
42+
}
43+
44+
// i : info length
45+
// k : key length
46+
// m : number of keys to extract
47+
// n : key length
48+
template Expand(i,k,m,n){
49+
signal input info[i];
50+
signal input key[k];
51+
52+
var size = 32 + i + 1; // 32 bytes for hmac, i bytes for info, 1 byte for counter
53+
54+
// hash size is 32 bytes
55+
var rounds = (m*n)\(32);
56+
rounds = (rounds * 32) < (m*n) ? rounds + 1 : rounds;
57+
58+
59+
component hmac[rounds];
60+
61+
signal expandedKeys [rounds][32];
62+
signal output out[m][n];
63+
64+
hmac[0] = HmacSha256(i+1,k);
65+
hmac[0].key <== key;
66+
for (var j = 0; j < i; j++){
67+
hmac[0].message[j] <== info[j];
68+
}
69+
hmac[0].message[i] <== 1; // here counter is byte(1)
70+
expandedKeys[0] <== hmac[0].hmac;
71+
72+
var counter = 2; // counter is byte(2)
73+
74+
for(var j = 1; j < rounds; j++){
75+
hmac[j] = HmacSha256(size, k);
76+
for (var o = 0; o < 32; o++){
77+
hmac[j].message[o] <== expandedKeys[j-1][o];
78+
}
79+
for (var o = 0; o < i; o++){
80+
hmac[j].message[32+o] <== info[o];
81+
}
82+
hmac[j].message[32+i] <== counter;
83+
hmac[j].key <== key;
84+
expandedKeys[j] <== hmac[j].hmac;
85+
counter = counter + 1;
86+
}
87+
88+
var byteIndex = 0;
89+
for (var j = 0; j < m; j++) {
90+
for (var o = 0; o < n; o++) {
91+
out[j][o] <== expandedKeys[byteIndex \ 32][byteIndex % 32];
92+
byteIndex++;
93+
}
94+
}
95+
}
96+
97+

circuits/hmac.circom

+161
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
pragma circom 2.1.8;
2+
3+
4+
include "circomlib/circuits/bitify.circom";
5+
include "circomlib/circuits/sha256/sha256.circom";
6+
include "circomlib/circuits/comparators.circom";
7+
include "circomlib/circuits/gates.circom";
8+
include "sha256Hasher.circom";
9+
10+
template HmacSha256(n, k) {
11+
var blockSize = 64;
12+
signal input message[n];
13+
signal input key[k];
14+
signal output hmac[32];
15+
16+
component keyPrep = KeyPrep(k);
17+
keyPrep.in <== key;
18+
19+
signal keyOut[64] <== keyPrep.key;
20+
21+
component innerKeyXOR[blockSize];
22+
component outerKeyXOR[blockSize];
23+
24+
for (var i = 0; i < blockSize; i++) {
25+
innerKeyXOR[i] = XorByte2();
26+
innerKeyXOR[i].a <== keyOut[i];
27+
innerKeyXOR[i].b <== 0x36;
28+
29+
outerKeyXOR[i] = XorByte2();
30+
outerKeyXOR[i].a <== keyOut[i];
31+
outerKeyXOR[i].b <== 0x5c;
32+
}
33+
34+
signal innerHashIn[blockSize + n];
35+
36+
for (var i = 0; i < blockSize; i++) {
37+
innerHashIn[i] <== innerKeyXOR[i].out;
38+
}
39+
for (var i = 0; i < n; i++) {
40+
innerHashIn[blockSize + i] <== message[i];
41+
}
42+
43+
component innerHash = Sha256Bytes(blockSize + n);
44+
45+
for (var i = 0; i < blockSize + n; i++) {
46+
innerHash.in[i] <== innerHashIn[i];
47+
}
48+
49+
signal outerHashIn[blockSize + 32];
50+
51+
for (var i = 0; i < blockSize; i++) {
52+
outerHashIn[i] <== outerKeyXOR[i].out;
53+
}
54+
55+
56+
for (var i = 0; i < 32; i++) {
57+
outerHashIn[blockSize + i] <== innerHash.out[i];
58+
}
59+
60+
component outerHash = Sha256Bytes(blockSize + 32);
61+
outerHash.in <== outerHashIn;
62+
hmac <== outerHash.out;
63+
}
64+
65+
66+
template Concat(n1, n2) {
67+
signal input in1[n1];
68+
signal input in2[n2];
69+
signal output out[n1+n2];
70+
71+
for (var i = 0; i < n1; i++) {
72+
out[i] <== in1[i];
73+
}
74+
for (var i = 0; i < n2; i++) {
75+
out[n1+i] <== in2[i];
76+
}
77+
}
78+
79+
template KeyPrep(k) {
80+
signal input in[k];
81+
signal output key[64];
82+
83+
signal blockSize <== 64;
84+
85+
signal paddingKey[k];
86+
signal shaKey[64];
87+
88+
component sha = Sha256Bytes(k);
89+
for (var i = 0; i < k; i++) {
90+
sha.in[i] <== in[i];
91+
}
92+
93+
component gtChecker = GreaterThan(8);
94+
gtChecker.in[0] <== k;
95+
gtChecker.in[1] <== blockSize;
96+
97+
component selectors[64];
98+
for (var i = 0; i < 64; i++) {
99+
selectors[i] = Selector();
100+
selectors[i].condition <== gtChecker.out;
101+
102+
if (i < 32) {
103+
selectors[i].in[0] <== sha.out[i];
104+
} else {
105+
selectors[i].in[0] <== 0;
106+
}
107+
108+
if (i < k) {
109+
selectors[i].in[1] <== in[i];
110+
} else {
111+
selectors[i].in[1] <== 0;
112+
}
113+
key[i] <== selectors[i].out;
114+
}
115+
}
116+
117+
template Selector() {
118+
signal input condition;
119+
signal input in[2];
120+
signal output out;
121+
122+
out <== condition * (in[0] - in[1]) + in[1];
123+
}
124+
125+
126+
// XORs two bytes
127+
template XorByte2(){
128+
signal input a;
129+
signal input b;
130+
signal output out;
131+
132+
component abits = Num2Bits(8);
133+
abits.in <== a;
134+
135+
component bbits = Num2Bits(8);
136+
bbits.in <== b;
137+
138+
component XorBits2 = XorBits2();
139+
XorBits2.a <== abits.out;
140+
XorBits2.b <== bbits.out;
141+
142+
component num = Bits2Num(8);
143+
num.in <== XorBits2.out;
144+
145+
out <== num.out;
146+
}
147+
148+
// XORs two arrays of bits
149+
template XorBits2(){
150+
signal input a[8];
151+
signal input b[8];
152+
signal output out[8];
153+
154+
component xor[8];
155+
for (var i = 0; i < 8; i++) {
156+
xor[i] = XOR();
157+
xor[i].a <== a[i];
158+
xor[i].b <== b[i];
159+
out[i] <== xor[i].out;
160+
}
161+
}

0 commit comments

Comments
 (0)