Dr.-Ing. Mario Heiderich, Cure53
Bielefelder Str. 14
D 10709 Berlin
cure53.de · mario@cure53.de

Audit-Report Silence Laboratories ECDSA lib 10.2022
Cure53, Dr.-Ing. M. Heiderich, Dr. N. Kobeissi

Index
Introduction
Scope
Cryptography Review
Code analysis according to TSS protocol flow logic
Key generation subprotocol
Signing subprotocol
Comparison to third-party Rust implementation
Key generation subprotocol
Signing subprotocol
Conclusion

Cure53, Berlin · 10/28/22

1/12

Dr.-Ing. Mario Heiderich, Cure53
Bielefelder Str. 14
D 10709 Berlin
cure53.de · mario@cure53.de

Introduction“The only library you need for Proofs supported MPC. Enabling enterprises to adopt
proofs-assisted Threshold Signatures (MPC) and MFA through unique fusion of
cryptography and signal processing.”

From https://silencelaboratories.com/

This report describes the results of a thorough cryptography review and source code
audit performed by Cure53 against the ECDSA secp256k1 TSS(2,2) JS library, which ismaintained by Silence Laboratories Pte. Ltd. As for the context and timeline, the work
was requested by Silence Laboratories Pte. Ltd. in September 2022 and carried out by
Cure53 in early-to-mid October 2022, namely in CW40 and CW41.
Note that this was the first time Cure53 looked at this library but some of its
dependencies have been subject to Cure53 audits before, for example
noble/secp256k11. Regarding resources, a total of ten days were invested to reach thecoverage expected for this project. It should also be noted that a team consisting of twosenior testers has been created and assigned to this project’s preparation, execution
and finalization.
The work was structured under one work package (WP):•

WP1: Cryptography reviews & Audits against ECDSA secp256k1 TSS(2,2) JSlibrary

In preparation for this assessment, Cure53 was given access to sources as well as anyother means of information required to perform this audit, the methodology chosen here
was crystal-box. All work necessary from the maintainers’ side was completed in late
September 2022, namely in CW39, so that the Cure53 team could have a smooth start
into the auditing stage in the following week.
Communications during the test were done using a dedicated shared Slack channel,
with which the two teams were connected and could exchange test-specific info, status
reports and Q&As. Test-related discussions were very smooth and not many questions
had to be asked. The scope was well prepared and clear, contributing to no noteworthy
roadblocks being encountered during this audit and review.

1

https://cure53.de/pentest-report_noble-lib.pdf
Cure53, Berlin · 10/28/22

2/12

Dr.-Ing. Mario Heiderich, Cure53
Bielefelder Str. 14
D 10709 Berlin
cure53.de · mario@cure53.deCure53 gave frequent status updates about their progress and the related findings; live
reporting of major issues was not necessary, since none such findings were made.
On that note, the Cure53 team managed to get very good coverage over the WP1 scope
items. Neither vulnerabilities nor weaknesses of any kind were observed by the auditors
as negatively affecting the security premise of the secp256k1 TSS(2,2) JS library. Thismeans that the library presented itself in a very good light with regard to cryptographic
features and guarantees it makes. As this report will describe in later chapters, allrelevant scope areas and key focus areas were inspected in depth, but none yieldedfindings. Hence, the overall impression gained is very positive.
The report will now delineate the scope and test setup, as well as present the available
material for testing. After that, the report will detail the steps undertaken during thecryptography audit and source code review, offering detailed descriptions of the adopted
approaches and corresponding outcomes.
The report will then close with a conclusion in which Cure53 will elaborate on the general
impressions gained throughout this test. The responsible test team will share somewords about the perceived security posture of the ECDSA secp256k1 TSS(2,2) JSlibrary.

Cure53, Berlin · 10/28/22

3/12

Dr.-Ing. Mario Heiderich, Cure53
Bielefelder Str. 14
D 10709 Berlin
cure53.de · mario@cure53.de

Scope
•

2

