├── .etc ├── action.awk ├── all_imports.go └── icon.png ├── .github └── workflows │ ├── ci-actions.yml │ └── semgrep.yml ├── .golangci.yaml ├── .semgrepignore ├── CITATION.cff ├── LICENSE ├── Makefile ├── README.md ├── abe ├── cpabe │ ├── doc.go │ └── tkn20 │ │ ├── bench_test.go │ │ ├── example_test.go │ │ ├── format_test.go │ │ ├── gen_testdata.go │ │ ├── internal │ │ ├── dsl │ │ │ ├── ast.go │ │ │ ├── dsl.go │ │ │ ├── dsl_test.go │ │ │ ├── expr.go │ │ │ ├── interpreter.go │ │ │ ├── lexer.go │ │ │ ├── lexer_test.go │ │ │ ├── parser.go │ │ │ ├── tokens.go │ │ │ └── util.go │ │ └── tkn │ │ │ ├── bk.go │ │ │ ├── bk_test.go │ │ │ ├── formula.go │ │ │ ├── formula_test.go │ │ │ ├── matrixG1.go │ │ │ ├── matrixG1_test.go │ │ │ ├── matrixG2.go │ │ │ ├── matrixG2_test.go │ │ │ ├── matrixGT.go │ │ │ ├── matrixGT_test.go │ │ │ ├── matrixZp.go │ │ │ ├── matrixZp_test.go │ │ │ ├── pairAccum.go │ │ │ ├── policy.go │ │ │ ├── policy_test.go │ │ │ ├── tk.go │ │ │ ├── tk_test.go │ │ │ └── util.go │ │ ├── longpt_test.go │ │ ├── testdata │ │ ├── attributeKey │ │ ├── ciphertext │ │ ├── ciphertext_v137 │ │ ├── policies.json │ │ ├── publicKey │ │ └── secretKey │ │ ├── tkn20.go │ │ └── tkn20_test.go └── doc.go ├── blindsign ├── blindrsa │ ├── brsa.go │ ├── brsa_test.go │ ├── internal │ │ ├── common │ │ │ ├── common.go │ │ │ ├── pss.go │ │ │ └── rsa.go │ │ └── keys │ │ │ └── big_keys.go │ ├── partiallyblindrsa │ │ ├── pbrsa.go │ │ └── pbrsa_test.go │ └── testdata │ │ ├── testRSA2048.rfc9500.pem │ │ └── test_vectors_rfc9474.json └── doc.go ├── cipher ├── ascon │ ├── ascon.go │ ├── ascon_test.go │ └── testdata │ │ ├── Ascon128.json │ │ ├── Ascon128a.json │ │ └── Ascon80pq.json └── doc.go ├── codecov.yml ├── dh ├── csidh │ ├── consts.go │ ├── csidh.go │ ├── csidh_test.go │ ├── curve.go │ ├── curve_test.go │ ├── doc.go │ ├── fp511.go │ ├── fp511_amd64.go │ ├── fp511_amd64.s │ ├── fp511_generic.go │ ├── fp511_noasm.go │ ├── fp511_test.go │ ├── testdata │ │ └── csidh_testvectors.json │ └── utils_test.go ├── curve4q │ ├── curve4Q.go │ ├── curve4Q_test.go │ └── doc.go ├── doc.go ├── sidh │ ├── doc.go │ ├── internal │ │ ├── common │ │ │ ├── doc.go │ │ │ ├── params.go │ │ │ ├── types.go │ │ │ └── utils.go │ │ ├── p434 │ │ │ ├── arith_amd64.s │ │ │ ├── arith_amd64_test.go │ │ │ ├── arith_decl.go │ │ │ ├── arith_generic.go │ │ │ ├── arith_test.go │ │ │ ├── core.go │ │ │ ├── curve.go │ │ │ ├── curve_test.go │ │ │ ├── fp2.go │ │ │ ├── fp2_test.go │ │ │ ├── params.go │ │ │ └── params_test.go │ │ ├── p503 │ │ │ ├── arith_amd64.s │ │ │ ├── arith_amd64_test.go │ │ │ ├── arith_arm64.s │ │ │ ├── arith_decl.go │ │ │ ├── arith_generic.go │ │ │ ├── arith_test.go │ │ │ ├── core.go │ │ │ ├── curve.go │ │ │ ├── curve_test.go │ │ │ ├── doc.go │ │ │ ├── fp2.go │ │ │ ├── fp2_test.go │ │ │ ├── params.go │ │ │ └── params_test.go │ │ ├── p751 │ │ │ ├── arith_amd64.s │ │ │ ├── arith_amd64_test.go │ │ │ ├── arith_arm64.s │ │ │ ├── arith_decl.go │ │ │ ├── arith_generic.go │ │ │ ├── arith_test.go │ │ │ ├── core.go │ │ │ ├── curve.go │ │ │ ├── curve_test.go │ │ │ ├── doc.go │ │ │ ├── fp2.go │ │ │ ├── fp2_test.go │ │ │ ├── params.go │ │ │ └── params_test.go │ │ └── templates │ │ │ ├── arith_decl.gotemp │ │ │ ├── arith_generic.gotemp │ │ │ ├── arith_test.gotemp │ │ │ ├── core.gotemp │ │ │ ├── curve.gotemp │ │ │ ├── curve_test.gotemp │ │ │ ├── fp2.gotemp │ │ │ ├── fp2_test.gotemp │ │ │ └── gen.go │ ├── sidh.go │ ├── sidh_test.go │ ├── sike.go │ ├── sike_test.go │ └── testdata │ │ ├── PQCkemKAT_374.rsp │ │ ├── PQCkemKAT_434.rsp │ │ └── PQCkemKAT_644.rsp ├── x25519 │ ├── curve.go │ ├── curve_amd64.go │ ├── curve_amd64.h │ ├── curve_amd64.s │ ├── curve_generic.go │ ├── curve_noasm.go │ ├── curve_test.go │ ├── doc.go │ ├── key.go │ ├── key_test.go │ ├── table.go │ └── testdata │ │ ├── rfc7748_kat_test.json │ │ ├── rfc7748_times_test.json │ │ └── wycheproof_kat.json └── x448 │ ├── curve.go │ ├── curve_amd64.go │ ├── curve_amd64.h │ ├── curve_amd64.s │ ├── curve_generic.go │ ├── curve_noasm.go │ ├── curve_test.go │ ├── doc.go │ ├── key.go │ ├── key_test.go │ ├── table.go │ └── testdata │ ├── rfc7748_kat_test.json │ └── rfc7748_times_test.json ├── doc.go ├── ecc ├── bls12381 │ ├── constants.go │ ├── doc.go │ ├── ec2.go │ ├── encoding_test.go │ ├── ff │ │ ├── common.go │ │ ├── cyclo6.go │ │ ├── cyclo6_test.go │ │ ├── doc.go │ │ ├── fp.go │ │ ├── fp12.go │ │ ├── fp12_test.go │ │ ├── fp12cubic.go │ │ ├── fp12cubic_test.go │ │ ├── fp2.go │ │ ├── fp2_test.go │ │ ├── fp4.go │ │ ├── fp6.go │ │ ├── fp6_test.go │ │ ├── fpMont381.go │ │ ├── fp_test.go │ │ ├── gen.go │ │ ├── scMont255.go │ │ ├── scalar.go │ │ ├── scalar_test.go │ │ ├── uroot.go │ │ └── uroot_test.go │ ├── g1.go │ ├── g1Isog.go │ ├── g1_test.go │ ├── g2.go │ ├── g2Isog.go │ ├── g2_test.go │ ├── gt.go │ ├── gt_test.go │ ├── hash_test.go │ ├── pair.go │ ├── pair_test.go │ ├── psi_test.go │ └── testdata │ │ ├── BLS12381G1_XMD-SHA-256_SSWU_NU_.json │ │ ├── BLS12381G1_XMD-SHA-256_SSWU_RO_.json │ │ ├── BLS12381G2_XMD-SHA-256_SSWU_NU_.json │ │ ├── BLS12381G2_XMD-SHA-256_SSWU_RO_.json │ │ ├── g1_compressed_valid_test_vectors.dat │ │ ├── g1_uncompressed_valid_test_vectors.dat │ │ ├── g2_compressed_valid_test_vectors.dat │ │ └── g2_uncompressed_valid_test_vectors.dat ├── doc.go ├── fourq │ ├── curve.go │ ├── curve_test.go │ ├── doc.go │ ├── fp.go │ ├── fp_amd64.go │ ├── fp_amd64.h │ ├── fp_amd64.s │ ├── fp_generic.go │ ├── fp_noasm.go │ ├── fp_test.go │ ├── fq.go │ ├── fq_amd64.go │ ├── fq_amd64.h │ ├── fq_amd64.s │ ├── fq_generic.go │ ├── fq_noasm.go │ ├── fq_test.go │ ├── params.go │ ├── point.go │ ├── point_amd64.go │ ├── point_amd64.h │ ├── point_amd64.s │ ├── point_generic.go │ ├── point_noasm.go │ ├── point_test.go │ └── tableBase.go ├── goldilocks │ ├── constants.go │ ├── curve.go │ ├── curve_test.go │ ├── isogeny.go │ ├── isogeny_test.go │ ├── point.go │ ├── point_test.go │ ├── scalar.go │ ├── scalar_test.go │ ├── twist.go │ ├── twistPoint.go │ ├── twistTables.go │ └── twist_basemult.go └── p384 │ ├── LICENSE │ ├── arith.go │ ├── arith_amd64.go │ ├── arith_amd64.s │ ├── arith_arm64.s │ ├── arith_test.go │ ├── doc.go │ ├── opt_test.go │ ├── p384.go │ ├── p384_generic.go │ ├── p384_test.go │ ├── p384opt.go │ ├── point.go │ ├── point_test.go │ └── tableBase.go ├── expander ├── expander.go ├── expander_test.go └── testdata │ ├── expand_message_xmd_SHA256_256.json │ ├── expand_message_xmd_SHA256_38.json │ ├── expand_message_xmd_SHA512_38.json │ ├── expand_message_xof_SHAKE128_256.json │ ├── expand_message_xof_SHAKE128_36.json │ └── expand_message_xof_SHAKE256_36.json ├── go.mod ├── go.sum ├── group ├── group.go ├── group_test.go ├── hash.go ├── hash_test.go ├── ristretto255.go ├── ristretto255_test.go ├── short.go └── testdata │ ├── P256_XMD-SHA-256_SSWU_NU_.json │ ├── P256_XMD-SHA-256_SSWU_RO_.json │ ├── P384_XMD-SHA-384_SSWU_NU_.json │ ├── P384_XMD-SHA-384_SSWU_RO_.json │ ├── P521_XMD-SHA-512_SSWU_NU_.json │ └── P521_XMD-SHA-512_SSWU_RO_.json ├── hpke ├── aead.go ├── aead_test.go ├── algs.go ├── genericnoauthkem.go ├── hpke.go ├── hpke_test.go ├── hybridkem.go ├── kembase.go ├── marshal.go ├── marshal_test.go ├── shortkem.go ├── testdata │ ├── hybrid-x25119-kyber768-test-vectors.json │ └── vectors_rfc9180_5f503c5.json ├── util.go ├── vectors_test.go └── xkem.go ├── internal ├── conv │ └── conv.go ├── nist │ └── drbg.go ├── sha3 │ ├── doc.go │ ├── hashes.go │ ├── keccakf.go │ ├── rc.go │ ├── sha3.go │ ├── sha3_s390x.s │ ├── sha3_test.go │ ├── shake.go │ ├── testdata │ │ └── keccakKats.json.deflate │ ├── xor.go │ ├── xor_generic.go │ └── xor_unaligned.go └── test │ └── test.go ├── kem ├── frodo │ ├── doc.go │ ├── frodo640shake │ │ ├── frodo.go │ │ ├── matrix_shake.go │ │ ├── noise.go │ │ └── util.go │ └── kat_test.go ├── hybrid │ ├── ckem.go │ ├── hybrid.go │ ├── xkem.go │ └── xkem_test.go ├── kem.go ├── kyber │ ├── doc.go │ ├── gen.go │ ├── kat_test.go │ ├── kyber1024 │ │ └── kyber.go │ ├── kyber512 │ │ └── kyber.go │ ├── kyber768 │ │ └── kyber.go │ └── templates │ │ └── pkg.templ.go ├── mlkem │ ├── acvp_test.go │ ├── doc.go │ ├── mlkem1024 │ │ └── kyber.go │ ├── mlkem512 │ │ └── kyber.go │ ├── mlkem768 │ │ └── kyber.go │ └── testdata │ │ ├── ML-KEM-encapDecap-FIPS203 │ │ ├── expectedResults.json.gz │ │ └── prompt.json.gz │ │ ├── ML-KEM-keyGen-FIPS203 │ │ ├── expectedResults.json.gz │ │ └── prompt.json.gz │ │ └── README.md ├── schemes │ ├── schemes.go │ └── schemes_test.go ├── sike │ ├── doc.go │ ├── gen.go │ ├── sikep434 │ │ └── sike.go │ ├── sikep503 │ │ └── sike.go │ ├── sikep751 │ │ └── sike.go │ └── templates │ │ └── pkg.templ.go └── xwing │ ├── scheme.go │ ├── xwing.go │ └── xwing_test.go ├── math ├── fp25519 │ ├── fp.go │ ├── fp_amd64.go │ ├── fp_amd64.h │ ├── fp_amd64.s │ ├── fp_generic.go │ ├── fp_noasm.go │ └── fp_test.go ├── fp448 │ ├── edgecases_test.go │ ├── fp.go │ ├── fp_amd64.go │ ├── fp_amd64.h │ ├── fp_amd64.s │ ├── fp_generic.go │ ├── fp_noasm.go │ ├── fp_test.go │ └── fuzzer.go ├── integer.go ├── mlsbset │ ├── mlsbset.go │ ├── mlsbset_test.go │ └── power.go ├── polynomial │ ├── polynomial.go │ └── polynomial_test.go ├── primes.go ├── primes_test.go ├── wnaf.go └── wnaf_test.go ├── oprf ├── client.go ├── keys.go ├── oprf.go ├── oprf_test.go ├── server.go ├── testdata │ └── rfc9497.json └── vectors_test.go ├── ot ├── doc.go └── simot │ ├── simot_test.go │ ├── simotlocal.go │ └── simotparty.go ├── pke ├── doc.go └── kyber │ ├── gen.go │ ├── internal │ └── common │ │ ├── amd64.go │ │ ├── amd64.s │ │ ├── asm │ │ ├── go.mod │ │ ├── go.sum │ │ └── src.go │ │ ├── field.go │ │ ├── field_test.go │ │ ├── generic.go │ │ ├── ntt.go │ │ ├── ntt_test.go │ │ ├── params.go │ │ ├── params │ │ └── params.go │ │ ├── poly.go │ │ ├── poly_test.go │ │ ├── sample.go │ │ ├── sample_test.go │ │ └── stubs_amd64.go │ ├── kyber.go │ ├── kyber1024 │ ├── internal │ │ ├── cpapke.go │ │ ├── cpapke_test.go │ │ ├── mat.go │ │ ├── params.go │ │ └── vec.go │ └── kyber.go │ ├── kyber512 │ ├── internal │ │ ├── cpapke.go │ │ ├── cpapke_test.go │ │ ├── mat.go │ │ ├── params.go │ │ └── vec.go │ └── kyber.go │ ├── kyber768 │ ├── internal │ │ ├── cpapke.go │ │ ├── cpapke_test.go │ │ ├── mat.go │ │ ├── params.go │ │ └── vec.go │ └── kyber.go │ └── templates │ ├── params.templ.go │ └── pkg.templ.go ├── pki ├── pki.go └── pki_test.go ├── secretsharing ├── example_test.go ├── ss.go └── ss_test.go ├── sign ├── bls │ ├── bls.go │ ├── bls_test.go │ ├── testdata │ │ ├── sig_g1_basic_P256.txt.zip │ │ ├── sig_g1_basic_P521.txt.zip │ │ ├── sig_g2_basic_P256.txt.zip │ │ └── sig_g2_basic_P521.txt.zip │ └── vectors_test.go ├── dilithium │ ├── dilithium.go │ ├── dilithium_test.go │ ├── gen.go │ ├── kat_test.go │ ├── mode2 │ │ ├── dilithium.go │ │ └── internal │ │ │ ├── dilithium.go │ │ │ ├── dilithium_test.go │ │ │ ├── mat.go │ │ │ ├── pack.go │ │ │ ├── pack_test.go │ │ │ ├── params.go │ │ │ ├── params_test.go │ │ │ ├── rounding.go │ │ │ ├── rounding_test.go │ │ │ ├── sample.go │ │ │ ├── sample_test.go │ │ │ └── vec.go │ ├── mode3 │ │ ├── dilithium.go │ │ └── internal │ │ │ ├── dilithium.go │ │ │ ├── dilithium_test.go │ │ │ ├── mat.go │ │ │ ├── pack.go │ │ │ ├── pack_test.go │ │ │ ├── params.go │ │ │ ├── params_test.go │ │ │ ├── rounding.go │ │ │ ├── rounding_test.go │ │ │ ├── sample.go │ │ │ ├── sample_test.go │ │ │ └── vec.go │ ├── mode5 │ │ ├── dilithium.go │ │ └── internal │ │ │ ├── dilithium.go │ │ │ ├── dilithium_test.go │ │ │ ├── mat.go │ │ │ ├── pack.go │ │ │ ├── pack_test.go │ │ │ ├── params.go │ │ │ ├── params_test.go │ │ │ ├── rounding.go │ │ │ ├── rounding_test.go │ │ │ ├── sample.go │ │ │ ├── sample_test.go │ │ │ └── vec.go │ └── templates │ │ ├── acvp.templ.go │ │ ├── params.templ.go │ │ └── pkg.templ.go ├── ed25519 │ ├── ed25519.go │ ├── ed25519_test.go │ ├── extra_test.go │ ├── modular.go │ ├── modular_test.go │ ├── mult.go │ ├── point.go │ ├── point_test.go │ ├── pubkey.go │ ├── pubkey112.go │ ├── rfc8032_test.go │ ├── signapi.go │ ├── tables.go │ ├── testdata │ │ ├── sign.input.zip │ │ └── wycheproof_Ed25519.json │ └── wycheproof_test.go ├── ed448 │ ├── ed448.go │ ├── ed448_test.go │ ├── rfc8032_test.go │ ├── signapi.go │ ├── testdata │ │ └── wycheproof_Ed448.json │ └── wycheproof_test.go ├── eddilithium2 │ ├── eddilithium.go │ ├── eddilithium_test.go │ ├── example_test.go │ └── signapi.go ├── eddilithium3 │ ├── eddilithium.go │ ├── eddilithium_test.go │ ├── example_test.go │ └── signapi.go ├── internal │ └── dilithium │ │ ├── amd64.go │ │ ├── amd64.s │ │ ├── asm │ │ ├── go.mod │ │ ├── go.sum │ │ └── src.go │ │ ├── field.go │ │ ├── field_test.go │ │ ├── generic.go │ │ ├── ntt.go │ │ ├── ntt_test.go │ │ ├── pack.go │ │ ├── pack_test.go │ │ ├── params.go │ │ ├── params │ │ └── params.go │ │ ├── poly.go │ │ ├── poly_test.go │ │ └── stubs_amd64.go ├── mldsa │ ├── doc.go │ ├── mldsa44 │ │ ├── acvp_test.go │ │ ├── dilithium.go │ │ └── internal │ │ │ ├── dilithium.go │ │ │ ├── dilithium_test.go │ │ │ ├── mat.go │ │ │ ├── pack.go │ │ │ ├── pack_test.go │ │ │ ├── params.go │ │ │ ├── rounding.go │ │ │ ├── rounding_test.go │ │ │ ├── sample.go │ │ │ ├── sample_test.go │ │ │ └── vec.go │ ├── mldsa65 │ │ ├── acvp_test.go │ │ ├── dilithium.go │ │ └── internal │ │ │ ├── dilithium.go │ │ │ ├── dilithium_test.go │ │ │ ├── mat.go │ │ │ ├── pack.go │ │ │ ├── pack_test.go │ │ │ ├── params.go │ │ │ ├── rounding.go │ │ │ ├── rounding_test.go │ │ │ ├── sample.go │ │ │ ├── sample_test.go │ │ │ └── vec.go │ ├── mldsa87 │ │ ├── acvp_test.go │ │ ├── dilithium.go │ │ └── internal │ │ │ ├── dilithium.go │ │ │ ├── dilithium_test.go │ │ │ ├── mat.go │ │ │ ├── pack.go │ │ │ ├── pack_test.go │ │ │ ├── params.go │ │ │ ├── rounding.go │ │ │ ├── rounding_test.go │ │ │ ├── sample.go │ │ │ ├── sample_test.go │ │ │ └── vec.go │ └── testdata │ │ ├── ML-DSA-keyGen-FIPS204 │ │ ├── expectedResults.json.gz │ │ └── prompt.json.gz │ │ ├── ML-DSA-sigGen-FIPS204 │ │ ├── expectedResults.json.gz │ │ └── prompt.json.gz │ │ └── ML-DSA-sigVer-FIPS204 │ │ ├── expectedResults.json.gz │ │ └── prompt.json.gz ├── schemes │ ├── schemes.go │ └── schemes_test.go └── sign.go ├── simd ├── doc.go └── keccakf1600 │ ├── example_test.go │ ├── f1600x.go │ ├── f1600x2_arm64.go │ ├── f1600x2_arm64.s │ ├── f1600x4_amd64.go │ ├── f1600x4_amd64.s │ ├── f1600x4stubs_amd64.go │ ├── f1600x_test.go │ ├── fallback.go │ └── internal │ └── asm │ ├── go.mod │ ├── go.sum │ └── src.go ├── tss ├── doc.go └── rsa │ ├── README.md │ ├── internal │ ├── pkcs1v15.go │ └── pss │ │ ├── pss.go │ │ └── rsa.go │ ├── keyshare.go │ ├── keyshare_test.go │ ├── padding.go │ ├── rsa_threshold.go │ ├── rsa_threshold_test.go │ ├── signShare.go │ ├── signShare_test.go │ ├── util.go │ └── util_test.go ├── vdaf ├── doc.go └── prio3 │ ├── arith │ ├── arith.go │ ├── field_test.go │ ├── fp128 │ │ ├── fiatMont.go │ │ ├── fp.go │ │ ├── inverse.go │ │ ├── poly.go │ │ └── vector.go │ ├── fp128_test.go │ ├── fp64 │ │ ├── fiatMont.go │ │ ├── fp.go │ │ ├── inverse.go │ │ ├── poly.go │ │ └── vector.go │ ├── fp64_test.go │ ├── gen.go │ ├── genFiatMont.go │ ├── poly_test.go │ ├── templates │ │ ├── fp.go.tmpl │ │ ├── fp_test.go.tmpl │ │ ├── poly.go.tmpl │ │ └── vector.go.tmpl │ └── vector_test.go │ ├── common_test.go │ ├── count │ ├── count.go │ └── count_test.go │ ├── doc.go │ ├── histogram │ ├── histogram.go │ └── histogram_test.go │ ├── internal │ ├── cursor │ │ └── cursor.go │ ├── flp │ │ ├── flp.go │ │ ├── gadgets.go │ │ └── valid.go │ ├── flp_test │ │ └── query.go │ └── prio3 │ │ ├── prio3.go │ │ ├── types.go │ │ └── xof.go │ ├── mhcv │ ├── mhcv.go │ └── mhcv_test.go │ ├── prio3_test.go │ ├── sum │ ├── sum.go │ └── sum_test.go │ ├── sumvec │ ├── sumvec.go │ └── sumvec_test.go │ ├── testdata │ ├── Prio3Count_0.json │ ├── Prio3Count_1.json │ ├── Prio3Count_2.json │ ├── Prio3Histogram_0.json │ ├── Prio3Histogram_1.json │ ├── Prio3Histogram_2.json │ ├── Prio3MultihotCountVec_0.json │ ├── Prio3MultihotCountVec_1.json │ ├── Prio3MultihotCountVec_2.json │ ├── Prio3SumVec_0.json │ ├── Prio3SumVec_1.json │ ├── Prio3Sum_0.json │ ├── Prio3Sum_1.json │ ├── Prio3Sum_2.json │ └── XofTurboShake128.json │ ├── vectors_test.go │ └── xof_test.go ├── xof ├── k12 │ ├── k12.go │ └── k12_test.go ├── xof.go └── xof_test.go └── zk ├── dl ├── dl.go └── dl_test.go ├── dleq ├── dleq.go └── dleq_test.go ├── doc.go └── qndleq ├── qndleq.go └── qndleq_test.go /.etc/action.awk: -------------------------------------------------------------------------------- 1 | !/^#/{split($0, a, ":"); print "::error file="a[1]",line="a[2]",col="a[3]"::"a[4]} END{if(NR!=0) exit 1} 2 | -------------------------------------------------------------------------------- /.etc/all_imports.go: -------------------------------------------------------------------------------- 1 | //go:build ignore 2 | // +build ignore 3 | 4 | // Generates a Go program with all the public imports of CIRCL. It is used to 5 | // test compilation using static (buildmode=default) and dynamic linking 6 | // (buildmode=plugin). 7 | package main 8 | 9 | import ( 10 | "flag" 11 | "fmt" 12 | "io/fs" 13 | "os" 14 | "strings" 15 | ) 16 | 17 | func main() { 18 | outputFileName := flag.String("out", "circl.go", "name of the output file.") 19 | flag.Parse() 20 | 21 | f, err := os.Create(*outputFileName) 22 | if err != nil { 23 | panic(err) 24 | } 25 | defer f.Close() 26 | 27 | skipDirs := []string{".", "testdata", "internal", "templates"} 28 | circl := "github.com/cloudflare/circl/" 29 | 30 | fmt.Fprintln(f, "package main") 31 | err = fs.WalkDir(os.DirFS("."), ".", func(path string, d fs.DirEntry, err error) error { 32 | if err != nil { 33 | panic(err) 34 | } 35 | if d.IsDir() { 36 | for _, sd := range skipDirs { 37 | if strings.Contains(path, sd) { 38 | return nil 39 | } 40 | } 41 | fmt.Fprintf(f, "import _ \"%v%v\"\n", circl, path) 42 | } 43 | return nil 44 | }) 45 | if err != nil { 46 | panic(err) 47 | } 48 | fmt.Fprintln(f, "func main() {}") 49 | } 50 | -------------------------------------------------------------------------------- /.etc/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/circl/main/.etc/icon.png -------------------------------------------------------------------------------- /.github/workflows/semgrep.yml: -------------------------------------------------------------------------------- 1 | on: 2 | pull_request: {} 3 | workflow_dispatch: {} 4 | push: 5 | branches: 6 | - main 7 | schedule: 8 | - cron: '0 0 * * *' 9 | name: Semgrep 10 | jobs: 11 | semgrep: 12 | name: semgrep/ci 13 | runs-on: ubuntu-latest 14 | if: github.repository == 'cloudflare/circl' 15 | env: 16 | SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} 17 | SEMGREP_URL: https://cloudflare.semgrep.dev 18 | SEMGREP_APP_URL: https://cloudflare.semgrep.dev 19 | SEMGREP_VERSION_CHECK_URL: https://cloudflare.semgrep.dev/api/check-version 20 | container: 21 | image: semgrep/semgrep 22 | steps: 23 | - uses: actions/checkout@v4 24 | - run: semgrep ci --verbose 25 | -------------------------------------------------------------------------------- /.golangci.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | linters: 3 | disable-all: true 4 | enable: 5 | # - lll 6 | # - gocritic 7 | # - gocognit 8 | # - gci (deprecated since v1.30.0) 9 | # - interfacer (deprecated since v1.38.0) 10 | # - scopelint (deprecated since v1.39.0) 11 | # - golint (deprecated since v1.41.0) 12 | # - structcheck (deprecated since v1.49.0) 13 | # - varcheck (deprecated since v1.49.0) 14 | # - deadcode (deprecated since v1.49.0) 15 | # - exportloopref (deprecated since v1.60.2) 16 | - bodyclose 17 | - copyloopvar 18 | - depguard 19 | - dogsled 20 | - errcheck 21 | - forbidigo 22 | - funlen 23 | - goconst 24 | - gocyclo 25 | - gofmt 26 | - gofumpt 27 | - goimports 28 | - gosec 29 | - gosimple 30 | - govet 31 | - ineffassign 32 | - misspell 33 | - nakedret 34 | - staticcheck 35 | - stylecheck 36 | - typecheck 37 | - unconvert 38 | - unparam 39 | - unused 40 | - whitespace 41 | 42 | linters-settings: 43 | depguard: 44 | rules: 45 | main: 46 | files: 47 | - $all 48 | allow: 49 | - $gostd 50 | - golang.org/x 51 | - github.com/bwesterb/go-ristretto 52 | - github.com/cloudflare/circl 53 | funlen: 54 | lines: 120 55 | statements: 80 56 | nestif: 57 | min-complexity: 6 58 | goconst: 59 | min-occurrences: 4 60 | govet: 61 | enable-all: true 62 | disable: 63 | - fieldalignment 64 | staticcheck: 65 | # TODO: replace deprecated elliptic.Marshal, elliptic.GenerateKey, 66 | # elliptic.Unmarshal, params.ScalarBaseMult before re-enabling SA1019. 67 | checks: ["*", "-SA1019"] 68 | gosec: 69 | excludes: 70 | - G115 71 | 72 | issues: 73 | max-issues-per-linter: 0 74 | max-same-issues: 0 75 | -------------------------------------------------------------------------------- /.semgrepignore: -------------------------------------------------------------------------------- 1 | .github/ 2 | -------------------------------------------------------------------------------- /CITATION.cff: -------------------------------------------------------------------------------- 1 | --- 2 | cff-version: 1.2.0 3 | version: 1.6.1 4 | title: "Introducing CIRCL: An Advanced Cryptographic Library" 5 | license: BSD-3-Clause 6 | abstract: > 7 | CIRCL (Cloudflare Interoperable, Reusable Cryptographic Library) is 8 | a collection of cryptographic primitives written in Go. The goal 9 | of this library is to be used as a tool for experimental 10 | deployment of cryptographic algorithms targeting Post-Quantum (PQ) 11 | and Elliptic Curve Cryptography (ECC). 12 | authors: 13 | - family-names: Faz-Hernandez 14 | given-names: Armando 15 | affiliation: Cloudflare, Inc. 16 | orcid: "https://orcid.org/0000-0001-5502-8666" 17 | - family-names: Kwiatkowski 18 | given-names: Kris 19 | orcid: "https://orcid.org/0000-0003-2363-317X" 20 | date-released: "2019-07-10" 21 | keywords: 22 | - cryptography 23 | - crypto 24 | - post-quantum 25 | - golang 26 | repository-code: "https://github.com/cloudflare/circl/" 27 | type: software 28 | message: "Available at https://github.com/cloudflare/circl. v1.6.1 Accessed Apr, 2025." 29 | contact: 30 | - name: "Cloudflare, Inc." 31 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # I'm sure there is better way. But I would need to find it first 2 | MK_FILE_PATH = $(lastword $(MAKEFILE_LIST)) 3 | PRJ_DIR = $(abspath $(dir $(MK_FILE_PATH))) 4 | GOPATH_BUILD = $(PRJ_DIR)/build 5 | COVER_DIR = $(GOPATH_BUILD)/coverage 6 | TOOLS_DIR ?= $(GOPATH)/bin 7 | ETC_DIR = $(PRJ_DIR)/.etc 8 | OPTS ?= 9 | NOASM ?= 10 | GO ?= go 11 | GOLANGCILINT ?= golangci-lint 12 | # -run="^_" as we want to avoid running tests by 'bench' and there never be a test starting with _ 13 | BENCH_OPTS ?= -bench=. -run="^_" -benchmem 14 | V ?= 1 15 | GOARCH ?= 16 | BUILD_ARCH = $(shell $(GO) env GOARCH) 17 | 18 | ifeq ($(NOASM),1) 19 | OPTS+=--tags purego 20 | endif 21 | 22 | ifeq ($(V),1) 23 | OPTS += -v # Be verbose 24 | endif 25 | 26 | all: build 27 | 28 | lint: 29 | $(GOLANGCILINT) run 30 | 31 | lint-fix: 32 | $(GOLANGCILINT) run --fix 33 | 34 | build: 35 | $(GO) build ./... 36 | 37 | test: clean 38 | $(GO) vet ./... 39 | $(GO) test $(OPTS) ./... 40 | 41 | bench: clean 42 | $(GO) test $(BENCH_OPTS) $(OPTS) ./... 43 | 44 | cover: clean 45 | mkdir -p $(COVER_DIR) 46 | $(GO) test -race -coverprofile=$(COVER_DIR)/coverage.txt -covermode=atomic $(OPTS) ./... 47 | $(GO) tool cover -html $(COVER_DIR)/coverage.txt -o $(COVER_DIR)/coverage.html 48 | 49 | generate: clean 50 | $(GO) generate -v ./... 51 | 52 | bootstrap: 53 | curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(TOOLS_DIR) v1.18.0 54 | 55 | clean: 56 | rm -rf $(GOPATH_BUILD) 57 | 58 | .INTERMEDIATE: circl.go circl_static.exe circl_plugin.so 59 | circl_static: circl_static.exe 60 | circl_static.exe: circl.go 61 | go clean -cache -modcache 62 | go build -buildmode=default -o $@ $^ 63 | 64 | circl_plugin: circl_plugin.so 65 | circl_plugin.so: circl.go 66 | go clean -cache -modcache 67 | go build -buildmode=plugin -o $@ $^ 68 | 69 | circl.go: 70 | go run .etc/all_imports.go -out $@ 71 | -------------------------------------------------------------------------------- /abe/cpabe/doc.go: -------------------------------------------------------------------------------- 1 | // Package cpabe provides Ciphertext-Policy Attribute-based Encryption algorithms. 2 | package cpabe 3 | -------------------------------------------------------------------------------- /abe/cpabe/tkn20/gen_testdata.go: -------------------------------------------------------------------------------- 1 | //go:build ignore 2 | // +build ignore 3 | 4 | // Generates golden files for tests. 5 | package main 6 | 7 | import ( 8 | "encoding" 9 | "os" 10 | 11 | cpabe "github.com/cloudflare/circl/abe/cpabe/tkn20" 12 | "github.com/cloudflare/circl/xof" 13 | ) 14 | 15 | func writeToFile(name string, data []byte) { 16 | err := os.WriteFile("testdata/"+name, data, 0o644) 17 | if err != nil { 18 | panic(err) 19 | } 20 | } 21 | 22 | func dumpToFile(name string, m encoding.BinaryMarshaler) { 23 | data, err := m.MarshalBinary() 24 | if err != nil { 25 | panic(err) 26 | } 27 | writeToFile(name, data) 28 | } 29 | 30 | func main() { 31 | // Using fixed PRNG for reproducibility, 32 | prng := xof.SHAKE128.New() 33 | 34 | err := os.MkdirAll("testdata", 0o755) 35 | if err != nil { 36 | panic(err) 37 | } 38 | 39 | publicParams, secretParams, err := cpabe.Setup(prng) 40 | if err != nil { 41 | panic(err) 42 | } 43 | 44 | dumpToFile("publicKey", &publicParams) 45 | dumpToFile("secretKey", &secretParams) 46 | 47 | attrs := cpabe.Attributes{} 48 | attrs.FromMap(map[string]string{"country": "NL", "EU": "true"}) 49 | 50 | policy := cpabe.Policy{} 51 | err = policy.FromString("EU: true") 52 | if err != nil { 53 | panic(err) 54 | } 55 | msg := []byte("Be sure to drink your ovaltine!") 56 | ciphertext, err := publicParams.Encrypt(prng, policy, msg) 57 | if err != nil { 58 | panic(err) 59 | } 60 | writeToFile("ciphertext", ciphertext) 61 | 62 | key, err := secretParams.KeyGen(prng, attrs) 63 | if err != nil { 64 | panic(err) 65 | } 66 | dumpToFile("attributeKey", &key) 67 | } 68 | -------------------------------------------------------------------------------- /abe/cpabe/tkn20/internal/dsl/dsl.go: -------------------------------------------------------------------------------- 1 | package dsl 2 | 3 | import "github.com/cloudflare/circl/abe/cpabe/tkn20/internal/tkn" 4 | 5 | var AttrHashKey = []byte("attribute value hashing") 6 | 7 | func Run(source string) (*tkn.Policy, error) { 8 | l := newLexer(source) 9 | err := l.scanTokens() 10 | if err != nil { 11 | return nil, err 12 | } 13 | p := newParser(l.tokens) 14 | ast, err := p.parse() 15 | if err != nil { 16 | return nil, err 17 | } 18 | return ast.RunPasses() 19 | } 20 | -------------------------------------------------------------------------------- /abe/cpabe/tkn20/internal/dsl/expr.go: -------------------------------------------------------------------------------- 1 | package dsl 2 | 3 | type Expr interface { 4 | Accept(ExprVisitor) 5 | } 6 | 7 | type ExprVisitor interface { 8 | visitBinary(binary Binary) 9 | visitUnary(unary Unary) 10 | visitGrouping(grouping Grouping) 11 | visitLiteral(literal Literal) 12 | } 13 | 14 | // Binary is used for And, Or 15 | type Binary struct { 16 | Left Expr 17 | Operator Token 18 | Right Expr 19 | Output attr 20 | } 21 | 22 | func (b Binary) Accept(visitor ExprVisitor) { 23 | visitor.visitBinary(b) 24 | } 25 | 26 | // Unary is used for Not 27 | type Unary struct { 28 | Operator Token 29 | Right Expr 30 | } 31 | 32 | func (u Unary) Accept(visitor ExprVisitor) { 33 | visitor.visitUnary(u) 34 | } 35 | 36 | // Grouping is used for LeftParen, RightParen 37 | type Grouping struct { 38 | Expr Expr 39 | } 40 | 41 | func (g Grouping) Accept(visitor ExprVisitor) { 42 | visitor.visitGrouping(g) 43 | } 44 | 45 | type Literal struct { 46 | Key attr 47 | Value attrValue 48 | } 49 | 50 | func (l Literal) Accept(visitor ExprVisitor) { 51 | visitor.visitLiteral(l) 52 | } 53 | -------------------------------------------------------------------------------- /abe/cpabe/tkn20/internal/dsl/interpreter.go: -------------------------------------------------------------------------------- 1 | package dsl 2 | 3 | type Interpreter struct { 4 | Literal 5 | } 6 | 7 | func (i *Interpreter) Evaluate(expr Expr) Literal { 8 | expr.Accept(i) 9 | return i.Literal 10 | } 11 | 12 | func (i *Interpreter) visitBinary(b Binary) { 13 | i.Literal.Key = b.Output 14 | } 15 | 16 | func (i *Interpreter) visitUnary(u Unary) { 17 | i.Evaluate(u.Right) 18 | } 19 | 20 | func (i *Interpreter) visitGrouping(g Grouping) { 21 | g.Expr.Accept(i) 22 | } 23 | 24 | func (i *Interpreter) visitLiteral(at Literal) { 25 | i.Literal = at 26 | } 27 | -------------------------------------------------------------------------------- /abe/cpabe/tkn20/internal/dsl/lexer.go: -------------------------------------------------------------------------------- 1 | package dsl 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "strings" 7 | ) 8 | 9 | var keywords = map[string]string{ 10 | "and": And, 11 | "or": Or, 12 | "not": Not, 13 | } 14 | 15 | type Lexer struct { 16 | source string 17 | tokens []Token 18 | start int 19 | curr int 20 | line int 21 | hadError bool 22 | } 23 | 24 | func newLexer(source string) Lexer { 25 | return Lexer{ 26 | source: source, 27 | tokens: nil, 28 | start: 0, 29 | curr: 0, 30 | line: 1, 31 | hadError: false, 32 | } 33 | } 34 | 35 | func (l *Lexer) scanTokens() error { 36 | errMsg := "unexpected character(s): " 37 | for l.curr < len(l.source) { 38 | l.start = l.curr 39 | c := l.source[l.curr] 40 | l.curr++ 41 | switch c { 42 | case '(': 43 | l.addToken(LeftParen) 44 | case ')': 45 | l.addToken(RightParen) 46 | case ':': 47 | l.addToken(Colon) 48 | case ' ', '\r', '\t': 49 | case '\n': 50 | l.line++ 51 | default: 52 | if isAlphaNumeric(c) { 53 | l.identifier() 54 | } else { 55 | errMsg += fmt.Sprintf("'%s' ", string(c)) 56 | l.hadError = true 57 | } 58 | } 59 | } 60 | l.addToken(EOF) 61 | if l.hadError { 62 | return errors.New(strings.TrimSpace(errMsg)) 63 | } 64 | return nil 65 | } 66 | 67 | func (l *Lexer) addToken(tokenType string) { 68 | token := Token{ 69 | tokenType, 70 | l.source[l.start:l.curr], 71 | l.line, 72 | } 73 | l.tokens = append(l.tokens, token) 74 | } 75 | 76 | func (l *Lexer) identifier() { 77 | for l.curr < len(l.source) { 78 | if isAlphaNumeric(l.source[l.curr]) { 79 | l.curr++ 80 | } else { 81 | break 82 | } 83 | } 84 | tokenType, ok := keywords[l.source[l.start:l.curr]] 85 | if !ok { 86 | tokenType = Identifier 87 | } 88 | l.addToken(tokenType) 89 | } 90 | -------------------------------------------------------------------------------- /abe/cpabe/tkn20/internal/dsl/lexer_test.go: -------------------------------------------------------------------------------- 1 | package dsl 2 | 3 | import ( 4 | "errors" 5 | "testing" 6 | ) 7 | 8 | func TestLexerErr(t *testing.T) { 9 | l := newLexer("sleep: @)") 10 | err := l.scanTokens() 11 | expectedErr := errors.New("unexpected character(s): '@'") 12 | if err == nil { 13 | t.Fatalf("missing expected err %v", expectedErr) 14 | } 15 | if expectedErr.Error() != err.Error() { 16 | t.Fatalf("incorrect error: expected %v, received %v", expectedErr, err) 17 | } 18 | } 19 | 20 | func TestLexer(t *testing.T) { 21 | l := newLexer("(sleep \n: \nnice\n)") 22 | err := l.scanTokens() 23 | if err != nil { 24 | t.Fatal(err) 25 | } 26 | 27 | types := []string{LeftParen, Identifier, Colon, Identifier, RightParen, EOF} 28 | 29 | if len(l.tokens) != len(types) { 30 | t.Fatalf("expected %d tokens, received: %v", len(types), len(l.tokens)) 31 | } 32 | for i, typ := range types { 33 | if typ != l.tokens[i].Type { 34 | t.Fatalf("expected token %s, received: %s", typ, l.tokens[i].Type) 35 | } 36 | } 37 | 38 | if l.tokens[2].Line != 2 { 39 | t.Fatalf("expected line 2, received: %d", l.tokens[2].Line) 40 | } 41 | if l.tokens[3].Line != 3 { 42 | t.Fatalf("expected line 3, received: %d", l.tokens[3].Line) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /abe/cpabe/tkn20/internal/dsl/tokens.go: -------------------------------------------------------------------------------- 1 | package dsl 2 | 3 | const ( 4 | LeftParen = "(" 5 | RightParen = ")" 6 | Colon = ":" 7 | And = "and" 8 | Or = "or" 9 | Not = "not" 10 | Identifier = "identifier" 11 | EOF = "eof" 12 | ) 13 | 14 | type Token struct { 15 | Type string 16 | Lexeme string 17 | Line int 18 | } 19 | -------------------------------------------------------------------------------- /abe/cpabe/tkn20/internal/dsl/util.go: -------------------------------------------------------------------------------- 1 | package dsl 2 | 3 | func isDigit(c uint8) bool { 4 | return c >= '0' && c <= '9' 5 | } 6 | 7 | func isAlpha(c uint8) bool { 8 | return (c >= 'a' && c <= 'z') || 9 | (c >= 'A' && c <= 'Z') || 10 | c == '_' 11 | } 12 | 13 | func isAlphaNumeric(c uint8) bool { 14 | return isAlpha(c) || isDigit(c) 15 | } 16 | -------------------------------------------------------------------------------- /abe/cpabe/tkn20/internal/tkn/formula_test.go: -------------------------------------------------------------------------------- 1 | package tkn 2 | 3 | import ( 4 | "crypto/rand" 5 | "testing" 6 | ) 7 | 8 | func TestShare(t *testing.T) { 9 | f := Formula{ 10 | Gates: []Gate{ 11 | {Andgate, 2, 3, 4}, 12 | {Andgate, 0, 1, 3}, 13 | }, 14 | } 15 | k, err := randomMatrixZp(rand.Reader, 1, 17) 16 | if err != nil { 17 | t.Fatalf("error generating vector: %s", err) 18 | } 19 | res, err := f.share(rand.Reader, k) 20 | if err != nil { 21 | t.Fatalf("error sharing: %s", err) 22 | } 23 | if len(res) != 3 { 24 | t.Errorf("res wrong size") 25 | } 26 | acc := newMatrixZp(1, 17) 27 | for i := 0; i < len(res); i++ { 28 | acc.add(acc, res[i]) 29 | } 30 | if !acc.Equal(k) { 31 | t.Errorf("incorrect share") 32 | } 33 | } 34 | 35 | func TestFormulaMarshal(t *testing.T) { 36 | f := Formula{ 37 | Gates: []Gate{ 38 | {Andgate, 0, 1, 3}, 39 | {Andgate, 2, 3, 4}, 40 | }, 41 | } 42 | data, err := f.MarshalBinary() 43 | if err != nil { 44 | t.Fatalf("error marshalling: %s", err) 45 | } 46 | g := &Formula{} 47 | err = g.UnmarshalBinary(data) 48 | if err != nil { 49 | t.Fatalf("error unmarshalling: %s", err) 50 | } 51 | if !f.Equal(*g) { 52 | t.Fatal("failure to recover formula") 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /abe/cpabe/tkn20/internal/tkn/pairAccum.go: -------------------------------------------------------------------------------- 1 | package tkn 2 | 3 | import ( 4 | "fmt" 5 | 6 | pairing "github.com/cloudflare/circl/ecc/bls12381" 7 | ) 8 | 9 | type pairAccum struct { 10 | as []*pairing.G1 11 | bs []*pairing.G2 12 | scalars []int 13 | } 14 | 15 | func (pairs *pairAccum) addDuals(m1 *matrixG1, m2 *matrixG2, n int) { 16 | if m1.cols != 1 || m2.cols != 1 { 17 | panic(fmt.Sprintf("misuse of addDuals: m1: %d x %d m2: %d x %d\n", m1.rows, m1.cols, m2.rows, m2.cols)) 18 | } 19 | for k := 0; k < m1.rows; k++ { 20 | pairs.as = append(pairs.as, &m1.entries[k]) 21 | pairs.bs = append(pairs.bs, &m2.entries[k]) 22 | pairs.scalars = append(pairs.scalars, n) 23 | } 24 | } 25 | 26 | func (pairs *pairAccum) eval() *pairing.Gt { 27 | return pairing.ProdPairFrac(pairs.as, pairs.bs, pairs.scalars) 28 | } 29 | -------------------------------------------------------------------------------- /abe/cpabe/tkn20/longpt_test.go: -------------------------------------------------------------------------------- 1 | package tkn20_test 2 | 3 | import ( 4 | "bytes" 5 | "crypto/sha256" 6 | "fmt" 7 | "io" 8 | "testing" 9 | 10 | cpabe "github.com/cloudflare/circl/abe/cpabe/tkn20" 11 | "github.com/cloudflare/circl/internal/test" 12 | "github.com/cloudflare/circl/xof" 13 | ) 14 | 15 | func TestLongPlaintext(t *testing.T) { 16 | // Fixed PRNG for test reproducibility. 17 | prng := xof.SHAKE128.New() 18 | 19 | pk, msk, err := cpabe.Setup(prng) 20 | test.CheckNoErr(t, err, "setup failed") 21 | 22 | attrs := cpabe.Attributes{} 23 | attrs.FromMap(map[string]string{ 24 | "occupation": "doctor", 25 | "country": "US", 26 | "age": "16", 27 | }) 28 | 29 | sk, err := msk.KeyGen(prng, attrs) 30 | test.CheckNoErr(t, err, "master key generation failed") 31 | 32 | policy := cpabe.Policy{} 33 | err = policy.FromString(`(occupation: doctor) and (country: US)`) 34 | test.CheckNoErr(t, err, "policy parsing failed") 35 | 36 | const N = 20 // 2^N bytes of plaintext 37 | buffer := make([]byte, 1<> 7) 11 | for i := range out { 12 | out[i] = (in1[i] & which) | (in2[i] & ^which) 13 | } 14 | } 15 | 16 | // Read 2*bytelen(p) bytes into the given ExtensionFieldElement. 17 | // 18 | // It is an error to call this function if the input byte slice is less than 2*bytelen(p) bytes long. 19 | func BytesToFp2(fp2 *Fp2, input []byte, bytelen int) { 20 | if len(input) < 2*bytelen { 21 | panic("input byte slice too short") 22 | } 23 | numW64 := (bytelen*8 + 63) / 64 24 | a := make([]byte, 8*numW64) 25 | b := make([]byte, 8*numW64) 26 | copy(a[:bytelen], input[:bytelen]) 27 | copy(b[:bytelen], input[bytelen:]) 28 | for i := 0; i < numW64; i++ { 29 | fp2.A[i] = binary.LittleEndian.Uint64(a[i*8 : (i+1)*8]) 30 | fp2.B[i] = binary.LittleEndian.Uint64(b[i*8 : (i+1)*8]) 31 | } 32 | } 33 | 34 | // Convert the input to wire format. 35 | // 36 | // The output byte slice must be at least 2*bytelen(p) bytes long. 37 | func Fp2ToBytes(output []byte, fp2 *Fp2, bytelen int) { 38 | if len(output) < 2*bytelen { 39 | panic("output byte slice too short") 40 | } 41 | numW64 := (bytelen*8 + 63) / 64 42 | a := make([]byte, 8*numW64) 43 | b := make([]byte, 8*numW64) 44 | for i := 0; i < numW64; i++ { 45 | binary.LittleEndian.PutUint64(a[i*8:(i+1)*8], fp2.A[i]) 46 | binary.LittleEndian.PutUint64(b[i*8:(i+1)*8], fp2.B[i]) 47 | } 48 | copy(output[:bytelen], a[:bytelen]) 49 | copy(output[bytelen:], b[:bytelen]) 50 | } 51 | -------------------------------------------------------------------------------- /dh/sidh/internal/p434/arith_decl.go: -------------------------------------------------------------------------------- 1 | // Code generated by go generate; DO NOT EDIT. 2 | // This file was generated by robots. 3 | 4 | //go:build amd64 && !purego 5 | // +build amd64,!purego 6 | 7 | package p434 8 | 9 | import ( 10 | . "github.com/cloudflare/circl/dh/sidh/internal/common" 11 | ) 12 | 13 | // If choice = 0, leave x unchanged. If choice = 1, sets x to y. 14 | // If choice is neither 0 nor 1 then behaviour is undefined. 15 | // This function executes in constant time. 16 | // 17 | //go:noescape 18 | func cmovP434(x, y *Fp, choice uint8) 19 | 20 | // If choice = 0, leave x,y unchanged. If choice = 1, set x,y = y,x. 21 | // If choice is neither 0 nor 1 then behaviour is undefined. 22 | // This function executes in constant time. 23 | // 24 | //go:noescape 25 | func cswapP434(x, y *Fp, choice uint8) 26 | 27 | // Compute z = x + y (mod p). 28 | // 29 | //go:noescape 30 | func addP434(z, x, y *Fp) 31 | 32 | // Compute z = x - y (mod p). 33 | // 34 | //go:noescape 35 | func subP434(z, x, y *Fp) 36 | 37 | // Compute z = x + y, without reducing mod p. 38 | // 39 | //go:noescape 40 | func adlP434(z, x, y *FpX2) 41 | 42 | // Compute z = x - y, without reducing mod p. 43 | // 44 | //go:noescape 45 | func sulP434(z, x, y *FpX2) 46 | 47 | // Reduce a field element in [0, 2*p) to one in [0,p). 48 | // 49 | //go:noescape 50 | func modP434(x *Fp) 51 | 52 | // Computes z = x * y. 53 | // 54 | //go:noescape 55 | func mulP434(z *FpX2, x, y *Fp) 56 | 57 | // Computes the Montgomery reduction z = x R^{-1} (mod 2*p). On return value 58 | // of x may be changed. z=x not allowed. 59 | // 60 | //go:noescape 61 | func rdcP434(z *Fp, x *FpX2) 62 | -------------------------------------------------------------------------------- /dh/sidh/internal/p503/arith_decl.go: -------------------------------------------------------------------------------- 1 | // Code generated by go generate; DO NOT EDIT. 2 | // This file was generated by robots. 3 | 4 | //go:build (amd64 && !purego) || (arm64 && !purego) 5 | // +build amd64,!purego arm64,!purego 6 | 7 | package p503 8 | 9 | import ( 10 | . "github.com/cloudflare/circl/dh/sidh/internal/common" 11 | ) 12 | 13 | // If choice = 0, leave x unchanged. If choice = 1, sets x to y. 14 | // If choice is neither 0 nor 1 then behaviour is undefined. 15 | // This function executes in constant time. 16 | // 17 | //go:noescape 18 | func cmovP503(x, y *Fp, choice uint8) 19 | 20 | // If choice = 0, leave x,y unchanged. If choice = 1, set x,y = y,x. 21 | // If choice is neither 0 nor 1 then behaviour is undefined. 22 | // This function executes in constant time. 23 | // 24 | //go:noescape 25 | func cswapP503(x, y *Fp, choice uint8) 26 | 27 | // Compute z = x + y (mod p). 28 | // 29 | //go:noescape 30 | func addP503(z, x, y *Fp) 31 | 32 | // Compute z = x - y (mod p). 33 | // 34 | //go:noescape 35 | func subP503(z, x, y *Fp) 36 | 37 | // Compute z = x + y, without reducing mod p. 38 | // 39 | //go:noescape 40 | func adlP503(z, x, y *FpX2) 41 | 42 | // Compute z = x - y, without reducing mod p. 43 | // 44 | //go:noescape 45 | func sulP503(z, x, y *FpX2) 46 | 47 | // Reduce a field element in [0, 2*p) to one in [0,p). 48 | // 49 | //go:noescape 50 | func modP503(x *Fp) 51 | 52 | // Computes z = x * y. 53 | // 54 | //go:noescape 55 | func mulP503(z *FpX2, x, y *Fp) 56 | 57 | // Computes the Montgomery reduction z = x R^{-1} (mod 2*p). On return value 58 | // of x may be changed. z=x not allowed. 59 | // 60 | //go:noescape 61 | func rdcP503(z *Fp, x *FpX2) 62 | -------------------------------------------------------------------------------- /dh/sidh/internal/p503/doc.go: -------------------------------------------------------------------------------- 1 | // Package p503 provides implementation of field arithmetic used in SIDH and SIKE. 2 | package p503 3 | -------------------------------------------------------------------------------- /dh/sidh/internal/p751/arith_decl.go: -------------------------------------------------------------------------------- 1 | // Code generated by go generate; DO NOT EDIT. 2 | // This file was generated by robots. 3 | 4 | //go:build (amd64 && !purego) || (arm64 && !purego) 5 | // +build amd64,!purego arm64,!purego 6 | 7 | package p751 8 | 9 | import ( 10 | . "github.com/cloudflare/circl/dh/sidh/internal/common" 11 | ) 12 | 13 | // If choice = 0, leave x unchanged. If choice = 1, sets x to y. 14 | // If choice is neither 0 nor 1 then behaviour is undefined. 15 | // This function executes in constant time. 16 | // 17 | //go:noescape 18 | func cmovP751(x, y *Fp, choice uint8) 19 | 20 | // If choice = 0, leave x,y unchanged. If choice = 1, set x,y = y,x. 21 | // If choice is neither 0 nor 1 then behaviour is undefined. 22 | // This function executes in constant time. 23 | // 24 | //go:noescape 25 | func cswapP751(x, y *Fp, choice uint8) 26 | 27 | // Compute z = x + y (mod p). 28 | // 29 | //go:noescape 30 | func addP751(z, x, y *Fp) 31 | 32 | // Compute z = x - y (mod p). 33 | // 34 | //go:noescape 35 | func subP751(z, x, y *Fp) 36 | 37 | // Compute z = x + y, without reducing mod p. 38 | // 39 | //go:noescape 40 | func adlP751(z, x, y *FpX2) 41 | 42 | // Compute z = x - y, without reducing mod p. 43 | // 44 | //go:noescape 45 | func sulP751(z, x, y *FpX2) 46 | 47 | // Reduce a field element in [0, 2*p) to one in [0,p). 48 | // 49 | //go:noescape 50 | func modP751(x *Fp) 51 | 52 | // Computes z = x * y. 53 | // 54 | //go:noescape 55 | func mulP751(z *FpX2, x, y *Fp) 56 | 57 | // Computes the Montgomery reduction z = x R^{-1} (mod 2*p). On return value 58 | // of x may be changed. z=x not allowed. 59 | // 60 | //go:noescape 61 | func rdcP751(z *Fp, x *FpX2) 62 | -------------------------------------------------------------------------------- /dh/sidh/internal/p751/doc.go: -------------------------------------------------------------------------------- 1 | // Package p751 provides implementation of field arithmetic used in SIDH and SIKE. 2 | package p751 3 | -------------------------------------------------------------------------------- /dh/sidh/internal/templates/arith_decl.gotemp: -------------------------------------------------------------------------------- 1 | // Code generated by go generate; DO NOT EDIT. 2 | // This file was generated by robots. 3 | 4 | //go:build {{if .OPT_ARM}}({{end}}amd64 && !purego{{if .OPT_ARM}}) || (arm64 && !purego){{end}} 5 | // +build amd64,!purego{{if .OPT_ARM}} arm64,!purego{{end}} 6 | 7 | package {{.PACKAGE}} 8 | 9 | import ( 10 | . "github.com/cloudflare/circl/dh/sidh/internal/common" 11 | ) 12 | 13 | // If choice = 0, leave x unchanged. If choice = 1, sets x to y. 14 | // If choice is neither 0 nor 1 then behaviour is undefined. 15 | // This function executes in constant time. 16 | // 17 | //go:noescape 18 | func cmov{{.FIELD}}(x, y *Fp, choice uint8) 19 | 20 | // If choice = 0, leave x,y unchanged. If choice = 1, set x,y = y,x. 21 | // If choice is neither 0 nor 1 then behaviour is undefined. 22 | // This function executes in constant time. 23 | // 24 | //go:noescape 25 | func cswap{{.FIELD}}(x, y *Fp, choice uint8) 26 | 27 | // Compute z = x + y (mod p). 28 | // 29 | //go:noescape 30 | func add{{.FIELD}}(z, x, y *Fp) 31 | 32 | // Compute z = x - y (mod p). 33 | // 34 | //go:noescape 35 | func sub{{.FIELD}}(z, x, y *Fp) 36 | 37 | // Compute z = x + y, without reducing mod p. 38 | // 39 | //go:noescape 40 | func adl{{.FIELD}}(z, x, y *FpX2) 41 | 42 | // Compute z = x - y, without reducing mod p. 43 | // 44 | //go:noescape 45 | func sul{{.FIELD}}(z, x, y *FpX2) 46 | 47 | // Reduce a field element in [0, 2*p) to one in [0,p). 48 | // 49 | //go:noescape 50 | func mod{{.FIELD}}(x *Fp) 51 | 52 | // Computes z = x * y. 53 | // 54 | //go:noescape 55 | func mul{{.FIELD}}(z *FpX2, x, y *Fp) 56 | 57 | // Computes the Montgomery reduction z = x R^{-1} (mod 2*p). On return value 58 | // of x may be changed. z=x not allowed. 59 | // 60 | //go:noescape 61 | func rdc{{.FIELD}}(z *Fp, x *FpX2) 62 | -------------------------------------------------------------------------------- /dh/x25519/curve_amd64.go: -------------------------------------------------------------------------------- 1 | //go:build amd64 && !purego 2 | // +build amd64,!purego 3 | 4 | package x25519 5 | 6 | import ( 7 | fp "github.com/cloudflare/circl/math/fp25519" 8 | "golang.org/x/sys/cpu" 9 | ) 10 | 11 | var hasBmi2Adx = cpu.X86.HasBMI2 && cpu.X86.HasADX 12 | 13 | var _ = hasBmi2Adx 14 | 15 | func double(x, z *fp.Elt) { doubleAmd64(x, z) } 16 | func diffAdd(w *[5]fp.Elt, b uint) { diffAddAmd64(w, b) } 17 | func ladderStep(w *[5]fp.Elt, b uint) { ladderStepAmd64(w, b) } 18 | func mulA24(z, x *fp.Elt) { mulA24Amd64(z, x) } 19 | 20 | //go:noescape 21 | func ladderStepAmd64(w *[5]fp.Elt, b uint) 22 | 23 | //go:noescape 24 | func diffAddAmd64(w *[5]fp.Elt, b uint) 25 | 26 | //go:noescape 27 | func doubleAmd64(x, z *fp.Elt) 28 | 29 | //go:noescape 30 | func mulA24Amd64(z, x *fp.Elt) 31 | -------------------------------------------------------------------------------- /dh/x25519/curve_noasm.go: -------------------------------------------------------------------------------- 1 | //go:build !amd64 || purego 2 | // +build !amd64 purego 3 | 4 | package x25519 5 | 6 | import fp "github.com/cloudflare/circl/math/fp25519" 7 | 8 | func double(x, z *fp.Elt) { doubleGeneric(x, z) } 9 | func diffAdd(w *[5]fp.Elt, b uint) { diffAddGeneric(w, b) } 10 | func ladderStep(w *[5]fp.Elt, b uint) { ladderStepGeneric(w, b) } 11 | func mulA24(z, x *fp.Elt) { mulA24Generic(z, x) } 12 | -------------------------------------------------------------------------------- /dh/x25519/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package x25519 provides Diffie-Hellman functions as specified in RFC-7748. 3 | 4 | Validation of public keys. 5 | 6 | The Diffie-Hellman function, as described in RFC-7748 [1], works for any 7 | public key. However, if a different protocol requires contributory 8 | behaviour [2,3], then the public keys must be validated against low-order 9 | points [3,4]. To do that, the Shared function performs this validation 10 | internally and returns false when the public key is invalid (i.e., it 11 | is a low-order point). 12 | 13 | References: 14 | - [1] RFC7748 by Langley, Hamburg, Turner (https://rfc-editor.org/rfc/rfc7748.txt) 15 | - [2] Curve25519 by Bernstein (https://cr.yp.to/ecdh.html) 16 | - [3] Bernstein (https://cr.yp.to/ecdh.html#validate) 17 | - [4] Cremers&Jackson (https://eprint.iacr.org/2019/526) 18 | */ 19 | package x25519 20 | -------------------------------------------------------------------------------- /dh/x25519/key.go: -------------------------------------------------------------------------------- 1 | package x25519 2 | 3 | import ( 4 | "crypto/subtle" 5 | 6 | fp "github.com/cloudflare/circl/math/fp25519" 7 | ) 8 | 9 | // Size is the length in bytes of a X25519 key. 10 | const Size = 32 11 | 12 | // Key represents a X25519 key. 13 | type Key [Size]byte 14 | 15 | func (k *Key) clamp(in *Key) *Key { 16 | *k = *in 17 | k[0] &= 248 18 | k[31] = (k[31] & 127) | 64 19 | return k 20 | } 21 | 22 | // isValidPubKey verifies if the public key is not a low-order point. 23 | func (k *Key) isValidPubKey() bool { 24 | fp.Modp((*fp.Elt)(k)) 25 | var isLowOrder int 26 | for _, P := range lowOrderPoints { 27 | isLowOrder |= subtle.ConstantTimeCompare(P[:], k[:]) 28 | } 29 | return isLowOrder == 0 30 | } 31 | 32 | // KeyGen obtains a public key given a secret key. 33 | func KeyGen(public, secret *Key) { 34 | ladderJoye(public.clamp(secret)) 35 | } 36 | 37 | // Shared calculates Alice's shared key from Alice's secret key and Bob's 38 | // public key returning true on success. A failure case happens when the public 39 | // key is a low-order point, thus the shared key is all-zeros and the function 40 | // returns false. 41 | func Shared(shared, secret, public *Key) bool { 42 | validPk := *public 43 | validPk[31] &= (1 << (255 % 8)) - 1 44 | ok := validPk.isValidPubKey() 45 | ladderMontgomery(shared.clamp(secret), &validPk) 46 | return ok 47 | } 48 | -------------------------------------------------------------------------------- /dh/x25519/testdata/rfc7748_kat_test.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "input": "e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c", 4 | "output": "c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552", 5 | "scalar": "a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4" 6 | }, 7 | { 8 | "input": "e5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493", 9 | "output": "95cbde9476e8907d7aade45cb4b873f88b595a68799fa152e6f8f7647aac7957", 10 | "scalar": "4b66e9d4d1b4673c5ad22691957d6af5c11b6421e0ea01d42ca4169e7918ba0d" 11 | }, 12 | { 13 | "input": "0900000000000000000000000000000000000000000000000000000000000000", 14 | "output": "8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a", 15 | "scalar": "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a" 16 | }, 17 | { 18 | "input": "0900000000000000000000000000000000000000000000000000000000000000", 19 | "output": "de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f", 20 | "scalar": "5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb" 21 | }, 22 | { 23 | "input": "de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f", 24 | "output": "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742", 25 | "scalar": "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a" 26 | }, 27 | { 28 | "input": "8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a", 29 | "output": "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742", 30 | "scalar": "5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb" 31 | } 32 | ] 33 | -------------------------------------------------------------------------------- /dh/x25519/testdata/rfc7748_times_test.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "times": 1, 4 | "key": "422c8e7a6227d7bca1350b3e2bb7279f7897b87bb6854b783c60e80311ae3079" 5 | }, 6 | { 7 | "times": 1000, 8 | "key": "684cf59ba83309552800ef566f2f4d3c1c3887c49360e3875f2eb94d99532c51" 9 | }, 10 | { 11 | "times": 1000000, 12 | "key": "7c3911e0ab2586fd864497297e575e6f3bc601c0883c30df5f4dd2d24f665424" 13 | } 14 | ] 15 | -------------------------------------------------------------------------------- /dh/x448/curve_amd64.go: -------------------------------------------------------------------------------- 1 | //go:build amd64 && !purego 2 | // +build amd64,!purego 3 | 4 | package x448 5 | 6 | import ( 7 | fp "github.com/cloudflare/circl/math/fp448" 8 | "golang.org/x/sys/cpu" 9 | ) 10 | 11 | var hasBmi2Adx = cpu.X86.HasBMI2 && cpu.X86.HasADX 12 | 13 | var _ = hasBmi2Adx 14 | 15 | func double(x, z *fp.Elt) { doubleAmd64(x, z) } 16 | func diffAdd(w *[5]fp.Elt, b uint) { diffAddAmd64(w, b) } 17 | func ladderStep(w *[5]fp.Elt, b uint) { ladderStepAmd64(w, b) } 18 | func mulA24(z, x *fp.Elt) { mulA24Amd64(z, x) } 19 | 20 | //go:noescape 21 | func doubleAmd64(x, z *fp.Elt) 22 | 23 | //go:noescape 24 | func diffAddAmd64(w *[5]fp.Elt, b uint) 25 | 26 | //go:noescape 27 | func ladderStepAmd64(w *[5]fp.Elt, b uint) 28 | 29 | //go:noescape 30 | func mulA24Amd64(z, x *fp.Elt) 31 | -------------------------------------------------------------------------------- /dh/x448/curve_noasm.go: -------------------------------------------------------------------------------- 1 | //go:build !amd64 || purego 2 | // +build !amd64 purego 3 | 4 | package x448 5 | 6 | import fp "github.com/cloudflare/circl/math/fp448" 7 | 8 | func double(x, z *fp.Elt) { doubleGeneric(x, z) } 9 | func diffAdd(w *[5]fp.Elt, b uint) { diffAddGeneric(w, b) } 10 | func ladderStep(w *[5]fp.Elt, b uint) { ladderStepGeneric(w, b) } 11 | func mulA24(z, x *fp.Elt) { mulA24Generic(z, x) } 12 | -------------------------------------------------------------------------------- /dh/x448/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package x448 provides Diffie-Hellman functions as specified in RFC-7748. 3 | 4 | Validation of public keys. 5 | 6 | The Diffie-Hellman function, as described in RFC-7748 [1], works for any 7 | public key. However, if a different protocol requires contributory 8 | behaviour [2,3], then the public keys must be validated against low-order 9 | points [3,4]. To do that, the Shared function performs this validation 10 | internally and returns false when the public key is invalid (i.e., it 11 | is a low-order point). 12 | 13 | References: 14 | - [1] RFC7748 by Langley, Hamburg, Turner (https://rfc-editor.org/rfc/rfc7748.txt) 15 | - [2] Curve25519 by Bernstein (https://cr.yp.to/ecdh.html) 16 | - [3] Bernstein (https://cr.yp.to/ecdh.html#validate) 17 | - [4] Cremers&Jackson (https://eprint.iacr.org/2019/526) 18 | */ 19 | package x448 20 | -------------------------------------------------------------------------------- /dh/x448/key.go: -------------------------------------------------------------------------------- 1 | package x448 2 | 3 | import ( 4 | "crypto/subtle" 5 | 6 | fp "github.com/cloudflare/circl/math/fp448" 7 | ) 8 | 9 | // Size is the length in bytes of a X448 key. 10 | const Size = 56 11 | 12 | // Key represents a X448 key. 13 | type Key [Size]byte 14 | 15 | func (k *Key) clamp(in *Key) *Key { 16 | *k = *in 17 | k[0] &= 252 18 | k[55] |= 128 19 | return k 20 | } 21 | 22 | // isValidPubKey verifies if the public key is not a low-order point. 23 | func (k *Key) isValidPubKey() bool { 24 | fp.Modp((*fp.Elt)(k)) 25 | var isLowOrder int 26 | for _, P := range lowOrderPoints { 27 | isLowOrder |= subtle.ConstantTimeCompare(P[:], k[:]) 28 | } 29 | return isLowOrder == 0 30 | } 31 | 32 | // KeyGen obtains a public key given a secret key. 33 | func KeyGen(public, secret *Key) { 34 | ladderJoye(public.clamp(secret)) 35 | } 36 | 37 | // Shared calculates Alice's shared key from Alice's secret key and Bob's 38 | // public key returning true on success. A failure case happens when the public 39 | // key is a low-order point, thus the shared key is all-zeros and the function 40 | // returns false. 41 | func Shared(shared, secret, public *Key) bool { 42 | validPk := *public 43 | ok := validPk.isValidPubKey() 44 | ladderMontgomery(shared.clamp(secret), &validPk) 45 | return ok 46 | } 47 | -------------------------------------------------------------------------------- /dh/x448/testdata/rfc7748_times_test.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "times": 1, 4 | "key": "3f482c8a9f19b01e6c46ee9711d9dc14fd4bf67af30765c2ae2b846a4d23a8cd0db897086239492caf350b51f833868b9bc2b3bca9cf4113" 5 | }, 6 | { 7 | "times": 1000, 8 | "key": "aa3b4749d55b9daf1e5b00288826c467274ce3ebbdd5c17b975e09d4af6c67cf10d087202db88286e2b79fceea3ec353ef54faa26e219f38" 9 | }, 10 | { 11 | "times": 1000000, 12 | "key": "077f453681caca3693198420bbe515cae0002472519b3e67661a7e89cab94695c8f4bcd66e61b9b9c946da8d524de3d69bd9d9d66b997e37" 13 | } 14 | ] 15 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | // Package circl provides a collection of cryptographic primitives. The goal 2 | // of this module is to be used as a tool for experimental deployment of 3 | // cryptographic algorithms targeting Post-Quantum (PQ) and Elliptic 4 | // Curve Cryptography (ECC). 5 | // 6 | // Following blog post describes ideas behind CIRCL in more details: 7 | // https://blog.cloudflare.com/introducing-circl/ 8 | package circl // github.com/cloudflare/circl 9 | -------------------------------------------------------------------------------- /ecc/bls12381/ff/fp12cubic_test.go: -------------------------------------------------------------------------------- 1 | package ff 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/cloudflare/circl/internal/test" 7 | ) 8 | 9 | func TestFP12CubicAdd(t *testing.T) { 10 | const testTimes = 1 << 8 11 | for i := 0; i < testTimes; i++ { 12 | var xalt, yalt, zalt Fp12Cubic 13 | var z, zcmp Fp12 14 | x := randomFp12(t) 15 | y := randomFp12(t) 16 | xalt.FromFp12(x) 17 | yalt.FromFp12(y) 18 | zalt.Add(&xalt, &yalt) 19 | z.Add(x, y) 20 | zcmp.FromFp12Cubic(&zalt) 21 | if z.IsEqual(&zcmp) == 0 { 22 | test.ReportError(t, z, zcmp, x, y) 23 | } 24 | } 25 | } 26 | 27 | func TestFP12CubicMul(t *testing.T) { 28 | const testTimes = 1 << 8 29 | for i := 0; i < testTimes; i++ { 30 | var xalt, yalt, zalt Fp12Cubic 31 | var z, zcmp Fp12 32 | x := randomFp12(t) 33 | y := randomFp12(t) 34 | xalt.FromFp12(x) 35 | yalt.FromFp12(y) 36 | zalt.Mul(&xalt, &yalt) 37 | z.Mul(x, y) 38 | zcmp.FromFp12Cubic(&zalt) 39 | if z.IsEqual(&zcmp) == 0 { 40 | test.ReportError(t, z, zcmp, x, y) 41 | } 42 | } 43 | } 44 | 45 | func TestFP12AltSqr(t *testing.T) { 46 | const testTimes = 1 << 8 47 | for i := 0; i < testTimes; i++ { 48 | var xalt, zalt Fp12Cubic 49 | var z, zcmp Fp12 50 | x := randomFp12(t) 51 | xalt.FromFp12(x) 52 | zalt.Sqr(&xalt) 53 | z.Sqr(x) 54 | zcmp.FromFp12Cubic(&zalt) 55 | if z.IsEqual(&zcmp) == 0 { 56 | test.ReportError(t, z, zcmp, x) 57 | } 58 | } 59 | } 60 | 61 | func TestFP12CubicLine(t *testing.T) { 62 | const testTimes = 1 << 8 63 | for i := 0; i < testTimes; i++ { 64 | var x, y, z, zcmp Fp12Cubic 65 | var yline LineValue 66 | xnorm := randomFp12(t) 67 | x.FromFp12(xnorm) 68 | 69 | yline[0] = *randomFp2(t) 70 | yline[1] = *randomFp2(t) 71 | yline[2] = *randomFp2(t) 72 | 73 | y[0][0] = yline[0] 74 | y[0][1] = yline[2] 75 | y[2][0] = yline[1] 76 | 77 | zcmp.Mul(&x, &y) 78 | z.MulLine(&x, &yline) 79 | if z.IsEqual(&zcmp) == 0 { 80 | test.ReportError(t, z, zcmp, x) 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /ecc/bls12381/ff/uroot.go: -------------------------------------------------------------------------------- 1 | package ff 2 | 3 | // URootSize is the length in bytes of a root of unit. 4 | const URootSize = Fp12Size 5 | 6 | // URoot represents an n-th root of unit, that is an element x in Cyclo6 such 7 | // that x^n=1, where n = ScalarOrder(). 8 | type URoot Cyclo6 9 | 10 | func (z URoot) String() string { return (Cyclo6)(z).String() } 11 | func (z *URoot) UnmarshalBinary(b []byte) error { return (*Fp12)(z).UnmarshalBinary(b) } 12 | func (z URoot) MarshalBinary() ([]byte, error) { return (Fp12)(z).MarshalBinary() } 13 | func (z *URoot) SetIdentity() { (*Fp12)(z).SetOne() } 14 | func (z URoot) IsEqual(x *URoot) int { return (Cyclo6)(z).IsEqual((*Cyclo6)(x)) } 15 | func (z URoot) IsIdentity() int { i := &URoot{}; i.SetIdentity(); return z.IsEqual(i) } 16 | func (z *URoot) Exp(x *URoot, n []byte) { (*Cyclo6)(z).exp((*Cyclo6)(x), n) } 17 | func (z *URoot) Mul(x, y *URoot) { (*Cyclo6)(z).Mul((*Cyclo6)(x), (*Cyclo6)(y)) } 18 | func (z *URoot) Sqr(x *URoot) { (*Cyclo6)(z).Sqr((*Cyclo6)(x)) } 19 | func (z *URoot) Inv(x *URoot) { (*Cyclo6)(z).Inv((*Cyclo6)(x)) } 20 | -------------------------------------------------------------------------------- /ecc/bls12381/ff/uroot_test.go: -------------------------------------------------------------------------------- 1 | package ff 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/cloudflare/circl/internal/test" 7 | ) 8 | 9 | func randomURoot(t testing.TB) *URoot { 10 | u := &URoot{} 11 | HardExponentiation(u, randomCyclo6(t)) 12 | return u 13 | } 14 | 15 | func TestURoot(t *testing.T) { 16 | const testTimes = 1 << 8 17 | t.Run("no_alias", func(t *testing.T) { 18 | var want, got URoot 19 | x := randomURoot(t) 20 | got = *x 21 | got.Sqr(&got) 22 | want = *x 23 | want.Mul(&want, &want) 24 | if got.IsEqual(&want) == 0 { 25 | test.ReportError(t, got, want, x) 26 | } 27 | }) 28 | t.Run("order", func(t *testing.T) { 29 | order := ScalarOrder() 30 | 31 | var z URoot 32 | for i := 0; i < 16; i++ { 33 | x := randomURoot(t) 34 | (*Cyclo6)(&z).exp((*Cyclo6)(x), order) 35 | 36 | // x^order = 1 37 | got := z.IsIdentity() 38 | want := 1 39 | if got != want { 40 | test.ReportError(t, got, want, x, z) 41 | } 42 | } 43 | }) 44 | t.Run("mul_inv", func(t *testing.T) { 45 | var z URoot 46 | for i := 0; i < testTimes; i++ { 47 | x := randomURoot(t) 48 | y := randomURoot(t) 49 | 50 | // x*y*x^1 = y 51 | z.Inv(x) 52 | z.Mul(&z, y) 53 | z.Mul(&z, x) 54 | got := z 55 | want := y 56 | if got.IsEqual(want) == 0 { 57 | test.ReportError(t, got, want, x, y) 58 | } 59 | } 60 | }) 61 | t.Run("mul_sqr", func(t *testing.T) { 62 | var want, got URoot 63 | for i := 0; i < testTimes; i++ { 64 | x := randomURoot(t) 65 | 66 | // x*x = x^2 67 | got.Mul(x, x) 68 | want.Sqr(x) 69 | if got.IsEqual(&want) == 0 { 70 | test.ReportError(t, got, want, x) 71 | } 72 | } 73 | }) 74 | } 75 | 76 | func BenchmarkURoot(b *testing.B) { 77 | x := randomURoot(b) 78 | y := randomURoot(b) 79 | z := randomURoot(b) 80 | b.Run("Mul", func(b *testing.B) { 81 | for i := 0; i < b.N; i++ { 82 | z.Mul(x, y) 83 | } 84 | }) 85 | b.Run("Sqr", func(b *testing.B) { 86 | for i := 0; i < b.N; i++ { 87 | z.Sqr(x) 88 | } 89 | }) 90 | b.Run("Inv", func(b *testing.B) { 91 | for i := 0; i < b.N; i++ { 92 | z.Inv(x) 93 | } 94 | }) 95 | } 96 | -------------------------------------------------------------------------------- /ecc/bls12381/gt.go: -------------------------------------------------------------------------------- 1 | package bls12381 2 | 3 | import "github.com/cloudflare/circl/ecc/bls12381/ff" 4 | 5 | // GtSize is the length in bytes of an element in Gt. 6 | const GtSize = ff.URootSize 7 | 8 | // Gt represents an element of the output (multiplicative) group of a pairing. 9 | type Gt struct{ i ff.URoot } 10 | 11 | func (z Gt) String() string { return z.i.String() } 12 | func (z *Gt) UnmarshalBinary(b []byte) error { return z.i.UnmarshalBinary(b) } 13 | func (z Gt) MarshalBinary() ([]byte, error) { return z.i.MarshalBinary() } 14 | func (z *Gt) SetIdentity() { z.i.SetIdentity() } 15 | func (z Gt) IsEqual(x *Gt) bool { return z.i.IsEqual(&x.i) == 1 } 16 | func (z Gt) IsIdentity() bool { i := &Gt{}; i.SetIdentity(); return z.IsEqual(i) } 17 | func (z *Gt) Mul(x, y *Gt) { z.i.Mul(&x.i, &y.i) } 18 | func (z *Gt) Sqr(x *Gt) { z.i.Sqr(&x.i) } 19 | func (z *Gt) Inv(x *Gt) { z.i.Inv(&x.i) } 20 | 21 | // Exp calculates z=x^n, where n is the exponent in big-endian order. 22 | func (z *Gt) Exp(x *Gt, n *Scalar) { b, _ := n.MarshalBinary(); z.i.Exp(&x.i, b) } 23 | -------------------------------------------------------------------------------- /ecc/bls12381/gt_test.go: -------------------------------------------------------------------------------- 1 | package bls12381 2 | 3 | import ( 4 | "crypto/rand" 5 | "testing" 6 | ) 7 | 8 | func BenchmarkGt(b *testing.B) { 9 | sc := &Scalar{} 10 | err := sc.Random(rand.Reader) 11 | if err != nil { 12 | b.Fatal(err) 13 | } 14 | 15 | g1 := G1Generator() 16 | g2 := G2Generator() 17 | e1 := Pair(g1, g2) 18 | 19 | g1.ScalarMult(sc, g1) 20 | e2 := Pair(g1, g2) 21 | e3 := &Gt{} 22 | 23 | b.Run("Mul", func(b *testing.B) { 24 | for i := 0; i < b.N; i++ { 25 | e3.Mul(e1, e2) 26 | } 27 | }) 28 | b.Run("Exp", func(b *testing.B) { 29 | for i := 0; i < b.N; i++ { 30 | e3.Exp(e1, sc) 31 | } 32 | }) 33 | } 34 | -------------------------------------------------------------------------------- /ecc/bls12381/testdata/g1_compressed_valid_test_vectors.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/circl/main/ecc/bls12381/testdata/g1_compressed_valid_test_vectors.dat -------------------------------------------------------------------------------- /ecc/bls12381/testdata/g1_uncompressed_valid_test_vectors.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/circl/main/ecc/bls12381/testdata/g1_uncompressed_valid_test_vectors.dat -------------------------------------------------------------------------------- /ecc/bls12381/testdata/g2_compressed_valid_test_vectors.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/circl/main/ecc/bls12381/testdata/g2_compressed_valid_test_vectors.dat -------------------------------------------------------------------------------- /ecc/bls12381/testdata/g2_uncompressed_valid_test_vectors.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/circl/main/ecc/bls12381/testdata/g2_uncompressed_valid_test_vectors.dat -------------------------------------------------------------------------------- /ecc/doc.go: -------------------------------------------------------------------------------- 1 | // Package ecc provides implementation of arithmetic on some elliptic curves. 2 | package ecc 3 | -------------------------------------------------------------------------------- /ecc/fourq/doc.go: -------------------------------------------------------------------------------- 1 | // Package fourq provides elliptic curve operations over FourQ curve. 2 | // 3 | // FourQ is a high-speed elliptic curve at the 128-bit security level. This package 4 | // contains an AMD64-optimized implementation. In particular, this package does 5 | // not implement FourQ's endomorphisms or lattice reduction techniques. 6 | // 7 | // References: 8 | // - https://eprint.iacr.org/2015/565 9 | package fourq 10 | -------------------------------------------------------------------------------- /ecc/fourq/fp_amd64.go: -------------------------------------------------------------------------------- 1 | //go:build amd64 && !purego 2 | // +build amd64,!purego 3 | 4 | package fourq 5 | 6 | import ( 7 | "golang.org/x/sys/cpu" 8 | ) 9 | 10 | var hasBMI2 = cpu.X86.HasBMI2 //nolint 11 | 12 | //go:noescape 13 | func fpMod(c *Fp) 14 | 15 | //go:noescape 16 | func fpAdd(c, a, b *Fp) 17 | 18 | //go:noescape 19 | func fpSub(c, a, b *Fp) 20 | 21 | //go:noescape 22 | func fpMul(c, a, b *Fp) 23 | 24 | //go:noescape 25 | func fpSqr(c, a *Fp) 26 | 27 | //go:noescape 28 | func fpHlf(c, a *Fp) 29 | -------------------------------------------------------------------------------- /ecc/fourq/fp_noasm.go: -------------------------------------------------------------------------------- 1 | //go:build !amd64 || purego 2 | // +build !amd64 purego 3 | 4 | package fourq 5 | 6 | func fpMod(c *Fp) { fpModGeneric(c) } 7 | func fpAdd(c, a, b *Fp) { fpAddGeneric(c, a, b) } 8 | func fpSub(c, a, b *Fp) { fpSubGeneric(c, a, b) } 9 | func fpMul(c, a, b *Fp) { fpMulGeneric(c, a, b) } 10 | func fpSqr(c, a *Fp) { fpSqrGeneric(c, a) } 11 | func fpHlf(c, a *Fp) { fpHlfGeneric(c, a) } 12 | -------------------------------------------------------------------------------- /ecc/fourq/fq_amd64.go: -------------------------------------------------------------------------------- 1 | //go:build amd64 && !purego 2 | // +build amd64,!purego 3 | 4 | package fourq 5 | 6 | //go:noescape 7 | func fqCmov(c, a *Fq, b int) 8 | 9 | //go:noescape 10 | func fqAdd(c, a, b *Fq) 11 | 12 | //go:noescape 13 | func fqSub(c, a, b *Fq) 14 | 15 | //go:noescape 16 | func fqMul(c, a, b *Fq) 17 | 18 | //go:noescape 19 | func fqSqr(c, a *Fq) 20 | -------------------------------------------------------------------------------- /ecc/fourq/fq_amd64.s: -------------------------------------------------------------------------------- 1 | // +build amd64,!purego 2 | 3 | #include "fq_amd64.h" 4 | 5 | #define fqMulLegacy \ 6 | _fqMulLeg(0(DI),0(SI),0(BX)) 7 | #define fqMulBmi2 \ 8 | _fqMulBmi2(0(DI),0(SI),0(BX)) 9 | 10 | #define fqSqrLegacy \ 11 | _fqSqrLeg(0(DI),0(SI)) 12 | #define fqSqrBmi2 \ 13 | _fqSqrBmi2(0(DI),0(SI)) 14 | 15 | // func fqCmov(c, a *fq, b int) 16 | TEXT ·fqCmov(SB),0,$0-24 17 | MOVQ c+0(FP), DI 18 | MOVQ a+8(FP), SI 19 | MOVQ b+16(FP), BX 20 | TESTQ BX, BX 21 | MOVQ 0(DI), AX; MOVQ 0(SI), DX; CMOVQNE DX, AX; MOVQ AX, 0(DI); 22 | MOVQ 8(DI), AX; MOVQ 8(SI), DX; CMOVQNE DX, AX; MOVQ AX, 8(DI); 23 | MOVQ 16(DI), AX; MOVQ 16(SI), DX; CMOVQNE DX, AX; MOVQ AX, 16(DI); 24 | MOVQ 24(DI), AX; MOVQ 24(SI), DX; CMOVQNE DX, AX; MOVQ AX, 24(DI); 25 | RET 26 | 27 | // func fqAdd(c, a, b *fq) 28 | TEXT ·fqAdd(SB),0,$0-24 29 | MOVQ c+0(FP), DI 30 | MOVQ a+8(FP), SI 31 | MOVQ b+16(FP), BX 32 | _fqAdd(0(DI), 0(SI), 0(BX)) 33 | RET 34 | 35 | // func fqSub(c, a, b *fq) 36 | TEXT ·fqSub(SB),0,$0-24 37 | MOVQ c+0(FP), DI 38 | MOVQ a+8(FP), SI 39 | MOVQ b+16(FP), BX 40 | _fqSub(0(DI), 0(SI), 0(BX)) 41 | RET 42 | 43 | // func fqMul(c, a, b *fq) 44 | TEXT ·fqMul(SB),0,$0-24 45 | MOVQ c+0(FP), DI 46 | MOVQ a+8(FP), SI 47 | MOVQ b+16(FP), BX 48 | CHECK_BMI2(LFQMUL, fqMulLegacy, fqMulBmi2) 49 | RET 50 | 51 | // func fqSqr(c, a *fq) 52 | TEXT ·fqSqr(SB),0,$0-16 53 | MOVQ c+0(FP), DI 54 | MOVQ a+8(FP), SI 55 | CHECK_BMI2(LFQSQR, fqSqrLegacy, fqSqrBmi2) 56 | RET 57 | -------------------------------------------------------------------------------- /ecc/fourq/fq_generic.go: -------------------------------------------------------------------------------- 1 | package fourq 2 | 3 | func fqAddGeneric(c, a, b *Fq) { 4 | fpAddGeneric(&c[0], &a[0], &b[0]) 5 | fpAddGeneric(&c[1], &a[1], &b[1]) 6 | } 7 | 8 | func fqSubGeneric(c, a, b *Fq) { 9 | fpSubGeneric(&c[0], &a[0], &b[0]) 10 | fpSubGeneric(&c[1], &a[1], &b[1]) 11 | } 12 | 13 | func fqMulGeneric(c, a, b *Fq) { 14 | var a0b0, a0b1, a1b0, a1b1 Fp 15 | fpMulGeneric(&a0b0, &a[0], &b[0]) 16 | fpMulGeneric(&a0b1, &a[0], &b[1]) 17 | fpMulGeneric(&a1b0, &a[1], &b[0]) 18 | fpMulGeneric(&a1b1, &a[1], &b[1]) 19 | fpSubGeneric(&c[0], &a0b0, &a1b1) 20 | fpAddGeneric(&c[1], &a0b1, &a1b0) 21 | } 22 | 23 | func fqSqrGeneric(c, a *Fq) { 24 | var aa0, a01, aa1 Fp 25 | fpSqrGeneric(&aa0, &a[0]) 26 | fpMulGeneric(&a01, &a[0], &a[1]) 27 | fpSqrGeneric(&aa1, &a[1]) 28 | fpSubGeneric(&c[0], &aa0, &aa1) 29 | fpAddGeneric(&c[1], &a01, &a01) 30 | } 31 | -------------------------------------------------------------------------------- /ecc/fourq/fq_noasm.go: -------------------------------------------------------------------------------- 1 | //go:build !amd64 || purego 2 | // +build !amd64 purego 3 | 4 | package fourq 5 | 6 | import "crypto/subtle" 7 | 8 | func fqCmov(c, a *Fq, b int) { 9 | subtle.ConstantTimeCopy(b, c[0][:], a[0][:]) 10 | subtle.ConstantTimeCopy(b, c[1][:], a[1][:]) 11 | } 12 | func fqAdd(c, a, b *Fq) { fqAddGeneric(c, a, b) } 13 | func fqSub(c, a, b *Fq) { fqSubGeneric(c, a, b) } 14 | func fqMul(c, a, b *Fq) { fqMulGeneric(c, a, b) } 15 | func fqSqr(c, a *Fq) { fqSqrGeneric(c, a) } 16 | -------------------------------------------------------------------------------- /ecc/fourq/params.go: -------------------------------------------------------------------------------- 1 | package fourq 2 | 3 | // All values in little endian 4 | var ( 5 | 6 | // prime is the modulus 2^127-1 7 | prime = [2]uint64{ 8 | 0xFFFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFF, 9 | } 10 | 11 | // orderGenerator is the size of the largest subgroup. 12 | orderGenerator = [4]uint64{ 13 | 0x2fb2540ec7768ce7, 0xdfbd004dfe0f7999, 14 | 0xf05397829cbc14e5, 0x0029cbc14e5e0a72, 15 | } 16 | 17 | paramD = Fq{ 18 | Fp{ 19 | 0x42, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 20 | 0xe4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 21 | }, 22 | Fp{ 23 | 0x8d, 0x0c, 0xfc, 0xf1, 0x88, 0x14, 0x82, 0xb3, 24 | 0xfc, 0xe0, 0x57, 0x66, 0x84, 0x2f, 0x47, 0x5e, 25 | }, 26 | } 27 | 28 | genX = Fq{ 29 | Fp{ 30 | 0xaa, 0x33, 0x38, 0x7b, 0xad, 0x92, 0x65, 0x28, 31 | 0x05, 0xb3, 0x2f, 0x7c, 0x23, 0x72, 0x34, 0x1a, 32 | }, 33 | Fp{ 34 | 0xf6, 0x77, 0xac, 0x60, 0xb3, 0x9f, 0x86, 0x96, 35 | 0x9c, 0xaa, 0x78, 0x28, 0x3f, 0x55, 0x1f, 0x1e, 36 | }, 37 | } 38 | 39 | genY = Fq{ 40 | Fp{ 41 | 0x87, 0xb2, 0xcb, 0x2b, 0x46, 0xa2, 0x24, 0xb9, 42 | 0x5a, 0x78, 0x20, 0xa1, 0x9b, 0xee, 0x3f, 0x0e, 43 | }, 44 | Fp{ 45 | 0x5c, 0x8b, 0x4c, 0x84, 0x44, 0xc3, 0xa7, 0x49, 46 | 0x42, 0x02, 0x0e, 0x63, 0xf8, 0x4a, 0x1c, 0x6e, 47 | }, 48 | } 49 | ) 50 | -------------------------------------------------------------------------------- /ecc/fourq/point_amd64.go: -------------------------------------------------------------------------------- 1 | //go:build amd64 && !purego 2 | // +build amd64,!purego 3 | 4 | package fourq 5 | 6 | import "unsafe" 7 | 8 | const ( // constants used in assembly implementation 9 | _x = unsafe.Offsetof(pointR1{}.X) 10 | _y = unsafe.Offsetof(pointR1{}.Y) 11 | _z = unsafe.Offsetof(pointR1{}.Z) 12 | _ta = unsafe.Offsetof(pointR1{}.Ta) 13 | _tb = unsafe.Offsetof(pointR1{}.Tb) 14 | _addYXR2 = unsafe.Offsetof(pointR2{}.addYX) 15 | _subYXR2 = unsafe.Offsetof(pointR2{}.subYX) 16 | _z2R2 = unsafe.Offsetof(pointR2{}.z2) 17 | _dt2R2 = unsafe.Offsetof(pointR2{}.dt2) 18 | _addYXR3 = unsafe.Offsetof(pointR3{}.addYX) 19 | _subYXR3 = unsafe.Offsetof(pointR3{}.subYX) 20 | _dt2R3 = unsafe.Offsetof(pointR3{}.dt2) 21 | _ = _x + _y + _z + _ta + _tb + _addYXR2 + _subYXR2 + 22 | _z2R2 + _dt2R2 + _addYXR3 + _subYXR3 + _dt2R3 23 | ) 24 | 25 | func (P *pointR1) double() { doubleAmd64(P) } 26 | func (P *pointR1) add(Q *pointR2) { addAmd64(P, Q) } 27 | func (P *pointR1) mixAdd(Q *pointR3) { mixAddAmd64(P, Q) } 28 | 29 | //go:noescape 30 | func doubleAmd64(P *pointR1) 31 | 32 | //go:noescape 33 | func addAmd64(P *pointR1, Q *pointR2) 34 | 35 | //go:noescape 36 | func mixAddAmd64(P *pointR1, Q *pointR3) 37 | -------------------------------------------------------------------------------- /ecc/fourq/point_generic.go: -------------------------------------------------------------------------------- 1 | //go:build !amd64 || purego 2 | // +build !amd64 purego 3 | 4 | package fourq 5 | 6 | func doubleGeneric(P *pointR1) { 7 | Px := &P.X 8 | Py := &P.Y 9 | Pz := &P.Z 10 | Pta := &P.Ta 11 | Ptb := &P.Tb 12 | a := Px 13 | b := Py 14 | c := Pz 15 | d := Pta 16 | e := Ptb 17 | f := b 18 | g := a 19 | fqAdd(e, Px, Py) 20 | fqSqr(a, Px) 21 | fqSqr(b, Py) 22 | fqSqr(c, Pz) 23 | fqAdd(c, c, c) 24 | fqAdd(d, a, b) 25 | fqSqr(e, e) 26 | fqSub(e, e, d) 27 | fqSub(f, b, a) 28 | fqSub(g, c, f) 29 | fqMul(Pz, f, g) 30 | fqMul(Px, e, g) 31 | fqMul(Py, d, f) 32 | } 33 | 34 | func addGeneric(P *pointR1, Q *pointR2) { 35 | addYX := &Q.addYX 36 | subYX := &Q.subYX 37 | z2 := &Q.z2 38 | dt2 := &Q.dt2 39 | Px := &P.X 40 | Py := &P.Y 41 | Pz := &P.Z 42 | Pta := &P.Ta 43 | Ptb := &P.Tb 44 | a := Px 45 | b := Py 46 | c := &Fq{} 47 | d := b 48 | e := Pta 49 | f := a 50 | g := b 51 | h := Ptb 52 | fqMul(c, Pta, Ptb) 53 | fqSub(h, b, a) 54 | fqAdd(b, b, a) 55 | fqMul(a, h, subYX) 56 | fqMul(b, b, addYX) 57 | fqSub(e, b, a) 58 | fqAdd(h, b, a) 59 | fqMul(d, Pz, z2) 60 | fqMul(c, c, dt2) 61 | fqSub(f, d, c) 62 | fqAdd(g, d, c) 63 | fqMul(Pz, f, g) 64 | fqMul(Px, e, f) 65 | fqMul(Py, g, h) 66 | } 67 | 68 | func mixAddGeneric(P *pointR1, Q *pointR3) { 69 | addYX := &Q.addYX 70 | subYX := &Q.subYX 71 | dt2 := &Q.dt2 72 | Px := &P.X 73 | Py := &P.Y 74 | Pz := &P.Z 75 | Pta := &P.Ta 76 | Ptb := &P.Tb 77 | a := Px 78 | b := Py 79 | c := &Fq{} 80 | d := b 81 | e := Pta 82 | f := a 83 | g := b 84 | h := Ptb 85 | fqMul(c, Pta, Ptb) 86 | fqSub(h, b, a) 87 | fqAdd(b, b, a) 88 | fqMul(a, h, subYX) 89 | fqMul(b, b, addYX) 90 | fqSub(e, b, a) 91 | fqAdd(h, b, a) 92 | fqAdd(d, Pz, Pz) 93 | fqMul(c, c, dt2) 94 | fqSub(f, d, c) 95 | fqAdd(g, d, c) 96 | fqMul(Pz, f, g) 97 | fqMul(Px, e, f) 98 | fqMul(Py, g, h) 99 | } 100 | -------------------------------------------------------------------------------- /ecc/fourq/point_noasm.go: -------------------------------------------------------------------------------- 1 | //go:build !amd64 || purego 2 | // +build !amd64 purego 3 | 4 | package fourq 5 | 6 | func (P *pointR1) double() { doubleGeneric(P) } 7 | func (P *pointR1) add(Q *pointR2) { addGeneric(P, Q) } 8 | func (P *pointR1) mixAdd(Q *pointR3) { mixAddGeneric(P, Q) } 9 | -------------------------------------------------------------------------------- /ecc/goldilocks/isogeny.go: -------------------------------------------------------------------------------- 1 | package goldilocks 2 | 3 | import fp "github.com/cloudflare/circl/math/fp448" 4 | 5 | func (Curve) pull(P *twistPoint) *Point { return twistCurve{}.push(P) } 6 | func (twistCurve) pull(P *Point) *twistPoint { return Curve{}.push(P) } 7 | 8 | // push sends a point on the Goldilocks curve to a point on the twist curve. 9 | func (Curve) push(P *Point) *twistPoint { 10 | Q := &twistPoint{} 11 | Px, Py, Pz := &P.x, &P.y, &P.z 12 | a, b, c, d, e, f, g, h := &Q.x, &Q.y, &Q.z, &fp.Elt{}, &Q.ta, &Q.x, &Q.y, &Q.tb 13 | fp.Add(e, Px, Py) // x+y 14 | fp.Sqr(a, Px) // A = x^2 15 | fp.Sqr(b, Py) // B = y^2 16 | fp.Sqr(c, Pz) // z^2 17 | fp.Add(c, c, c) // C = 2*z^2 18 | *d = *a // D = A 19 | fp.Sqr(e, e) // (x+y)^2 20 | fp.Sub(e, e, a) // (x+y)^2-A 21 | fp.Sub(e, e, b) // E = (x+y)^2-A-B 22 | fp.Add(h, b, d) // H = B+D 23 | fp.Sub(g, b, d) // G = B-D 24 | fp.Sub(f, c, h) // F = C-H 25 | fp.Mul(&Q.z, f, g) // Z = F * G 26 | fp.Mul(&Q.x, e, f) // X = E * F 27 | fp.Mul(&Q.y, g, h) // Y = G * H, // T = E * H 28 | return Q 29 | } 30 | 31 | // push sends a point on the twist curve to a point on the Goldilocks curve. 32 | func (twistCurve) push(P *twistPoint) *Point { 33 | Q := &Point{} 34 | Px, Py, Pz := &P.x, &P.y, &P.z 35 | a, b, c, d, e, f, g, h := &Q.x, &Q.y, &Q.z, &fp.Elt{}, &Q.ta, &Q.x, &Q.y, &Q.tb 36 | fp.Add(e, Px, Py) // x+y 37 | fp.Sqr(a, Px) // A = x^2 38 | fp.Sqr(b, Py) // B = y^2 39 | fp.Sqr(c, Pz) // z^2 40 | fp.Add(c, c, c) // C = 2*z^2 41 | fp.Neg(d, a) // D = -A 42 | fp.Sqr(e, e) // (x+y)^2 43 | fp.Sub(e, e, a) // (x+y)^2-A 44 | fp.Sub(e, e, b) // E = (x+y)^2-A-B 45 | fp.Add(h, b, d) // H = B+D 46 | fp.Sub(g, b, d) // G = B-D 47 | fp.Sub(f, c, h) // F = C-H 48 | fp.Mul(&Q.z, f, g) // Z = F * G 49 | fp.Mul(&Q.x, e, f) // X = E * F 50 | fp.Mul(&Q.y, g, h) // Y = G * H, // T = E * H 51 | return Q 52 | } 53 | -------------------------------------------------------------------------------- /ecc/goldilocks/isogeny_test.go: -------------------------------------------------------------------------------- 1 | package goldilocks 2 | 3 | import ( 4 | "crypto/rand" 5 | "testing" 6 | 7 | "github.com/cloudflare/circl/internal/test" 8 | ) 9 | 10 | func randomPoint() *Point { 11 | var k Scalar 12 | _, _ = rand.Read(k[:]) 13 | return Curve{}.ScalarBaseMult(&k) 14 | } 15 | 16 | func TestIsogeny(t *testing.T) { 17 | const testTimes = 1 << 10 18 | var gold Curve 19 | var twist twistCurve 20 | 21 | for i := 0; i < testTimes; i++ { 22 | P := randomPoint() 23 | Q := gold.pull(gold.push(P)) // phi^-(phi^+(P)) 24 | got := Q 25 | want := gold.Double(gold.Double(P)) // 4P 26 | if !got.IsEqual(want) { 27 | test.ReportError(t, got, want, P) 28 | } 29 | got = twist.push(twist.pull(Q)) // phi^-(phi^+(Q)) 30 | want = gold.Double(gold.Double(Q)) // 4Q 31 | if !got.IsEqual(want) { 32 | test.ReportError(t, got, want, P) 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /ecc/goldilocks/twist_basemult.go: -------------------------------------------------------------------------------- 1 | package goldilocks 2 | 3 | import ( 4 | "crypto/subtle" 5 | 6 | mlsb "github.com/cloudflare/circl/math/mlsbset" 7 | ) 8 | 9 | const ( 10 | // MLSBRecoding parameters 11 | fxT = 448 12 | fxV = 2 13 | fxW = 3 14 | fx2w1 = 1 << (uint(fxW) - 1) 15 | ) 16 | 17 | // ScalarBaseMult returns kG where G is the generator point. 18 | func (e twistCurve) ScalarBaseMult(k *Scalar) *twistPoint { 19 | m, err := mlsb.New(fxT, fxV, fxW) 20 | if err != nil { 21 | panic(err) 22 | } 23 | if m.IsExtended() { 24 | panic("not extended") 25 | } 26 | 27 | var isZero int 28 | if k.IsZero() { 29 | isZero = 1 30 | } 31 | subtle.ConstantTimeCopy(isZero, k[:], order[:]) 32 | 33 | minusK := *k 34 | isEven := 1 - int(k[0]&0x1) 35 | minusK.Neg() 36 | subtle.ConstantTimeCopy(isEven, k[:], minusK[:]) 37 | c, err := m.Encode(k[:]) 38 | if err != nil { 39 | panic(err) 40 | } 41 | 42 | gP := c.Exp(groupMLSB{}) 43 | P := gP.(*twistPoint) 44 | P.cneg(uint(isEven)) 45 | return P 46 | } 47 | 48 | type groupMLSB struct{} 49 | 50 | func (e groupMLSB) ExtendedEltP() mlsb.EltP { return nil } 51 | func (e groupMLSB) Sqr(x mlsb.EltG) { x.(*twistPoint).Double() } 52 | func (e groupMLSB) Mul(x mlsb.EltG, y mlsb.EltP) { x.(*twistPoint).mixAddZ1(y.(*preTwistPointAffine)) } 53 | func (e groupMLSB) Identity() mlsb.EltG { return twistCurve{}.Identity() } 54 | func (e groupMLSB) NewEltP() mlsb.EltP { return &preTwistPointAffine{} } 55 | func (e groupMLSB) Lookup(a mlsb.EltP, v uint, s, u int32) { 56 | Tabj := &tabFixMult[v] 57 | P := a.(*preTwistPointAffine) 58 | for k := range Tabj { 59 | P.cmov(&Tabj[k], uint(subtle.ConstantTimeEq(int32(k), u))) 60 | } 61 | P.cneg(int(s >> 31)) 62 | } 63 | -------------------------------------------------------------------------------- /ecc/p384/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018, Brendan McMillion. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, 4 | are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this 7 | list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation and/or 11 | other materials provided with the distribution. 12 | 13 | 3. Neither the name of the copyright holder nor the names of its contributors 14 | may be used to endorse or promote products derived from this software without 15 | specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 21 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 24 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /ecc/p384/arith_amd64.go: -------------------------------------------------------------------------------- 1 | //go:build amd64 && !purego 2 | // +build amd64,!purego 3 | 4 | package p384 5 | 6 | import "golang.org/x/sys/cpu" 7 | 8 | var hasBMI2 = cpu.X86.HasBMI2 //nolint 9 | -------------------------------------------------------------------------------- /ecc/p384/doc.go: -------------------------------------------------------------------------------- 1 | // Package p384 provides optimized elliptic curve operations on the P-384 curve. 2 | // 3 | // These are some improvements over crypto/elliptic package: 4 | // - Around 10x faster in amd64 architecture. 5 | // - Reduced number of memory allocations. 6 | // - Native support for arm64 architecture. 7 | // - ScalarMult is performed using a constant-time algorithm. 8 | // - ScalarBaseMult fallbacks into ScalarMult. 9 | // - A new method included for double-point multiplication. 10 | package p384 11 | -------------------------------------------------------------------------------- /ecc/p384/p384.go: -------------------------------------------------------------------------------- 1 | package p384 2 | 3 | import ( 4 | "crypto/elliptic" 5 | "math/big" 6 | ) 7 | 8 | // Curve is used to provide the extended functionality and performance of 9 | // elliptic.Curve interface. 10 | type Curve interface { 11 | elliptic.Curve 12 | // IsAtInfinity returns True is the point is the identity point. 13 | IsAtInfinity(X, Y *big.Int) bool 14 | // CombinedMult calculates P=mG+nQ, where G is the generator and 15 | // Q=(Qx,Qy). The scalars m and n are positive integers in big-endian form. 16 | // Runs in non-constant time to be used in signature verification. 17 | CombinedMult(Qx, Qy *big.Int, m, n []byte) (Px, Py *big.Int) 18 | } 19 | 20 | // Params returns the parameters for the curve. Note: The value returned by 21 | // this function fallbacks to the stdlib implementation of elliptic curve 22 | // operations. Use this method to only recover elliptic curve parameters. 23 | func (c curve) Params() *elliptic.CurveParams { return elliptic.P384().Params() } 24 | 25 | // IsAtInfinity returns True is the point is the identity point. 26 | func (c curve) IsAtInfinity(x, y *big.Int) bool { 27 | return x.Sign() == 0 && y.Sign() == 0 28 | } 29 | -------------------------------------------------------------------------------- /ecc/p384/p384_generic.go: -------------------------------------------------------------------------------- 1 | //go:build purego || (!amd64 && !arm64) 2 | // +build purego !amd64,!arm64 3 | 4 | package p384 5 | 6 | import ( 7 | "crypto/elliptic" 8 | "math/big" 9 | ) 10 | 11 | type curve struct{ elliptic.Curve } 12 | 13 | func P384() Curve { return curve{elliptic.P384()} } 14 | 15 | // CombinedMult calculates P=mG+nQ, where G is the generator and Q=(x,y,z). 16 | // The scalars m and n are integers in big-endian form. Non-constant time. 17 | func (c curve) CombinedMult(xQ, yQ *big.Int, m, n []byte) (xP, yP *big.Int) { 18 | x1, y1 := c.ScalarBaseMult(m) 19 | x2, y2 := c.ScalarMult(xQ, yQ, n) 20 | return c.Add(x1, y1, x2, y2) 21 | } 22 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/cloudflare/circl 2 | 3 | go 1.22.0 4 | 5 | require ( 6 | github.com/bwesterb/go-ristretto v1.2.3 7 | golang.org/x/crypto v0.11.1-0.20230711161743-2e82bdd1719d 8 | golang.org/x/sys v0.10.0 9 | ) 10 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/bwesterb/go-ristretto v1.2.3 h1:1w53tCkGhCQ5djbat3+MH0BAQ5Kfgbt56UZQ/JMzngw= 2 | github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= 3 | golang.org/x/crypto v0.11.1-0.20230711161743-2e82bdd1719d h1:LiA25/KWKuXfIq5pMIBq1s5hz3HQxhJJSu/SUGlD+SM= 4 | golang.org/x/crypto v0.11.1-0.20230711161743-2e82bdd1719d/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= 5 | golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= 6 | golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 7 | -------------------------------------------------------------------------------- /group/hash.go: -------------------------------------------------------------------------------- 1 | package group 2 | 3 | import ( 4 | "math/big" 5 | 6 | "github.com/cloudflare/circl/expander" 7 | ) 8 | 9 | // HashToField generates a set of elements {u1,..., uN} = Hash(b) where each 10 | // u in GF(p) and L is the security parameter. 11 | func HashToField(u []big.Int, b []byte, e expander.Expander, p *big.Int, L uint) { 12 | count := uint(len(u)) 13 | bytes := e.Expand(b, count*L) 14 | for i := range u { 15 | j := uint(i) * L 16 | u[i].Mod(u[i].SetBytes(bytes[j:j+L]), p) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /hpke/genericnoauthkem.go: -------------------------------------------------------------------------------- 1 | package hpke 2 | 3 | // Shim to use generic KEM (kem.Scheme) as HPKE KEM. 4 | 5 | import ( 6 | "github.com/cloudflare/circl/internal/sha3" 7 | "github.com/cloudflare/circl/kem" 8 | ) 9 | 10 | // genericNoAuthKEM wraps a generic KEM (kem.Scheme) to be used as a HPKE KEM. 11 | type genericNoAuthKEM struct { 12 | kem.Scheme 13 | name string 14 | } 15 | 16 | func (h genericNoAuthKEM) Name() string { return h.name } 17 | 18 | // HPKE requires DeriveKeyPair() to take any seed larger than the private key 19 | // size, whereas typical KEMs expect a specific seed size. We'll just use 20 | // SHAKE256 to hash it to the right size as in X-Wing. 21 | func (h genericNoAuthKEM) DeriveKeyPair(seed []byte) (kem.PublicKey, kem.PrivateKey) { 22 | seed2 := make([]byte, h.Scheme.SeedSize()) 23 | hh := sha3.NewShake256() 24 | _, _ = hh.Write(seed) 25 | _, _ = hh.Read(seed2) 26 | return h.Scheme.DeriveKeyPair(seed2) 27 | } 28 | -------------------------------------------------------------------------------- /internal/nist/drbg.go: -------------------------------------------------------------------------------- 1 | // Package nist implements helpers to generate NIST's Known Answer Tests (KATs). 2 | package nist 3 | 4 | import ( 5 | "crypto/aes" 6 | ) 7 | 8 | // See NIST's PQCgenKAT.c. 9 | type DRBG struct { 10 | key [32]byte 11 | v [16]byte 12 | } 13 | 14 | func (g *DRBG) incV() { 15 | for j := 15; j >= 0; j-- { 16 | if g.v[j] == 255 { 17 | g.v[j] = 0 18 | } else { 19 | g.v[j]++ 20 | break 21 | } 22 | } 23 | } 24 | 25 | // AES256_CTR_DRBG_Update(pd, &g.key, &g.v). 26 | func (g *DRBG) update(pd *[48]byte) { 27 | var buf [48]byte 28 | b, _ := aes.NewCipher(g.key[:]) 29 | for i := 0; i < 3; i++ { 30 | g.incV() 31 | b.Encrypt(buf[i*16:(i+1)*16], g.v[:]) 32 | } 33 | if pd != nil { 34 | for i := 0; i < 48; i++ { 35 | buf[i] ^= pd[i] 36 | } 37 | } 38 | copy(g.key[:], buf[:32]) 39 | copy(g.v[:], buf[32:]) 40 | } 41 | 42 | // randombyte_init(seed, NULL, 256). 43 | func NewDRBG(seed *[48]byte) (g DRBG) { 44 | g.update(seed) 45 | return 46 | } 47 | 48 | // randombytes. 49 | func (g *DRBG) Fill(x []byte) { 50 | var block [16]byte 51 | 52 | b, _ := aes.NewCipher(g.key[:]) 53 | for len(x) > 0 { 54 | g.incV() 55 | b.Encrypt(block[:], g.v[:]) 56 | if len(x) < 16 { 57 | copy(x[:], block[:len(x)]) 58 | break 59 | } 60 | copy(x[:], block[:]) 61 | x = x[16:] 62 | } 63 | g.update(nil) 64 | } 65 | -------------------------------------------------------------------------------- /internal/sha3/rc.go: -------------------------------------------------------------------------------- 1 | package sha3 2 | 3 | // RC stores the round constants for use in the ι step. 4 | var RC = [24]uint64{ 5 | 0x0000000000000001, 6 | 0x0000000000008082, 7 | 0x800000000000808A, 8 | 0x8000000080008000, 9 | 0x000000000000808B, 10 | 0x0000000080000001, 11 | 0x8000000080008081, 12 | 0x8000000000008009, 13 | 0x000000000000008A, 14 | 0x0000000000000088, 15 | 0x0000000080008009, 16 | 0x000000008000000A, 17 | 0x000000008000808B, 18 | 0x800000000000008B, 19 | 0x8000000000008089, 20 | 0x8000000000008003, 21 | 0x8000000000008002, 22 | 0x8000000000000080, 23 | 0x000000000000800A, 24 | 0x800000008000000A, 25 | 0x8000000080008081, 26 | 0x8000000000008080, 27 | 0x0000000080000001, 28 | 0x8000000080008008, 29 | } 30 | -------------------------------------------------------------------------------- /internal/sha3/sha3_s390x.s: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build !gccgo,!appengine 6 | 7 | #include "textflag.h" 8 | 9 | // func kimd(function code, chain *[200]byte, src []byte) 10 | TEXT ·kimd(SB), NOFRAME|NOSPLIT, $0-40 11 | MOVD function+0(FP), R0 12 | MOVD chain+8(FP), R1 13 | LMG src+16(FP), R2, R3 // R2=base, R3=len 14 | 15 | continue: 16 | WORD $0xB93E0002 // KIMD --, R2 17 | BVS continue // continue if interrupted 18 | MOVD $0, R0 // reset R0 for pre-go1.8 compilers 19 | RET 20 | 21 | // func klmd(function code, chain *[200]byte, dst, src []byte) 22 | TEXT ·klmd(SB), NOFRAME|NOSPLIT, $0-64 23 | // TODO: SHAKE support 24 | MOVD function+0(FP), R0 25 | MOVD chain+8(FP), R1 26 | LMG dst+16(FP), R2, R3 // R2=base, R3=len 27 | LMG src+40(FP), R4, R5 // R4=base, R5=len 28 | 29 | continue: 30 | WORD $0xB93F0024 // KLMD R2, R4 31 | BVS continue // continue if interrupted 32 | MOVD $0, R0 // reset R0 for pre-go1.8 compilers 33 | RET 34 | -------------------------------------------------------------------------------- /internal/sha3/testdata/keccakKats.json.deflate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/circl/main/internal/sha3/testdata/keccakKats.json.deflate -------------------------------------------------------------------------------- /internal/sha3/xor.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | //go:build (!amd64 && !386 && !ppc64le) || appengine 6 | // +build !amd64,!386,!ppc64le appengine 7 | 8 | package sha3 9 | 10 | // A storageBuf is an aligned array of maxRate bytes. 11 | type storageBuf [maxRate]byte 12 | 13 | func (b *storageBuf) asBytes() *[maxRate]byte { 14 | return (*[maxRate]byte)(b) 15 | } 16 | -------------------------------------------------------------------------------- /internal/sha3/xor_generic.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | //go:build (!amd64 || appengine) && (!386 || appengine) && (!ppc64le || appengine) 6 | // +build !amd64 appengine 7 | // +build !386 appengine 8 | // +build !ppc64le appengine 9 | 10 | package sha3 11 | 12 | import "encoding/binary" 13 | 14 | // xorIn xors the bytes in buf into the state; it 15 | // makes no non-portable assumptions about memory layout 16 | // or alignment. 17 | func xorIn(d *State, buf []byte) { 18 | n := len(buf) / 8 19 | 20 | for i := 0; i < n; i++ { 21 | a := binary.LittleEndian.Uint64(buf) 22 | d.a[i] ^= a 23 | buf = buf[8:] 24 | } 25 | } 26 | 27 | // copyOut copies ulint64s to a byte buffer. 28 | func copyOut(d *State, b []byte) { 29 | for i := 0; len(b) >= 8; i++ { 30 | binary.LittleEndian.PutUint64(b, d.a[i]) 31 | b = b[8:] 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /internal/sha3/xor_unaligned.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | //go:build (amd64 || 386 || ppc64le) && !appengine 6 | // +build amd64 386 ppc64le 7 | // +build !appengine 8 | 9 | package sha3 10 | 11 | import "unsafe" 12 | 13 | // A storageBuf is an aligned array of maxRate bytes. 14 | type storageBuf [maxRate / 8]uint64 15 | 16 | func (b *storageBuf) asBytes() *[maxRate]byte { 17 | return (*[maxRate]byte)(unsafe.Pointer(b)) 18 | } 19 | 20 | // xorInuses unaligned reads and writes to update d.a to contain d.a 21 | // XOR buf. 22 | func xorIn(d *State, buf []byte) { 23 | n := len(buf) 24 | bw := (*[maxRate / 8]uint64)(unsafe.Pointer(&buf[0]))[: n/8 : n/8] 25 | if n >= 72 { 26 | d.a[0] ^= bw[0] 27 | d.a[1] ^= bw[1] 28 | d.a[2] ^= bw[2] 29 | d.a[3] ^= bw[3] 30 | d.a[4] ^= bw[4] 31 | d.a[5] ^= bw[5] 32 | d.a[6] ^= bw[6] 33 | d.a[7] ^= bw[7] 34 | d.a[8] ^= bw[8] 35 | } 36 | if n >= 104 { 37 | d.a[9] ^= bw[9] 38 | d.a[10] ^= bw[10] 39 | d.a[11] ^= bw[11] 40 | d.a[12] ^= bw[12] 41 | } 42 | if n >= 136 { 43 | d.a[13] ^= bw[13] 44 | d.a[14] ^= bw[14] 45 | d.a[15] ^= bw[15] 46 | d.a[16] ^= bw[16] 47 | } 48 | if n >= 144 { 49 | d.a[17] ^= bw[17] 50 | } 51 | if n >= 168 { 52 | d.a[18] ^= bw[18] 53 | d.a[19] ^= bw[19] 54 | d.a[20] ^= bw[20] 55 | } 56 | } 57 | 58 | func copyOut(d *State, buf []byte) { 59 | ab := (*[maxRate]uint8)(unsafe.Pointer(&d.a[0])) 60 | copy(buf, ab[:]) 61 | } 62 | -------------------------------------------------------------------------------- /internal/test/test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "strings" 7 | "testing" 8 | ) 9 | 10 | // ReportError reports an error if got is different from want. 11 | func ReportError(t testing.TB, got, want interface{}, inputs ...interface{}) { 12 | b := &strings.Builder{} 13 | fmt.Fprint(b, "\n") 14 | for i, in := range inputs { 15 | fmt.Fprintf(b, "in[%v]: %v\n", i, in) 16 | } 17 | fmt.Fprintf(b, "got: %v\nwant: %v", got, want) 18 | t.Helper() 19 | t.Fatal(b.String()) 20 | } 21 | 22 | // CheckOk fails the test if result == false. 23 | func CheckOk(result bool, msg string, t testing.TB) { 24 | t.Helper() 25 | 26 | if !result { 27 | t.Fatal(msg) 28 | } 29 | } 30 | 31 | // checkErr fails on error condition. mustFail indicates whether err is expected 32 | // to be nil or not. 33 | func checkErr(t testing.TB, err error, mustFail bool, msg string) { 34 | t.Helper() 35 | if err != nil && !mustFail { 36 | t.Fatalf("msg: %v\nerr: %v", msg, err) 37 | } 38 | 39 | if err == nil && mustFail { 40 | t.Fatalf("msg: %v\nerr: %v", msg, err) 41 | } 42 | } 43 | 44 | // CheckNoErr fails if err !=nil. Print msg as an error message. 45 | func CheckNoErr(t testing.TB, err error, msg string) { t.Helper(); checkErr(t, err, false, msg) } 46 | 47 | // CheckIsErr fails if err ==nil. Print msg as an error message. 48 | func CheckIsErr(t testing.TB, err error, msg string) { t.Helper(); checkErr(t, err, true, msg) } 49 | 50 | // CheckPanic returns true if call to function 'f' caused panic. 51 | func CheckPanic(f func()) error { 52 | hasPanicked := errors.New("no panic detected") 53 | defer func() { 54 | if r := recover(); r != nil { 55 | hasPanicked = nil 56 | } 57 | }() 58 | f() 59 | return hasPanicked 60 | } 61 | -------------------------------------------------------------------------------- /kem/frodo/doc.go: -------------------------------------------------------------------------------- 1 | // Package frodo provides the key encapsulation mechanism FrodoKEM. 2 | // 3 | // Compatible with the implementation submitted to round 3 of the 4 | // NIST PQC competition [1]. This implementation draws heavily from the PQClean 5 | // implementation [2]. 6 | // 7 | // References: 8 | // 9 | // [1] https://frodokem.org/files/FrodoKEM-specification-20210604.pdf 10 | // [2] https://github.com/PQClean/PQClean/tree/master/crypto_kem/frodokem640shake/clean 11 | package frodo 12 | -------------------------------------------------------------------------------- /kem/frodo/frodo640shake/matrix_shake.go: -------------------------------------------------------------------------------- 1 | package frodo640shake 2 | 3 | import ( 4 | "github.com/cloudflare/circl/internal/sha3" 5 | ) 6 | 7 | func expandSeedIntoA(A *nByNU16, seed *[seedASize]byte, xof *sha3.State) { 8 | var ARow [paramN * 2]byte 9 | var seedSeparated [2 + seedASize]byte 10 | 11 | copy(seedSeparated[2:], seed[:]) 12 | 13 | for i := 0; i < paramN; i++ { 14 | seedSeparated[0] = byte(i) 15 | seedSeparated[1] = byte(i >> 8) 16 | 17 | xof.Reset() 18 | _, _ = xof.Write(seedSeparated[:]) 19 | _, _ = xof.Read(ARow[:]) 20 | 21 | for j := 0; j < paramN; j++ { 22 | // No need to reduce modulo 2^15, extra bits are removed 23 | // later on via packing or explicit reduction. 24 | A[(i*paramN)+j] = uint16(ARow[j*2]) | (uint16(ARow[(j*2)+1]) << 8) 25 | } 26 | } 27 | } 28 | 29 | func mulAddASPlusE(out *nByNbarU16, A *nByNU16, s *nByNbarU16, e *nByNbarU16) { 30 | for i := 0; i < paramN; i++ { 31 | for k := 0; k < paramNbar; k++ { 32 | sum := e[i*paramNbar+k] 33 | for j := 0; j < paramN; j++ { 34 | sum += A[i*paramN+j] * s[k*paramN+j] 35 | } 36 | // No need to reduce modulo 2^15, extra bits are removed 37 | // later on via packing or explicit reduction. 38 | out[i*paramNbar+k] += sum 39 | } 40 | } 41 | } 42 | 43 | func mulAddSAPlusE(out *nbarByNU16, s []uint16, A *nByNU16, e []uint16) { 44 | for i := 0; i < paramN; i++ { 45 | for k := 0; k < paramNbar; k++ { 46 | sum := e[k*paramN+i] 47 | for j := 0; j < paramN; j++ { 48 | sum += A[j*paramN+i] * s[k*paramN+j] 49 | } 50 | // No need to reduce modulo 2^15, extra bits are removed 51 | // later on via packing or explicit reduction. 52 | out[k*paramN+i] += sum 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /kem/frodo/frodo640shake/noise.go: -------------------------------------------------------------------------------- 1 | package frodo640shake 2 | 3 | const cdfTableLen = 13 4 | 5 | var cdfTable [cdfTableLen]uint16 = [cdfTableLen]uint16{4643, 13363, 20579, 25843, 29227, 31145, 32103, 32525, 32689, 32745, 32762, 32766, 32767} 6 | 7 | // Take a uniformly distributed sample, and produce a sample in the FrodoKEM 8 | // discrete Gaussian distribution using inverse transform sampling. 9 | func sample(sampled []uint16) { 10 | for i := 0; i < len(sampled); i++ { 11 | var gaussianSample uint16 = 0 12 | sign := sampled[i] & 1 13 | unifSample := sampled[i] >> 1 14 | 15 | for j := 0; j < cdfTableLen-1; j++ { 16 | gaussianSample += (cdfTable[j] - unifSample) >> 15 17 | } 18 | // If sign = 1, -sign = 0xFFFF and the bits of gaussianSample 19 | // are flipped. Since gaussianSample is uint16, we have: 20 | // 21 | // flippedBits(gaussianSample) + 1 ≡ -gaussianSample (mod 2^16), 22 | // 23 | // and so the sign of gaussianSample is flipped. 24 | sampled[i] = ((-sign) ^ gaussianSample) + sign 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /kem/frodo/kat_test.go: -------------------------------------------------------------------------------- 1 | package frodo 2 | 3 | // Code to generate the NIST "PQCsignKAT" test vectors. 4 | // See PQCsignKAT_sign.c and randombytes.c in the reference implementation. 5 | 6 | import ( 7 | "bytes" 8 | "crypto/sha256" 9 | "fmt" 10 | "testing" 11 | 12 | "github.com/cloudflare/circl/internal/nist" 13 | "github.com/cloudflare/circl/kem/schemes" 14 | ) 15 | 16 | func TestPQCgenKATKem(t *testing.T) { 17 | kats := []struct { 18 | name string 19 | want string 20 | }{ 21 | // Computed from: 22 | // https://github.com/microsoft/PQCrypto-LWEKE/blob/66fc7744c3aae6acfc5fcc587ec7f2cdec48d216/KAT/PQCkemKAT_19888_shake.rsp 23 | {"FrodoKEM-640-SHAKE", "604a10cfc871dfaed9cb5b057c644ab03b16852cea7f39bc7f9831513b5b1cfa"}, 24 | } 25 | for _, kat := range kats { 26 | t.Run(kat.name, func(t *testing.T) { 27 | testPQCgenKATKem(t, kat.name, kat.want) 28 | }) 29 | } 30 | } 31 | 32 | func testPQCgenKATKem(t *testing.T, name, expected string) { 33 | scheme := schemes.ByName(name) 34 | if scheme == nil { 35 | t.Fatal() 36 | } 37 | 38 | var seed [48]byte 39 | kseed := make([]byte, scheme.SeedSize()) 40 | eseed := make([]byte, scheme.EncapsulationSeedSize()) 41 | for i := 0; i < 48; i++ { 42 | seed[i] = byte(i) 43 | } 44 | f := sha256.New() 45 | g := nist.NewDRBG(&seed) 46 | fmt.Fprintf(f, "# %s\n\n", name) 47 | for i := 0; i < 100; i++ { 48 | g.Fill(seed[:]) 49 | fmt.Fprintf(f, "count = %d\n", i) 50 | fmt.Fprintf(f, "seed = %X\n", seed) 51 | g2 := nist.NewDRBG(&seed) 52 | 53 | g2.Fill(kseed[:]) 54 | 55 | pk, sk := scheme.DeriveKeyPair(kseed) 56 | ppk, _ := pk.MarshalBinary() 57 | psk, _ := sk.MarshalBinary() 58 | 59 | g2.Fill(eseed) 60 | ct, ss, err := scheme.EncapsulateDeterministically(pk, eseed) 61 | if err != nil { 62 | t.Fatal(err) 63 | } 64 | ss2, _ := scheme.Decapsulate(sk, ct) 65 | if !bytes.Equal(ss, ss2) { 66 | t.Fatal() 67 | } 68 | fmt.Fprintf(f, "pk = %X\n", ppk) 69 | fmt.Fprintf(f, "sk = %X\n", psk) 70 | fmt.Fprintf(f, "ct = %X\n", ct) 71 | fmt.Fprintf(f, "ss = %X\n\n", ss) 72 | } 73 | if fmt.Sprintf("%x", f.Sum(nil)) != expected { 74 | t.Fatal() 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /kem/hybrid/xkem_test.go: -------------------------------------------------------------------------------- 1 | package hybrid 2 | 3 | import ( 4 | "encoding/hex" 5 | "testing" 6 | 7 | "github.com/cloudflare/circl/kem" 8 | ) 9 | 10 | func mustDecodeString(s string) []byte { 11 | b, err := hex.DecodeString(s) 12 | if err != nil { 13 | panic(err) 14 | } 15 | return b 16 | } 17 | 18 | // patchHybridWithLowOrderX25519 replaces the last half of the given ciphertext 19 | // or public key by a 32-byte Curve25519 public key with a point of low order. 20 | func patchHybridWithLowOrderX25519(hybridKey []byte) { 21 | // order 8 22 | xPub := mustDecodeString("e0eb7a7c3b41b8ae1656e3faf19fc46ada098deb9c32b1fd866205165f49b800") 23 | copy(hybridKey[len(hybridKey)-len(xPub):], xPub) 24 | } 25 | 26 | func patchHybridPublicKeyWithLowOrderX25519(pub kem.PublicKey) (kem.PublicKey, error) { 27 | packed, err := pub.MarshalBinary() 28 | if err != nil { 29 | return nil, err 30 | } 31 | patchHybridWithLowOrderX25519(packed) 32 | return pub.Scheme().UnmarshalBinaryPublicKey(packed) 33 | } 34 | 35 | func TestLowOrderX25519PointEncapsulate(t *testing.T) { 36 | scheme := X25519MLKEM768() 37 | pk, _, err := scheme.GenerateKeyPair() 38 | if err != nil { 39 | t.Fatalf("X25519MLKEM768 keygen: %s", err) 40 | } 41 | badPk, err := patchHybridPublicKeyWithLowOrderX25519(pk) 42 | if err != nil { 43 | t.Fatalf("patching X25519 key failed: %s", err) 44 | } 45 | _, _, err = scheme.Encapsulate(badPk) 46 | want := kem.ErrPubKey 47 | if err != want { 48 | t.Fatalf("Encapsulate error: expected %v; got %v", want, err) 49 | } 50 | } 51 | 52 | func TestLowOrderX25519PointDecapsulate(t *testing.T) { 53 | scheme := X25519MLKEM768() 54 | pk, sk, err := scheme.GenerateKeyPair() 55 | if err != nil { 56 | t.Fatalf("X25519MLKEM768 keygen: %s", err) 57 | } 58 | ct, _, err := scheme.Encapsulate(pk) 59 | if err != nil { 60 | t.Fatalf("Encapsulate failed: %s", err) 61 | } 62 | patchHybridWithLowOrderX25519(ct) 63 | _, err = scheme.Decapsulate(sk, ct) 64 | want := kem.ErrPubKey 65 | if err != want { 66 | t.Fatalf("Decapsulate error: expected %v; got %v", want, err) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /kem/kyber/doc.go: -------------------------------------------------------------------------------- 1 | //go:generate go run gen.go 2 | 3 | // Package kyber implements the CRYSTALS-Kyber.CCAKEM IND-CCA2 secure 4 | // key encapsulation mechanism (KEM) as submitted to round 3 of the NIST PQC 5 | // competition and described in 6 | // 7 | // https://pq-crystals.org/kyber/data/kyber-specification-round3.pdf 8 | // 9 | // The related public key encryption scheme CRYSTALS-Kyber.CPAPKE can be 10 | // found in the package github.com/cloudflare/circl/pke/kyber. 11 | package kyber 12 | -------------------------------------------------------------------------------- /kem/mlkem/doc.go: -------------------------------------------------------------------------------- 1 | // Package mlkem implements IND-CCA2 secure ML-KEM key encapsulation 2 | // mechanism (KEM) as defined in FIPS 203. 3 | // 4 | // https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.203.pdf 5 | package mlkem 6 | 7 | // See ../kyber/gen.go and ../kyber/kat_test.go. 8 | -------------------------------------------------------------------------------- /kem/mlkem/testdata/ML-KEM-encapDecap-FIPS203/expectedResults.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/circl/main/kem/mlkem/testdata/ML-KEM-encapDecap-FIPS203/expectedResults.json.gz -------------------------------------------------------------------------------- /kem/mlkem/testdata/ML-KEM-encapDecap-FIPS203/prompt.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/circl/main/kem/mlkem/testdata/ML-KEM-encapDecap-FIPS203/prompt.json.gz -------------------------------------------------------------------------------- /kem/mlkem/testdata/ML-KEM-keyGen-FIPS203/expectedResults.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/circl/main/kem/mlkem/testdata/ML-KEM-keyGen-FIPS203/expectedResults.json.gz -------------------------------------------------------------------------------- /kem/mlkem/testdata/ML-KEM-keyGen-FIPS203/prompt.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/circl/main/kem/mlkem/testdata/ML-KEM-keyGen-FIPS203/prompt.json.gz -------------------------------------------------------------------------------- /kem/mlkem/testdata/README.md: -------------------------------------------------------------------------------- 1 | Sources 2 | 3 | 1. https://github.com/usnistgov/ACVP-Server/tree/f38183487eebff2952da0e5a3441371218acfe3f/gen-val/json-files/ML-KEM-encapDecap-FIPS203 4 | 2. https://github.com/usnistgov/ACVP-Server/tree/f38183487eebff2952da0e5a3441371218acfe3f/gen-val/json-files/ML-KEM-keyGen-FIPS203 5 | -------------------------------------------------------------------------------- /kem/sike/doc.go: -------------------------------------------------------------------------------- 1 | //go:generate go run gen.go 2 | 3 | // Package sike is deprecated, it contains the SIKE key encapsulation mechanism. 4 | // 5 | // # DEPRECATION NOTICE 6 | // 7 | // SIDH and SIKE are deprecated as were shown vulnerable to a key recovery 8 | // attack by Castryck-Decru's paper (https://eprint.iacr.org/2022/975). New 9 | // systems should not rely on this package. This package is frozen. 10 | package sike 11 | -------------------------------------------------------------------------------- /kem/sike/gen.go: -------------------------------------------------------------------------------- 1 | //go:build ignore 2 | // +build ignore 3 | 4 | // Autogenerates wrappers from templates to prevent too much duplicated code 5 | // between the code for different modes. 6 | package main 7 | 8 | import ( 9 | "bytes" 10 | "fmt" 11 | "go/format" 12 | "io/ioutil" 13 | "strings" 14 | "text/template" 15 | ) 16 | 17 | type Instance struct { 18 | Bits int 19 | } 20 | 21 | func (m Instance) Pkg() string { 22 | return strings.ToLower(m.Name()) 23 | } 24 | 25 | func (m Instance) Name() string { 26 | return fmt.Sprintf("SIKEp%d", m.Bits) 27 | } 28 | 29 | func (m Instance) Field() string { 30 | return fmt.Sprintf("Fp%d", m.Bits) 31 | } 32 | 33 | var ( 34 | Instances = []Instance{ 35 | {Bits: 434}, 36 | {Bits: 503}, 37 | {Bits: 751}, 38 | } 39 | TemplateWarning = "// Code generated from" 40 | ) 41 | 42 | func main() { 43 | generatePackageFiles() 44 | } 45 | 46 | // Generates instance/sike.go from templates/pkg.templ.go 47 | func generatePackageFiles() { 48 | tl, err := template.ParseFiles("templates/pkg.templ.go") 49 | if err != nil { 50 | panic(err) 51 | } 52 | 53 | for _, mode := range Instances { 54 | buf := new(bytes.Buffer) 55 | err := tl.Execute(buf, mode) 56 | if err != nil { 57 | panic(err) 58 | } 59 | 60 | // Formating output code 61 | code, err := format.Source(buf.Bytes()) 62 | if err != nil { 63 | panic("error formating code") 64 | } 65 | 66 | res := string(code) 67 | offset := strings.Index(res, TemplateWarning) 68 | if offset == -1 { 69 | panic("Missing template warning in pkg.templ.go") 70 | } 71 | err = ioutil.WriteFile(mode.Pkg()+"/sike.go", []byte(res[offset:]), 0o644) 72 | if err != nil { 73 | panic(err) 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /kem/xwing/xwing_test.go: -------------------------------------------------------------------------------- 1 | package xwing 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "testing" 8 | 9 | "github.com/cloudflare/circl/internal/sha3" 10 | ) 11 | 12 | func writeHex(w io.Writer, prefix string, val interface{}) { 13 | indent := " " 14 | width := 74 15 | hex := fmt.Sprintf("%x", val) 16 | if len(prefix)+len(hex)+5 < width { 17 | fmt.Fprintf(w, "%s %s\n", prefix, hex) 18 | return 19 | } 20 | fmt.Fprintf(w, "%s\n", prefix) 21 | for len(hex) != 0 { 22 | var toPrint string 23 | if len(hex) < width-len(indent) { 24 | toPrint = hex 25 | hex = "" 26 | } else { 27 | toPrint = hex[:width-len(indent)] 28 | hex = hex[width-len(indent):] 29 | } 30 | fmt.Fprintf(w, "%s%s\n", indent, toPrint) 31 | } 32 | } 33 | 34 | func TestVectors(t *testing.T) { 35 | h := sha3.NewShake128() 36 | w := new(bytes.Buffer) 37 | 38 | for i := 0; i < 3; i++ { 39 | var seed [SeedSize]byte 40 | _, _ = h.Read(seed[:]) 41 | writeHex(w, "seed", seed) 42 | 43 | sk, pk := DeriveKeyPairPacked(seed[:]) 44 | writeHex(w, "sk", sk) 45 | writeHex(w, "pk", pk) 46 | 47 | var eseed [EncapsulationSeedSize]byte 48 | _, _ = h.Read(eseed[:]) 49 | writeHex(w, "eseed", eseed) 50 | 51 | ss, ct, err := Encapsulate(pk, eseed[:]) 52 | if err != nil { 53 | t.Fatal(err) 54 | } 55 | writeHex(w, "ct", ct) 56 | writeHex(w, "ss", ss) 57 | 58 | ss2 := Decapsulate(ct, sk) 59 | if !bytes.Equal(ss, ss2) { 60 | t.Fatal() 61 | } 62 | 63 | fmt.Fprintf(w, "\n") 64 | } 65 | 66 | t.Logf("%s", w.String()) 67 | h.Reset() 68 | _, _ = h.Write(w.Bytes()) 69 | var cs [32]byte 70 | _, _ = h.Read(cs[:]) 71 | got := fmt.Sprintf("%x", cs) 72 | 73 | // shake128 of spec/test-vectors.txt from X-Wing spec at 74 | // https://github.com/dconnolly/draft-connolly-cfrg-xwing-kem 75 | want := "1bcd0057d861d6b866239936cadcaeee1ec0164dedc181c386e9e54fe46156fe" 76 | if got != want { 77 | t.Fatalf("%s ≠ %s", got, want) 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /math/fp25519/fp_amd64.go: -------------------------------------------------------------------------------- 1 | //go:build amd64 && !purego 2 | // +build amd64,!purego 3 | 4 | package fp25519 5 | 6 | import ( 7 | "golang.org/x/sys/cpu" 8 | ) 9 | 10 | var hasBmi2Adx = cpu.X86.HasBMI2 && cpu.X86.HasADX 11 | 12 | var _ = hasBmi2Adx 13 | 14 | func cmov(x, y *Elt, n uint) { cmovAmd64(x, y, n) } 15 | func cswap(x, y *Elt, n uint) { cswapAmd64(x, y, n) } 16 | func add(z, x, y *Elt) { addAmd64(z, x, y) } 17 | func sub(z, x, y *Elt) { subAmd64(z, x, y) } 18 | func addsub(x, y *Elt) { addsubAmd64(x, y) } 19 | func mul(z, x, y *Elt) { mulAmd64(z, x, y) } 20 | func sqr(z, x *Elt) { sqrAmd64(z, x) } 21 | func modp(z *Elt) { modpAmd64(z) } 22 | 23 | //go:noescape 24 | func cmovAmd64(x, y *Elt, n uint) 25 | 26 | //go:noescape 27 | func cswapAmd64(x, y *Elt, n uint) 28 | 29 | //go:noescape 30 | func addAmd64(z, x, y *Elt) 31 | 32 | //go:noescape 33 | func subAmd64(z, x, y *Elt) 34 | 35 | //go:noescape 36 | func addsubAmd64(x, y *Elt) 37 | 38 | //go:noescape 39 | func mulAmd64(z, x, y *Elt) 40 | 41 | //go:noescape 42 | func sqrAmd64(z, x *Elt) 43 | 44 | //go:noescape 45 | func modpAmd64(z *Elt) 46 | -------------------------------------------------------------------------------- /math/fp25519/fp_noasm.go: -------------------------------------------------------------------------------- 1 | //go:build !amd64 || purego 2 | // +build !amd64 purego 3 | 4 | package fp25519 5 | 6 | func cmov(x, y *Elt, n uint) { cmovGeneric(x, y, n) } 7 | func cswap(x, y *Elt, n uint) { cswapGeneric(x, y, n) } 8 | func add(z, x, y *Elt) { addGeneric(z, x, y) } 9 | func sub(z, x, y *Elt) { subGeneric(z, x, y) } 10 | func addsub(x, y *Elt) { addsubGeneric(x, y) } 11 | func mul(z, x, y *Elt) { mulGeneric(z, x, y) } 12 | func sqr(z, x *Elt) { sqrGeneric(z, x) } 13 | func modp(z *Elt) { modpGeneric(z) } 14 | -------------------------------------------------------------------------------- /math/fp448/fp_amd64.go: -------------------------------------------------------------------------------- 1 | //go:build amd64 && !purego 2 | // +build amd64,!purego 3 | 4 | package fp448 5 | 6 | import ( 7 | "golang.org/x/sys/cpu" 8 | ) 9 | 10 | var hasBmi2Adx = cpu.X86.HasBMI2 && cpu.X86.HasADX 11 | 12 | var _ = hasBmi2Adx 13 | 14 | func cmov(x, y *Elt, n uint) { cmovAmd64(x, y, n) } 15 | func cswap(x, y *Elt, n uint) { cswapAmd64(x, y, n) } 16 | func add(z, x, y *Elt) { addAmd64(z, x, y) } 17 | func sub(z, x, y *Elt) { subAmd64(z, x, y) } 18 | func addsub(x, y *Elt) { addsubAmd64(x, y) } 19 | func mul(z, x, y *Elt) { mulAmd64(z, x, y) } 20 | func sqr(z, x *Elt) { sqrAmd64(z, x) } 21 | 22 | /* Functions defined in fp_amd64.s */ 23 | 24 | //go:noescape 25 | func cmovAmd64(x, y *Elt, n uint) 26 | 27 | //go:noescape 28 | func cswapAmd64(x, y *Elt, n uint) 29 | 30 | //go:noescape 31 | func addAmd64(z, x, y *Elt) 32 | 33 | //go:noescape 34 | func subAmd64(z, x, y *Elt) 35 | 36 | //go:noescape 37 | func addsubAmd64(x, y *Elt) 38 | 39 | //go:noescape 40 | func mulAmd64(z, x, y *Elt) 41 | 42 | //go:noescape 43 | func sqrAmd64(z, x *Elt) 44 | -------------------------------------------------------------------------------- /math/fp448/fp_amd64.s: -------------------------------------------------------------------------------- 1 | //go:build amd64 && !purego 2 | // +build amd64,!purego 3 | 4 | #include "textflag.h" 5 | #include "fp_amd64.h" 6 | 7 | // func cmovAmd64(x, y *Elt, n uint) 8 | TEXT ·cmovAmd64(SB),NOSPLIT,$0-24 9 | MOVQ x+0(FP), DI 10 | MOVQ y+8(FP), SI 11 | MOVQ n+16(FP), BX 12 | cselect(0(DI),0(SI),BX) 13 | RET 14 | 15 | // func cswapAmd64(x, y *Elt, n uint) 16 | TEXT ·cswapAmd64(SB),NOSPLIT,$0-24 17 | MOVQ x+0(FP), DI 18 | MOVQ y+8(FP), SI 19 | MOVQ n+16(FP), BX 20 | cswap(0(DI),0(SI),BX) 21 | RET 22 | 23 | // func subAmd64(z, x, y *Elt) 24 | TEXT ·subAmd64(SB),NOSPLIT,$0-24 25 | MOVQ z+0(FP), DI 26 | MOVQ x+8(FP), SI 27 | MOVQ y+16(FP), BX 28 | subtraction(0(DI),0(SI),0(BX)) 29 | RET 30 | 31 | // func addsubAmd64(x, y *Elt) 32 | TEXT ·addsubAmd64(SB),NOSPLIT,$0-16 33 | MOVQ x+0(FP), DI 34 | MOVQ y+8(FP), SI 35 | addSub(0(DI),0(SI)) 36 | RET 37 | 38 | #define addLegacy \ 39 | additionLeg(0(DI),0(SI),0(BX)) 40 | #define addBmi2Adx \ 41 | additionAdx(0(DI),0(SI),0(BX)) 42 | 43 | #define mulLegacy \ 44 | integerMulLeg(0(SP),0(SI),0(BX)) \ 45 | reduceFromDoubleLeg(0(DI),0(SP)) 46 | #define mulBmi2Adx \ 47 | integerMulAdx(0(SP),0(SI),0(BX)) \ 48 | reduceFromDoubleAdx(0(DI),0(SP)) 49 | 50 | #define sqrLegacy \ 51 | integerSqrLeg(0(SP),0(SI)) \ 52 | reduceFromDoubleLeg(0(DI),0(SP)) 53 | #define sqrBmi2Adx \ 54 | integerSqrAdx(0(SP),0(SI)) \ 55 | reduceFromDoubleAdx(0(DI),0(SP)) 56 | 57 | // func addAmd64(z, x, y *Elt) 58 | TEXT ·addAmd64(SB),NOSPLIT,$0-24 59 | MOVQ z+0(FP), DI 60 | MOVQ x+8(FP), SI 61 | MOVQ y+16(FP), BX 62 | CHECK_BMI2ADX(LADD, addLegacy, addBmi2Adx) 63 | 64 | // func mulAmd64(z, x, y *Elt) 65 | TEXT ·mulAmd64(SB),NOSPLIT,$112-24 66 | MOVQ z+0(FP), DI 67 | MOVQ x+8(FP), SI 68 | MOVQ y+16(FP), BX 69 | CHECK_BMI2ADX(LMUL, mulLegacy, mulBmi2Adx) 70 | 71 | // func sqrAmd64(z, x *Elt) 72 | TEXT ·sqrAmd64(SB),NOSPLIT,$112-16 73 | MOVQ z+0(FP), DI 74 | MOVQ x+8(FP), SI 75 | CHECK_BMI2ADX(LSQR, sqrLegacy, sqrBmi2Adx) 76 | -------------------------------------------------------------------------------- /math/fp448/fp_noasm.go: -------------------------------------------------------------------------------- 1 | //go:build !amd64 || purego 2 | // +build !amd64 purego 3 | 4 | package fp448 5 | 6 | func cmov(x, y *Elt, n uint) { cmovGeneric(x, y, n) } 7 | func cswap(x, y *Elt, n uint) { cswapGeneric(x, y, n) } 8 | func add(z, x, y *Elt) { addGeneric(z, x, y) } 9 | func sub(z, x, y *Elt) { subGeneric(z, x, y) } 10 | func addsub(x, y *Elt) { addsubGeneric(x, y) } 11 | func mul(z, x, y *Elt) { mulGeneric(z, x, y) } 12 | func sqr(z, x *Elt) { sqrGeneric(z, x) } 13 | -------------------------------------------------------------------------------- /math/integer.go: -------------------------------------------------------------------------------- 1 | package math 2 | 3 | import "math/bits" 4 | 5 | // NextPow2 finds the next power of two (N=2^k, k>=0) greater than n. 6 | // If n is already a power of two, then this function returns n, and log2(n). 7 | func NextPow2(n uint) (N uint, k uint) { 8 | if bits.OnesCount(n) == 1 { 9 | k = uint(bits.TrailingZeros(n)) 10 | N = n 11 | } else { 12 | k = uint(bits.Len(n)) 13 | N = uint(1) << k 14 | } 15 | return 16 | } 17 | -------------------------------------------------------------------------------- /math/mlsbset/power.go: -------------------------------------------------------------------------------- 1 | package mlsbset 2 | 3 | import "fmt" 4 | 5 | // Power is a valid exponent produced by the MLSBSet encoding algorithm. 6 | type Power struct { 7 | set Encoder // parameters of code. 8 | s []int32 // set of signs. 9 | b []int32 // set of digits. 10 | c int // carry is {0,1}. 11 | } 12 | 13 | // Exp is calculates x^k, where x is a predetermined element of a group G. 14 | func (p *Power) Exp(G Group) EltG { 15 | a, b := G.Identity(), G.NewEltP() 16 | for e := int(p.set.p.E - 1); e >= 0; e-- { 17 | G.Sqr(a) 18 | for v := uint(0); v < p.set.p.V; v++ { 19 | sgnElt, idElt := p.Digit(v, uint(e)) 20 | G.Lookup(b, v, sgnElt, idElt) 21 | G.Mul(a, b) 22 | } 23 | } 24 | if p.set.IsExtended() && p.c == 1 { 25 | G.Mul(a, G.ExtendedEltP()) 26 | } 27 | return a 28 | } 29 | 30 | // Digit returns the (v,e)-th digit and its sign. 31 | func (p *Power) Digit(v, e uint) (sgn, dig int32) { 32 | sgn = p.bit(0, v, e) 33 | dig = 0 34 | for i := p.set.p.W - 1; i > 0; i-- { 35 | dig = 2*dig + p.bit(i, v, e) 36 | } 37 | mask := dig >> 31 38 | dig = (dig + mask) ^ mask 39 | return sgn, dig 40 | } 41 | 42 | // bit returns the (w,v,e)-th bit of the code. 43 | func (p *Power) bit(w, v, e uint) int32 { 44 | if !(w < p.set.p.W && 45 | v < p.set.p.V && 46 | e < p.set.p.E) { 47 | panic(fmt.Errorf("indexes outside (%v,%v,%v)", w, v, e)) 48 | } 49 | if w == 0 { 50 | return p.s[p.set.p.E*v+e] 51 | } 52 | return p.b[p.set.p.D*(w-1)+p.set.p.E*v+e] 53 | } 54 | 55 | func (p *Power) String() string { 56 | dig := "" 57 | for j := uint(0); j < p.set.p.V; j++ { 58 | for i := uint(0); i < p.set.p.E; i++ { 59 | s, d := p.Digit(j, i) 60 | dig += fmt.Sprintf("(%2v,%2v) = %+2v %+2v\n", j, i, s, d) 61 | } 62 | } 63 | return fmt.Sprintf("len: %v\ncarry: %v\ndigits:\n%v", len(p.b)+len(p.s), p.c, dig) 64 | } 65 | -------------------------------------------------------------------------------- /math/primes.go: -------------------------------------------------------------------------------- 1 | package math 2 | 3 | import ( 4 | "crypto/rand" 5 | "io" 6 | "math/big" 7 | ) 8 | 9 | // IsSafePrime reports whether p is (probably) a safe prime. 10 | // The prime p=2*q+1 is safe prime if both p and q are primes. 11 | // Note that ProbablyPrime is not suitable for judging primes 12 | // that an adversary may have crafted to fool the test. 13 | func IsSafePrime(p *big.Int) bool { 14 | pdiv2 := new(big.Int).Rsh(p, 1) 15 | return p.ProbablyPrime(20) && pdiv2.ProbablyPrime(20) 16 | } 17 | 18 | // SafePrime returns a number of the given bit length that is a safe prime with high probability. 19 | // The number returned p=2*q+1 is a safe prime if both p and q are primes. 20 | // SafePrime will return error for any error returned by rand.Read or if bits < 2. 21 | func SafePrime(random io.Reader, bits int) (*big.Int, error) { 22 | one := big.NewInt(1) 23 | p := new(big.Int) 24 | for { 25 | q, err := rand.Prime(random, bits-1) 26 | if err != nil { 27 | return nil, err 28 | } 29 | p.Lsh(q, 1).Add(p, one) 30 | if p.ProbablyPrime(20) { 31 | return p, nil 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /math/primes_test.go: -------------------------------------------------------------------------------- 1 | package math 2 | 3 | import ( 4 | "crypto/rand" 5 | "fmt" 6 | "math/big" 7 | "testing" 8 | 9 | "github.com/cloudflare/circl/internal/test" 10 | ) 11 | 12 | func TestSafePrime(t *testing.T) { 13 | firstSafePrimes := []int64{ 14 | 5, 7, 11, 23, 47, 59, 83, 107, 167, 179, 227, 263, 347, 359, 383, 467, 15 | 479, 503, 563, 587, 719, 839, 863, 887, 983, 1019, 1187, 1283, 1307, 16 | 1319, 1367, 1439, 1487, 1523, 1619, 1823, 1907, 2027, 2039, 2063, 2099, 17 | 2207, 2447, 2459, 2579, 2819, 2879, 2903, 2963, 2999, 3023, 3119, 3167, 18 | 3203, 3467, 3623, 3779, 3803, 3863, 3947, 4007, 4079, 4127, 4139, 4259, 19 | 4283, 4547, 4679, 4703, 4787, 4799, 4919, 5087, 5099, 5387, 5399, 5483, 20 | 5507, 5639, 5807, 5879, 5927, 5939, 6047, 6599, 6659, 6719, 6779, 6827, 21 | 6899, 6983, 7079, 7187, 7247, 7523, 7559, 7607, 7643, 7703, 7727, 22 | } 23 | 24 | p := new(big.Int) 25 | for _, pi := range firstSafePrimes { 26 | p.SetInt64(pi) 27 | test.CheckOk(IsSafePrime(p), fmt.Sprintf("it should be a safe prime p=%v", p), t) 28 | } 29 | } 30 | 31 | func TestIsSafePrime(t *testing.T) { 32 | for i := 1; i < 5; i++ { 33 | bits := 128 * i 34 | t.Run(fmt.Sprint(bits), func(t *testing.T) { 35 | p, err := SafePrime(rand.Reader, bits) 36 | test.CheckNoErr(t, err, "safeprime failed") 37 | test.CheckOk(IsSafePrime(p), fmt.Sprintf("it should be a safe prime p=%v", p), t) 38 | }) 39 | } 40 | } 41 | 42 | func BenchmarkSafePrime(b *testing.B) { 43 | for i := 0; i < b.N; i++ { 44 | _, _ = SafePrime(rand.Reader, 256) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /ot/doc.go: -------------------------------------------------------------------------------- 1 | // Package ot provides oblivious-transfer protocols. 2 | package ot 3 | -------------------------------------------------------------------------------- /ot/simot/simotparty.go: -------------------------------------------------------------------------------- 1 | package simot 2 | 3 | import "github.com/cloudflare/circl/group" 4 | 5 | type Sender struct { 6 | index int // Indicate which OT 7 | m0 []byte // The M0 message from sender 8 | m1 []byte // The M1 message from sender 9 | a group.Scalar // The randomness of the sender 10 | A group.Element // [a]G 11 | B group.Element // The random group element from the receiver 12 | k0 []byte // The encryption key of M0 13 | k1 []byte // The encryption key of M1 14 | e0 []byte // The encryption of M0 under k0 15 | e1 []byte // The encryption of M1 under k1 16 | myGroup group.Group // The elliptic curve we operate in 17 | } 18 | 19 | type Receiver struct { 20 | index int // Indicate which OT 21 | c int // The choice bit of the receiver 22 | A group.Element // The random group element from the sender 23 | b group.Scalar // The randomness of the receiver 24 | B group.Element // B = [b]G if c == 0, B = A+[b]G if c == 1 25 | kR []byte // The decryption key of receiver 26 | ec []byte // The encryption of mc 27 | mc []byte // The decrypted message from sender 28 | myGroup group.Group // The elliptic curve we operate in 29 | } 30 | -------------------------------------------------------------------------------- /pke/doc.go: -------------------------------------------------------------------------------- 1 | // Package pke provides a variety of public key encryption mechanisms. 2 | package pke 3 | -------------------------------------------------------------------------------- /pke/kyber/internal/common/asm/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/cloudflare/circl/pke/kyber/internal/common/asm 2 | 3 | go 1.22.0 4 | 5 | require ( 6 | github.com/cloudflare/circl v1.4.0 7 | github.com/mmcloughlin/avo v0.6.0 8 | ) 9 | 10 | require ( 11 | golang.org/x/mod v0.14.0 // indirect 12 | golang.org/x/tools v0.16.1 // indirect 13 | ) 14 | 15 | replace github.com/cloudflare/circl => ../../../../../ 16 | -------------------------------------------------------------------------------- /pke/kyber/internal/common/asm/go.sum: -------------------------------------------------------------------------------- 1 | github.com/mmcloughlin/avo v0.6.0 h1:QH6FU8SKoTLaVs80GA8TJuLNkUYl4VokHKlPhVDg4YY= 2 | github.com/mmcloughlin/avo v0.6.0/go.mod h1:8CoAGaCSYXtCPR+8y18Y9aB/kxb8JSS6FRI7mSkvD+8= 3 | golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= 4 | golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 5 | golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= 6 | golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 7 | golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA= 8 | golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= 9 | -------------------------------------------------------------------------------- /pke/kyber/internal/common/params.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "github.com/cloudflare/circl/pke/kyber/internal/common/params" 5 | ) 6 | 7 | const ( 8 | // Q is the parameter q ≡ 3329 = 2¹¹ + 2¹⁰ + 2⁸ + 1. 9 | Q = params.Q 10 | 11 | // N is the parameter N: the length of the polynomials 12 | N = params.N 13 | 14 | // PolySize is the size of a packed polynomial. 15 | PolySize = params.PolySize 16 | 17 | // PlaintextSize is the size of the plaintext 18 | PlaintextSize = params.PlaintextSize 19 | 20 | // Eta2 is the parameter η₂ 21 | Eta2 = params.Eta2 22 | ) 23 | -------------------------------------------------------------------------------- /pke/kyber/internal/common/params/params.go: -------------------------------------------------------------------------------- 1 | package params 2 | 3 | // We put these parameters in a separate package so that the Go code, 4 | // such as asm/src.go, that generates assembler can import it. 5 | 6 | const ( 7 | // Q is the parameter q ≡ 3329 = 2¹¹ + 2¹⁰ + 2⁸ + 1. 8 | Q int16 = 3329 9 | 10 | // N is the parameter N: the length of the polynomials 11 | N = 256 12 | 13 | // PolySize is the size of a packed polynomial. 14 | PolySize = 384 15 | 16 | // PlaintextSize is the size of the plaintext 17 | PlaintextSize = 32 18 | 19 | // Eta2 is the parameter η₂ 20 | Eta2 = 2 21 | ) 22 | -------------------------------------------------------------------------------- /pke/kyber/internal/common/stubs_amd64.go: -------------------------------------------------------------------------------- 1 | // Code generated by command: go run src.go -out ../amd64.s -stubs ../stubs_amd64.go -pkg common. DO NOT EDIT. 2 | 3 | //go:build amd64 && !purego 4 | 5 | package common 6 | 7 | //go:noescape 8 | func addAVX2(p *[256]int16, a *[256]int16, b *[256]int16) 9 | 10 | //go:noescape 11 | func subAVX2(p *[256]int16, a *[256]int16, b *[256]int16) 12 | 13 | //go:noescape 14 | func nttAVX2(p *[256]int16) 15 | 16 | //go:noescape 17 | func invNttAVX2(p *[256]int16) 18 | 19 | //go:noescape 20 | func mulHatAVX2(p *[256]int16, a *[256]int16, b *[256]int16) 21 | 22 | //go:noescape 23 | func detangleAVX2(p *[256]int16) 24 | 25 | //go:noescape 26 | func tangleAVX2(p *[256]int16) 27 | 28 | //go:noescape 29 | func barrettReduceAVX2(p *[256]int16) 30 | 31 | //go:noescape 32 | func normalizeAVX2(p *[256]int16) 33 | -------------------------------------------------------------------------------- /pke/kyber/kyber.go: -------------------------------------------------------------------------------- 1 | //go:generate go run gen.go 2 | 3 | // Package kyber implements the CRYSTALS-Kyber.CPAPKE public key encryption 4 | // as submitted to round 3 of the NIST PQC competition and described in 5 | // 6 | // https://pq-crystals.org/kyber/data/kyber-specification-round3.pdf 7 | // 8 | // The related key encapsulation mechanism (KEM) CRYSTALS-Kyber.CCAKEM can 9 | // be found in the package github.com/cloudflare/circl/kem/kyber. 10 | package kyber 11 | -------------------------------------------------------------------------------- /pke/kyber/kyber1024/internal/cpapke_test.go: -------------------------------------------------------------------------------- 1 | // Code generated from kyber512/internal/cpapke_test.go by gen.go 2 | 3 | package internal 4 | 5 | import ( 6 | "crypto/rand" 7 | "testing" 8 | ) 9 | 10 | func TestEncryptThenDecrypt(t *testing.T) { 11 | var seed [32]byte 12 | var coin [SeedSize]byte 13 | 14 | for i := 0; i < 32; i++ { 15 | seed[i] = byte(i) 16 | coin[i] = byte(i) 17 | } 18 | 19 | for i := 0; i < 100; i++ { 20 | seed[0] = byte(i) 21 | pk, sk := NewKeyFromSeed(seed[:]) 22 | 23 | for j := 0; j < 100; j++ { 24 | var msg, msg2 [PlaintextSize]byte 25 | var ct [CiphertextSize]byte 26 | 27 | _, _ = rand.Read(msg[:]) 28 | _, _ = rand.Read(coin[:]) 29 | 30 | pk.EncryptTo(ct[:], msg[:], coin[:]) 31 | sk.DecryptTo(msg2[:], ct[:]) 32 | 33 | if msg != msg2 { 34 | t.Fatalf("%v %v %v", ct, msg, msg2) 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /pke/kyber/kyber1024/internal/mat.go: -------------------------------------------------------------------------------- 1 | // Code generated from kyber512/internal/mat.go by gen.go 2 | 3 | package internal 4 | 5 | import ( 6 | "github.com/cloudflare/circl/pke/kyber/internal/common" 7 | ) 8 | 9 | // A k by k matrix of polynomials. 10 | type Mat [K]Vec 11 | 12 | // Expands the given seed to the corresponding matrix A or its transpose Aᵀ. 13 | func (m *Mat) Derive(seed *[32]byte, transpose bool) { 14 | if !common.DeriveX4Available { 15 | if transpose { 16 | for i := 0; i < K; i++ { 17 | for j := 0; j < K; j++ { 18 | m[i][j].DeriveUniform(seed, uint8(i), uint8(j)) 19 | } 20 | } 21 | } else { 22 | for i := 0; i < K; i++ { 23 | for j := 0; j < K; j++ { 24 | m[i][j].DeriveUniform(seed, uint8(j), uint8(i)) 25 | } 26 | } 27 | } 28 | return 29 | } 30 | 31 | var ps [4]*common.Poly 32 | var xs [4]uint8 33 | var ys [4]uint8 34 | x := uint8(0) 35 | y := uint8(0) 36 | 37 | for x != K { 38 | idx := 0 39 | for ; idx < 4; idx++ { 40 | ps[idx] = &m[x][y] 41 | 42 | if transpose { 43 | xs[idx] = x 44 | ys[idx] = y 45 | } else { 46 | xs[idx] = y 47 | ys[idx] = x 48 | } 49 | 50 | y++ 51 | if y == K { 52 | x++ 53 | y = 0 54 | 55 | if x == K { 56 | if idx == 0 { 57 | // If there is just one left, then a plain DeriveUniform 58 | // is quicker than the X4 variant. 59 | ps[0].DeriveUniform(seed, xs[0], ys[0]) 60 | return 61 | } 62 | 63 | for idx++; idx < 4; idx++ { 64 | ps[idx] = nil 65 | } 66 | 67 | break 68 | } 69 | } 70 | } 71 | 72 | common.PolyDeriveUniformX4(ps, seed, xs, ys) 73 | } 74 | } 75 | 76 | // Transposes A in place. 77 | func (m *Mat) Transpose() { 78 | for i := 0; i < K-1; i++ { 79 | for j := i + 1; j < K; j++ { 80 | t := m[i][j] 81 | m[i][j] = m[j][i] 82 | m[j][i] = t 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /pke/kyber/kyber1024/internal/params.go: -------------------------------------------------------------------------------- 1 | // Code generated from params.templ.go. DO NOT EDIT. 2 | 3 | package internal 4 | 5 | import ( 6 | "github.com/cloudflare/circl/pke/kyber/internal/common" 7 | ) 8 | 9 | const ( 10 | K = 4 11 | Eta1 = 2 12 | DU = 11 13 | DV = 5 14 | PublicKeySize = 32 + K*common.PolySize 15 | 16 | PrivateKeySize = K * common.PolySize 17 | 18 | PlaintextSize = common.PlaintextSize 19 | SeedSize = 32 20 | CiphertextSize = 1568 21 | ) 22 | -------------------------------------------------------------------------------- /pke/kyber/kyber512/internal/cpapke_test.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import ( 4 | "crypto/rand" 5 | "testing" 6 | ) 7 | 8 | func TestEncryptThenDecrypt(t *testing.T) { 9 | var seed [32]byte 10 | var coin [SeedSize]byte 11 | 12 | for i := 0; i < 32; i++ { 13 | seed[i] = byte(i) 14 | coin[i] = byte(i) 15 | } 16 | 17 | for i := 0; i < 100; i++ { 18 | seed[0] = byte(i) 19 | pk, sk := NewKeyFromSeed(seed[:]) 20 | 21 | for j := 0; j < 100; j++ { 22 | var msg, msg2 [PlaintextSize]byte 23 | var ct [CiphertextSize]byte 24 | 25 | _, _ = rand.Read(msg[:]) 26 | _, _ = rand.Read(coin[:]) 27 | 28 | pk.EncryptTo(ct[:], msg[:], coin[:]) 29 | sk.DecryptTo(msg2[:], ct[:]) 30 | 31 | if msg != msg2 { 32 | t.Fatalf("%v %v %v", ct, msg, msg2) 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /pke/kyber/kyber512/internal/mat.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import ( 4 | "github.com/cloudflare/circl/pke/kyber/internal/common" 5 | ) 6 | 7 | // A k by k matrix of polynomials. 8 | type Mat [K]Vec 9 | 10 | // Expands the given seed to the corresponding matrix A or its transpose Aᵀ. 11 | func (m *Mat) Derive(seed *[32]byte, transpose bool) { 12 | if !common.DeriveX4Available { 13 | if transpose { 14 | for i := 0; i < K; i++ { 15 | for j := 0; j < K; j++ { 16 | m[i][j].DeriveUniform(seed, uint8(i), uint8(j)) 17 | } 18 | } 19 | } else { 20 | for i := 0; i < K; i++ { 21 | for j := 0; j < K; j++ { 22 | m[i][j].DeriveUniform(seed, uint8(j), uint8(i)) 23 | } 24 | } 25 | } 26 | return 27 | } 28 | 29 | var ps [4]*common.Poly 30 | var xs [4]uint8 31 | var ys [4]uint8 32 | x := uint8(0) 33 | y := uint8(0) 34 | 35 | for x != K { 36 | idx := 0 37 | for ; idx < 4; idx++ { 38 | ps[idx] = &m[x][y] 39 | 40 | if transpose { 41 | xs[idx] = x 42 | ys[idx] = y 43 | } else { 44 | xs[idx] = y 45 | ys[idx] = x 46 | } 47 | 48 | y++ 49 | if y == K { 50 | x++ 51 | y = 0 52 | 53 | if x == K { 54 | if idx == 0 { 55 | // If there is just one left, then a plain DeriveUniform 56 | // is quicker than the X4 variant. 57 | ps[0].DeriveUniform(seed, xs[0], ys[0]) 58 | return 59 | } 60 | 61 | for idx++; idx < 4; idx++ { 62 | ps[idx] = nil 63 | } 64 | 65 | break 66 | } 67 | } 68 | } 69 | 70 | common.PolyDeriveUniformX4(ps, seed, xs, ys) 71 | } 72 | } 73 | 74 | // Transposes A in place. 75 | func (m *Mat) Transpose() { 76 | for i := 0; i < K-1; i++ { 77 | for j := i + 1; j < K; j++ { 78 | t := m[i][j] 79 | m[i][j] = m[j][i] 80 | m[j][i] = t 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /pke/kyber/kyber512/internal/params.go: -------------------------------------------------------------------------------- 1 | // Code generated from params.templ.go. DO NOT EDIT. 2 | 3 | package internal 4 | 5 | import ( 6 | "github.com/cloudflare/circl/pke/kyber/internal/common" 7 | ) 8 | 9 | const ( 10 | K = 2 11 | Eta1 = 3 12 | DU = 10 13 | DV = 4 14 | PublicKeySize = 32 + K*common.PolySize 15 | 16 | PrivateKeySize = K * common.PolySize 17 | 18 | PlaintextSize = common.PlaintextSize 19 | SeedSize = 32 20 | CiphertextSize = 768 21 | ) 22 | -------------------------------------------------------------------------------- /pke/kyber/kyber768/internal/cpapke_test.go: -------------------------------------------------------------------------------- 1 | // Code generated from kyber512/internal/cpapke_test.go by gen.go 2 | 3 | package internal 4 | 5 | import ( 6 | "crypto/rand" 7 | "testing" 8 | ) 9 | 10 | func TestEncryptThenDecrypt(t *testing.T) { 11 | var seed [32]byte 12 | var coin [SeedSize]byte 13 | 14 | for i := 0; i < 32; i++ { 15 | seed[i] = byte(i) 16 | coin[i] = byte(i) 17 | } 18 | 19 | for i := 0; i < 100; i++ { 20 | seed[0] = byte(i) 21 | pk, sk := NewKeyFromSeed(seed[:]) 22 | 23 | for j := 0; j < 100; j++ { 24 | var msg, msg2 [PlaintextSize]byte 25 | var ct [CiphertextSize]byte 26 | 27 | _, _ = rand.Read(msg[:]) 28 | _, _ = rand.Read(coin[:]) 29 | 30 | pk.EncryptTo(ct[:], msg[:], coin[:]) 31 | sk.DecryptTo(msg2[:], ct[:]) 32 | 33 | if msg != msg2 { 34 | t.Fatalf("%v %v %v", ct, msg, msg2) 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /pke/kyber/kyber768/internal/mat.go: -------------------------------------------------------------------------------- 1 | // Code generated from kyber512/internal/mat.go by gen.go 2 | 3 | package internal 4 | 5 | import ( 6 | "github.com/cloudflare/circl/pke/kyber/internal/common" 7 | ) 8 | 9 | // A k by k matrix of polynomials. 10 | type Mat [K]Vec 11 | 12 | // Expands the given seed to the corresponding matrix A or its transpose Aᵀ. 13 | func (m *Mat) Derive(seed *[32]byte, transpose bool) { 14 | if !common.DeriveX4Available { 15 | if transpose { 16 | for i := 0; i < K; i++ { 17 | for j := 0; j < K; j++ { 18 | m[i][j].DeriveUniform(seed, uint8(i), uint8(j)) 19 | } 20 | } 21 | } else { 22 | for i := 0; i < K; i++ { 23 | for j := 0; j < K; j++ { 24 | m[i][j].DeriveUniform(seed, uint8(j), uint8(i)) 25 | } 26 | } 27 | } 28 | return 29 | } 30 | 31 | var ps [4]*common.Poly 32 | var xs [4]uint8 33 | var ys [4]uint8 34 | x := uint8(0) 35 | y := uint8(0) 36 | 37 | for x != K { 38 | idx := 0 39 | for ; idx < 4; idx++ { 40 | ps[idx] = &m[x][y] 41 | 42 | if transpose { 43 | xs[idx] = x 44 | ys[idx] = y 45 | } else { 46 | xs[idx] = y 47 | ys[idx] = x 48 | } 49 | 50 | y++ 51 | if y == K { 52 | x++ 53 | y = 0 54 | 55 | if x == K { 56 | if idx == 0 { 57 | // If there is just one left, then a plain DeriveUniform 58 | // is quicker than the X4 variant. 59 | ps[0].DeriveUniform(seed, xs[0], ys[0]) 60 | return 61 | } 62 | 63 | for idx++; idx < 4; idx++ { 64 | ps[idx] = nil 65 | } 66 | 67 | break 68 | } 69 | } 70 | } 71 | 72 | common.PolyDeriveUniformX4(ps, seed, xs, ys) 73 | } 74 | } 75 | 76 | // Transposes A in place. 77 | func (m *Mat) Transpose() { 78 | for i := 0; i < K-1; i++ { 79 | for j := i + 1; j < K; j++ { 80 | t := m[i][j] 81 | m[i][j] = m[j][i] 82 | m[j][i] = t 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /pke/kyber/kyber768/internal/params.go: -------------------------------------------------------------------------------- 1 | // Code generated from params.templ.go. DO NOT EDIT. 2 | 3 | package internal 4 | 5 | import ( 6 | "github.com/cloudflare/circl/pke/kyber/internal/common" 7 | ) 8 | 9 | const ( 10 | K = 3 11 | Eta1 = 2 12 | DU = 10 13 | DV = 4 14 | PublicKeySize = 32 + K*common.PolySize 15 | 16 | PrivateKeySize = K * common.PolySize 17 | 18 | PlaintextSize = common.PlaintextSize 19 | SeedSize = 32 20 | CiphertextSize = 1088 21 | ) 22 | -------------------------------------------------------------------------------- /pke/kyber/templates/params.templ.go: -------------------------------------------------------------------------------- 1 | // +build ignore 2 | // The previous line (and this one up to the warning below) is removed by the 3 | // template generator. 4 | 5 | // Code generated from params.templ.go. DO NOT EDIT. 6 | 7 | package internal 8 | 9 | import ( 10 | "github.com/cloudflare/circl/pke/kyber/internal/common" 11 | ) 12 | 13 | const ( 14 | K = {{.K}} 15 | Eta1 = {{.Eta1}} 16 | DU = {{.DU}} 17 | DV = {{.DV}} 18 | PublicKeySize = 32 + K*common.PolySize 19 | 20 | PrivateKeySize = K * common.PolySize 21 | 22 | PlaintextSize = common.PlaintextSize 23 | SeedSize = 32 24 | CiphertextSize = {{.CiphertextSize}} 25 | ) 26 | -------------------------------------------------------------------------------- /pki/pki_test.go: -------------------------------------------------------------------------------- 1 | package pki_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/cloudflare/circl/pki" 7 | "github.com/cloudflare/circl/sign/schemes" 8 | ) 9 | 10 | func TestPEM(t *testing.T) { 11 | for _, scheme := range schemes.All() { 12 | t.Run(scheme.Name(), func(t *testing.T) { 13 | if scheme == nil { 14 | t.Fatal() 15 | } 16 | 17 | _, ok := scheme.(pki.CertificateScheme) 18 | if !ok { 19 | return 20 | } 21 | 22 | pk, sk, err := scheme.GenerateKey() 23 | if err != nil { 24 | t.Fatal(err) 25 | } 26 | 27 | packedPk, err := pki.MarshalPEMPublicKey(pk) 28 | if err != nil { 29 | t.Fatal(err) 30 | } 31 | 32 | pk2, err := pki.UnmarshalPEMPublicKey(packedPk) 33 | if err != nil { 34 | t.Fatal(err) 35 | } 36 | if !pk.Equal(pk2) { 37 | t.Fatal() 38 | } 39 | 40 | packedSk, err := pki.MarshalPEMPrivateKey(sk) 41 | if err != nil { 42 | t.Fatal(err) 43 | } 44 | 45 | sk2, err := pki.UnmarshalPEMPrivateKey(packedSk) 46 | if err != nil { 47 | t.Fatal(err) 48 | } 49 | 50 | if !sk.Equal(sk2) { 51 | t.Fatal() 52 | } 53 | }) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /secretsharing/example_test.go: -------------------------------------------------------------------------------- 1 | package secretsharing_test 2 | 3 | import ( 4 | "crypto/rand" 5 | "fmt" 6 | 7 | "github.com/cloudflare/circl/group" 8 | "github.com/cloudflare/circl/secretsharing" 9 | ) 10 | 11 | func ExampleSecretSharing() { 12 | g := group.P256 13 | t := uint(2) 14 | n := uint(5) 15 | 16 | secret := g.RandomScalar(rand.Reader) 17 | ss := secretsharing.New(rand.Reader, t, secret) 18 | shares := ss.Share(n) 19 | 20 | got, err := secretsharing.Recover(t, shares[:t]) 21 | fmt.Printf("Recover secret: %v\nError: %v\n", secret.IsEqual(got), err) 22 | 23 | got, err = secretsharing.Recover(t, shares[:t+1]) 24 | fmt.Printf("Recover secret: %v\nError: %v\n", secret.IsEqual(got), err) 25 | // Output: 26 | // Recover secret: false 27 | // Error: secretsharing: number of shares (n=2) must be above the threshold (t=2) 28 | // Recover secret: true 29 | // Error: 30 | } 31 | 32 | func ExampleVerify() { 33 | g := group.P256 34 | t := uint(2) 35 | n := uint(5) 36 | 37 | secret := g.RandomScalar(rand.Reader) 38 | ss := secretsharing.New(rand.Reader, t, secret) 39 | shares := ss.Share(n) 40 | coms := ss.CommitSecret() 41 | 42 | for i := range shares { 43 | ok := secretsharing.Verify(t, shares[i], coms) 44 | fmt.Printf("Share %v is valid: %v\n", i, ok) 45 | } 46 | 47 | got, err := secretsharing.Recover(t, shares) 48 | fmt.Printf("Recover secret: %v\nError: %v\n", secret.IsEqual(got), err) 49 | // Output: 50 | // Share 0 is valid: true 51 | // Share 1 is valid: true 52 | // Share 2 is valid: true 53 | // Share 3 is valid: true 54 | // Share 4 is valid: true 55 | // Recover secret: true 56 | // Error: 57 | } 58 | -------------------------------------------------------------------------------- /sign/bls/testdata/sig_g1_basic_P256.txt.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/circl/main/sign/bls/testdata/sig_g1_basic_P256.txt.zip -------------------------------------------------------------------------------- /sign/bls/testdata/sig_g1_basic_P521.txt.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/circl/main/sign/bls/testdata/sig_g1_basic_P521.txt.zip -------------------------------------------------------------------------------- /sign/bls/testdata/sig_g2_basic_P256.txt.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/circl/main/sign/bls/testdata/sig_g2_basic_P256.txt.zip -------------------------------------------------------------------------------- /sign/bls/testdata/sig_g2_basic_P521.txt.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/circl/main/sign/bls/testdata/sig_g2_basic_P521.txt.zip -------------------------------------------------------------------------------- /sign/bls/vectors_test.go: -------------------------------------------------------------------------------- 1 | package bls_test 2 | 3 | import ( 4 | "archive/zip" 5 | "bufio" 6 | "encoding/hex" 7 | "fmt" 8 | "strings" 9 | "testing" 10 | 11 | "github.com/cloudflare/circl/internal/test" 12 | "github.com/cloudflare/circl/sign/bls" 13 | ) 14 | 15 | func TestVectors(t *testing.T) { 16 | // Test vectors taken from: 17 | // Repository: https://github.com/kwantam/bls_sigs_ref/tree/sgn0_fix/test-vectors 18 | // Branch: sig0_fix 19 | // Path: /test-vectors/sig_[g1|g2]_basic/[name] 20 | // Compression: zip 21 | 22 | for _, name := range []string{"P256", "P521"} { 23 | t.Run(name+"/G1", func(t *testing.T) { testVector[bls.KeyG2SigG1](t, "g1", name) }) 24 | t.Run(name+"/G2", func(t *testing.T) { testVector[bls.KeyG1SigG2](t, "g2", name) }) 25 | } 26 | } 27 | 28 | func testVector[K bls.KeyGroup](t *testing.T, group, name string) { 29 | nameFile := fmt.Sprintf("./testdata/sig_%v_basic_%v.txt.zip", group, name) 30 | zipFile, err := zip.OpenReader(nameFile) 31 | test.CheckNoErr(t, err, "error opening zipped file") 32 | 33 | for _, f := range zipFile.File { 34 | unzipped, err := f.Open() 35 | test.CheckNoErr(t, err, "error opening unzipped file") 36 | 37 | scanner := bufio.NewScanner(unzipped) 38 | for scanner.Scan() { 39 | line := scanner.Text() 40 | inputs := strings.Split(line, " ") 41 | if len(inputs) != 3 { 42 | t.Fatalf("bad input length") 43 | } 44 | 45 | msg, err := hex.DecodeString(inputs[0]) 46 | test.CheckNoErr(t, err, "error decoding msg") 47 | seed, err := hex.DecodeString(inputs[1]) 48 | test.CheckNoErr(t, err, "error decoding sk") 49 | wantSig := inputs[2] 50 | 51 | salt := []byte("BLS-SIG-KEYGEN-SALT-") 52 | keyInfo := []byte("") 53 | priv, err := bls.KeyGen[K](seed, salt, keyInfo) 54 | test.CheckNoErr(t, err, "error generating priv key") 55 | 56 | sig := bls.Sign(priv, msg) 57 | gotSig := hex.EncodeToString(sig) 58 | 59 | if gotSig != wantSig { 60 | test.ReportError(t, gotSig, wantSig, msg) 61 | } 62 | 63 | pub := priv.PublicKey() 64 | test.CheckOk(bls.Verify(pub, msg, sig), "cannot verify", t) 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /sign/dilithium/dilithium.go: -------------------------------------------------------------------------------- 1 | //go:generate go run gen.go 2 | 3 | // Deprecated. This package implements Dilithium, an early proposal 4 | // for what is now ML-DSA (FIPS 204). An implementation of ML-DSA 5 | // can be found in sign/mldsa. 6 | // 7 | // Dilithium implements the CRYSTALS-Dilithium signature schemes 8 | // as submitted to round3 of the NIST PQC competition and described in 9 | // 10 | // https://pq-crystals.org/dilithium/data/dilithium-specification-round3-20210208.pdf 11 | // 12 | // Each of the three different modes of Dilithium is implemented by a 13 | // subpackage. For instance, Dilithium2 (the recommended mode) 14 | // can be found in 15 | // 16 | // github.com/cloudflare/circl/sign/dilithium/mode2 17 | // 18 | // If your choice for mode is fixed compile-time, use the subpackages. 19 | // To choose a scheme at runtime, use the generic signatures API under 20 | // 21 | // github.com/cloudflare/circl/sign/schemes 22 | // 23 | // The packages 24 | // 25 | // github.com/cloudflare/circl/sign/eddilithium2 26 | // github.com/cloudflare/circl/sign/eddilithium3 27 | // 28 | // implement hybrids of Dilithium2 with Ed25519 respectively and 29 | // Dilithium3 with Ed448. These packages are a drop in replacements for the 30 | // mode subpackages of this package. 31 | package dilithium 32 | -------------------------------------------------------------------------------- /sign/dilithium/dilithium_test.go: -------------------------------------------------------------------------------- 1 | package dilithium 2 | 3 | import ( 4 | "encoding/hex" 5 | "testing" 6 | 7 | "github.com/cloudflare/circl/sign/schemes" 8 | 9 | "github.com/cloudflare/circl/internal/sha3" 10 | ) 11 | 12 | func hexHash(in []byte) string { 13 | var ret [16]byte 14 | h := sha3.NewShake256() 15 | _, _ = h.Write(in[:]) 16 | _, _ = h.Read(ret[:]) 17 | return hex.EncodeToString(ret[:]) 18 | } 19 | 20 | func TestNewKeyFromSeed(t *testing.T) { 21 | // Test vectors generated from reference implementation 22 | for _, tc := range []struct { 23 | name string 24 | esk string 25 | epk string 26 | }{ 27 | { 28 | "Dilithium2", "afe2e91f5f5899354230744c18410498", 29 | "7522162619f3329b5312322d3ee45b87", 30 | }, 31 | { 32 | "Dilithium3", "8ad3142e08b718b33f7c2668cd9d053c", 33 | "3562fc184dce1a10aad099051705b5d3", 34 | }, 35 | { 36 | "Dilithium5", "3956d812a7961af6e5dad16af15c736c", 37 | "665388291aa01e12e7f94bdc7769db18", 38 | }, 39 | } { 40 | t.Run(tc.name, func(t *testing.T) { 41 | mode := schemes.ByName(tc.name) 42 | if mode == nil { 43 | t.Fatal() 44 | } 45 | var seed [32]byte 46 | pk, sk := mode.DeriveKey(seed[:]) 47 | 48 | ppk, err := pk.MarshalBinary() 49 | if err != nil { 50 | t.Fatal(err) 51 | } 52 | psk, err := sk.MarshalBinary() 53 | if err != nil { 54 | t.Fatal(err) 55 | } 56 | 57 | pkh := hexHash(ppk) 58 | skh := hexHash(psk) 59 | if pkh != tc.epk { 60 | t.Fatalf("%s expected pk %s, got %s", tc.name, tc.epk, pkh) 61 | } 62 | if skh != tc.esk { 63 | t.Fatalf("%s expected pk %s, got %s", tc.name, tc.esk, skh) 64 | } 65 | }) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /sign/dilithium/mode2/internal/mat.go: -------------------------------------------------------------------------------- 1 | // Code generated from mode3/internal/mat.go by gen.go 2 | 3 | package internal 4 | 5 | import ( 6 | common "github.com/cloudflare/circl/sign/internal/dilithium" 7 | ) 8 | 9 | // A k by l matrix of polynomials. 10 | type Mat [K]VecL 11 | 12 | // Expands the given seed to a complete matrix. 13 | // 14 | // This function is called ExpandA in the specification. 15 | func (m *Mat) Derive(seed *[32]byte) { 16 | if !DeriveX4Available { 17 | for i := uint16(0); i < K; i++ { 18 | for j := uint16(0); j < L; j++ { 19 | PolyDeriveUniform(&m[i][j], seed, (i<<8)+j) 20 | } 21 | } 22 | return 23 | } 24 | 25 | idx := 0 26 | var nonces [4]uint16 27 | var ps [4]*common.Poly 28 | for i := uint16(0); i < K; i++ { 29 | for j := uint16(0); j < L; j++ { 30 | nonces[idx] = (i << 8) + j 31 | ps[idx] = &m[i][j] 32 | idx++ 33 | if idx == 4 { 34 | idx = 0 35 | PolyDeriveUniformX4(ps, seed, nonces) 36 | } 37 | } 38 | } 39 | if idx != 0 { 40 | for i := idx; i < 4; i++ { 41 | ps[i] = nil 42 | } 43 | PolyDeriveUniformX4(ps, seed, nonces) 44 | } 45 | } 46 | 47 | // Set p to the inner product of a and b using pointwise multiplication. 48 | // 49 | // Assumes a and b are in Montgomery form and their coefficients are 50 | // pairwise sufficiently small to multiply, see Poly.MulHat(). Resulting 51 | // coefficients are bounded by 2Lq. 52 | func PolyDotHat(p *common.Poly, a, b *VecL) { 53 | var t common.Poly 54 | *p = common.Poly{} // zero p 55 | for i := 0; i < L; i++ { 56 | t.MulHat(&a[i], &b[i]) 57 | p.Add(&t, p) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /sign/dilithium/mode2/internal/params.go: -------------------------------------------------------------------------------- 1 | // Code generated from params.templ.go. DO NOT EDIT. 2 | 3 | package internal 4 | 5 | const ( 6 | Name = "Dilithium2" 7 | K = 4 8 | L = 4 9 | Eta = 2 10 | DoubleEtaBits = 3 11 | Omega = 80 12 | Tau = 39 13 | Gamma1Bits = 17 14 | Gamma2 = 95232 15 | NIST = false 16 | TRSize = 32 17 | CTildeSize = 32 18 | ) 19 | -------------------------------------------------------------------------------- /sign/dilithium/mode2/internal/rounding_test.go: -------------------------------------------------------------------------------- 1 | // Code generated from mode3/internal/rounding_test.go by gen.go 2 | 3 | package internal 4 | 5 | import ( 6 | "flag" 7 | "testing" 8 | 9 | common "github.com/cloudflare/circl/sign/internal/dilithium" 10 | ) 11 | 12 | var runVeryLongTest = flag.Bool("very-long", false, "runs very long tests") 13 | 14 | func TestDecompose(t *testing.T) { 15 | for a := uint32(0); a < common.Q; a++ { 16 | a0PlusQ, a1 := decompose(a) 17 | a0 := int32(a0PlusQ) - int32(common.Q) 18 | recombined := a0 + int32(Alpha*a1) 19 | if a1 == 0 && recombined < 0 { 20 | recombined += common.Q 21 | if -(Alpha/2) > a0 || a0 >= 0 { 22 | t.Fatalf("decompose(%v): a0 out of bounds", a) 23 | } 24 | } else { 25 | if (-(Alpha / 2) >= a0) || (a0 > Alpha/2) { 26 | t.Fatalf("decompose(%v): a0 out of bounds", a) 27 | } 28 | } 29 | if int32(a) != recombined { 30 | t.Fatalf("decompose(%v) doesn't recombine %v %v", a, a0, a1) 31 | } 32 | } 33 | } 34 | 35 | func TestMakeHint(t *testing.T) { 36 | if !*runVeryLongTest { 37 | t.SkipNow() 38 | } 39 | for w := uint32(0); w < common.Q; w++ { 40 | w0, w1 := decompose(w) 41 | for fn := uint32(0); fn <= Gamma2; fn++ { 42 | fsign := false 43 | for { 44 | var f uint32 45 | if fsign { 46 | if fn == 0 { 47 | break 48 | } 49 | f = common.Q - fn 50 | } else { 51 | f = fn 52 | } 53 | 54 | hint := makeHint(common.ReduceLe2Q(w0+common.Q-f), w1) 55 | w1p := useHint(common.ReduceLe2Q(w+common.Q-f), hint) 56 | if w1p != w1 { 57 | t.Fatal() 58 | } 59 | 60 | if fsign { 61 | break 62 | } 63 | fsign = true 64 | } 65 | } 66 | } 67 | } 68 | 69 | func BenchmarkDecompose(b *testing.B) { 70 | var p, p0, p1 common.Poly 71 | for i := 0; i < b.N; i++ { 72 | PolyDecompose(&p, &p0, &p1) 73 | } 74 | } 75 | 76 | func BenchmarkMakeHint(b *testing.B) { 77 | var p, p0, p1 common.Poly 78 | for i := 0; i < b.N; i++ { 79 | PolyMakeHint(&p, &p0, &p1) 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /sign/dilithium/mode3/internal/mat.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import ( 4 | common "github.com/cloudflare/circl/sign/internal/dilithium" 5 | ) 6 | 7 | // A k by l matrix of polynomials. 8 | type Mat [K]VecL 9 | 10 | // Expands the given seed to a complete matrix. 11 | // 12 | // This function is called ExpandA in the specification. 13 | func (m *Mat) Derive(seed *[32]byte) { 14 | if !DeriveX4Available { 15 | for i := uint16(0); i < K; i++ { 16 | for j := uint16(0); j < L; j++ { 17 | PolyDeriveUniform(&m[i][j], seed, (i<<8)+j) 18 | } 19 | } 20 | return 21 | } 22 | 23 | idx := 0 24 | var nonces [4]uint16 25 | var ps [4]*common.Poly 26 | for i := uint16(0); i < K; i++ { 27 | for j := uint16(0); j < L; j++ { 28 | nonces[idx] = (i << 8) + j 29 | ps[idx] = &m[i][j] 30 | idx++ 31 | if idx == 4 { 32 | idx = 0 33 | PolyDeriveUniformX4(ps, seed, nonces) 34 | } 35 | } 36 | } 37 | if idx != 0 { 38 | for i := idx; i < 4; i++ { 39 | ps[i] = nil 40 | } 41 | PolyDeriveUniformX4(ps, seed, nonces) 42 | } 43 | } 44 | 45 | // Set p to the inner product of a and b using pointwise multiplication. 46 | // 47 | // Assumes a and b are in Montgomery form and their coefficients are 48 | // pairwise sufficiently small to multiply, see Poly.MulHat(). Resulting 49 | // coefficients are bounded by 2Lq. 50 | func PolyDotHat(p *common.Poly, a, b *VecL) { 51 | var t common.Poly 52 | *p = common.Poly{} // zero p 53 | for i := 0; i < L; i++ { 54 | t.MulHat(&a[i], &b[i]) 55 | p.Add(&t, p) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /sign/dilithium/mode3/internal/params.go: -------------------------------------------------------------------------------- 1 | // Code generated from params.templ.go. DO NOT EDIT. 2 | 3 | package internal 4 | 5 | const ( 6 | Name = "Dilithium3" 7 | K = 6 8 | L = 5 9 | Eta = 4 10 | DoubleEtaBits = 4 11 | Omega = 55 12 | Tau = 49 13 | Gamma1Bits = 19 14 | Gamma2 = 261888 15 | NIST = false 16 | TRSize = 32 17 | CTildeSize = 32 18 | ) 19 | -------------------------------------------------------------------------------- /sign/dilithium/mode3/internal/rounding_test.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import ( 4 | "flag" 5 | "testing" 6 | 7 | common "github.com/cloudflare/circl/sign/internal/dilithium" 8 | ) 9 | 10 | var runVeryLongTest = flag.Bool("very-long", false, "runs very long tests") 11 | 12 | func TestDecompose(t *testing.T) { 13 | for a := uint32(0); a < common.Q; a++ { 14 | a0PlusQ, a1 := decompose(a) 15 | a0 := int32(a0PlusQ) - int32(common.Q) 16 | recombined := a0 + int32(Alpha*a1) 17 | if a1 == 0 && recombined < 0 { 18 | recombined += common.Q 19 | if -(Alpha/2) > a0 || a0 >= 0 { 20 | t.Fatalf("decompose(%v): a0 out of bounds", a) 21 | } 22 | } else { 23 | if (-(Alpha / 2) >= a0) || (a0 > Alpha/2) { 24 | t.Fatalf("decompose(%v): a0 out of bounds", a) 25 | } 26 | } 27 | if int32(a) != recombined { 28 | t.Fatalf("decompose(%v) doesn't recombine %v %v", a, a0, a1) 29 | } 30 | } 31 | } 32 | 33 | func TestMakeHint(t *testing.T) { 34 | if !*runVeryLongTest { 35 | t.SkipNow() 36 | } 37 | for w := uint32(0); w < common.Q; w++ { 38 | w0, w1 := decompose(w) 39 | for fn := uint32(0); fn <= Gamma2; fn++ { 40 | fsign := false 41 | for { 42 | var f uint32 43 | if fsign { 44 | if fn == 0 { 45 | break 46 | } 47 | f = common.Q - fn 48 | } else { 49 | f = fn 50 | } 51 | 52 | hint := makeHint(common.ReduceLe2Q(w0+common.Q-f), w1) 53 | w1p := useHint(common.ReduceLe2Q(w+common.Q-f), hint) 54 | if w1p != w1 { 55 | t.Fatal() 56 | } 57 | 58 | if fsign { 59 | break 60 | } 61 | fsign = true 62 | } 63 | } 64 | } 65 | } 66 | 67 | func BenchmarkDecompose(b *testing.B) { 68 | var p, p0, p1 common.Poly 69 | for i := 0; i < b.N; i++ { 70 | PolyDecompose(&p, &p0, &p1) 71 | } 72 | } 73 | 74 | func BenchmarkMakeHint(b *testing.B) { 75 | var p, p0, p1 common.Poly 76 | for i := 0; i < b.N; i++ { 77 | PolyMakeHint(&p, &p0, &p1) 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /sign/dilithium/mode5/internal/mat.go: -------------------------------------------------------------------------------- 1 | // Code generated from mode3/internal/mat.go by gen.go 2 | 3 | package internal 4 | 5 | import ( 6 | common "github.com/cloudflare/circl/sign/internal/dilithium" 7 | ) 8 | 9 | // A k by l matrix of polynomials. 10 | type Mat [K]VecL 11 | 12 | // Expands the given seed to a complete matrix. 13 | // 14 | // This function is called ExpandA in the specification. 15 | func (m *Mat) Derive(seed *[32]byte) { 16 | if !DeriveX4Available { 17 | for i := uint16(0); i < K; i++ { 18 | for j := uint16(0); j < L; j++ { 19 | PolyDeriveUniform(&m[i][j], seed, (i<<8)+j) 20 | } 21 | } 22 | return 23 | } 24 | 25 | idx := 0 26 | var nonces [4]uint16 27 | var ps [4]*common.Poly 28 | for i := uint16(0); i < K; i++ { 29 | for j := uint16(0); j < L; j++ { 30 | nonces[idx] = (i << 8) + j 31 | ps[idx] = &m[i][j] 32 | idx++ 33 | if idx == 4 { 34 | idx = 0 35 | PolyDeriveUniformX4(ps, seed, nonces) 36 | } 37 | } 38 | } 39 | if idx != 0 { 40 | for i := idx; i < 4; i++ { 41 | ps[i] = nil 42 | } 43 | PolyDeriveUniformX4(ps, seed, nonces) 44 | } 45 | } 46 | 47 | // Set p to the inner product of a and b using pointwise multiplication. 48 | // 49 | // Assumes a and b are in Montgomery form and their coefficients are 50 | // pairwise sufficiently small to multiply, see Poly.MulHat(). Resulting 51 | // coefficients are bounded by 2Lq. 52 | func PolyDotHat(p *common.Poly, a, b *VecL) { 53 | var t common.Poly 54 | *p = common.Poly{} // zero p 55 | for i := 0; i < L; i++ { 56 | t.MulHat(&a[i], &b[i]) 57 | p.Add(&t, p) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /sign/dilithium/mode5/internal/params.go: -------------------------------------------------------------------------------- 1 | // Code generated from params.templ.go. DO NOT EDIT. 2 | 3 | package internal 4 | 5 | const ( 6 | Name = "Dilithium5" 7 | K = 8 8 | L = 7 9 | Eta = 2 10 | DoubleEtaBits = 3 11 | Omega = 75 12 | Tau = 60 13 | Gamma1Bits = 19 14 | Gamma2 = 261888 15 | NIST = false 16 | TRSize = 32 17 | CTildeSize = 32 18 | ) 19 | -------------------------------------------------------------------------------- /sign/dilithium/mode5/internal/rounding_test.go: -------------------------------------------------------------------------------- 1 | // Code generated from mode3/internal/rounding_test.go by gen.go 2 | 3 | package internal 4 | 5 | import ( 6 | "flag" 7 | "testing" 8 | 9 | common "github.com/cloudflare/circl/sign/internal/dilithium" 10 | ) 11 | 12 | var runVeryLongTest = flag.Bool("very-long", false, "runs very long tests") 13 | 14 | func TestDecompose(t *testing.T) { 15 | for a := uint32(0); a < common.Q; a++ { 16 | a0PlusQ, a1 := decompose(a) 17 | a0 := int32(a0PlusQ) - int32(common.Q) 18 | recombined := a0 + int32(Alpha*a1) 19 | if a1 == 0 && recombined < 0 { 20 | recombined += common.Q 21 | if -(Alpha/2) > a0 || a0 >= 0 { 22 | t.Fatalf("decompose(%v): a0 out of bounds", a) 23 | } 24 | } else { 25 | if (-(Alpha / 2) >= a0) || (a0 > Alpha/2) { 26 | t.Fatalf("decompose(%v): a0 out of bounds", a) 27 | } 28 | } 29 | if int32(a) != recombined { 30 | t.Fatalf("decompose(%v) doesn't recombine %v %v", a, a0, a1) 31 | } 32 | } 33 | } 34 | 35 | func TestMakeHint(t *testing.T) { 36 | if !*runVeryLongTest { 37 | t.SkipNow() 38 | } 39 | for w := uint32(0); w < common.Q; w++ { 40 | w0, w1 := decompose(w) 41 | for fn := uint32(0); fn <= Gamma2; fn++ { 42 | fsign := false 43 | for { 44 | var f uint32 45 | if fsign { 46 | if fn == 0 { 47 | break 48 | } 49 | f = common.Q - fn 50 | } else { 51 | f = fn 52 | } 53 | 54 | hint := makeHint(common.ReduceLe2Q(w0+common.Q-f), w1) 55 | w1p := useHint(common.ReduceLe2Q(w+common.Q-f), hint) 56 | if w1p != w1 { 57 | t.Fatal() 58 | } 59 | 60 | if fsign { 61 | break 62 | } 63 | fsign = true 64 | } 65 | } 66 | } 67 | } 68 | 69 | func BenchmarkDecompose(b *testing.B) { 70 | var p, p0, p1 common.Poly 71 | for i := 0; i < b.N; i++ { 72 | PolyDecompose(&p, &p0, &p1) 73 | } 74 | } 75 | 76 | func BenchmarkMakeHint(b *testing.B) { 77 | var p, p0, p1 common.Poly 78 | for i := 0; i < b.N; i++ { 79 | PolyMakeHint(&p, &p0, &p1) 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /sign/dilithium/templates/params.templ.go: -------------------------------------------------------------------------------- 1 | // +build ignore 2 | // The previous line (and this one up to the warning below) is removed by the 3 | // template generator. 4 | 5 | // Code generated from params.templ.go. DO NOT EDIT. 6 | 7 | package internal 8 | 9 | const ( 10 | Name = "{{.Name}}" 11 | K = {{.K}} 12 | L = {{.L}} 13 | Eta = {{.Eta}} 14 | DoubleEtaBits = {{.DoubleEtaBits}} 15 | Omega = {{.Omega}} 16 | Tau = {{.Tau}} 17 | Gamma1Bits = {{.Gamma1Bits}} 18 | Gamma2 = {{.Gamma2}} 19 | NIST = {{.NIST}} 20 | TRSize = {{.TRSize}} 21 | CTildeSize = {{.CTildeSize}} 22 | ) 23 | -------------------------------------------------------------------------------- /sign/ed25519/pubkey.go: -------------------------------------------------------------------------------- 1 | //go:build go1.13 2 | // +build go1.13 3 | 4 | package ed25519 5 | 6 | import cryptoEd25519 "crypto/ed25519" 7 | 8 | // PublicKey is the type of Ed25519 public keys. 9 | type PublicKey cryptoEd25519.PublicKey 10 | -------------------------------------------------------------------------------- /sign/ed25519/pubkey112.go: -------------------------------------------------------------------------------- 1 | //go:build !go1.13 2 | // +build !go1.13 3 | 4 | package ed25519 5 | 6 | // PublicKey is the type of Ed25519 public keys. 7 | type PublicKey []byte 8 | -------------------------------------------------------------------------------- /sign/ed25519/testdata/sign.input.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/circl/main/sign/ed25519/testdata/sign.input.zip -------------------------------------------------------------------------------- /sign/eddilithium2/example_test.go: -------------------------------------------------------------------------------- 1 | package eddilithium2_test 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/cloudflare/circl/sign/eddilithium2" 7 | ) 8 | 9 | func Example() { 10 | // Generates a keypair. 11 | pk, sk, err := eddilithium2.GenerateKey(nil) 12 | if err != nil { 13 | panic(err) 14 | } 15 | 16 | // (Alternatively one can derive a keypair from a seed, 17 | // see NewKeyFromSeed().) 18 | 19 | // Packs public and private key 20 | var packedSk [eddilithium2.PrivateKeySize]byte 21 | var packedPk [eddilithium2.PublicKeySize]byte 22 | sk.Pack(&packedSk) 23 | pk.Pack(&packedPk) 24 | 25 | // Load it again 26 | var sk2 eddilithium2.PrivateKey 27 | var pk2 eddilithium2.PublicKey 28 | sk2.Unpack(&packedSk) 29 | pk2.Unpack(&packedPk) 30 | 31 | // Creates a signature on our message with the generated private key. 32 | msg := []byte("Some message") 33 | var signature [eddilithium2.SignatureSize]byte 34 | eddilithium2.SignTo(&sk2, msg, signature[:]) 35 | 36 | // Checks whether a signature is correct 37 | if !eddilithium2.Verify(&pk2, msg, signature[:]) { 38 | panic("incorrect signature") 39 | } 40 | 41 | fmt.Printf("O.K.") 42 | 43 | // Output: 44 | // O.K. 45 | } 46 | -------------------------------------------------------------------------------- /sign/eddilithium3/example_test.go: -------------------------------------------------------------------------------- 1 | package eddilithium3_test 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/cloudflare/circl/sign/eddilithium3" 7 | ) 8 | 9 | func Example() { 10 | // Generates a keypair. 11 | pk, sk, err := eddilithium3.GenerateKey(nil) 12 | if err != nil { 13 | panic(err) 14 | } 15 | 16 | // (Alternatively one can derive a keypair from a seed, 17 | // see NewKeyFromSeed().) 18 | 19 | // Packs public and private key 20 | var packedSk [eddilithium3.PrivateKeySize]byte 21 | var packedPk [eddilithium3.PublicKeySize]byte 22 | sk.Pack(&packedSk) 23 | pk.Pack(&packedPk) 24 | 25 | // Load it again 26 | var sk2 eddilithium3.PrivateKey 27 | var pk2 eddilithium3.PublicKey 28 | sk2.Unpack(&packedSk) 29 | pk2.Unpack(&packedPk) 30 | 31 | // Creates a signature on our message with the generated private key. 32 | msg := []byte("Some message") 33 | var signature [eddilithium3.SignatureSize]byte 34 | eddilithium3.SignTo(&sk2, msg, signature[:]) 35 | 36 | // Checks whether a signature is correct 37 | if !eddilithium3.Verify(&pk2, msg, signature[:]) { 38 | panic("incorrect signature") 39 | } 40 | 41 | fmt.Printf("O.K.") 42 | 43 | // Output: 44 | // O.K. 45 | } 46 | -------------------------------------------------------------------------------- /sign/internal/dilithium/asm/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/cloudflare/circl/sign/internal/dilithium/asm 2 | 3 | go 1.22.0 4 | 5 | require ( 6 | github.com/cloudflare/circl v1.4.0 7 | github.com/mmcloughlin/avo v0.6.0 8 | ) 9 | 10 | require ( 11 | golang.org/x/mod v0.14.0 // indirect 12 | golang.org/x/tools v0.16.1 // indirect 13 | ) 14 | 15 | replace github.com/cloudflare/circl => ../../../../ 16 | -------------------------------------------------------------------------------- /sign/internal/dilithium/asm/go.sum: -------------------------------------------------------------------------------- 1 | github.com/mmcloughlin/avo v0.6.0 h1:QH6FU8SKoTLaVs80GA8TJuLNkUYl4VokHKlPhVDg4YY= 2 | github.com/mmcloughlin/avo v0.6.0/go.mod h1:8CoAGaCSYXtCPR+8y18Y9aB/kxb8JSS6FRI7mSkvD+8= 3 | golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= 4 | golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 5 | golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= 6 | golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 7 | golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA= 8 | golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= 9 | -------------------------------------------------------------------------------- /sign/internal/dilithium/field.go: -------------------------------------------------------------------------------- 1 | package dilithium 2 | 3 | // Returns a y with y < 2q and y = x mod q. 4 | // Note that in general *not*: ReduceLe2Q(ReduceLe2Q(x)) == x. 5 | func ReduceLe2Q(x uint32) uint32 { 6 | // Note 2²³ = 2¹³ - 1 mod q. So, writing x = x₁ 2²³ + x₂ with x₂ < 2²³ 7 | // and x₁ < 2⁹, we have x = y (mod q) where 8 | // y = x₂ + x₁ 2¹³ - x₁ ≤ 2²³ + 2¹³ < 2q. 9 | x1 := x >> 23 10 | x2 := x & 0x7FFFFF // 2²³-1 11 | return x2 + (x1 << 13) - x1 12 | } 13 | 14 | // Returns x mod q. 15 | func modQ(x uint32) uint32 { 16 | return le2qModQ(ReduceLe2Q(x)) 17 | } 18 | 19 | // For x R ≤ q 2³², find y ≤ 2q with y = x mod q. 20 | func montReduceLe2Q(x uint64) uint32 { 21 | // Qinv = 4236238847 = -(q⁻¹) mod 2³² 22 | m := (x * Qinv) & 0xffffffff 23 | return uint32((x + m*uint64(Q)) >> 32) 24 | } 25 | 26 | // Returns x mod q for 0 ≤ x < 2q. 27 | func le2qModQ(x uint32) uint32 { 28 | x -= Q 29 | mask := uint32(int32(x) >> 31) // mask is 2³²-1 if x was neg.; 0 otherwise 30 | return x + (mask & Q) 31 | } 32 | 33 | // Splits 0 ≤ a < Q into a0 and a1 with a = a1*2ᴰ + a0 34 | // and -2ᴰ⁻¹ < a0 < 2ᴰ⁻¹. Returns a0 + Q and a1. 35 | func power2round(a uint32) (a0plusQ, a1 uint32) { 36 | // We effectively compute a0 = a mod± 2ᵈ 37 | // and a1 = (a - a0) / 2ᵈ. 38 | a0 := a & ((1 << D) - 1) // a mod 2ᵈ 39 | 40 | // a0 is one of 0, 1, ..., 2ᵈ⁻¹-1, 2ᵈ⁻¹, 2ᵈ⁻¹+1, ..., 2ᵈ-1 41 | a0 -= (1 << (D - 1)) + 1 42 | // now a0 is -2ᵈ⁻¹-1, -2ᵈ⁻¹, ..., -2, -1, 0, ..., 2ᵈ⁻¹-2 43 | // Next, we add 2ᴰ to those a0 that are negative (seen as int32). 44 | a0 += uint32(int32(a0)>>31) & (1 << D) 45 | // now a0 is 2ᵈ⁻¹-1, 2ᵈ⁻¹, ..., 2ᵈ-2, 2ᵈ-1, 0, ..., 2ᵈ⁻¹-2 46 | a0 -= (1 << (D - 1)) - 1 47 | // now a0 id 0, 1, 2, ..., 2ᵈ⁻¹-1, 2ᵈ⁻¹-1, -2ᵈ⁻¹-1, ... 48 | // which is what we want. 49 | a0plusQ = Q + a0 50 | a1 = (a - a0) >> D 51 | return 52 | } 53 | -------------------------------------------------------------------------------- /sign/internal/dilithium/field_test.go: -------------------------------------------------------------------------------- 1 | package dilithium 2 | 3 | import ( 4 | "crypto/rand" 5 | "encoding/binary" 6 | "math" 7 | "testing" 8 | ) 9 | 10 | func randSliceUint32(length uint) []uint32 { return randSliceUint32WithMax(length, math.MaxUint32) } 11 | 12 | func randSliceUint32WithMax(length uint, max uint32) []uint32 { 13 | bytes := make([]uint8, 4*length) 14 | if n, err := rand.Read(bytes); err != nil { 15 | panic(err) 16 | } else if n < len(bytes) { 17 | panic("short read from RNG") 18 | } 19 | x := make([]uint32, length) 20 | for i := range x { 21 | x[i] = binary.LittleEndian.Uint32(bytes[4*i:]) % max 22 | } 23 | return x 24 | } 25 | 26 | func TestModQ(t *testing.T) { 27 | const testTimes = 1000 28 | r := randSliceUint32(testTimes) 29 | for i := 0; i < testTimes; i++ { 30 | x := r[i] 31 | y := modQ(x) 32 | if y > Q { 33 | t.Fatalf("modQ(%d) > Q", x) 34 | } 35 | if y != x%Q { 36 | t.Fatalf("modQ(%d) != %d (mod Q)", x, x) 37 | } 38 | } 39 | } 40 | 41 | func TestReduceLe2Q(t *testing.T) { 42 | const testTimes = 1000 43 | r := randSliceUint32(testTimes) 44 | for i := 0; i < testTimes; i++ { 45 | x := r[i] 46 | y := ReduceLe2Q(x) 47 | if y > 2*Q { 48 | t.Fatalf("reduce_le2q(%d) > 2Q", x) 49 | } 50 | if y%Q != x%Q { 51 | t.Fatalf("reduce_le2q(%d) != %d (mod Q)", x, x) 52 | } 53 | } 54 | } 55 | 56 | func TestPower2Round(t *testing.T) { 57 | for a := uint32(0); a < Q; a++ { 58 | a0PlusQ, a1 := power2round(a) 59 | a0 := int32(a0PlusQ) - int32(Q) 60 | if int32(a) != a0+int32((1<= a0) || (a0 > 1<<(D-1)) { 64 | t.Fatalf("power2round(%v): a0 out of bounds", a) 65 | } 66 | if a1 > (1 << (QBits - D)) { 67 | t.Fatalf("power2round(%v): a1 out of bounds", a) 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /sign/internal/dilithium/ntt_test.go: -------------------------------------------------------------------------------- 1 | package dilithium 2 | 3 | import "testing" 4 | 5 | func (p *Poly) RandLe2Q() { 6 | max := 2 * uint32(Q) 7 | r := randSliceUint32WithMax(N, max) 8 | copy(p[:], r) 9 | } 10 | 11 | func TestNTTAgainstGeneric(t *testing.T) { 12 | for k := 0; k < 1000; k++ { 13 | var p Poly 14 | p.RandLe2Q() 15 | q1 := p 16 | q2 := p 17 | q1.NTT() 18 | q2.nttGeneric() 19 | if q1 != q2 { 20 | t.Fatalf("NTT(%v) = %v != %v", p, q1, q2) 21 | } 22 | } 23 | } 24 | 25 | func TestNTT(t *testing.T) { 26 | for k := 0; k < 1000; k++ { 27 | var p, q Poly 28 | p.RandLe2Q() 29 | q = p 30 | q.Normalize() 31 | p.NTT() 32 | for i := uint(0); i < N; i++ { 33 | if p[i] > 18*Q { 34 | t.Fatalf("NTT(%v)[%d] = %d > 18*Q", q, i, p[i]) 35 | } 36 | } 37 | p.ReduceLe2Q() 38 | p.InvNTT() 39 | for i := uint(0); i < N; i++ { 40 | if p[i] > 2*Q { 41 | t.Fatalf("InvNTT(%v)[%d] > 2*Q", q, i) 42 | } 43 | } 44 | p.Normalize() 45 | for i := uint(0); i < N; i++ { 46 | if p[i] != uint32((uint64(q[i])*uint64(1<<32))%Q) { 47 | t.Fatalf("%v != %v", p, q) 48 | } 49 | } 50 | } 51 | } 52 | 53 | func BenchmarkNTTGeneric(b *testing.B) { 54 | var p Poly 55 | for i := 0; i < b.N; i++ { 56 | p.nttGeneric() 57 | } 58 | } 59 | 60 | func BenchmarkInvNTTGeneric(b *testing.B) { 61 | var p Poly 62 | for i := 0; i < b.N; i++ { 63 | p.invNttGeneric() 64 | } 65 | } 66 | 67 | func BenchmarkNTT(b *testing.B) { 68 | var p Poly 69 | for i := 0; i < b.N; i++ { 70 | p.NTT() 71 | } 72 | } 73 | 74 | func BenchmarkInvNTT(b *testing.B) { 75 | var p Poly 76 | for i := 0; i < b.N; i++ { 77 | p.InvNTT() 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /sign/internal/dilithium/pack_test.go: -------------------------------------------------------------------------------- 1 | package dilithium 2 | 3 | import "testing" 4 | 5 | func TestPackLe16AgainstGeneric(t *testing.T) { 6 | var p Poly 7 | var buf1, buf2 [PolyLe16Size]byte 8 | 9 | for j := 0; j < 1000; j++ { 10 | pp := randSliceUint32WithMax(N, 16) 11 | copy(p[:], pp) 12 | p.PackLe16(buf1[:]) 13 | p.packLe16Generic(buf2[:]) 14 | if buf1 != buf2 { 15 | t.Fatal() 16 | } 17 | } 18 | } 19 | 20 | func BenchmarkPackLe16(b *testing.B) { 21 | var p Poly 22 | var buf [PolyLe16Size]byte 23 | for i := 0; i < b.N; i++ { 24 | p.PackLe16(buf[:]) 25 | } 26 | } 27 | 28 | func BenchmarkPackLe16Generic(b *testing.B) { 29 | var p Poly 30 | var buf [PolyLe16Size]byte 31 | for i := 0; i < b.N; i++ { 32 | p.packLe16Generic(buf[:]) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /sign/internal/dilithium/params.go: -------------------------------------------------------------------------------- 1 | package dilithium 2 | 3 | import ( 4 | "github.com/cloudflare/circl/sign/internal/dilithium/params" 5 | ) 6 | 7 | const ( 8 | SeedSize = params.SeedSize 9 | N = params.N 10 | Q = params.Q 11 | QBits = params.QBits 12 | Qinv = params.Qinv 13 | ROver256 = params.ROver256 14 | D = params.D 15 | PolyT1Size = params.PolyT1Size 16 | PolyT0Size = params.PolyT0Size 17 | PolyLe16Size = params.PolyLe16Size 18 | ) 19 | -------------------------------------------------------------------------------- /sign/internal/dilithium/params/params.go: -------------------------------------------------------------------------------- 1 | package params 2 | 3 | // We put these parameters in a separate package so that the Go code, 4 | // such as ntt_amd64_src.go, that generates assembler can import it. 5 | 6 | const ( 7 | SeedSize = 32 8 | N = 256 9 | Q = 8380417 // 2²³ - 2¹³ + 1 10 | QBits = 23 11 | Qinv = 4236238847 // = -(q^-1) mod 2³² 12 | ROver256 = 41978 // = (256)⁻¹ R² mod q, where R=2³² 13 | D = 13 14 | 15 | // Size of T1 packed. (Note that the formula is not valid in general, 16 | // but it is for the parameters used in the modes of Dilithium.) 17 | PolyT1Size = (N * (QBits - D)) / 8 18 | 19 | // Size of T0 packed. (Note that the formula is not valid in general, 20 | // but it is for the parameters used in the modes of Dilithium.) 21 | PolyT0Size = (N * D) / 8 22 | 23 | // Size of a packed polynomial whose coefficients are in [0,16). 24 | PolyLe16Size = N / 2 25 | ) 26 | -------------------------------------------------------------------------------- /sign/internal/dilithium/stubs_amd64.go: -------------------------------------------------------------------------------- 1 | // Code generated by command: go run src.go -out ../amd64.s -stubs ../stubs_amd64.go -pkg dilithium. DO NOT EDIT. 2 | 3 | //go:build amd64 && !purego 4 | 5 | package dilithium 6 | 7 | //go:noescape 8 | func nttAVX2(p *[256]uint32) 9 | 10 | //go:noescape 11 | func invNttAVX2(p *[256]uint32) 12 | 13 | //go:noescape 14 | func mulHatAVX2(p *[256]uint32, a *[256]uint32, b *[256]uint32) 15 | 16 | //go:noescape 17 | func addAVX2(p *[256]uint32, a *[256]uint32, b *[256]uint32) 18 | 19 | //go:noescape 20 | func subAVX2(p *[256]uint32, a *[256]uint32, b *[256]uint32) 21 | 22 | //go:noescape 23 | func packLe16AVX2(p *[256]uint32, buf *byte) 24 | 25 | //go:noescape 26 | func reduceLe2QAVX2(p *[256]uint32) 27 | 28 | //go:noescape 29 | func le2qModQAVX2(p *[256]uint32) 30 | 31 | //go:noescape 32 | func exceedsAVX2(p *[256]uint32, bound uint32) uint8 33 | 34 | //go:noescape 35 | func mulBy2toDAVX2(p *[256]uint32, q *[256]uint32) 36 | -------------------------------------------------------------------------------- /sign/mldsa/doc.go: -------------------------------------------------------------------------------- 1 | // mldsa implements NIST post-quantum signature scheme ML-DSA (FIPS204) 2 | // 3 | // Each of the three different security levels of ML-DSA is implemented by a 4 | // subpackage. For instance, mldsa44 can be found in 5 | // 6 | // github.com/cloudflare/circl/sign/mldsa/mldsa44 7 | // 8 | // If your choice for mode is fixed compile-time, use the subpackages. 9 | // To choose a scheme at runtime, use the generic signatures API under 10 | // 11 | // github.com/cloudflare/circl/sign/schemes 12 | package mldsa 13 | -------------------------------------------------------------------------------- /sign/mldsa/mldsa44/internal/mat.go: -------------------------------------------------------------------------------- 1 | // Code generated from mode3/internal/mat.go by gen.go 2 | 3 | package internal 4 | 5 | import ( 6 | common "github.com/cloudflare/circl/sign/internal/dilithium" 7 | ) 8 | 9 | // A k by l matrix of polynomials. 10 | type Mat [K]VecL 11 | 12 | // Expands the given seed to a complete matrix. 13 | // 14 | // This function is called ExpandA in the specification. 15 | func (m *Mat) Derive(seed *[32]byte) { 16 | if !DeriveX4Available { 17 | for i := uint16(0); i < K; i++ { 18 | for j := uint16(0); j < L; j++ { 19 | PolyDeriveUniform(&m[i][j], seed, (i<<8)+j) 20 | } 21 | } 22 | return 23 | } 24 | 25 | idx := 0 26 | var nonces [4]uint16 27 | var ps [4]*common.Poly 28 | for i := uint16(0); i < K; i++ { 29 | for j := uint16(0); j < L; j++ { 30 | nonces[idx] = (i << 8) + j 31 | ps[idx] = &m[i][j] 32 | idx++ 33 | if idx == 4 { 34 | idx = 0 35 | PolyDeriveUniformX4(ps, seed, nonces) 36 | } 37 | } 38 | } 39 | if idx != 0 { 40 | for i := idx; i < 4; i++ { 41 | ps[i] = nil 42 | } 43 | PolyDeriveUniformX4(ps, seed, nonces) 44 | } 45 | } 46 | 47 | // Set p to the inner product of a and b using pointwise multiplication. 48 | // 49 | // Assumes a and b are in Montgomery form and their coefficients are 50 | // pairwise sufficiently small to multiply, see Poly.MulHat(). Resulting 51 | // coefficients are bounded by 2Lq. 52 | func PolyDotHat(p *common.Poly, a, b *VecL) { 53 | var t common.Poly 54 | *p = common.Poly{} // zero p 55 | for i := 0; i < L; i++ { 56 | t.MulHat(&a[i], &b[i]) 57 | p.Add(&t, p) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /sign/mldsa/mldsa44/internal/params.go: -------------------------------------------------------------------------------- 1 | // Code generated from params.templ.go. DO NOT EDIT. 2 | 3 | package internal 4 | 5 | const ( 6 | Name = "ML-DSA-44" 7 | K = 4 8 | L = 4 9 | Eta = 2 10 | DoubleEtaBits = 3 11 | Omega = 80 12 | Tau = 39 13 | Gamma1Bits = 17 14 | Gamma2 = 95232 15 | NIST = true 16 | TRSize = 64 17 | CTildeSize = 32 18 | ) 19 | -------------------------------------------------------------------------------- /sign/mldsa/mldsa44/internal/rounding_test.go: -------------------------------------------------------------------------------- 1 | // Code generated from mode3/internal/rounding_test.go by gen.go 2 | 3 | package internal 4 | 5 | import ( 6 | "flag" 7 | "testing" 8 | 9 | common "github.com/cloudflare/circl/sign/internal/dilithium" 10 | ) 11 | 12 | var runVeryLongTest = flag.Bool("very-long", false, "runs very long tests") 13 | 14 | func TestDecompose(t *testing.T) { 15 | for a := uint32(0); a < common.Q; a++ { 16 | a0PlusQ, a1 := decompose(a) 17 | a0 := int32(a0PlusQ) - int32(common.Q) 18 | recombined := a0 + int32(Alpha*a1) 19 | if a1 == 0 && recombined < 0 { 20 | recombined += common.Q 21 | if -(Alpha/2) > a0 || a0 >= 0 { 22 | t.Fatalf("decompose(%v): a0 out of bounds", a) 23 | } 24 | } else { 25 | if (-(Alpha / 2) >= a0) || (a0 > Alpha/2) { 26 | t.Fatalf("decompose(%v): a0 out of bounds", a) 27 | } 28 | } 29 | if int32(a) != recombined { 30 | t.Fatalf("decompose(%v) doesn't recombine %v %v", a, a0, a1) 31 | } 32 | } 33 | } 34 | 35 | func TestMakeHint(t *testing.T) { 36 | if !*runVeryLongTest { 37 | t.SkipNow() 38 | } 39 | for w := uint32(0); w < common.Q; w++ { 40 | w0, w1 := decompose(w) 41 | for fn := uint32(0); fn <= Gamma2; fn++ { 42 | fsign := false 43 | for { 44 | var f uint32 45 | if fsign { 46 | if fn == 0 { 47 | break 48 | } 49 | f = common.Q - fn 50 | } else { 51 | f = fn 52 | } 53 | 54 | hint := makeHint(common.ReduceLe2Q(w0+common.Q-f), w1) 55 | w1p := useHint(common.ReduceLe2Q(w+common.Q-f), hint) 56 | if w1p != w1 { 57 | t.Fatal() 58 | } 59 | 60 | if fsign { 61 | break 62 | } 63 | fsign = true 64 | } 65 | } 66 | } 67 | } 68 | 69 | func BenchmarkDecompose(b *testing.B) { 70 | var p, p0, p1 common.Poly 71 | for i := 0; i < b.N; i++ { 72 | PolyDecompose(&p, &p0, &p1) 73 | } 74 | } 75 | 76 | func BenchmarkMakeHint(b *testing.B) { 77 | var p, p0, p1 common.Poly 78 | for i := 0; i < b.N; i++ { 79 | PolyMakeHint(&p, &p0, &p1) 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /sign/mldsa/mldsa65/internal/mat.go: -------------------------------------------------------------------------------- 1 | // Code generated from mode3/internal/mat.go by gen.go 2 | 3 | package internal 4 | 5 | import ( 6 | common "github.com/cloudflare/circl/sign/internal/dilithium" 7 | ) 8 | 9 | // A k by l matrix of polynomials. 10 | type Mat [K]VecL 11 | 12 | // Expands the given seed to a complete matrix. 13 | // 14 | // This function is called ExpandA in the specification. 15 | func (m *Mat) Derive(seed *[32]byte) { 16 | if !DeriveX4Available { 17 | for i := uint16(0); i < K; i++ { 18 | for j := uint16(0); j < L; j++ { 19 | PolyDeriveUniform(&m[i][j], seed, (i<<8)+j) 20 | } 21 | } 22 | return 23 | } 24 | 25 | idx := 0 26 | var nonces [4]uint16 27 | var ps [4]*common.Poly 28 | for i := uint16(0); i < K; i++ { 29 | for j := uint16(0); j < L; j++ { 30 | nonces[idx] = (i << 8) + j 31 | ps[idx] = &m[i][j] 32 | idx++ 33 | if idx == 4 { 34 | idx = 0 35 | PolyDeriveUniformX4(ps, seed, nonces) 36 | } 37 | } 38 | } 39 | if idx != 0 { 40 | for i := idx; i < 4; i++ { 41 | ps[i] = nil 42 | } 43 | PolyDeriveUniformX4(ps, seed, nonces) 44 | } 45 | } 46 | 47 | // Set p to the inner product of a and b using pointwise multiplication. 48 | // 49 | // Assumes a and b are in Montgomery form and their coefficients are 50 | // pairwise sufficiently small to multiply, see Poly.MulHat(). Resulting 51 | // coefficients are bounded by 2Lq. 52 | func PolyDotHat(p *common.Poly, a, b *VecL) { 53 | var t common.Poly 54 | *p = common.Poly{} // zero p 55 | for i := 0; i < L; i++ { 56 | t.MulHat(&a[i], &b[i]) 57 | p.Add(&t, p) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /sign/mldsa/mldsa65/internal/params.go: -------------------------------------------------------------------------------- 1 | // Code generated from params.templ.go. DO NOT EDIT. 2 | 3 | package internal 4 | 5 | const ( 6 | Name = "ML-DSA-65" 7 | K = 6 8 | L = 5 9 | Eta = 4 10 | DoubleEtaBits = 4 11 | Omega = 55 12 | Tau = 49 13 | Gamma1Bits = 19 14 | Gamma2 = 261888 15 | NIST = true 16 | TRSize = 64 17 | CTildeSize = 48 18 | ) 19 | -------------------------------------------------------------------------------- /sign/mldsa/mldsa65/internal/rounding_test.go: -------------------------------------------------------------------------------- 1 | // Code generated from mode3/internal/rounding_test.go by gen.go 2 | 3 | package internal 4 | 5 | import ( 6 | "flag" 7 | "testing" 8 | 9 | common "github.com/cloudflare/circl/sign/internal/dilithium" 10 | ) 11 | 12 | var runVeryLongTest = flag.Bool("very-long", false, "runs very long tests") 13 | 14 | func TestDecompose(t *testing.T) { 15 | for a := uint32(0); a < common.Q; a++ { 16 | a0PlusQ, a1 := decompose(a) 17 | a0 := int32(a0PlusQ) - int32(common.Q) 18 | recombined := a0 + int32(Alpha*a1) 19 | if a1 == 0 && recombined < 0 { 20 | recombined += common.Q 21 | if -(Alpha/2) > a0 || a0 >= 0 { 22 | t.Fatalf("decompose(%v): a0 out of bounds", a) 23 | } 24 | } else { 25 | if (-(Alpha / 2) >= a0) || (a0 > Alpha/2) { 26 | t.Fatalf("decompose(%v): a0 out of bounds", a) 27 | } 28 | } 29 | if int32(a) != recombined { 30 | t.Fatalf("decompose(%v) doesn't recombine %v %v", a, a0, a1) 31 | } 32 | } 33 | } 34 | 35 | func TestMakeHint(t *testing.T) { 36 | if !*runVeryLongTest { 37 | t.SkipNow() 38 | } 39 | for w := uint32(0); w < common.Q; w++ { 40 | w0, w1 := decompose(w) 41 | for fn := uint32(0); fn <= Gamma2; fn++ { 42 | fsign := false 43 | for { 44 | var f uint32 45 | if fsign { 46 | if fn == 0 { 47 | break 48 | } 49 | f = common.Q - fn 50 | } else { 51 | f = fn 52 | } 53 | 54 | hint := makeHint(common.ReduceLe2Q(w0+common.Q-f), w1) 55 | w1p := useHint(common.ReduceLe2Q(w+common.Q-f), hint) 56 | if w1p != w1 { 57 | t.Fatal() 58 | } 59 | 60 | if fsign { 61 | break 62 | } 63 | fsign = true 64 | } 65 | } 66 | } 67 | } 68 | 69 | func BenchmarkDecompose(b *testing.B) { 70 | var p, p0, p1 common.Poly 71 | for i := 0; i < b.N; i++ { 72 | PolyDecompose(&p, &p0, &p1) 73 | } 74 | } 75 | 76 | func BenchmarkMakeHint(b *testing.B) { 77 | var p, p0, p1 common.Poly 78 | for i := 0; i < b.N; i++ { 79 | PolyMakeHint(&p, &p0, &p1) 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /sign/mldsa/mldsa87/internal/mat.go: -------------------------------------------------------------------------------- 1 | // Code generated from mode3/internal/mat.go by gen.go 2 | 3 | package internal 4 | 5 | import ( 6 | common "github.com/cloudflare/circl/sign/internal/dilithium" 7 | ) 8 | 9 | // A k by l matrix of polynomials. 10 | type Mat [K]VecL 11 | 12 | // Expands the given seed to a complete matrix. 13 | // 14 | // This function is called ExpandA in the specification. 15 | func (m *Mat) Derive(seed *[32]byte) { 16 | if !DeriveX4Available { 17 | for i := uint16(0); i < K; i++ { 18 | for j := uint16(0); j < L; j++ { 19 | PolyDeriveUniform(&m[i][j], seed, (i<<8)+j) 20 | } 21 | } 22 | return 23 | } 24 | 25 | idx := 0 26 | var nonces [4]uint16 27 | var ps [4]*common.Poly 28 | for i := uint16(0); i < K; i++ { 29 | for j := uint16(0); j < L; j++ { 30 | nonces[idx] = (i << 8) + j 31 | ps[idx] = &m[i][j] 32 | idx++ 33 | if idx == 4 { 34 | idx = 0 35 | PolyDeriveUniformX4(ps, seed, nonces) 36 | } 37 | } 38 | } 39 | if idx != 0 { 40 | for i := idx; i < 4; i++ { 41 | ps[i] = nil 42 | } 43 | PolyDeriveUniformX4(ps, seed, nonces) 44 | } 45 | } 46 | 47 | // Set p to the inner product of a and b using pointwise multiplication. 48 | // 49 | // Assumes a and b are in Montgomery form and their coefficients are 50 | // pairwise sufficiently small to multiply, see Poly.MulHat(). Resulting 51 | // coefficients are bounded by 2Lq. 52 | func PolyDotHat(p *common.Poly, a, b *VecL) { 53 | var t common.Poly 54 | *p = common.Poly{} // zero p 55 | for i := 0; i < L; i++ { 56 | t.MulHat(&a[i], &b[i]) 57 | p.Add(&t, p) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /sign/mldsa/mldsa87/internal/params.go: -------------------------------------------------------------------------------- 1 | // Code generated from params.templ.go. DO NOT EDIT. 2 | 3 | package internal 4 | 5 | const ( 6 | Name = "ML-DSA-87" 7 | K = 8 8 | L = 7 9 | Eta = 2 10 | DoubleEtaBits = 3 11 | Omega = 75 12 | Tau = 60 13 | Gamma1Bits = 19 14 | Gamma2 = 261888 15 | NIST = true 16 | TRSize = 64 17 | CTildeSize = 64 18 | ) 19 | -------------------------------------------------------------------------------- /sign/mldsa/mldsa87/internal/rounding_test.go: -------------------------------------------------------------------------------- 1 | // Code generated from mode3/internal/rounding_test.go by gen.go 2 | 3 | package internal 4 | 5 | import ( 6 | "flag" 7 | "testing" 8 | 9 | common "github.com/cloudflare/circl/sign/internal/dilithium" 10 | ) 11 | 12 | var runVeryLongTest = flag.Bool("very-long", false, "runs very long tests") 13 | 14 | func TestDecompose(t *testing.T) { 15 | for a := uint32(0); a < common.Q; a++ { 16 | a0PlusQ, a1 := decompose(a) 17 | a0 := int32(a0PlusQ) - int32(common.Q) 18 | recombined := a0 + int32(Alpha*a1) 19 | if a1 == 0 && recombined < 0 { 20 | recombined += common.Q 21 | if -(Alpha/2) > a0 || a0 >= 0 { 22 | t.Fatalf("decompose(%v): a0 out of bounds", a) 23 | } 24 | } else { 25 | if (-(Alpha / 2) >= a0) || (a0 > Alpha/2) { 26 | t.Fatalf("decompose(%v): a0 out of bounds", a) 27 | } 28 | } 29 | if int32(a) != recombined { 30 | t.Fatalf("decompose(%v) doesn't recombine %v %v", a, a0, a1) 31 | } 32 | } 33 | } 34 | 35 | func TestMakeHint(t *testing.T) { 36 | if !*runVeryLongTest { 37 | t.SkipNow() 38 | } 39 | for w := uint32(0); w < common.Q; w++ { 40 | w0, w1 := decompose(w) 41 | for fn := uint32(0); fn <= Gamma2; fn++ { 42 | fsign := false 43 | for { 44 | var f uint32 45 | if fsign { 46 | if fn == 0 { 47 | break 48 | } 49 | f = common.Q - fn 50 | } else { 51 | f = fn 52 | } 53 | 54 | hint := makeHint(common.ReduceLe2Q(w0+common.Q-f), w1) 55 | w1p := useHint(common.ReduceLe2Q(w+common.Q-f), hint) 56 | if w1p != w1 { 57 | t.Fatal() 58 | } 59 | 60 | if fsign { 61 | break 62 | } 63 | fsign = true 64 | } 65 | } 66 | } 67 | } 68 | 69 | func BenchmarkDecompose(b *testing.B) { 70 | var p, p0, p1 common.Poly 71 | for i := 0; i < b.N; i++ { 72 | PolyDecompose(&p, &p0, &p1) 73 | } 74 | } 75 | 76 | func BenchmarkMakeHint(b *testing.B) { 77 | var p, p0, p1 common.Poly 78 | for i := 0; i < b.N; i++ { 79 | PolyMakeHint(&p, &p0, &p1) 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /sign/mldsa/testdata/ML-DSA-keyGen-FIPS204/expectedResults.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/circl/main/sign/mldsa/testdata/ML-DSA-keyGen-FIPS204/expectedResults.json.gz -------------------------------------------------------------------------------- /sign/mldsa/testdata/ML-DSA-keyGen-FIPS204/prompt.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/circl/main/sign/mldsa/testdata/ML-DSA-keyGen-FIPS204/prompt.json.gz -------------------------------------------------------------------------------- /sign/mldsa/testdata/ML-DSA-sigGen-FIPS204/expectedResults.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/circl/main/sign/mldsa/testdata/ML-DSA-sigGen-FIPS204/expectedResults.json.gz -------------------------------------------------------------------------------- /sign/mldsa/testdata/ML-DSA-sigGen-FIPS204/prompt.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/circl/main/sign/mldsa/testdata/ML-DSA-sigGen-FIPS204/prompt.json.gz -------------------------------------------------------------------------------- /sign/mldsa/testdata/ML-DSA-sigVer-FIPS204/expectedResults.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/circl/main/sign/mldsa/testdata/ML-DSA-sigVer-FIPS204/expectedResults.json.gz -------------------------------------------------------------------------------- /sign/mldsa/testdata/ML-DSA-sigVer-FIPS204/prompt.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudflare/circl/main/sign/mldsa/testdata/ML-DSA-sigVer-FIPS204/prompt.json.gz -------------------------------------------------------------------------------- /sign/schemes/schemes.go: -------------------------------------------------------------------------------- 1 | // Package schemes contains a register of signature algorithms. 2 | // 3 | // Implemented schemes: 4 | // 5 | // Ed25519 6 | // Ed448 7 | // Ed25519-Dilithium2 8 | // Ed448-Dilithium3 9 | package schemes 10 | 11 | import ( 12 | "strings" 13 | 14 | "github.com/cloudflare/circl/sign" 15 | "github.com/cloudflare/circl/sign/ed25519" 16 | "github.com/cloudflare/circl/sign/ed448" 17 | "github.com/cloudflare/circl/sign/eddilithium2" 18 | "github.com/cloudflare/circl/sign/eddilithium3" 19 | 20 | dilithium2 "github.com/cloudflare/circl/sign/dilithium/mode2" 21 | dilithium3 "github.com/cloudflare/circl/sign/dilithium/mode3" 22 | dilithium5 "github.com/cloudflare/circl/sign/dilithium/mode5" 23 | "github.com/cloudflare/circl/sign/mldsa/mldsa44" 24 | "github.com/cloudflare/circl/sign/mldsa/mldsa65" 25 | "github.com/cloudflare/circl/sign/mldsa/mldsa87" 26 | ) 27 | 28 | var allSchemes = [...]sign.Scheme{ 29 | ed25519.Scheme(), 30 | ed448.Scheme(), 31 | eddilithium2.Scheme(), 32 | eddilithium3.Scheme(), 33 | dilithium2.Scheme(), 34 | dilithium3.Scheme(), 35 | dilithium5.Scheme(), 36 | mldsa44.Scheme(), 37 | mldsa65.Scheme(), 38 | mldsa87.Scheme(), 39 | } 40 | 41 | var allSchemeNames map[string]sign.Scheme 42 | 43 | func init() { 44 | allSchemeNames = make(map[string]sign.Scheme) 45 | for _, scheme := range allSchemes { 46 | allSchemeNames[strings.ToLower(scheme.Name())] = scheme 47 | } 48 | } 49 | 50 | // ByName returns the scheme with the given name and nil if it is not 51 | // supported. 52 | // 53 | // Names are case insensitive. 54 | func ByName(name string) sign.Scheme { 55 | return allSchemeNames[strings.ToLower(name)] 56 | } 57 | 58 | // All returns all signature schemes supported. 59 | func All() []sign.Scheme { a := allSchemes; return a[:] } 60 | -------------------------------------------------------------------------------- /simd/doc.go: -------------------------------------------------------------------------------- 1 | // Package simd provides parallel implementations of some primitives. 2 | package simd 3 | -------------------------------------------------------------------------------- /simd/keccakf1600/f1600x2_arm64.go: -------------------------------------------------------------------------------- 1 | //go:build arm64 && go1.16 && !purego 2 | // +build arm64,go1.16,!purego 3 | 4 | package keccakf1600 5 | 6 | import "github.com/cloudflare/circl/internal/sha3" 7 | 8 | func permuteSIMDx2(state []uint64, turbo bool) { f1600x2ARM(&state[0], &sha3.RC, turbo) } 9 | 10 | func permuteSIMDx4(state []uint64, turbo bool) { permuteScalarX4(state, turbo) } 11 | 12 | //go:noescape 13 | func f1600x2ARM(state *uint64, rc *[24]uint64, turbo bool) 14 | -------------------------------------------------------------------------------- /simd/keccakf1600/f1600x4_amd64.go: -------------------------------------------------------------------------------- 1 | //go:build amd64 && !purego 2 | // +build amd64,!purego 3 | 4 | package keccakf1600 5 | 6 | import "github.com/cloudflare/circl/internal/sha3" 7 | 8 | func permuteSIMDx4(state []uint64, turbo bool) { f1600x4AVX2(&state[0], &sha3.RC, turbo) } 9 | 10 | func permuteSIMDx2(state []uint64, turbo bool) { permuteScalarX2(state, turbo) } 11 | -------------------------------------------------------------------------------- /simd/keccakf1600/f1600x4stubs_amd64.go: -------------------------------------------------------------------------------- 1 | // Code generated by command: go run src.go -out ../../f1600x4_amd64.s -stubs ../../f1600x4stubs_amd64.go -pkg keccakf1600. DO NOT EDIT. 2 | 3 | //go:build amd64 && !purego 4 | 5 | package keccakf1600 6 | 7 | //go:noescape 8 | func f1600x4AVX2(state *uint64, rc *[24]uint64, turbo bool) 9 | -------------------------------------------------------------------------------- /simd/keccakf1600/fallback.go: -------------------------------------------------------------------------------- 1 | //go:build (!amd64 && !arm64) || (arm64 && !go1.16) || purego 2 | // +build !amd64,!arm64 arm64,!go1.16 purego 3 | 4 | package keccakf1600 5 | 6 | func permuteSIMDx2(state []uint64, turbo bool) { permuteScalarX2(state, turbo) } 7 | 8 | func permuteSIMDx4(state []uint64, turbo bool) { permuteScalarX4(state, turbo) } 9 | -------------------------------------------------------------------------------- /simd/keccakf1600/internal/asm/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/cloudflare/circl/simd/keccakf1600/internal/asm 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/mmcloughlin/avo v0.5.0 7 | golang.org/x/tools v0.8.0 // indirect 8 | ) 9 | -------------------------------------------------------------------------------- /tss/doc.go: -------------------------------------------------------------------------------- 1 | // Package tss provides threshold signature schemes. 2 | package tss 3 | -------------------------------------------------------------------------------- /tss/rsa/README.md: -------------------------------------------------------------------------------- 1 | # RSA Threshold Signatures 2 | 3 | This is an implementation of ["Practical Threshold Signatures" by Victor Shoup](https://www.iacr.org/archive/eurocrypt2000/1807/18070209-new.pdf). 4 | Protocol 1 is implemented. 5 | 6 | ## Threshold Primer 7 | 8 | Let *l* be the total number of players, *t* be the number of corrupted players, and *k* be the threshold. 9 | The idea of threshold signatures is that at least *k* players need to participate to form a valid signature. 10 | 11 | Setup consists of a dealer generating *l* key shares from a key pair and "dealing" them to the players. In this implementation the dealer is trusted. 12 | 13 | During the signing phase, at least *k* players use their key share and the message to generate a signature share. 14 | Finally, the *k* signature shares are combined to form a valid signature for the message. 15 | 16 | ## Modifications 17 | 18 | 1. Our implementation is not robust. That is, the corrupted players can prevent a valid signature from being formed by the non-corrupted players. As such, we remove all verification. 19 | 2. The paper requires p and q to be safe primes. We do not. -------------------------------------------------------------------------------- /tss/rsa/padding.go: -------------------------------------------------------------------------------- 1 | package rsa 2 | 3 | import ( 4 | "crypto" 5 | "crypto/rsa" 6 | "io" 7 | 8 | "github.com/cloudflare/circl/tss/rsa/internal" 9 | pss2 "github.com/cloudflare/circl/tss/rsa/internal/pss" 10 | ) 11 | 12 | type Padder interface { 13 | Pad(pub *rsa.PublicKey, hash crypto.Hash, hashed []byte) ([]byte, error) 14 | } 15 | 16 | type PKCS1v15Padder struct{} 17 | 18 | func (PKCS1v15Padder) Pad(pub *rsa.PublicKey, hash crypto.Hash, hashed []byte) ([]byte, error) { 19 | return internal.PadPKCS1v15(pub, hash, hashed) 20 | } 21 | 22 | // PSSPadder is a padder for RSA Probabilistic Padding Scheme (RSA-PSS) used in TLS 1.3 23 | // 24 | // Note: If the salt length is non-zero, PSS padding is not deterministic. 25 | // TLS 1.3 mandates that the salt length is the same as the hash output length. As such, each player cannot 26 | // pad the message individually, otherwise they will produce unique messages and the signature will not be valid. 27 | // Instead, one party should generate a random saltLen byte string. When requesting signatures from the rest of the 28 | // parties they should send along the same random string to be used as `rand` here. 29 | // 30 | // For TLS, rsa.PSSOptions.SaltLength should be PSSSaltLengthEqualsHash. 31 | type PSSPadder struct { 32 | Rand io.Reader 33 | Opts *rsa.PSSOptions 34 | } 35 | 36 | func (pss *PSSPadder) Pad(pub *rsa.PublicKey, hash crypto.Hash, hashed []byte) ([]byte, error) { 37 | return pss2.PadPSS(pss.Rand, pub, hash, hashed, pss.Opts) 38 | } 39 | -------------------------------------------------------------------------------- /tss/rsa/util.go: -------------------------------------------------------------------------------- 1 | package rsa 2 | 3 | import ( 4 | "math/big" 5 | ) 6 | 7 | func calculateDelta(l int64) *big.Int { 8 | // ∆ = l! 9 | delta := big.Int{} 10 | delta.MulRange(1, l) 11 | return &delta 12 | } 13 | -------------------------------------------------------------------------------- /tss/rsa/util_test.go: -------------------------------------------------------------------------------- 1 | package rsa 2 | 3 | import ( 4 | "math/big" 5 | "testing" 6 | ) 7 | 8 | func TestCalculateDelta(t *testing.T) { 9 | ONE := big.NewInt(1) 10 | if calculateDelta(0).Cmp(ONE) != 0 { 11 | t.Fatal("calculateDelta failed on 0") 12 | } 13 | 14 | if calculateDelta(1).Cmp(ONE) != 0 { 15 | t.Fatal("calculateDelta failed on 1") 16 | } 17 | 18 | if calculateDelta(5).Cmp(big.NewInt(120)) != 0 { 19 | t.Fatal("calculateDelta failed on 5") 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /vdaf/doc.go: -------------------------------------------------------------------------------- 1 | // Package vdaf provides verifiable distributed aggregation functions. 2 | // 3 | // This package supports Prio3 as specified in [v13]. 4 | // [v13]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-13 5 | package vdaf 6 | -------------------------------------------------------------------------------- /vdaf/prio3/arith/fp128/inverse.go: -------------------------------------------------------------------------------- 1 | package fp128 2 | 3 | func (z *Fp) Inv(x *Fp) { 4 | // Addition chain found using mmcloughlin/addchain: v0.4.0 5 | // (McLoughlin, 2021). https://doi.org/10.5281/zenodo.4758226 6 | var t, t0, t1, t2 Fp 7 | t.Sqr(x) 8 | t.Mul(x, &t) 9 | t.Sqr(&t) 10 | t0.Mul(x, &t) 11 | t.Sqr(&t0) 12 | t1.sqri(&t, 3) 13 | t.Mul(&t, &t1) 14 | t.Mul(x, &t) 15 | t1.sqri(&t, 3) 16 | t2.sqri(&t1, 7) 17 | t1.Mul(&t1, &t2) 18 | t2.sqri(&t1, 14) 19 | t1.Mul(&t1, &t2) 20 | t2.sqri(&t1, 28) 21 | t1.Mul(&t1, &t2) 22 | t0.Mul(&t0, &t1) 23 | t1.sqri(&t0, 62) 24 | t0.Mul(&t0, &t1) 25 | t0.sqri(&t0, 7) 26 | z.Mul(&t, &t0) 27 | } 28 | -------------------------------------------------------------------------------- /vdaf/prio3/arith/fp128/poly.go: -------------------------------------------------------------------------------- 1 | // Code generated from ./templates/poly.go.tmpl. DO NOT EDIT. 2 | 3 | package fp128 4 | 5 | import "github.com/cloudflare/circl/math" 6 | 7 | type Poly []Fp 8 | 9 | func (p Poly) AddAssign(x Poly) { Vec(p).AddAssign(Vec(x)) } 10 | func (p Poly) SubAssign(x Poly) { Vec(p).SubAssign(Vec(x)) } 11 | func (p Poly) Mul(x, y Poly) { 12 | const thresholdPolyMul = 128 13 | if len(x)+len(y)-1 < thresholdPolyMul { 14 | p.MulNSquare(x, y) 15 | } else { 16 | p.MulNlogN(x, y) 17 | } 18 | } 19 | 20 | func (p Poly) MulNSquare(x, y Poly) { 21 | mustSumLen(p, x, y) 22 | clear(p) 23 | var xiyj Fp 24 | for i := range x { 25 | for j := range y { 26 | xiyj.Mul(&x[i], &y[j]) 27 | p[i+j].AddAssign(&xiyj) 28 | } 29 | } 30 | } 31 | 32 | func (p Poly) MulNlogN(x, y Poly) { 33 | mustSumLen(p, x, y) 34 | N, logN := math.NextPow2(uint(len(x) + len(y) - 1)) 35 | buf := make(Vec, 2*N) 36 | lx, ly := buf[:N], buf[N:] 37 | lx.NTT(Vec(x), N) 38 | ly.NTT(Vec(y), N) 39 | for i := range lx { 40 | lx[i].MulAssign(&ly[i]) 41 | } 42 | 43 | ly.InvNTT(lx, N) 44 | var invN Fp 45 | invN.InvTwoN(logN) 46 | copy(p, ly) 47 | Vec(p).ScalarMul(&invN) 48 | } 49 | 50 | func (p Poly) Sqr(x Poly) { 51 | mustSumLen(p, x, x) 52 | clear(p) 53 | for i := range x { 54 | p[2*i].Sqr(&x[i]) 55 | } 56 | 57 | var xixj Fp 58 | for i := 0; i < len(x); i++ { 59 | for j := i + 1; j < len(x); j++ { 60 | xixj.Mul(&x[i], &x[j]) 61 | xixj.AddAssign(&xixj) 62 | p[i+j].AddAssign(&xixj) 63 | } 64 | } 65 | } 66 | 67 | func (p Poly) Evaluate(x *Fp) (px Fp) { 68 | if l := len(p); l != 0 { 69 | px = p[l-1] 70 | for i := l - 2; i >= 0; i-- { 71 | px.MulAssign(x) 72 | px.AddAssign(&p[i]) 73 | } 74 | } 75 | 76 | return 77 | } 78 | 79 | func (p Poly) Strip() Poly { 80 | for i := len(p) - 1; i >= 0; i-- { 81 | if !p[i].IsZero() { 82 | return p[:i+1] 83 | } 84 | } 85 | 86 | return p[:0] 87 | } 88 | -------------------------------------------------------------------------------- /vdaf/prio3/arith/fp128_test.go: -------------------------------------------------------------------------------- 1 | // Code generated from ./templates/field_test.go.tmpl. DO NOT EDIT. 2 | 3 | package arith 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/cloudflare/circl/vdaf/prio3/arith/fp128" 9 | ) 10 | 11 | func TestFp128(t *testing.T) { 12 | t.Run("Fp", testFp[fp128.Fp]) 13 | t.Run("Vec", testVec[fp128.Vec]) 14 | t.Run("Poly", testPoly[fp128.Poly, fp128.Vec]) 15 | } 16 | 17 | func BenchmarkFp128(b *testing.B) { 18 | b.Run("Fp", benchmarkFp[fp128.Fp]) 19 | b.Run("Vec", benchmarkVec[fp128.Vec]) 20 | b.Run("Poly", benchmarkPoly[fp128.Poly, fp128.Vec]) 21 | } 22 | -------------------------------------------------------------------------------- /vdaf/prio3/arith/fp64/inverse.go: -------------------------------------------------------------------------------- 1 | package fp64 2 | 3 | func (z *Fp) Inv(x *Fp) { 4 | // Addition chain found using mmcloughlin/addchain: v0.4.0 5 | // (McLoughlin, 2021). https://doi.org/10.5281/zenodo.4758226 6 | var t, t0, t1 Fp 7 | t.Sqr(x) 8 | t.Mul(x, &t) 9 | t.Sqr(&t) 10 | t.Mul(x, &t) 11 | t0.sqri(&t, 3) 12 | t0.Mul(&t, &t0) 13 | t1.Sqr(&t0) 14 | t.Mul(x, &t1) 15 | t1.sqri(&t1, 5) 16 | t0.Mul(&t0, &t1) 17 | t1.sqri(&t0, 12) 18 | t0.Mul(&t0, &t1) 19 | t0.sqri(&t0, 7) 20 | t.Mul(&t, &t0) 21 | t0.sqri(&t, 32) 22 | t.Mul(&t, &t0) 23 | t.Sqr(&t) 24 | z.Mul(x, &t) 25 | } 26 | -------------------------------------------------------------------------------- /vdaf/prio3/arith/fp64/poly.go: -------------------------------------------------------------------------------- 1 | // Code generated from ./templates/poly.go.tmpl. DO NOT EDIT. 2 | 3 | package fp64 4 | 5 | import "github.com/cloudflare/circl/math" 6 | 7 | type Poly []Fp 8 | 9 | func (p Poly) AddAssign(x Poly) { Vec(p).AddAssign(Vec(x)) } 10 | func (p Poly) SubAssign(x Poly) { Vec(p).SubAssign(Vec(x)) } 11 | func (p Poly) Mul(x, y Poly) { 12 | const thresholdPolyMul = 128 13 | if len(x)+len(y)-1 < thresholdPolyMul { 14 | p.MulNSquare(x, y) 15 | } else { 16 | p.MulNlogN(x, y) 17 | } 18 | } 19 | 20 | func (p Poly) MulNSquare(x, y Poly) { 21 | mustSumLen(p, x, y) 22 | clear(p) 23 | var xiyj Fp 24 | for i := range x { 25 | for j := range y { 26 | xiyj.Mul(&x[i], &y[j]) 27 | p[i+j].AddAssign(&xiyj) 28 | } 29 | } 30 | } 31 | 32 | func (p Poly) MulNlogN(x, y Poly) { 33 | mustSumLen(p, x, y) 34 | N, logN := math.NextPow2(uint(len(x) + len(y) - 1)) 35 | buf := make(Vec, 2*N) 36 | lx, ly := buf[:N], buf[N:] 37 | lx.NTT(Vec(x), N) 38 | ly.NTT(Vec(y), N) 39 | for i := range lx { 40 | lx[i].MulAssign(&ly[i]) 41 | } 42 | 43 | ly.InvNTT(lx, N) 44 | var invN Fp 45 | invN.InvTwoN(logN) 46 | copy(p, ly) 47 | Vec(p).ScalarMul(&invN) 48 | } 49 | 50 | func (p Poly) Sqr(x Poly) { 51 | mustSumLen(p, x, x) 52 | clear(p) 53 | for i := range x { 54 | p[2*i].Sqr(&x[i]) 55 | } 56 | 57 | var xixj Fp 58 | for i := 0; i < len(x); i++ { 59 | for j := i + 1; j < len(x); j++ { 60 | xixj.Mul(&x[i], &x[j]) 61 | xixj.AddAssign(&xixj) 62 | p[i+j].AddAssign(&xixj) 63 | } 64 | } 65 | } 66 | 67 | func (p Poly) Evaluate(x *Fp) (px Fp) { 68 | if l := len(p); l != 0 { 69 | px = p[l-1] 70 | for i := l - 2; i >= 0; i-- { 71 | px.MulAssign(x) 72 | px.AddAssign(&p[i]) 73 | } 74 | } 75 | 76 | return 77 | } 78 | 79 | func (p Poly) Strip() Poly { 80 | for i := len(p) - 1; i >= 0; i-- { 81 | if !p[i].IsZero() { 82 | return p[:i+1] 83 | } 84 | } 85 | 86 | return p[:0] 87 | } 88 | -------------------------------------------------------------------------------- /vdaf/prio3/arith/fp64_test.go: -------------------------------------------------------------------------------- 1 | // Code generated from ./templates/field_test.go.tmpl. DO NOT EDIT. 2 | 3 | package arith 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/cloudflare/circl/vdaf/prio3/arith/fp64" 9 | ) 10 | 11 | func TestFp64(t *testing.T) { 12 | t.Run("Fp", testFp[fp64.Fp]) 13 | t.Run("Vec", testVec[fp64.Vec]) 14 | t.Run("Poly", testPoly[fp64.Poly, fp64.Vec]) 15 | } 16 | 17 | func BenchmarkFp64(b *testing.B) { 18 | b.Run("Fp", benchmarkFp[fp64.Fp]) 19 | b.Run("Vec", benchmarkVec[fp64.Vec]) 20 | b.Run("Poly", benchmarkPoly[fp64.Poly, fp64.Vec]) 21 | } 22 | -------------------------------------------------------------------------------- /vdaf/prio3/arith/templates/fp_test.go.tmpl: -------------------------------------------------------------------------------- 1 | // +build ignore 2 | // The previous line (and this one up to the warning below) is removed by the 3 | // template generator. 4 | 5 | // Code generated from ./templates/field_test.go.tmpl. DO NOT EDIT. 6 | 7 | package arith 8 | 9 | import ( 10 | "testing" 11 | 12 | "github.com/cloudflare/circl/vdaf/prio3/arith/{{.Name | ToLower}}" 13 | ) 14 | 15 | func Test{{.Name}}(t *testing.T) { 16 | t.Run("Fp", testFp[{{.Name | ToLower}}.Fp]) 17 | t.Run("Vec", testVec[{{.Name | ToLower}}.Vec]) 18 | t.Run("Poly",testPoly[{{.Name | ToLower}}.Poly, {{.Name | ToLower}}.Vec]) 19 | } 20 | 21 | func Benchmark{{.Name}}(b *testing.B) { 22 | b.Run("Fp", benchmarkFp[{{.Name | ToLower}}.Fp]) 23 | b.Run("Vec", benchmarkVec[{{.Name | ToLower}}.Vec]) 24 | b.Run("Poly", benchmarkPoly[{{.Name | ToLower}}.Poly, {{.Name | ToLower}}.Vec]) 25 | } 26 | -------------------------------------------------------------------------------- /vdaf/prio3/arith/templates/poly.go.tmpl: -------------------------------------------------------------------------------- 1 | // +build ignore 2 | // The previous line (and this one up to the warning below) is removed by the 3 | // template generator. 4 | 5 | // Code generated from ./templates/poly.go.tmpl. DO NOT EDIT. 6 | 7 | package {{.Name | ToLower}} 8 | 9 | import "github.com/cloudflare/circl/math" 10 | 11 | type Poly []Fp 12 | 13 | func (p Poly) AddAssign(x Poly) { Vec(p).AddAssign(Vec(x)) } 14 | func (p Poly) SubAssign(x Poly) { Vec(p).SubAssign(Vec(x)) } 15 | func (p Poly) Mul(x, y Poly) { 16 | const thresholdPolyMul = 128 17 | if len(x) + len(y) - 1 < thresholdPolyMul { 18 | p.MulNSquare(x, y) 19 | } else{ 20 | p.MulNlogN(x, y) 21 | } 22 | } 23 | 24 | func (p Poly) MulNSquare(x, y Poly) { 25 | mustSumLen(p, x, y) 26 | clear(p) 27 | var xiyj Fp 28 | for i := range x { 29 | for j := range y { 30 | xiyj.Mul(&x[i], &y[j]) 31 | p[i+j].AddAssign(&xiyj) 32 | } 33 | } 34 | } 35 | 36 | func (p Poly) MulNlogN(x, y Poly) { 37 | mustSumLen(p, x, y) 38 | N, logN := math.NextPow2(uint(len(x) + len(y) - 1)) 39 | buf := make(Vec, 2*N) 40 | lx, ly := buf[:N], buf[N:] 41 | lx.NTT(Vec(x), N) 42 | ly.NTT(Vec(y), N) 43 | for i := range lx { 44 | lx[i].MulAssign(&ly[i]) 45 | } 46 | 47 | ly.InvNTT(lx, N) 48 | var invN Fp 49 | invN.InvTwoN(logN) 50 | copy(p, ly) 51 | Vec(p).ScalarMul(&invN) 52 | } 53 | 54 | func (p Poly) Sqr(x Poly) { 55 | mustSumLen(p, x, x) 56 | clear(p) 57 | for i := range x { 58 | p[2*i].Sqr(&x[i]) 59 | } 60 | 61 | var xixj Fp 62 | for i := 0; i < len(x); i++ { 63 | for j := i + 1; j < len(x); j++ { 64 | xixj.Mul(&x[i], &x[j]) 65 | xixj.AddAssign(&xixj) 66 | p[i+j].AddAssign(&xixj) 67 | } 68 | } 69 | } 70 | 71 | func (p Poly) Evaluate(x *Fp) (px Fp) { 72 | if l := len(p); l != 0 { 73 | px = p[l-1] 74 | for i := l - 2; i >= 0; i-- { 75 | px.MulAssign(x) 76 | px.AddAssign(&p[i]) 77 | } 78 | } 79 | 80 | return 81 | } 82 | 83 | func (p Poly) Strip() Poly { 84 | for i := len(p) - 1; i >= 0; i-- { 85 | if !p[i].IsZero() { 86 | return p[:i+1] 87 | } 88 | } 89 | 90 | return p[:0] 91 | } 92 | 93 | -------------------------------------------------------------------------------- /vdaf/prio3/count/count_test.go: -------------------------------------------------------------------------------- 1 | package count 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/cloudflare/circl/vdaf/prio3/internal/flp_test" 7 | ) 8 | 9 | func TestCount(t *testing.T) { 10 | t.Run("Query", func(t *testing.T) { 11 | c := newFlpCount() 12 | flp_test.TestInvalidQuery(t, &c.FLP) 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /vdaf/prio3/doc.go: -------------------------------------------------------------------------------- 1 | // Package prio3 implements Prio3, a set of Verifiable Distributed 2 | // Aggregation Functions (VDAFs). It provides several concrete VDAFs 3 | // described in draft-irtf-cfrg-vdaf [v14]: 4 | // - Count [github.com/cloudflare/circl/vdaf/prio3/count] 5 | // - Sum [github.com/cloudflare/circl/vdaf/prio3/sum] 6 | // - SumVec [github.com/cloudflare/circl/vdaf/prio3/sumvec] 7 | // - Histogram [github.com/cloudflare/circl/vdaf/prio3/mhcv] 8 | // - MultiHotCountVec [github.com/cloudflare/circl/vdaf/prio3/histogram] 9 | // 10 | // [v14]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-vdaf-14 11 | package prio3 12 | -------------------------------------------------------------------------------- /vdaf/prio3/histogram/histogram_test.go: -------------------------------------------------------------------------------- 1 | package histogram 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/cloudflare/circl/vdaf/prio3/internal/flp_test" 7 | ) 8 | 9 | func TestHistogram(t *testing.T) { 10 | t.Run("Query", func(t *testing.T) { 11 | h := newFlpHistogram(4, 3) 12 | flp_test.TestInvalidQuery(t, &h.FLP) 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /vdaf/prio3/internal/cursor/cursor.go: -------------------------------------------------------------------------------- 1 | // Package cursor aids with iteration of slices. 2 | package cursor 3 | 4 | type Cursor[V ~[]E, E any] []E 5 | 6 | func New[V ~[]E, E any](x V) Cursor[V, E] { return Cursor[V, E](x) } 7 | 8 | // Next return an slice of size n and advances the pointer. 9 | func (s *Cursor[V, E]) Next(n uint) (out V) { 10 | if uint(len(*s)) >= n { 11 | out = V(*s)[:n] 12 | *s = (*s)[n:] 13 | } 14 | return 15 | } 16 | -------------------------------------------------------------------------------- /vdaf/prio3/internal/flp_test/query.go: -------------------------------------------------------------------------------- 1 | package flp_test 2 | 3 | import ( 4 | "errors" 5 | "testing" 6 | 7 | "github.com/cloudflare/circl/internal/sha3" 8 | "github.com/cloudflare/circl/internal/test" 9 | "github.com/cloudflare/circl/math" 10 | "github.com/cloudflare/circl/vdaf/prio3/arith" 11 | "github.com/cloudflare/circl/vdaf/prio3/internal/flp" 12 | ) 13 | 14 | func TestInvalidQuery[ 15 | G flp.Gadget[P, V, E, F], 16 | P arith.Poly[P, E], V arith.Vec[V, E], E arith.Elt, F arith.Fp[E], 17 | ](t *testing.T, f *flp.FLP[G, P, V, E, F]) { 18 | const NumShares = 2 19 | measShare := arith.NewVec[V](f.MeasurementLength()) 20 | proofShare := arith.NewVec[V](f.ProofLength()) 21 | queryRand := arith.NewVec[V](f.QueryRandLength()) 22 | jointRand := arith.NewVec[V](f.JointRandLength()) 23 | 24 | s := sha3.NewShake128() 25 | test.CheckNoErr(t, measShare.Random(&s), "measShare random failed") 26 | test.CheckNoErr(t, proofShare.Random(&s), "proofShare random failed") 27 | test.CheckNoErr(t, queryRand.Random(&s), "queryRand random failed") 28 | test.CheckNoErr(t, jointRand.Random(&s), "jointRand random failed") 29 | 30 | var index uint 31 | if f.EvalOutputLength() > 1 { 32 | index = f.EvalOutputLength() 33 | } 34 | 35 | invalidEvaluationPoint := F(&queryRand[index]) 36 | _, logP := math.NextPow2(1 + f.Valid.NumGadgetCalls) 37 | root := F(new(E)) 38 | // Check all subgroups of order 2^logN <= 2^logP. 39 | for logN := range logP + 1 { 40 | root.SetRootOfUnityTwoN(logN) 41 | invalidEvaluationPoint.SetOne() 42 | // Check every element in the subgroup of order 2^logN. 43 | for range 1 << logN { 44 | _, err := f.Query(measShare, proofShare, queryRand, jointRand, NumShares) 45 | if !errors.Is(err, flp.ErrInvalidEval) { 46 | test.ReportError(t, err, flp.ErrInvalidEval) 47 | } 48 | 49 | invalidEvaluationPoint.MulAssign(root) 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /vdaf/prio3/mhcv/mhcv_test.go: -------------------------------------------------------------------------------- 1 | package mhcv 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/cloudflare/circl/internal/test" 7 | "github.com/cloudflare/circl/vdaf/prio3/internal/flp_test" 8 | ) 9 | 10 | func TestMhcv(t *testing.T) { 11 | t.Run("Query", func(t *testing.T) { 12 | const MaxWeight = 2 13 | m, err := newFlpMultiCountHotVec(5, MaxWeight, 3) 14 | test.CheckNoErr(t, err, "new flp failed") 15 | flp_test.TestInvalidQuery(t, &m.FLP) 16 | }) 17 | } 18 | -------------------------------------------------------------------------------- /vdaf/prio3/sum/sum_test.go: -------------------------------------------------------------------------------- 1 | package sum 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/cloudflare/circl/internal/test" 7 | "github.com/cloudflare/circl/vdaf/prio3/internal/flp_test" 8 | ) 9 | 10 | func TestSum(t *testing.T) { 11 | t.Run("Query", func(t *testing.T) { 12 | const MaxMeas = 4 13 | s, err := newFlpSum(MaxMeas) 14 | test.CheckNoErr(t, err, "new flp failed") 15 | flp_test.TestInvalidQuery(t, &s.FLP) 16 | }) 17 | } 18 | -------------------------------------------------------------------------------- /vdaf/prio3/sumvec/sumvec_test.go: -------------------------------------------------------------------------------- 1 | package sumvec 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/cloudflare/circl/internal/test" 7 | "github.com/cloudflare/circl/vdaf/prio3/internal/flp_test" 8 | ) 9 | 10 | func TestSumVec(t *testing.T) { 11 | t.Run("Query", func(t *testing.T) { 12 | s, err := newFlpSumVec(4, 4, 3) 13 | test.CheckNoErr(t, err, "new flp failed") 14 | flp_test.TestInvalidQuery(t, &s.FLP) 15 | }) 16 | } 17 | -------------------------------------------------------------------------------- /vdaf/prio3/testdata/Prio3Count_0.json: -------------------------------------------------------------------------------- 1 | { 2 | "agg_param": "", 3 | "agg_result": 1, 4 | "agg_shares": [ 5 | "e369056891a9fd95", 6 | "1f96fa976d56026a" 7 | ], 8 | "ctx": "736f6d65206170706c69636174696f6e", 9 | "prep": [ 10 | { 11 | "input_shares": [ 12 | "e369056891a9fd95d44e6fadb3b75e6774b666d312bcc59b57694d189321ffe06f46b37d26db61d056b17152e3726a2e", 13 | "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" 14 | ], 15 | "measurement": 1, 16 | "nonce": "000102030405060708090a0b0c0d0e0f", 17 | "out_shares": [ 18 | [ 19 | "e369056891a9fd95" 20 | ], 21 | [ 22 | "1f96fa976d56026a" 23 | ] 24 | ], 25 | "prep_messages": [ 26 | "" 27 | ], 28 | "prep_shares": [ 29 | [ 30 | "5c6a0685bd0f0aa9b19b8c1c4431ec49eca02338e5e05da8fc91575311627200", 31 | "a595f97a41f0f5565abc07086ef01d5b3cb2629a3c534bd4dbd8f5187ad75aad" 32 | ] 33 | ], 34 | "public_share": "", 35 | "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f" 36 | } 37 | ], 38 | "shares": 2, 39 | "verify_key": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" 40 | } 41 | -------------------------------------------------------------------------------- /vdaf/prio3/testdata/Prio3Count_1.json: -------------------------------------------------------------------------------- 1 | { 2 | "agg_param": "", 3 | "agg_result": 1, 4 | "agg_shares": [ 5 | "afccf0c22c8901be", 6 | "1f96fa976d56026a", 7 | "359d14a56320fcd7" 8 | ], 9 | "ctx": "736f6d65206170706c69636174696f6e", 10 | "prep": [ 11 | { 12 | "input_shares": [ 13 | "afccf0c22c8901be040bc9d44987fd40085bf595185a34267ec8e975e8fdfa331abaaecc9d7104785e186102448192ad", 14 | "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 15 | "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f" 16 | ], 17 | "measurement": 1, 18 | "nonce": "000102030405060708090a0b0c0d0e0f", 19 | "out_shares": [ 20 | [ 21 | "afccf0c22c8901be" 22 | ], 23 | [ 24 | "1f96fa976d56026a" 25 | ], 26 | [ 27 | "359d14a56320fcd7" 28 | ] 29 | ], 30 | "prep_messages": [ 31 | "" 32 | ], 33 | "prep_shares": [ 34 | [ 35 | "145aabe8608487ab66ff1e11a196662b0d268a8dbd2b01481daf7d190bf1b0b6", 36 | "a595f97a41f0f5565abc07086ef01d5b3cb2629a3c534bd4dbd8f5187ad75aad", 37 | "49105b9c5b8b82fd30916e72506a0c5679b07c05a3255a85103f30cfd5ab310e" 38 | ] 39 | ], 40 | "public_share": "", 41 | "rand": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f" 42 | } 43 | ], 44 | "shares": 3, 45 | "verify_key": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" 46 | } 47 | -------------------------------------------------------------------------------- /vdaf/prio3/testdata/XofTurboShake128.json: -------------------------------------------------------------------------------- 1 | { 2 | "binder": "62696e64657220737472696e67", 3 | "derived_seed": "b62ef0a2778190792d4d42d8c167ba20e0c37a3f319ba79645829c427d70eea5", 4 | "dst": "646f6d61696e2073657061726174696f6e20746167", 5 | "expanded_vec_field128": "b62ef0a2778190792d4d42d8c167ba20e0c37a3f319ba79645829c427d70eea56d92fef65a07b17a0438e25452cdc7f15f63caf0e8a2a3c72ac69524729e64e03c7ec3a3afa7eb21cb6da6abf0a3b73630a91a5fa05dcbd33da3476f1c8bf4fd66fe5a80dd04bc95f0f02cb8fc9035b9e16e3a5c373bf81c820af513e0c832ca672c66dcc3b302fb8b27a48f09e0a843f5caf87b3c6c1c4b6765b5923e1d152c2e695601abbc69dbe810860fb30e871a2549861110672335ce50ee632264cbb21f62595298d1d1ad9303b84664801e52112989dfce93f0f9dc833ee0f4a0672ffe47cb0a13f80f9e9b7a2e267db7f7890ccd064bf2458cd4e27162d13e60dbc1b6cae71635a3e603f2c15d1c64a12d4e8235f7bf0a8efe6bb15f3e2adae06f7dd1c4d63ac6cecae731250f73c063c6e59aef630a7b6f4bc64bddadc8b8a479bfdb64ea31e6ab44540a52a8d3399d64a060d50190d66cac1335d739e5f8d508201058a2e0cc1ed90e23cfdc7a253f24710ef3b1604688606386dcc4c90e8476be9daac3271ac51301868df71a719a5f32184145d70fec31b4693d527f53875a2ea013523d3daa33bc49c22f66c9ae70dd7f06f227f50515ea9ab1fbe0162cf761e596d8999809cf672cd2d82b22231f841c36e494d7e44f7c6f07e29758b1b73ce95b202325116f04067a54aa767eab2e00ce55b3abcd5c3d5b05040a6bf5d4ba8a61267004bb82b12d43b08fed8f9aced3e833a58fc01004526631b0f4192d8754a397e1096511ee23761a29fcd6511ad2e5020683ca877e4075fe6bc5907f7df1ed4b6c97e0f897d781e850da0cf584842c124cdb6011fe8660e3b8c354cd659985332ea158ffcba83253d39803fa7efb9fcd02cea38089f239f68404814973", 6 | "length": 40, 7 | "seed": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" 8 | } 9 | -------------------------------------------------------------------------------- /zk/dl/dl_test.go: -------------------------------------------------------------------------------- 1 | package dl_test 2 | 3 | import ( 4 | "crypto/rand" 5 | "testing" 6 | 7 | "github.com/cloudflare/circl/group" 8 | "github.com/cloudflare/circl/zk/dl" 9 | ) 10 | 11 | const testzkDLCount = 1 << 8 12 | 13 | func testzkDL(t *testing.T, myGroup group.Group) { 14 | kA := myGroup.RandomNonZeroScalar(rand.Reader) 15 | DB := myGroup.RandomElement(rand.Reader) 16 | 17 | R := myGroup.NewElement() 18 | R.Mul(DB, kA) 19 | 20 | dst := "zeroknowledge" 21 | rnd := rand.Reader 22 | proof := dl.Prove(myGroup, DB, R, kA, []byte("Prover"), []byte(dst), rnd) 23 | 24 | verify := dl.Verify(myGroup, DB, R, proof, []byte("Prover"), []byte(dst)) 25 | if verify == false { 26 | t.Error("zk/dl verification failed") 27 | } 28 | } 29 | 30 | func testzkDLNegative(t *testing.T, myGroup group.Group) { 31 | kA := myGroup.RandomNonZeroScalar(rand.Reader) 32 | DB := myGroup.RandomElement(rand.Reader) 33 | 34 | R := myGroup.RandomElement(rand.Reader) 35 | 36 | dst := "zeroknowledge" 37 | rnd := rand.Reader 38 | proof := dl.Prove(myGroup, DB, R, kA, []byte("Prover"), []byte(dst), rnd) 39 | 40 | verify := dl.Verify(myGroup, DB, R, proof, []byte("Prover"), []byte(dst)) 41 | if verify == true { 42 | t.Error("zk/dl verification should fail") 43 | } 44 | } 45 | 46 | func TestZKDL(t *testing.T) { 47 | t.Run("zkDL", func(t *testing.T) { 48 | for i := 0; i < testzkDLCount; i++ { 49 | currGroup := group.P256 50 | testzkDL(t, currGroup) 51 | } 52 | }) 53 | 54 | t.Run("zkDLNegative", func(t *testing.T) { 55 | for i := 0; i < testzkDLCount; i++ { 56 | currGroup := group.P256 57 | testzkDLNegative(t, currGroup) 58 | } 59 | }) 60 | } 61 | -------------------------------------------------------------------------------- /zk/doc.go: -------------------------------------------------------------------------------- 1 | // Package zk provides primitives for zero-knowledge proofs of knowledge. 2 | package zk 3 | --------------------------------------------------------------------------------