Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file ec_pbt.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544openMec_curve_sigletrecrepeatnf()=ifn>0then(f();repeat(n-1)f())moduleMakeEquality(G:Ec_sig.BASE)=struct(** Verify the equality is correct with the value zero *)letzero()=assert(G.eqG.zeroG.zero)(** Verify the equality is correct with the value one *)letone()=assert(G.eqG.oneG.one)(** Verify the equality of two random values created invidually *)letrandom_same_objects()=letrandom=G.random()inassert(G.eqrandomrandom)(** Returns the tests to be used with Alcotest *)letget_tests()=letopenAlcotestin("equality",[test_case"zero"`Quick(repeat1zero);test_case"one"`Quick(repeat1one);test_case"random_same_objects"`Quick(repeat100random_same_objects)])endmoduleMakeValueGeneration(G:Ec_sig.BASE)=structletrandom()=ignore@@G.random()letnegation_with_random()=letrandom=G.random()inignore@@G.negaterandomletnegation_with_zero()=ignore@@G.negateG.zeroletnegation_with_one()=ignore@@G.negateG.oneletdouble_with_zero()=ignore@@G.doubleG.zeroletdouble_with_one()=ignore@@G.doubleG.oneletdouble_with_random()=letg=G.random()inignore@@G.doublegletaddition_generates_valid_point()=assert(G.(check_bytes(to_bytes(add(random())(random())))))letdouble_generates_valid_point()=assert(G.(check_bytes(to_bytes(double(random())))))letscalar_multiplication_generates_valid_point()=assert(G.(check_bytes(to_bytes(mul(random())(Scalar.random())))))letcheck_bytes_random_with_to_bytes()=letg=G.random()inassert(G.(check_bytes(to_bytesg)))letnegate_generates_a_valid_point()=letg=G.random()inassert(G.(check_bytes(to_bytes(negateg))))letof_bytes_with_to_bytes_are_inverse_functions()=letg=G.random()inassert(G.(eq(of_bytes_exn(to_bytesg))g))(** Returns the tests to be used with Alcotest *)letget_tests()=letopenAlcotestin("value generation",[test_case"random"`Quick(repeat100random);test_case"negate_with_one"`Quick(repeat1negation_with_one);test_case"negate_with_zero"`Quick(repeat1negation_with_zero);test_case"negate_with_random"`Quick(repeat100negation_with_random);test_case"double_with_random"`Quick(repeat100double_with_random);test_case"negate generates a valid point"`Quick(repeat100negate_generates_a_valid_point);test_case"addition generates a valid point"`Quick(repeat100addition_generates_valid_point);test_case"double generates a valid point"`Quick(repeat100double_generates_valid_point);test_case"scalar multiplication generates a valid point"`Quick(repeat100scalar_multiplication_generates_valid_point);test_case"of_bytes_exn and to_bytes are inverse functions"`Quick(repeat100of_bytes_with_to_bytes_are_inverse_functions);test_case"check bytes on random with to_bytes"`Quick(repeat100check_bytes_random_with_to_bytes);test_case"double_with_one"`Quick(repeat1double_with_one);test_case"double_with_zero"`Quick(repeat100double_with_zero)])endmoduleMakeIsZero(G:Ec_sig.BASE)=structletwith_zero_value()=assert(G.is_zeroG.zero=true)letwith_one_value()=assert(G.is_zeroG.one=false)letwith_random_value()=assert(G.is_zero(G.random())=false)(** Returns the tests to be used with Alcotest *)letget_tests()=letopenAlcotestin("is_zero",[test_case"with zero value"`Quick(repeat1with_zero_value);test_case"with one value"`Quick(repeat1with_one_value);test_case"with random value"`Quick(repeat100with_random_value)])endmoduleMakeECProperties(G:Ec_sig.BASE)=struct(** Verify that a random point is valid *)letcheck_bytes_random()=assert(G.(check_bytes@@to_bytes@@random()))(** Verify that the zero point is valid *)letcheck_bytes_zero()=assert(G.(check_bytes@@to_bytes@@zero))(** Verify that the fixed generator point is valid *)letcheck_bytes_one()=assert(G.(check_bytes@@to_bytes@@one))(** Verify that doubling a random point gives a valid point *)letcheck_bytes_random_double()=assert(G.(check_bytes@@to_bytes@@double(random())))(** Verify that the sum of random points is valid *)letcheck_bytes_random_sum()=assert(G.(check_bytes@@to_bytes@@add(random())(random())))(** Verify that multiplying a random point by a scalar gives a valid point *)letcheck_bytes_random_multiplication()=assert(G.(check_bytes@@to_bytes@@mul(random())(Scalar.random())))(** Verify 0_S * g_EC = 0_EC where 0_S is the zero of the scalar field, 0_EC
is the point at infinity and g_EC is an element of the EC *)letzero_scalar_nullifier_random()=letrandom=G.random()inassert(G.is_zero(G.mulrandomG.Scalar.zero))(** Verify 0_S * 0_EC = 0_EC where 0_S is the zero of the scalar field and
0_EC is the point at infinity of the EC *)letzero_scalar_nullifier_zero()=assert(G.is_zero(G.mulG.zeroG.Scalar.zero))(** Verify 0_S * 1_EC = 0_EC where 0_S is the 0 of the scalar field, 1_EC is a
fixed generator and 0_EC is the point at infinity of the EC *)letzero_scalar_nullifier_one()=assert(G.is_zero(G.mulG.oneG.Scalar.zero))letmultiply_by_one_does_nothing()=letg=G.random()inassert(G.(eq(mulgScalar.one)g))(** Verify -(-g) = g where g is an element of the EC *)letopposite_of_opposite()=letrandom=G.random()inassert(G.eq(G.negate(G.negaterandom))random)letopposite_of_opposite_using_scalar()=letr=G.random()inassert(G.(eqr(mulr(Scalar.negate(Scalar.negateScalar.one)))))(** Verify -(-0_EC) = 0_EC where 0_EC is the point at infinity of the EC *)letopposite_of_zero_is_zero()=assert(G.eq(G.negateG.zero)G.zero)(** Verify -(-0_EC) = 0_EC where 0_EC is the point at infinity of the EC *)letopposite_of_opposite_of_zero_is_zero()=assert(G.eq(G.negate(G.negateG.zero))G.zero)(** Verify -(-0_EC) = 0_EC where 0_EC is the point at infinity of the EC *)letopposite_of_opposite_of_one_is_one()=assert(G.eq(G.negate(G.negateG.one))G.one)(** Verify g1 + (g2 + g3) = (g1 + g2) + g3 *)letadditive_associativity()=letg1=G.random()inletg2=G.random()inletg3=G.random()inassert(G.eq(G.add(G.addg1g2)g3)(G.addg1(G.addg2g3)))(** Verify (g1 + g2) = (g2 + g1) *)letadditive_commutativity()=letg1=G.random()inletg2=G.random()inassert(G.eq(G.addg1g2)(G.addg2g1))(** Verify that g + (-g) = 0 *)letopposite_existential_property()=letg=G.random()inassert(G.(eq(addg(negateg))zero))(** Verify a (g1 + g2) = a * g1 + a * g2 where a is a scalar, g1, g2 two
elements of the EC *)letdistributivity()=lets=G.Scalar.random()inletg1=G.random()inletg2=G.random()inassert(G.eq(G.mul(G.addg1g2)s)(G.add(G.mulg1s)(G.mulg2s)))(** Verify (a + -a) * g = a * g - a * g = 0 *)letopposite_equality()=leta=G.Scalar.random()inletg=G.random()inassert(G.(eq(mulg(Scalar.adda(Scalar.negatea)))zero));assert(G.(eqzero(add(mulga)(mulg(Scalar.negatea)))));assert(G.(eq(mulg(Scalar.adda(Scalar.negatea)))(add(mulga)(mulg(Scalar.negatea)))))(** a g + b + g = (a + b) g*)letadditive_associativity_with_scalar()=leta=G.Scalar.random()inletb=G.Scalar.random()inletg=G.random()inletleft=G.(add(mulga)(mulgb))inletright=G.(mulg(Scalar.addab))inassert(G.(eqleftright))(** (a * b) g = a (b g) = b (a g) *)letmultiplication_properties_on_base_field_element()=leta=G.Scalar.random()inletb=G.Scalar.random()inletg=G.random()inassert(G.(eq(mulg(Scalar.mulab))(mul(mulga)b)));assert(G.(eq(mulg(Scalar.mulab))(mul(mulgb)a)))(** Verify (-s) * g = s * (-g) *)letopposite_of_scalar_is_opposite_of_ec()=lets=G.Scalar.random()inletg=G.random()inletleft=G.mulg(G.Scalar.negates)inletright=G.mul(G.negateg)sinassert(G.eqleftright)letgenerator_is_of_prime_order()=assert(G.(eq(mulone(G.Scalar.of_zG.Scalar.order))zero))letmul_by_order_of_scalar_field_equals_zero()=lets=G.Scalar.random()inletg=G.random()in(* (g * s) * order = zero *)assert(G.(eq(mul(mulgs)(G.Scalar.of_zG.Scalar.order))zero));(* (one * s) * order = zero *)assert(G.(eq(mul(mulones)(G.Scalar.of_zG.Scalar.order))zero))(** Verify 2*g = g + g *)letdouble()=lets=G.random()inassert(G.(eq(doubles)(addss)))letinverse_on_scalar()=letg=G.random()inleta=G.Scalar.random()inletinv_a=G.Scalar.inverse_exnainletga=G.mulgainletga_inv=G.mulginv_ain(* g * (a * a^(-1)) *)letres1=G.mulg(G.Scalar.mulinv_aa)in(* (g * a^(-1)) * a *)letres2=G.mulga_invain(* (g * a) * a^(-1) *)letres3=G.mulgainv_ainassert(G.(eqres2res3));(* g * (a * a^(-1)) = g *)assert(G.(eqres1g));(* (g * a^(-1)) * a = g *)assert(G.(eqres2g));(* (g * a) * a^(-1) = g *)assert(G.(eqres3g))letzero_is_the_identity()=letg=G.random()inassert(G.(eq(addgzero)(addzerog)));assert(G.(eq(addgzero)g))(** Returns the tests to be used with Alcotest *)letget_tests()=letopenAlcotestin("Group properties",[test_case"check_bytes_random"`Quick(repeat100check_bytes_random);test_case"check_bytes_zero"`Quick(repeat1check_bytes_zero);test_case"check_bytes_one"`Quick(repeat1check_bytes_one);test_case"check_bytes_random_double"`Quick(repeat100check_bytes_random_double);test_case"check_bytes_random_sum"`Quick(repeat100check_bytes_random_sum);test_case"check_bytes_random_multiplication"`Quick(repeat100check_bytes_random_multiplication);test_case"zero_scalar_nullifier_one"`Quick(repeat1zero_scalar_nullifier_one);test_case"zero_scalar_nullifier_zero"`Quick(repeat1zero_scalar_nullifier_zero);test_case"zero_scalar_nullifier_random"`Quick(repeat100zero_scalar_nullifier_random);test_case"multiply_by_one_does_nothing"`Quick(repeat100multiply_by_one_does_nothing);test_case"opposite_of_opposite"`Quick(repeat100opposite_of_opposite);test_case"opposite_of_opposite_using_scalar"`Quick(repeat100opposite_of_opposite_using_scalar);test_case"opposite_of_zero_is_zero"`Quick(repeat1opposite_of_zero_is_zero);test_case"opposite_of_opposite_of_zero_is_zero"`Quick(repeat1opposite_of_opposite_of_zero_is_zero);test_case"opposite_of_opposite_of_one_is_one"`Quick(repeat1opposite_of_opposite_of_one_is_one);test_case"opposite_equality"`Quick(repeat1opposite_equality);test_case"zero is the identity"`Quick(repeat100zero_is_the_identity);test_case"distributivity"`Quick(repeat100distributivity);test_case"opposite_of_scalar_is_opposite_of_ec"`Quick(repeat100opposite_of_scalar_is_opposite_of_ec);test_case"opposite_existential_property"`Quick(repeat100opposite_existential_property);test_case"mul_by_order_of_base_field_equals_element"`Quick(repeat100mul_by_order_of_scalar_field_equals_zero);test_case"multiplication_properties_on_base_field_element"`Quick(repeat100multiplication_properties_on_base_field_element);test_case"double"`Quick(repeat100double);test_case"additive_associativity_with_scalar"`Quick(repeat100additive_associativity_with_scalar);test_case"inverse on scalar"`Quick(repeat100inverse_on_scalar);test_case"additive_associativity"`Quick(repeat100additive_associativity);test_case"additive_commutativity"`Quick(repeat100additive_commutativity);test_case"Generator is of prime order"`Quick(repeat1generator_is_of_prime_order)])endmoduleMakeEdwardsCurveProperties(G:Ec_sig.AffineEdwardsT)=structletrectest_of_bytes_and_check_bytes_with_different_size_of_bytes()=(* Generate a random number of bytes between 0 and 10 * G.size_in_bytes. If
the random value is the correct number of bytes, we ignore
*)letb_size=Random.int(G.size_in_bytes*10)inifb_size=G.size_in_bytesthentest_of_bytes_and_check_bytes_with_different_size_of_bytes()elseletb=Bytes.createb_sizeinassert(not(G.check_bytesb));assert(Option.is_none(G.of_bytes_optb));tryignore@@G.of_bytes_exnb;assertfalsewith|G.Not_on_curveexn_bytes->assert(Bytes.equalexn_bytesb)|_->assertfalselettest_unsafe_from_coordinates_do_not_check()=letu=G.Base.random()inletv=G.Base.random()inignore@@G.unsafe_from_coordinates~u~vletget_tests()=letopenAlcotestin("Group properties of Edwards curve",[test_case"unsafe_from_coordinates do not check the point is on the curve"`Quicktest_unsafe_from_coordinates_do_not_check;test_case"Test check_bytes and of_bytes_[exn/opt] with a different number of \
bytes than expected"`Quicktest_of_bytes_and_check_bytes_with_different_size_of_bytes])endmoduleMakeSerialisationProperties(G:Ec_sig.BASE)=structlettest_of_bytes_exn_to_bytes_are_inverse_functions()=letr=G.random()inassert(G.(eq(of_bytes_exn(to_bytesr))r))lettest_of_bytes_opt_to_bytes_are_inverse_functions()=letr=G.random()inassert(G.(eq(Option.get(of_bytes_opt(to_bytesr)))r))letget_tests()=letopenAlcotestin("Serialisation",[test_case"of_bytes_exn and to_bytes are inverse functions"`Quicktest_of_bytes_exn_to_bytes_are_inverse_functions;test_case"of_bytes_opt and to_bytes are inverse functions"`Quicktest_of_bytes_opt_to_bytes_are_inverse_functions])endmoduleMakeCompressedSerialisationAffine(G:sigincludeEc_sig.BASEvalof_compressed_bytes_exn:Bytes.t->tvalof_compressed_bytes_opt:Bytes.t->toptionvalto_compressed_bytes:t->Bytes.tend)=structlettest_zero()=letexpected_zero_bytes_compressed=Bytes.make(G.size_in_bytes/2)'\000'inassert(Bytes.(equal(G.to_compressed_bytesG.zero)expected_zero_bytes_compressed))lettest_of_compressed_bytes_exn_recover_correct_point_from_uncompressed_representation()=letg=G.random()inletcompressed_bytes=G.to_compressed_bytesginletuncompressed_g=G.of_compressed_bytes_exncompressed_bytesinassert(G.eqguncompressed_g)lettest_of_compressed_bytes_opt_recover_correct_point_from_uncompressed_representation()=letg=G.random()inletcompressed_bytes=G.to_compressed_bytesginletuncompressed_g=Option.get(G.of_compressed_bytes_optcompressed_bytes)inassert(G.eqguncompressed_g)(* it is correct to test this for BLS12-381 *)lettest_compressed_version_is_half_the_size()=letg=G.random()inassert(Bytes.length(G.to_compressed_bytesg)=G.size_in_bytes/2)lettest_of_compressed_bytes_exn_and_opt_do_not_accept_uncompressed_bytes_representation()=letx=G.random()inletx_uncompressed_bytes=G.to_bytesxinassert(Option.is_none(G.of_compressed_bytes_optx_uncompressed_bytes));tryignore@@G.of_compressed_bytes_exnx_uncompressed_bytes;assertfalsewithG.Not_on_curve_b->()lettest_of_bytes_exn_and_opt_do_not_accept_compressed_bytes_representation()=letx=G.random()inletx_compressed_bytes=G.to_compressed_bytesxinassert(Option.is_none(G.of_bytes_optx_compressed_bytes));tryignore@@G.of_bytes_exnx_compressed_bytes;assertfalsewithG.Not_on_curve_b->()letget_tests()=letopenAlcotestin("Compressed representation",[test_case"Compressed representation of zero is the bs with zeroes"`Quicktest_zero;test_case"of_compressed_bytes_exn recovers correct point from uncompressed \
representation"`Quick(repeat100test_of_compressed_bytes_exn_recover_correct_point_from_uncompressed_representation);test_case"of_compressed_bytes_opt recovers correct point from uncompressed \
representation"`Quick(repeat100test_of_compressed_bytes_opt_recover_correct_point_from_uncompressed_representation);test_case"Compressed version is half the size"`Quicktest_compressed_version_is_half_the_size;test_case"of_compressed_bytes_exn/opt do not accept uncompressed bytes \
representation"`Quick(repeat100test_of_compressed_bytes_exn_and_opt_do_not_accept_uncompressed_bytes_representation);test_case"of_bytes_exn/opt do not accept compressed bytes representation"`Quick(repeat100test_of_bytes_exn_and_opt_do_not_accept_compressed_bytes_representation)])end