Cryptography reviews & Code audits against ECDSA secp256k1 TSS(2,2) JSlibrary◦ WP1: Cryptography reviews & Audits of ECDSA secp256k1 TSS(2,2) JS library▪ Library in scope:• ecdsa-tss-js▪ Repository URL:
• https://github.com/silence-laboratories/ecdsa-tss-js▪ Commit ID:• 9eefe4ec90dab75904542df5fbfa50a535cb3ef6▪ Key focus areas:• Paillier cryptosystem◦ External dependency:▪ paillier-bigint (not in scope)• ECDSA implementation◦ External dependency:▪ noble/secp256k1 (not in scope, audited before2)• Key-generation◦ ecdsa/keygen/P1KeyGen.ts◦ ecdsa/keygen/P2KeyGen.ts• Establishing a threshold signature◦ ecdsa/signature/P1Signature.ts◦ ecdsa/signature/P2Signature.ts• Zero-knowledge proof logic◦ Proofs of knowledge regarding discrete log:
▪ zkProofs/pDLProof◦ Hash commitments:▪ zkProofs/hashCommitments◦ Test-supporting material was shared with Cure53◦ All relevant sources were shared with Cure53

https://cure53.de/pentest-report_noble-lib.pdf
Cure53, Berlin · 10/28/22

4/12

Dr.-Ing. Mario Heiderich, Cure53
Bielefelder Str. 14
D 10709 Berlin
cure53.de · mario@cure53.de

Cryptography Review
ECDSA-TSS is a clean-room implementation of Yehuda Lindell’s Fast Secure Two-Party
ECDSA Signing scheme3, first introduced in 2017 as foundational work for Lindell’sstartup company, Unbound Security Ltd., recently acquired by Coinbase. The scheme
proposes a faster, simpler protocol to tackle the restricted “2-of-2” threshold signaturecase, which is especially useful in custodial cryptocurrency wallet scenarios.
Cure53 was tasked with a comprehensive cryptographic review of ECDSA-TSS. This
review was split into three major work components:•••

Zero-knowledge logic library (zkProofs)
Key generation protocol logic for parties 1 and 2 (ecdsa/keygen)
Threshold signature establishment logic for parties 1 and 2 (ecdsa/signature)

For each of the above, the following review methodologies were performed:••

Code analysis according to the TSS protocol’s flow logic and comparison to theoriginal protocol. as specified in Lindell’s paper.
Comparison to a third-party implementation of Lindell paper’s contribution in
Rust.4

Review methodologies failed to identify any outstanding security issues or vulnerabilities
in ECDSA-TSS. As such, this documentation of the cryptography review aims to outline
the process adopted during the project, as it has been followed for each of the abovementioned methodologies.
It is crucial to note that Lindell (2017) does not provide an IETF-style protocol
implementation spec, but rather sticks to high-level descriptions, leaving much of theimplementation details unspecified. This results in protocol engineers needing to fill in
the gaps. Hence, it fosters a certain lack of consistency among independent
implementations.
While ECDSA-TSS does fill these gaps with how it applies and implements low-level
primitives, the high-level specification is still sufficiently close to the 2017 description by
Lindell. In essence, the paper can be used as a benchmark for evaluating the designand security of the resulting software library.

34

https://eprint.iacr.org/2017/552
https://github.com/ZenGo-X/multi-party-ecdsa/tree/master/src/protocols/two_party_ecdsa/lindell_2017
Cure53, Berlin · 10/28/22

5/12

Dr.-Ing. Mario Heiderich, Cure53
Bielefelder Str. 14
D 10709 Berlin
cure53.de · mario@cure53.de

Code analysis according to TSS protocol flow logic
ECDSA-TSS’s README.md provides a sample description of the top-level protocol flowthat is expected to be executed by both parties for session setup and signature. Session
ID generation is handled outside of the scope of the library, with private keys being
optionally provided from a third-party source or generated internally as a random curve
scalar using secure pseudorandomness.

Key generation subprotocol
In accordance with the original protocol specification laid out by Lindell, Party 1 (P1) istasked with generating the Paillier cryptosystem parameters and communicating theinitial session commitment message to Party 2 (P2).

Figure 1. Key generation subprotocol description, from Lindell (2017).

Cure53, Berlin · 10/28/22

6/12

Dr.-Ing. Mario Heiderich, Cure53
Bielefelder Str. 14
D 10709 Berlin
cure53.de · mario@cure53.de

In P1KeyGen.getKeyGenMessage1(), P1:
1.

generates q1 in accordance with the spec, with a random x15 (line 102): this.q1= P1KeyGen.G.multiply(this.x1)

2. generates com-prove and creates a message containing two discrete log proof
commitments, which are then communicated to P2.
In P2KeyGen._processKeyGenMessage1(), P2:
1. validates the state to ensure protocol context and correctness of session ID
2. generates q2 in accordance with the spec, whereas a random x2 (line 77) is q2 =P2KeyGen.G.multiply(this.x2)

