[{"data":1,"prerenderedAt":706},["ShallowReactive",2],{"navigation_docs":3,"-math-brainpoolp256r1":80,"-math-brainpoolp256r1-surround":701},[4,24],{"title":5,"path":6,"stem":7,"children":8,"icon":23},"Guide","\u002Fguide","1.guide\u002F01.index",[9,11,15,19],{"title":10,"path":6,"stem":7},"Getting started",{"title":12,"path":13,"stem":14},"CLI","\u002Fguide\u002Fcli","1.guide\u002F02.cli",{"title":16,"path":17,"stem":18},"Agents","\u002Fguide\u002Fagents","1.guide\u002F03.agents",{"title":20,"path":21,"stem":22},"Playground","\u002Fguide\u002Fplayground","1.guide\u002F04.playground","i-lucide-book-open",{"title":25,"path":26,"stem":27,"children":28,"icon":79},"Math","\u002Fmath","2.math\u002F00.index",[29,31,35,39,43,47,51,55,59,63,67,71,75],{"title":30,"path":26,"stem":27},"Overview",{"title":32,"path":33,"stem":34},"Curves and points","\u002Fmath\u002Fcurves","2.math\u002F01.curves",{"title":36,"path":37,"stem":38},"Orders and logs","\u002Fmath\u002Fgroups","2.math\u002F02.groups",{"title":40,"path":41,"stem":42},"secp256k1","\u002Fmath\u002Fsecp256k1","2.math\u002F03.secp256k1",{"title":44,"path":45,"stem":46},"sr25519","\u002Fmath\u002Fsr25519","2.math\u002F04.sr25519",{"title":48,"path":49,"stem":50},"ed25519","\u002Fmath\u002Fed25519","2.math\u002F05.ed25519",{"title":52,"path":53,"stem":54},"P-256","\u002Fmath\u002Fp256","2.math\u002F06.p256",{"title":56,"path":57,"stem":58},"P-384","\u002Fmath\u002Fp384","2.math\u002F07.p384",{"title":60,"path":61,"stem":62},"P-521","\u002Fmath\u002Fp521","2.math\u002F08.p521",{"title":64,"path":65,"stem":66},"brainpoolP256r1","\u002Fmath\u002Fbrainpoolp256r1","2.math\u002F09.brainpoolp256r1",{"title":68,"path":69,"stem":70},"brainpoolP384r1","\u002Fmath\u002Fbrainpoolp384r1","2.math\u002F10.brainpoolp384r1",{"title":72,"path":73,"stem":74},"brainpoolP512r1","\u002Fmath\u002Fbrainpoolp512r1","2.math\u002F11.brainpoolp512r1",{"title":76,"path":77,"stem":78},"Ed448","\u002Fmath\u002Fed448","2.math\u002F12.ed448","i-lucide-sigma",{"id":81,"title":64,"body":82,"description":693,"extension":694,"links":695,"meta":696,"navigation":153,"path":65,"seo":698,"stem":66,"__hash__":700},"docs\u002F2.math\u002F09.brainpoolp256r1.md",{"type":83,"value":84,"toc":683},"minimark",[85,90,94,97,107,118,219,222,226,232,371,382,385,390,396,402,406,412,419,437,441,447,483,486,492,544,548,555,596,605,608,614,617,620,624,627,643,650,653,656,663,666,669,679],[86,87,89],"h2",{"id":88},"brainpoolp256r1-from-rfc-5639","brainpoolP256r1, from RFC 5639",[91,92,93],"p",{},"brainpoolP256r1 handles points and ECDSA verification for OpenPGP keys and certificates. RFC 9580 lists it for ECDSA and ECDH. RFC 7027 brings Brainpool curves to TLS. The twisted brainpoolP256t1 isn't in this package.",[91,95,96],{},"RFC 5639 defines the curve in section 3.4. Its equation is y² = x³ + ax + b. The field uses a 256-bit prime. The cofactor is 1.",[91,98,99,100,103,104,106],{},"Brainpool's a is neither 0 nor -3. That makes it different from ",[101,102,40],"a",{"href":41}," and ",[101,105,52],{"href":53},". Here's a in hex:",[108,109,115],"pre",{"className":110,"code":112,"language":113,"meta":114},[111],"language-text","7d5a0975fc2c3057eef67530417affe7fb8055c126dc5c6ce94a4b44f330b5d9\n","text","",[116,117,112],"code",{"__ignoreMap":114},[108,119,123],{"className":120,"code":121,"language":122,"meta":114,"style":114},"language-ts shiki shiki-themes compressions compressions compressions","import { isOnCurve, multiplyGenerator } from \"@agntn\u002Fcurves\u002Fbrainpoolp256r1\";\n\nmultiplyGenerator(1n); \u002F\u002F \"038bd2aeb9cb7e57…9ace3262\"\nisOnCurve(`02${\"0\".repeat(64)}`); \u002F\u002F false\nisOnCurve(\"036b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296\"); \u002F\u002F true, P-256's compressed G\n","ts",[116,124,125,148,155,175,204],{"__ignoreMap":114},[126,127,130,134,138,141,145],"span",{"class":128,"line":129},"line",1,[126,131,133],{"class":132},"skH_V","import",[126,135,137],{"class":136},"s38Sx"," { isOnCurve, multiplyGenerator } ",[126,139,140],{"class":132},"from",[126,142,144],{"class":143},"shU9J"," \"@agntn\u002Fcurves\u002Fbrainpoolp256r1\"",[126,146,147],{"class":136},";\n",[126,149,151],{"class":128,"line":150},2,[126,152,154],{"emptyLinePlaceholder":153},true,"\n",[126,156,158,162,165,168,171],{"class":128,"line":157},3,[126,159,161],{"class":160},"sK71F","multiplyGenerator",[126,163,164],{"class":136},"(1",[126,166,167],{"class":132},"n",[126,169,170],{"class":136},"); ",[126,172,174],{"class":173},"scIB-","\u002F\u002F \"038bd2aeb9cb7e57…9ace3262\"\n",[126,176,178,181,184,187,190,193,196,199,201],{"class":128,"line":177},4,[126,179,180],{"class":160},"isOnCurve",[126,182,183],{"class":136},"(",[126,185,186],{"class":143},"`02${\"0\"",[126,188,189],{"class":143},".",[126,191,192],{"class":160},"repeat",[126,194,195],{"class":143},"(64)",[126,197,198],{"class":143},"}`",[126,200,170],{"class":136},[126,202,203],{"class":173},"\u002F\u002F false\n",[126,205,207,209,211,214,216],{"class":128,"line":206},5,[126,208,180],{"class":160},[126,210,183],{"class":136},[126,212,213],{"class":143},"\"036b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296\"",[126,215,170],{"class":136},[126,217,218],{"class":173},"\u002F\u002F true, P-256's compressed G\n",[91,220,221],{},"Coordinates and scalars take 32 bytes, or 64 hex digits. Compressed points take 33 bytes. Uncompressed points take 65. P-256 uses those same lengths. A length check won't tell you which curve a key belongs to.",[86,223,225],{"id":224},"verify-a-brainpoolp256r1-ecdsa-signature","Verify a brainpoolP256r1 ECDSA signature",[91,227,228,229,189],{},"Have a signature and its public key? Hash the message first. Then pass the digest, signature and key to ",[116,230,231],{},"verify",[108,233,235],{"className":120,"code":234,"language":122,"meta":114,"style":114},"import { verify } from \"@agntn\u002Fcurves\u002Fbrainpoolp256r1\";\n\nconst publicKey =\n  \"04019a2d9637743a63ddaefdbca0ee229a163b809b9b145e5313bbeb8defeab9d6\" +\n  \"548caf89bf5ba49499404145651234336401b9b2843a579ed152e090f11b9e59\";\nconst digest =\n  \"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023\"; \u002F\u002F SHA-256 of 313233343030\nconst signature =\n  \"0a5f8c70ba2d0842d5d0f841f160ad15195769a8159bfe692634d73d469d111f\" +\n  \"426e857aad3ff7aa96e4d200c03b45f1846a36d089ee3917768ca1a0d6d4da6e\";\n\nverify(signature, { digest, publicKey }); \u002F\u002F true\nverify(signature, { digest: `00${digest.slice(2)}`, publicKey }); \u002F\u002F false\n",[116,236,237,250,254,265,273,280,290,302,312,320,328,333,344],{"__ignoreMap":114},[126,238,239,241,244,246,248],{"class":128,"line":129},[126,240,133],{"class":132},[126,242,243],{"class":136}," { verify } ",[126,245,140],{"class":132},[126,247,144],{"class":143},[126,249,147],{"class":136},[126,251,252],{"class":128,"line":150},[126,253,154],{"emptyLinePlaceholder":153},[126,255,256,259,262],{"class":128,"line":157},[126,257,258],{"class":132},"const",[126,260,261],{"class":136}," publicKey ",[126,263,264],{"class":132},"=\n",[126,266,267,270],{"class":128,"line":177},[126,268,269],{"class":143},"  \"04019a2d9637743a63ddaefdbca0ee229a163b809b9b145e5313bbeb8defeab9d6\"",[126,271,272],{"class":132}," +\n",[126,274,275,278],{"class":128,"line":206},[126,276,277],{"class":143},"  \"548caf89bf5ba49499404145651234336401b9b2843a579ed152e090f11b9e59\"",[126,279,147],{"class":136},[126,281,283,285,288],{"class":128,"line":282},6,[126,284,258],{"class":132},[126,286,287],{"class":136}," digest ",[126,289,264],{"class":132},[126,291,293,296,299],{"class":128,"line":292},7,[126,294,295],{"class":143},"  \"bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023\"",[126,297,298],{"class":136},"; ",[126,300,301],{"class":173},"\u002F\u002F SHA-256 of 313233343030\n",[126,303,305,307,310],{"class":128,"line":304},8,[126,306,258],{"class":132},[126,308,309],{"class":136}," signature ",[126,311,264],{"class":132},[126,313,315,318],{"class":128,"line":314},9,[126,316,317],{"class":143},"  \"0a5f8c70ba2d0842d5d0f841f160ad15195769a8159bfe692634d73d469d111f\"",[126,319,272],{"class":132},[126,321,323,326],{"class":128,"line":322},10,[126,324,325],{"class":143},"  \"426e857aad3ff7aa96e4d200c03b45f1846a36d089ee3917768ca1a0d6d4da6e\"",[126,327,147],{"class":136},[126,329,331],{"class":128,"line":330},11,[126,332,154],{"emptyLinePlaceholder":153},[126,334,336,338,341],{"class":128,"line":335},12,[126,337,231],{"class":160},[126,339,340],{"class":136},"(signature, { digest, publicKey }); ",[126,342,343],{"class":173},"\u002F\u002F true\n",[126,345,347,349,352,355,358,361,364,366,369],{"class":128,"line":346},13,[126,348,231],{"class":160},[126,350,351],{"class":136},"(signature, { digest: ",[126,353,354],{"class":143},"`00${",[126,356,357],{"class":143},"digest.",[126,359,360],{"class":160},"slice",[126,362,363],{"class":143},"(2)",[126,365,198],{"class":143},[126,367,368],{"class":136},", publicKey }); ",[126,370,203],{"class":173},[91,372,373,374,377,378,381],{},"This is Wycheproof's SHA-256 vector tcId 1. The message is six bytes: ",[116,375,376],{},"313233343030"," in hex, or ",[116,379,380],{},"123400"," in ASCII. The second call replaces the digest's first byte. It doesn't prepend a byte.",[91,383,384],{},"The signature is r followed by s. It takes 64 bytes, or 128 hex digits. The public key is compressed or uncompressed SEC1 hex.",[386,387,389],"h3",{"id":388},"what-about-der-and-the-digest","What about DER and the digest?",[91,391,392,393,189],{},"X.509 uses DER signatures. OpenPGP uses two MPIs. Extract r and s, then pad each to 64 hex digits. Join them without ",[116,394,395],{},"0x",[91,397,398,399,401],{},"The digest takes 1 to 64 bytes of hex without ",[116,400,395],{},". The order n has 256 bits. For longer digests, only the leftmost 256 bits count. The library doesn't hash the message for you.",[386,403,405],{"id":404},"what-does-it-refuse","What does it refuse?",[108,407,410],{"className":408,"code":409,"language":113,"meta":114},[111],"verify(\"00\", { digest, publicKey })               \u002F\u002F Signature must be 128 hex digits without 0x, r then s\nverify(signature, { digest: \"0x00\", publicKey })  \u002F\u002F Digest must be hex without 0x, 1 to 64 bytes\nverify(signature, { digest, publicKey: p256G })   \u002F\u002F Invalid SEC1 brainpoolP256r1 public key\nliftX(\"0\".repeat(64))                             \u002F\u002F No point of brainpoolP256r1 has this x\n",[116,411,409],{"__ignoreMap":114},[91,413,414,415,418],{},"Here ",[116,416,417],{},"p256G"," is P-256's uncompressed generator. Wrong shapes throw. So do points that don't lie on this curve.",[91,420,421,422,425,426,429,430,432,433,436],{},"An r or s outside 1 to n - 1 returns ",[116,423,424],{},"false",". The ",[116,427,428],{},"lowS"," option defaults to ",[116,431,424],{},". Set it to ",[116,434,435],{},"true"," to reject s above n \u002F 2.",[386,438,440],{"id":439},"cli-and-agent-tool","CLI and agent tool",[91,442,443,444,189],{},"Want the same check from a terminal? Use ",[116,445,446],{},"curves brainpoolp256r1 \u003Coperation>",[108,448,452],{"className":449,"code":450,"language":451,"meta":114,"style":114},"language-bash shiki shiki-themes compressions compressions compressions","curves brainpoolp256r1 verify --point 04019a2d9637743a63ddaefdbca0ee229a163b809b9b145e5313bbeb8defeab9d6548caf89bf5ba49499404145651234336401b9b2843a579ed152e090f11b9e59 --digest bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023 --signature 0a5f8c70ba2d0842d5d0f841f160ad15195769a8159bfe692634d73d469d111f426e857aad3ff7aa96e4d200c03b45f1846a36d089ee3917768ca1a0d6d4da6e\n","bash",[116,453,454],{"__ignoreMap":114},[126,455,456,459,462,465,468,471,474,477,480],{"class":128,"line":129},[126,457,458],{"class":160},"curves",[126,460,461],{"class":143}," brainpoolp256r1",[126,463,464],{"class":143}," verify",[126,466,467],{"class":143}," --point",[126,469,470],{"class":143}," 04019a2d9637743a63ddaefdbca0ee229a163b809b9b145e5313bbeb8defeab9d6548caf89bf5ba49499404145651234336401b9b2843a579ed152e090f11b9e59",[126,472,473],{"class":143}," --digest",[126,475,476],{"class":143}," bb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023",[126,478,479],{"class":143}," --signature",[126,481,482],{"class":143}," 0a5f8c70ba2d0842d5d0f841f160ad15195769a8159bfe692634d73d469d111f426e857aad3ff7aa96e4d200c03b45f1846a36d089ee3917768ca1a0d6d4da6e\n",[91,484,485],{},"It prints:",[108,487,490],{"className":488,"code":489,"language":113,"meta":114},[111],"{\"operation\":\"verify\",\"valid\":true}\n",[116,491,489],{"__ignoreMap":114},[91,493,494,495,498,499,498,502,498,505,498,508,498,511,103,514,516,517,520,521,498,524,498,527,498,530,498,533,498,536,498,539,103,541,189],{},"The CLI offers ",[116,496,497],{},"add",", ",[116,500,501],{},"subtract",[116,503,504],{},"negate",[116,506,507],{},"multiply",[116,509,510],{},"lift",[116,512,513],{},"check",[116,515,231],{},". The agent tool ",[116,518,519],{},"curves_brainpoolp256r1_compute"," offers the same operations. Its arguments are ",[116,522,523],{},"point",[116,525,526],{},"other",[116,528,529],{},"scalar",[116,531,532],{},"x",[116,534,535],{},"digest",[116,537,538],{},"signature",[116,540,428],{},[116,542,543],{},"compressed",[86,545,547],{"id":546},"brainpoolp256r1-point-math","brainpoolP256r1 point math",[91,549,550,551,554],{},"The ",[116,552,553],{},"@agntn\u002Fcurves\u002Fbrainpoolp256r1"," entry exports:",[556,557,558,570,577,587],"ul",{},[559,560,561,498,564,103,567],"li",{},[116,562,563],{},"addPoints",[116,565,566],{},"subtractPoints",[116,568,569],{},"negatePoint",[559,571,572,103,575],{},[116,573,574],{},"multiplyPoint",[116,576,161],{},[559,578,579,498,582,103,584],{},[116,580,581],{},"liftX",[116,583,180],{},[116,585,586],{},"convertPoint",[559,588,589,498,591,103,593],{},[116,590,231],{},[116,592,64],{},[116,594,595],{},"INVALID_POINT",[91,597,598,599,601,602,604],{},"The names match P-256 except for the domain export. ",[116,600,64],{}," holds the domain parameters. Give ",[116,603,581],{}," an x as 64 hex digits. Scalars run from 1 to n - 1. Use a bigint or hex with at most 64 digits.",[91,606,607],{},"Try x = 0 and x = 1. Zero has no point here because b isn't a square modulo p. One does have a point.",[91,609,610,611,613],{},"Why did P-256's compressed generator pass ",[116,612,180],{}," above? A compressed point contains x and a choice of y. About half of all x values have a point on any curve. That x happens to work here too. Its uncompressed P-256 point fails because its y doesn't match.",[91,615,616],{},"Know the key's curve before checking it. A passing point check isn't a curve label.",[91,618,619],{},"There's no signing, key recovery or scalar math here. Like P-256, this entry verifies signatures.",[86,621,623],{"id":622},"written-from-the-specs","Written from the specs",[91,625,626],{},"RFC 5639 objected to older curves' seeds being \"chosen ad hoc\". It also noted primes with special forms that make implementation efficient. Brainpool instead generated its parameters pseudo-randomly, in a systematic and reproducible way. The prime isn't a shortcut. Neither is a.",[91,628,629,630,633,634,498,636,498,638,103,640,642],{},"The curve shares ",[116,631,632],{},"src\u002Fcore\u002Fsec1.ts"," with six others: secp256k1, P-256, ",[101,635,56],{"href":57},[101,637,60],{"href":61},[101,639,68],{"href":69},[101,641,72],{"href":73},". Seven curves, one implementation. The odd a was the real work.",[91,644,645,646,649],{},"The a = 0 and a = -3 formulas refuse this curve. They report ",[116,647,648],{},"These formulas are for another a",". Addition and doubling instead use algorithms 1 and 3 from Renes, Costello and Batina (2016). These complete formulas work for any a. They cost a few more multiplications.",[91,651,652],{},"On P-256, the general formulas moved point multiplication by a few percent in a local run. Both versions took about 1.1 ms. The special formulas stay where they fit. That's a sensible trade.",[91,654,655],{},"Both n and p have 256 bits. Since p is 3 mod 4, a square root takes one power. Multiplication walks 64 hex digits. The secret multiplication comb has four rows, 16 steps apart. The verification table has 64 rows of 15 points.",[91,657,658,659,662],{},"A secret multiply takes the same steps for every scalar. ",[116,660,661],{},"test\u002Fbrainpoolp256r1.test.ts"," times 1 against n - 1. JavaScript bigints don't promise constant timing. The library is unaudited. Keep real money away.",[91,664,665],{},"In a local run, G multiplication took about 0.46 ms. Another point took about 1.2 ms. Verification took about 1.3 ms. The generic code for curves you define took about 7.5 ms for one multiplication.",[91,667,668],{},"All 261 Wycheproof SHA-256 vectors pass in P1363 form. That's 175 valid and 86 invalid signatures. RFC 7027 appendix A.1 supplies two key pairs and their shared secret. Both match.",[91,670,671,674,675,678],{},[116,672,673],{},"@noble\u002Fcurves"," has no Brainpool. Multiples of G are frozen from OpenSSL 3.6.5 through ",[116,676,677],{},"node:crypto",". In a local run, OpenSSL agreed on 199 keys. The library also verified 20 signatures made by OpenSSL.",[680,681,682],"style",{},"html pre.shiki code .skH_V, html code.shiki .skH_V{--shiki-light:var(--shiki-token-keyword);--shiki-default:var(--shiki-token-keyword);--shiki-dark:var(--shiki-token-keyword)}html pre.shiki code .s38Sx, html code.shiki .s38Sx{--shiki-light:var(--ui-text-highlighted);--shiki-default:var(--ui-text-highlighted);--shiki-dark:var(--ui-text-highlighted)}html pre.shiki code .shU9J, html code.shiki .shU9J{--shiki-light:var(--shiki-token-string);--shiki-default:var(--shiki-token-string);--shiki-dark:var(--shiki-token-string)}html pre.shiki code .sK71F, html code.shiki .sK71F{--shiki-light:var(--shiki-token-function);--shiki-default:var(--shiki-token-function);--shiki-dark:var(--shiki-token-function)}html pre.shiki code .scIB-, html code.shiki .scIB-{--shiki-light:var(--shiki-token-comment);--shiki-default:var(--shiki-token-comment);--shiki-dark:var(--shiki-token-comment)}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":114,"searchDepth":150,"depth":150,"links":684},[685,686,691,692],{"id":88,"depth":150,"text":89},{"id":224,"depth":150,"text":225,"children":687},[688,689,690],{"id":388,"depth":157,"text":389},{"id":404,"depth":157,"text":405},{"id":439,"depth":157,"text":440},{"id":546,"depth":150,"text":547},{"id":622,"depth":150,"text":623},"brainpoolP256r1 point math and ECDSA verification for OpenPGP keys and Brainpool certificates","md",null,{"icon":697},"i-lucide-sprout",{"title":699,"description":693},"brainpoolP256r1 ECDSA verification and SEC1 points in TypeScript","zTPTVnsx9NNKuoBTqHstlgGUOUc8RpZMLuERbD3X0n0",[702,704],{"title":60,"path":61,"stem":62,"description":703,"children":-1},"P-521 point math and ECDSA verification for ES512 and certificates",{"title":68,"path":69,"stem":70,"description":705,"children":-1},"brainpoolP384r1 point math and ECDSA verification for OpenPGP keys and Brainpool certificates",1793795813696]