<p>Your <code>right</code> is calculated with <code>(a * c % SECP256K1_ORDER) - (b * c % SECP256K1_ORDER)</code>. There's no guarantee that one side of the <code>-</code> will always be bigger than the other side, so it's possible that <code>(b * c % SECP256K1_ORDER)</code> is bigger than <code>(a * c % SECP256K1_ORDER)</code> which results in <code>right</code> being a negative number. As a negative number, it cannot be a valid scalar, and so its <code>secret</code> is not set. Since all of the numbers are random, this happens with 50% probability.</p>
<p>To resolve this, you just need to handle the negatives correctly. A negative number in a prime is just its absolute value subtracted from the prime (<code>SECP256K1_ORDER</code>). How you achieve that is left as an exercise to the reader :)</p>

CC BY-SA 4.0
2023-03-13T23:01:30.067Z
That makes tons of sense thank you for the clear explanation!
Poseidon
CC BY-SA 4.0
2023-03-13T21:36:48.813Z
2023-03-14T13:04:36.430Z
2023-03-14T13:04:36.430Z
Ava Chow
<p>Workshop link: <a href="https://github.com/bitcoinops/taproot-workshop/" rel="nofollow noreferrer">https://github.com/bitcoinops/taproot-workshop/</a></p>
<p>In the section <code>0.2.4 Programming Exercise: Distributivity of scalar operations </code> we implement the following code:</p>
<pre><code>a_key = ECKey().set(a)

b = random.randrange(1, SECP256K1_ORDER)
b_key = ECKey().set(b)

c = random.randrange(1, SECP256K1_ORDER)
c_key = ECKey().set(c)

# Left: Compute a - b as ints (modulo the sepc256k1 group order)
a_minus_b =  (a - b) % SECP256K1_ORDER# TODO: implement

# Left: Compute (a - b) * c as ints (modulo the sepc256k1 group order)
left =  (a_minus_b * c) % SECP256K1_ORDER# TODO: implement

# Right: Compute a * c - b * c as ECKeys
right = (a * c % SECP256K1_ORDER) - (b * c % SECP256K1_ORDER) # TODO: implement 
#if you dont modulo curve order in both parenthesis your number (probably) becomes too large for the curve
#therefore calling .secret on it will not work even if you cast it to ECKey Object (so the assertion cannot even happen in this case)
#you would only be able to call .secret on a value within the curve order

print(&quot;Left: {}&quot;.format(left))
print(&quot;Right: {}&quot;.format(right))


right = ECKey().set(right)
# Left/Right: Assert equality
assert left == right.secret
print(&quot;\nSuccess!&quot;)
</code></pre>
<p>Note that the lines with <code>#TODO: implement</code> are the only ones I have modified.</p>
<p>When trying this code block a few times I noticed that it fails occasionally with:</p>
<pre><code>Left: 84229569338898829804715923445734053841060795723920762893503652295039608159004
Right: -31562519898417365618855061562953854011776768555154141489101510846478553335333
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[32], line 28
     26 right = ECKey().set(right)
     27 # Left/Right: Assert equality
---&gt; 28 assert left == right.secret
     29 print(&quot;\nSuccess!&quot;)

AttributeError: 'ECKey' object has no attribute 'secret'
</code></pre>
<p>The attribute error suggests that the generated secret is outside the curve order and was not properly turned into the ECKey</p>
<p>But for at least 50% of the time it returns something like:</p>
<pre><code>Left: 51082417157028894624564857296082907029625179491897309339882235219613900809295
Right: 51082417157028894624564857296082907029625179491897309339882235219613900809295

Success!
</code></pre>
<p>What is causing this inconsistency?</p>

<taproot><secp256k1>
Inconsistent behavior testing Taproot Workshop - Section: 0.2 Elliptic Curve Math
Poseidon
# Inconsistent behavior testing Taproot Workshop - Section: 0.2 Elliptic Curve Math

(Asked by: username_0 on 2023-03-13)

Workshop link: <https://github.com/bitcoinops/taproot-workshop/>

In the section `0.2.4 Programming Exercise: Distributivity of scalar operations`  we implement the following code:

```
a_key = ECKey().set(a)

b = random.randrange(1, SECP256K1_ORDER)
b_key = ECKey().set(b)

c = random.randrange(1, SECP256K1_ORDER)
c_key = ECKey().set(c)

# Left: Compute a - b as ints (modulo the sepc256k1 group order)
a_minus_b =  (a - b) % SECP256K1_ORDER# TODO: implement

# Left: Compute (a - b) * c as ints (modulo the sepc256k1 group order)
left =  (a_minus_b * c) % SECP256K1_ORDER# TODO: implement

# Right: Compute a * c - b * c as ECKeys
right = (a * c % SECP256K1_ORDER) - (b * c % SECP256K1_ORDER) # TODO: implement 
#if you dont modulo curve order in both parenthesis your number (probably) becomes too large for the curve
#therefore calling .secret on it will not work even if you cast it to ECKey Object (so the assertion cannot even happen in this case)
#you would only be able to call .secret on a value within the curve order

print("Left: {}".format(left))
print("Right: {}".format(right))

right = ECKey().set(right)
# Left/Right: Assert equality
assert left == right.secret
print("\nSuccess!")

```

Note that the lines with `#TODO: implement` are the only ones I have modified.

When trying this code block a few times I noticed that it fails occasionally with:

```
Left: 84229569338898829804715923445734053841060795723920762893503652295039608159004
Right: -31562519898417365618855061562953854011776768555154141489101510846478553335333
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[32], line 28
     26 right = ECKey().set(right)
     27 # Left/Right: Assert equality
---> 28 assert left == right.secret
     29 print("\nSuccess!")

AttributeError: 'ECKey' object has no attribute 'secret'

```

The attribute error suggests that the generated secret is outside the curve order and was not properly turned into the ECKey

But for at least 50% of the time it returns something like:

```
Left: 51082417157028894624564857296082907029625179491897309339882235219613900809295
Right: 51082417157028894624564857296082907029625179491897309339882235219613900809295

Success!

```

What is causing this inconsistency?

**Tags:** taproot, secp256k1


---

## 1 answers

### Answer by username_1 on 2023-03-13. Score: 4 | Accepted answer

Your `right` is calculated with `(a * c % SECP256K1_ORDER) - (b * c % SECP256K1_ORDER)`. There's no guarantee that one side of the `-` will always be bigger than the other side, so it's possible that `(b * c % SECP256K1_ORDER)` is bigger than `(a * c % SECP256K1_ORDER)` which results in `right` being a negative number. As a negative number, it cannot be a valid scalar, and so its `secret` is not set. Since all of the numbers are random, this happens with 50% probability.

To resolve this, you just need to handle the negatives correctly. A negative number in a prime is just its absolute value subtracted from the prime (`SECP256K1_ORDER`). How you achieve that is left as an exercise to the reader :)

> **Comments:**
> **username_0**: That makes tons of sense thank you for the clear explanation!  

---