3. generates proof and creates a message containing two discrete log proof
commitments, which are then communicated to P2.
In P1KeyGen._processKeyGenMessage2(), P1:
1. validates the state to ensure protocol context and correctness of the session ID
2. verifies dLogProof1 shared in the previous message by P2.
3. Step 3(c) of Figure 1 is pre-calculated by P1 before protocol messages occur,
meaning that the Paillier cryptosystem keys are pre-generated. This is likely donein order to optimize performance.
4. generates a Paillier cryptosystem commitment under the session ID.
5. generates and encrypts cKey in accordance with Step 3(c) of Figure 1.
6. calculates the proofs described in Step 4 in Figure 1.
In P2KeyGen._processKeyGenMessage3(), P2:
1. validates the state to ensure protocol context and correctness of the session ID
2. validates all of the necessary zero-knowledge proofs described in Step 4 of
Figure 1 and is able to authenticate and derive the shared signing public key.

5

Note that Lindell (2017) describes x1 as being within the range {q/3, …, 2q/2}. ECDSA-TSS does notenforce this restriction, allowing x1 to be generated and provided fully outside of the scope of theimplementation.
Cure53, Berlin · 10/28/22

7/12

Dr.-Ing. Mario Heiderich, Cure53
Bielefelder Str. 14
D 10709 Berlin
cure53.de · mario@cure53.deSigning subprotocol

Figure 2: Signing subprotocol description, based on Lindell (2017).
In P1Signature._getSignMessage1(), P1:
1. generates k1 and r1 in accordance with Step 1(a) from Figure 2.
2. generates a discrete log proof over k1 and r1 for the session ID as the context,
3. creates a commitment which is shared with P2, in accordance with Step 1(b) of
Figure 2.
In P2Signature._processSignMessage1(), P2:
1. validates the state to ensure protocol context and correctness of session ID.

Cure53, Berlin · 10/28/22

8/12

