Skip to content

Commit 0b8fc72

Browse files
authored
Merge pull request #48 from bitcoinjs/addStrict
Fix discrepancies between JS and Native implementations
2 parents 9f07a89 + d74e9fe commit 0b8fc72

File tree

7 files changed

+40
-7
lines changed

7 files changed

+40
-7
lines changed

js.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,12 +110,14 @@ function pointAddScalar (p, tweak, __compressed) {
110110
return getEncoded(uu, compressed)
111111
}
112112

113-
function pointCompress (p, compressed) {
113+
function pointCompress (p, __compressed) {
114114
if (!isPoint(p)) throw new TypeError(THROW_BAD_POINT)
115115

116116
const pp = decodeFrom(p)
117117
if (pp.isInfinity()) throw new TypeError(THROW_BAD_POINT)
118118

119+
const compressed = assumeCompression(__compressed, p)
120+
119121
return getEncoded(pp, compressed)
120122
}
121123

@@ -215,7 +217,7 @@ function __sign (hash, x, addData) {
215217
return buffer
216218
}
217219

218-
function verify (hash, q, signature) {
220+
function verify (hash, q, signature, strict) {
219221
if (!isScalar(hash)) throw new TypeError(THROW_BAD_HASH)
220222
if (!isPoint(q)) throw new TypeError(THROW_BAD_POINT)
221223

@@ -226,6 +228,10 @@ function verify (hash, q, signature) {
226228
const r = fromBuffer(signature.slice(0, 32))
227229
const s = fromBuffer(signature.slice(32, 64))
228230

231+
if (strict && s.cmp(nDiv2) > 0) {
232+
return false
233+
}
234+
229235
// 1.4.1 Enforce r and s are both integers in the interval [1, n − 1] (2, enforces '> 0')
230236
if (r.gtn(0) <= 0 /* || r.compareTo(n) >= 0 */) return false
231237
if (s.gtn(0) <= 0 /* || s.compareTo(n) >= 0 */) return false

native/addon.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,9 @@ namespace {
7777

7878
template <size_t index, typename I, typename A>
7979
unsigned int assumeCompression (const I& info, const A& p) {
80-
if (info.Length() <= index) return __isPointCompressed(p) ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED;
81-
if (info[index]->IsUndefined()) return SECP256K1_EC_COMPRESSED;
80+
if (info.Length() <= index || info[index]->IsUndefined()) {
81+
return __isPointCompressed(p) ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED;
82+
}
8283
#if (NODE_MODULE_VERSION > NODE_11_0_MODULE_VERSION)
8384
return info[index]->BooleanValue(v8::Isolate::GetCurrent()) ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED;
8485
#else

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "tiny-secp256k1",
3-
"version": "1.1.4",
3+
"version": "1.1.5",
44
"description": "A tiny secp256k1 native/JS wrapper",
55
"main": "index.js",
66
"gypfile": true,

tests/ecdsa.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,10 @@ function test (binding) {
9393
binding.verify(m, Q, signature)
9494
}, new RegExp(f.exception), `${f.description} throws ${f.exception}`)
9595
} else {
96-
t.equal(binding.verify(m, Q, signature), false, `verify(${f.signature}) is rejected`)
96+
t.equal(binding.verify(m, Q, signature, f.strict), false, `verify(${f.signature}) is rejected`)
97+
if (f.strict === true) {
98+
t.equal(binding.verify(m, Q, signature, false), true, `verify(${f.signature}) is OK without strict`)
99+
}
97100
}
98101
})
99102

tests/fixtures/ecdsa.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10301,6 +10301,13 @@
1030110301
"Q": "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
1030210302
"m": "0000000000000000000000000000000000000000000000000000000000000003",
1030310303
"signature": "0000000000000000000000000000000000000000000000000000000000000001fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"
10304+
},
10305+
{
10306+
"description": "Fails verification if strict set to truthy value with high s value",
10307+
"strict": true,
10308+
"Q": "034cd032cdc72820498aeb0fdd25712aa4f6d263997cf7df140b8c42d44626b08c",
10309+
"m": "df8e1382d17bdac18f3c854815071226385803e85f06114129ebbcfcef991278",
10310+
"signature": "ec8cd8d7dcda4ff770c2858bdd93dd64806e218b11bb1971a4a09b065760b040c1095cf554dab161b2b2c46386fab2c81e57035be714b760ef507981f8f70073"
1030410311
}
1030510312
]
1030610313
},

tests/fixtures/points.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10078,6 +10078,18 @@
1007810078
"P": "04d5747c593533e620dc7b576febd13fb758525670eeb42006166fcfbaf273bb416f32cb9ea9d5403e4bdb5ca38037e169e95004324c0786c5ab5ee32050cc0213",
1007910079
"compress": false,
1008010080
"expected": "04d5747c593533e620dc7b576febd13fb758525670eeb42006166fcfbaf273bb416f32cb9ea9d5403e4bdb5ca38037e169e95004324c0786c5ab5ee32050cc0213"
10081+
},
10082+
{
10083+
"P": "042f01e5e15cca351daff3843fb70f3c2f0a1bdd05e5af888a67784ef3e10a2a015c4da8a741539949293d082a132d13b4c2e213d6ba5b7617b5da2cb76cbde904",
10084+
"noarg": true,
10085+
"expected": "042f01e5e15cca351daff3843fb70f3c2f0a1bdd05e5af888a67784ef3e10a2a015c4da8a741539949293d082a132d13b4c2e213d6ba5b7617b5da2cb76cbde904",
10086+
"note": "Need to test if pointCompress keeps compressed status without any compressed arg"
10087+
},
10088+
{
10089+
"P": "042f01e5e15cca351daff3843fb70f3c2f0a1bdd05e5af888a67784ef3e10a2a015c4da8a741539949293d082a132d13b4c2e213d6ba5b7617b5da2cb76cbde904",
10090+
"noarg": false,
10091+
"expected": "042f01e5e15cca351daff3843fb70f3c2f0a1bdd05e5af888a67784ef3e10a2a015c4da8a741539949293d082a132d13b4c2e213d6ba5b7617b5da2cb76cbde904",
10092+
"note": "Need to test if pointCompress keeps compressed status when explicitly passing undefined. (This is why this fixture has no 'compressed')"
1008110093
}
1008210094
],
1008310095
"pointFromScalar": [

tests/points.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,11 @@ function test (binding) {
8585
const p = Buffer.from(f.P, 'hex')
8686
const expected = Buffer.from(f.expected, 'hex')
8787

88-
t.same(binding.pointCompress(p, f.compress), expected)
88+
if (f.noarg) {
89+
t.same(binding.pointCompress(p), expected)
90+
} else {
91+
t.same(binding.pointCompress(p, f.compress), expected)
92+
}
8993
})
9094

9195
fpoints.invalid.pointCompress.forEach((f) => {

0 commit comments

Comments
 (0)