Let us denote curve_order by q. When computing a signature (r,s) it is important to remember that r and s are meant to represent elements of Fq (the field of integers modulo q). The formula s = k^(-1)(e + rx) is an algebraic expression in Fq. So r an s are not really integers, they are integers modulo q (so for example two integers u and u + q represent the same elements of Fq). When implementing a function returning (r,s) there is nothing wrong with internally representing these quantities as integers. But when it comes to returning values, you have to decide how you wish to encode the values r and s. If s represents your implementation specific integer, do you simply want to return s? or s + q? or s - 3q? All these answers are the same (simply different encodings) but there is little chance you will match a test-vector unless you have a common encoding with it. When returning an integer s modulo q it is customary to encode s as the unique integer s' with 0 <= s' < q equal to s mod q.
So for example, when you say that test_s = my_s + curve_order, you effectively agree with the test, but have not enforced the usual encoding. When you say that test_s = my_s * -1, you genuinely disagree with the test but this is explained by 'standardization' (so make sure that you have 0 <= s < q and if s > q/2 replace it by -s, but make sure you encode -s as an integer within [0,q), which means s should in fact be replaced by q - s).
seriously, you are a magnificent human being. While it is admittedly difficult to understand this, I think I have a grasp of it, and nevertheless do have some working code that produces the same results as the tests, and hopefully thereby uses the same encoding. I will post my code in order to expose whatever flaws may exist in the logic, or optimizations that could be made to it. – doffing81 – 2017-01-28T00:53:54.030
@BrettDoffing In my opinion, you should avoid cluttering your code with tests
0 <= x < q. You probably have a methodmodon your typeIntegerso thatx.mod(q)always gives you an integer in the interval[0,q)(whenx >= 0it is simply the remainder of the division ofxbyq). So ifx.mul(y)is the normal integer product,x.mul(y).mod(q)gives you the product inFqetc. So compute(r,s)as usual and before returning it you simply standardize it by calling a method which replaces the signature(r,s)by the (valid) signature(r, -s.mod(q))whens > q/2. – Sven Williamson – 2017-01-28T05:40:21.053Thanks for the advice. Swift uses a remainder, while my current big integer library is pretty small, with limited functionality, using remainder as well. – doffing81 – 2017-01-28T10:23:36.973
@BrettDoffing if your remainder function for big integers always returns a non-negative integer after dividing by q, then whatever (r,s) you were calculating before, take the reminders instead, and then do a last filtering to standardize before returning signature, and you should match the test vector perfectly :) – Sven Williamson – 2017-01-28T10:43:01.017
The derivation of this answer is wrong.
– ens – 2018-02-24T21:02:24.837sand-sare NOT equal mod q. The explanation is: During signature calculations we're multiplyingswith a curve pointG. From the resulting point we're only using the x coordinate and discard the y coordinate. Because((-s)*G).x == (-(s*G)).x == (s*G).x(negation of a point only inverts its y coord, x stays the same), bothsand-swork interchangeably in the signature. For the canonical encoding (Low S) ofswe're using the smaller value of the two.