Dr.-Ing. Mario Heiderich, Cure53
Bielefelder Str. 14
D 10709 Berlin
cure53.de · mario@cure53.de2. generates k2 and r2 in accordance with Step 2(b) of Figure 2.
3. generates a discrete log proof over k2 and r2 for the session ID as the context,
4. creates a commitment which is shared with P1, in accordance with Step 2(c) of
Figure 2.
In P1Signature._processSignMessage2(), P1:
1. validates the state to ensure protocol context and correctness of session ID.
2. validates the discrete log proof received from P2 (Step 3(a) of Figure 2).
3. performs Step 5(a) of Figure 2 in advance.
In P2Signature.processSignMessage3(), P2:
1. validates the state to ensure protocol context and correctness of session ID.
2. verifies the discrete log proof received from P1 (Step 4(a) of Figure 2).
3. performs Step 4(b) of Figure 2; the calculation of rUpper and r (r1 * k2 and rx %q is done.
4. performs all of the calculations described in Step 4(c) of Figure 2 in the sameorder, and with the same naming conventions:const m = utils.Uint8ArraytoBigint(this.messageHash);const ro = utils.randBelow(q ** 2n);const k2Inv = utils.bigintModInv(this.k2, q);const c1 = paillierPublicKey.encrypt(
ro * q + utils.modPositive(k2Inv * m, q));
const v = k2Inv * r * this.p2KeyShare.x2;
const c2 = paillierPublicKey.multiply(cKeyX1, v);
const c3 = paillierPublicKey.addition(c1, c2);

Finally, in P1Signature._processSignMessage4(), P1:
1. validates the state to ensure protocol context and correctness of session ID
2. uses Paillier in order to decrypt the homomorphically calculated value c3.
3. performs Step 5(b) of Figure 2 (Step 5(a) was performed in advance inP1Signature._processSignMessage2()), choosing the smaller signature.
4. performs Step 5(c), verifying whether the signature communicated by P2 is valid.
Overall, ECDSA-TSS constitutes an exceptionally readable and to-spec implementationof Lindell 2017. No major deviations were found, except for the potential inclusion of theadditional discrete log proofs for ephemeral values. These values do not seem to be
described in the original paper.

Cure53, Berlin · 10/28/22

9/12

Dr.-Ing. Mario Heiderich, Cure53
Bielefelder Str. 14
D 10709 Berlin
cure53.de · mario@cure53.deComparison to third-party Rust implementation
The cryptographic protocol implemented by ECDSA-TSS poses multiple challenges tothe security auditor. First, it involves a rarely implemented protocol. Second, the protocol“specification” is limited to a high-level academic description with no engineering
specification for setting low-level details in stone. It also fails to provide test vectors.
Third, the protocol depends on highly specialized low-level primitives, such as discrete
log proofs and commitment schemes. On homomorphic encryption, it requires theimplementation of the rarely used Paillier cryptosystem.
In order to ascertain a higher level of assurance with regard to the results of this audit, athird-party Rust implementation6 was chosen as an additional target for the ECDSA-TSS
code comparison. The results of the comparison are presented next.

Key generation subprotocol
For all key generation messages, the protocol flow was strikingly similar in terms of how
low-level primitives were designed. Similarities were also documented in the orderingand separation of operation. They mark the only difference in variable names: both
implementations use a hash-based approach in their commitment schemes.
Both implementations calculate a discrete log proof over P1’s initial secret share, q1, etc.
The involved parties structure their internal states similarly and communicate the samemessages over the wire. The same carries on for the entire key generation subprotocol.

Signing subprotocol
Similarly to the key generation subprotocol, the protocol flow, ordering of messages,
ordering of operations and low-level implementation details, were highly similar between
ECDSA-TSS and the independent Rust implementation. Only minor differences invariable names (with ECDSA-TSS being closer to Lindell 2017) were spotted.

6

https://github.com/ZenGo-X/multi-party-ecdsa/tree/master/src/protocols/two_party_ecdsa/lindell_2017

Cure53, Berlin · 10/28/22

10/12

Dr.-Ing. Mario Heiderich, Cure53
Bielefelder Str. 14
D 10709 Berlin
cure53.de · mario@cure53.deFigure 3: Example of the strong similarity between ECDSA-TSS (right) and the
independent Rust implementation (left).
It can be explained that the figure above (Figure 3) is showing implementations of Step
5 from Figure 2. The independent Rust implementation does not seem to immediately
validate the signature.

Cure53, Berlin · 10/28/22

11/12

Dr.-Ing. Mario Heiderich, Cure53
Bielefelder Str. 14
D 10709 Berlin
cure53.de · mario@cure53.de

Conclusion
This audit’s scope targeted a full and original implementation of the two-party thresholdsignature scheme first described in 2017 in an academic paper by Yehuda Lindell. This
scheme was subsequently deployed within major cryptocurrency wallet infrastructure
instances. In autumn 2022, Cure53 was tasked with an audit of the cryptographic
correctness of the protocol logic and flow, the protocol operations, as well as theunderlying custom-implemented cryptographic primitives. The latter considered items
outside of the core signing primitive and the Paillier cryptosystem primitive, both sourced
from external libraries.
To assess the ECDSA secp256k1 TSS(2,2) JS library, which is maintained by Silence
Laboratories, Cure53 carried out a rigorous analysis of ECDSA-TSS by evaluating its
protocol flow logic. The auditors were checking for platform-specific issues that may
arise through the engineering of cryptographic protocols in TypeScript/JavaScript, as
well as audited the custom-implemented low-level cryptographic primitives. Furthermore,
Cure53 performed a complete set of comparisons for the implementation, positioning it
both against the original 2017 Lindell paper, and an independent Rust implementation of
the same protocol.
For context, it should be noted that some consider the nature of Lindell’s 2017 work to
be relatively exotic. The project did not have a long or large implementation history andis characterized by unusual dependencies in terms of cryptographic primitives. In
addition, this assignment framed the unusual target of TypeScript/JavaScript as aruntime for the implementation of cryptographic protocols involving homomorphic
encryption and zero-knowledge proofs. Despite all these possibly adversarial conditions,no outstanding issues could be identified within ECDSA-TSS within the scope of thisaudit.
After a rigorous comparison to both the original 2017 Lindell paper and to anindependent Rust implementation, Cure53 determined that ECDSA-TSS correctly
implemented both of the core subprotocols of Lindell’s 2017 work, and offered a highlevel API that is also relatively hardened against unintentional misuse by the application
layer.
Cure53 would like to thank Vlad Khomenko, Jay Prakash and Dr. Andrei Bytes from the
Silence Laboratories Pte. Ltd. team for their excellent project coordination, support andassistance, both before and during this assignment.

Cure53, Berlin · 10/28/22

12/12