-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ML-DSA keyGen and sigVer success only after byte order reversal of seed / message #320
Comments
Can you please verify the implementation has the algorithm in Draft FIPS 204 Section 8.1 defined properly? They define how to read the byte values. The reverse byte order is an interesting problem. We've published tests produced from this code previously and didn't receive such feedback. I'd like to verify that it isn't just this implementation before diving deeper. |
@celic I'm a little confused by your statement. As far as I can tell (and I may be wrong!), Algorithm 2 In particular, we define
i.e., simple concatenation into the XOF's input stream. Building a simple reproducer here in C, based off of the reference implementation: Source code#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "../sign.h"
#include "../api.h"
uint8_t *decode_hex(const char *hex, size_t *size);
uint8_t *swapped_msg(uint8_t *msg, size_t msg_len);
int randombytes(unsigned char *x, unsigned long long xlen)
{
return -1;
}
int
main()
{
const char *pk_hex = "051EB9609C254C299E2105FDB4DB2F4783B6D65504CF93289188A443B4CA59EDD372C8272A4DDCA95D890D8AFB9D7122D7463A22FEEB7A118C67A836CC1BB987D4149EBDA0BC05B0EF337ABAAE2F6216B8A7A497128F14B38051D87023328DC016E7277B0204A8399BB553FCC88666A1C1B58129C9AB07BAD3980F11EFFD1CA4347C0FDE6BE896D9F33B5AA69B70F077395CC00B0C82365470E516E789034B3A4CA5A147F8B50FB210C2C2AF8EB4D24E9F7CE298FF4763A161BB3984A16E34B111065491A38E36A1ACCBED68D1494ACA6805E304E1DE41C517DF983C41EC19E6CE3BF4F4119F7CDB2F34A81847D1C599BF350F2E081FD952652973912077F99E6F6474883D86838D4D09BD0FF56850A54CD778BB3F89CB4188BA3279D643E681509380E68D48E6B97A7D03B5E76D8331600620BCCC3508B64C91E1A6E1ED37D6536D9AB485039F26160232E9B699317E6DF634B9C947E43461C9DF225856F5EBE122918135063E3051CCC87D6EBB5CA72B134874D98A60EC7619E8D9B8C2FE9B9AA757CEE702EF23FB312D44460D6183558D9DD042EAC217FAA0A875F92CCC6103069DF9220E2EEC5394778146A6437DE24110D0B1EAF4D84A0583B355D77F0605188A97228F28CD6A67EA2B1B423363F9FD8ECA2A2B031B1D8A4B0AEE0A44C622BE372EEB52255CDDB6FC082477E7CED75BEC36D76F13E30688171DB20FA8E517178AEF0578765D63B39298205A3AAE23B3EC043A7753BEF489D27D14922D5B8BFEBA436EFF7E1C3E07CE8CA928652EDA9798A4AEAC7264199CF7F974AE56C1D877A565C0BC27488E96F123D005BF1A29AB1DD402881989C43824A4300D476CAE73D817B081D792B232FF58E79BEBEE010EC27B09CEB52E559C4F1AF1758B4107D2BD2299862B9E7DD1140F4EEF22FF3EE9696368ACDA352610563943B66AC6763854CE79C3CDED7AD86822F8A0FDDDCA7ED6136B8DD758E9C4A848ED1C5C935B08EC1640B7809C6E8ECE70080BB52154D26AE19916E172709940673B647E842C6F94E1FBF386C63589E0BD5B6FB8A34D618DF0AB2A64AF8C91A681C85297BA311F9D214FAFA20CD4043565207C63997974F78AF76E239DEB8492C108BFA2A753736FCF57245EF774DE581F815AC9A7D0BDDDD59CAD45D384F09762F23088FE1795290DF9AE3CF4F1A6F727C372FB906166471F01AB594CEAEB97B3E6AE26EB9D77AA87132C0EB536A8807B8FA24B832567395E6DFACAAE555C66AAA226A1C6B61CFD8C2E2BDD23F344952186C6762583278F0C61E6557F705414FE9FC6F63EBDA281ACECB32DB1292C2E74B7A90B75D8B62207AF3B4249BE439332C4931637BEF3D274F6038168EF17A2FA72010D3212416B933B07E4805B92275110A0E74EB369377EF0A4CE553C3EC1041BFBE5856339850D279C2FA1FD02503CA8BDE02B62266366DD6D601F7B7C2DB8833AA155DCB3C22981917BEFA0DD000E6382FC19A41F4811EE636C1CFFC226D10C5C30E64B7363C64C9D76461E4B4DB9758C4FFAFEEB3D6FFC8234C6FAFAB0257859481131B7B17BC77461AE4D852978281952F16FE487A08CD229F15C3556CC174456CF56EE5410C5288EEF6B08C60C73F9DF0D545FC11153FC6EADB51D5545356CCE75C178A219F8CCA21408E8350A93187F55FE1AF904B1E350D3B3B16E87C1E52E763F0B3B4895BFC117DD16A062C113A950DC91F9A936314CBF0AA277F895E11136F8B4CB48FA1EB089C78B76222DDD578E9B08B4DA7583EE1BFEAE3F563213C5ABE611B3B66435C8336E11EBF850EE4F3C061C5EC8CB87B1E92A62DBD5DCEC9E6A75F70F24C279793E1BAAA23099659569";
const char *msg_hex = "FC8B7DBB1859F24012BB262D521FE00F439A517A9C8AF25066B9C09C4BE78C1D7E9FE4E987CBD13A3C0F29864E9A1D7F0143AC0BE0C576E1740487EA932F4F3C4274C86F9EE252EFA6323F126B6755EEA354CB9B23CF91460F82CBD9BB776C7B2194EDA388C1D3CDDED0DA720C856340DE426200AB71D03018513071AF31BF80";
const char *sig_hex = "9FDF37B39592DB390D24F9C6553F125DBC708256A31427C4AEF28D79D883960C5D064FD43F692B296F67660B1B30EFD94F706907C626CA1A2C30755FAE2752662209A39F109CB468AA66981DC682A25B02434A1396AE62B89132AC4413C597D81F535BCBB0FF76716E8F17533FF7B7B904D3E8E4906B77029B61799AD87EE3A744A1B4FAB55884B6D8463C18ED5E14E542E2C58D36892C6AFA94165906770D6A0A0BBC9E572C61EB565571BBA2BBC951CE4F1DFF9C88E40FEB2EEFEA60C0B88EFA85D70B25191B0895231E31497F0F526DB259FB9DA91DADF3019445C00FF7A94DFF4E3B7DF849F70E2A8F0A3919E16F4E2EDD537052C06FE971D541168A56DEE45537D04649A17C2838ECCB3796D2D7348CA3E80BC87E5085FB6D569BEADE9281413137B8C43E9C2E6C760ECF5F70135ABCABBE6E3D62383A10DFA27730F3C27E3105AB3E96368AEF94AD66B6FE3C9551D2B0AD21D20A67214DD6502888F06F87B716D79AEFBB4DBB3374444BB2F378AB813A550927D77EACA667026E156AF083C6138C12C5404BEBD66AE0B3BFA97411CA48BD644F076128D6BE7B8BAB57B972F1857E1004619305F62550249E2B5B1F30E33009CF94C449524F81FDB64D99A28B1969609A0A4474E7E3ADF53F8480EC1F9C5F65857C46A00099A5C2036E29557F0B9A4B211CC6DB7E727E8211B0BF3531ABDCF023DC775BA5FE02145D50ADD2027740FAA75C41840929A096DBA63E0D078E4EC7B60BC8682FE6961D0F8BEF7B91BA3BE94395D173C9E6995BB1DD47C7F3023D54E15EC6DC6AFEEB3A13D7C6B83242931B30E4F8372F26CC920B3F8F9DBF03B22275F4766B13B2DFAC2A655B7E0C889053D4CF45B1315A81A9495C75A23DFDC9CACBEF9E65A6BD2A1B0D97D37F9289A40A395C61BDEABE00CCE68031844DDCF009DDED2EF5D482A4A3134D3F08E3C1E62FE3C5DC6A71CE6664DC2FC2AB4AC818F617BC6746E32C8F77B4E59F01F159D61E5C12238AD6880C877602E09202E2799E91C85EAEC5A1FB822A89F8DE6A87FE170959F27006D67C0A5B3AB44B28FA8A6EE6C87AFFD94FDDA84827642733196C698CB7BF54D3ABA0F93E14A2AA9B885A08ED580219EAC22A16B1141BE4D746AFFB8C7E8870A2C8AB4EC8D6C20323194A2B74EA0C27D5A46655B05088F6EC52BBD5B0331010FE16FE9F81068A677E6F8DC085BF20EAF66FB9242FF85FFE7FFE5A2583B6150AAD78F4B708E43CEF8C83525C8EA57A5E7FFEF8D48685D3A32811CDF99C0D4ED64F210BF55C069411C25FEF0973CEC32DA53FF37C61026D315803DD93592FB41037CB0EAF69ED8B0966737276838EE740B8FA72C1BE20050894812437DC463D2A3D5A390AF7D13D0BE957EC2DFE3C99D5CE38FFC07CA9B01606C9F4BBD8D7AB97DDE34EE04EF1E37595CF367F34174EA2815B2DF98B5376974ABD58C73A21C30106665CCDD826F5F00E5A8E7627FF0063E1AF99E0DD525AB95929A07503485F209C4A95D0AACD77996572AD510234FE328CA14C8E270BB08544EDE507E97A60425D51C818ED51948F10CF53C66357C9DC73AC63FF9FF7293C3F765AA22A1C91D3841C76004C21BE7DC47D3B6DEDFBD2CA02C525E1AC316EF53E1D19E7A560435E453D85498F500751F07E9D2994749890CE685EB6C01A1A921BCBC4AC4FBA57FE59E5F272845062278064D45A5733A97497D83A69EBD1D96B870CB93C9E70AB7678B6C9D20698D503846F389E5B0CDD8D289CEEB84A66E2B41A7F2414073974A66DB55369A027E615F78150BA5094404171083D4BE2BF6171E29AF1BEFC1BC43DD825EB2BDA06A3EA7BBF6D32FBC9F1A705B01962A10C80D98FFFD8F568D5A01B1DE62C3102BF6229277850EB7157C840C90D1DA1DAC970275E8D43A1548F24BF04ACCC64D2900BFDEDF67B39A28A0BEBB0E8DAE1F07FE9F121DEF35974D5E82BC6533745F8ED659A213C83514950EE1E1CA7CF6F74D3DD5D13C2B218DDC8B63CD5808E728DCCAD088E87F130F3A68A03F8C0D8DFD00FF2C7EA45C5F150657A866AE5FA5BA362E232952E14C6D959D7F432B20E6F3AEF37A7DC521A8D1DACF068F3CB361207F61A2853297B0167509E8B1C0EA1C3B25611B0349C226B80F22B9A7B6A2FA1A24181787588312C36BE9C7A565FEEC81B6EF017303ED77B4B272262BCDA7C9A1E1CE1A0C43F1D7A2CF849D111B23573902E972B7248B74E83317BBE04158433BC1CBB5E41FD12B644A713456142412978E2B8B4423486429D2BF88F63C2B7B6E861D2382FD9F6A1C20FACA05D01B1040D35F8948FABAF9B6E3243D16D5230A0A8E4C750983080C737513D956306F8222A430D79C3B5B9258B141E95CCAA119F409D945EC9A8B99139707B701412D8290DE324C7E371E21AD32D15A1B655924F91C057018CE1691803CD65838BDDAE8B778C9115018684C6024C6BBA5CC2083E69F26B82846A702DF8733D892753568FED7DD48C15DCEB1AAA3F12A082166FD60B7D467EAD4C3538A73F444BC2312D269EF3505B426B494DEBC8B08B91FDDBA7FE5BD235AAFC6ECF015103D169F80CB7CDC0886E57F551F44A50A6141E399F24C91D3122C96CCE0A452B6AFE2B5A5CFA8C5AC2EDCE7777CED16AFFF53D6462205C8E5E1CB02D8E02E4A935E0D68778CFA62947825CA44D49A9EC961E79512015FC1E3B22E44F50F2F1604771BB1680BFCBE7A948371CB9C6D59F827829AB427D41B43F073140F8572475A2F16C9A63FB63B1D7A1F7D84E65A1EAC535021F03D992AA4D1696C260DA02387288E26C967C6792E95C38C434278B23D0F22AFAE4764E6A4132178AC5CF05EA56B20E3529CCC912B080BA184F0E5CD2A100542DBA5FA34F517ECF19F522985ECFC8950089433C9E3ABFF5A7D9A8F23A5CE25ECAF6CC8E4504927D400726D8D368ACF6D49AF67481240ABA0909382B4FD01066A243A6DCC8DC38222CA097E52E99F7DE2DD102CB49DEC426672BEE45A26F614F4C054E5DD23E1BFC887A7C40992D8FAE51CDEF8A319869A1D5FEB49E30CD0F51D3EC5A740211DFF541C2E91AD8DBAC7707C748A10696E65932F226E255202DF05F2A516C7047B8CE0681895A876E58767EEB75E461ACB4C2E8A5CFE097A4117DAA43DB3F04CB50ADC28214074DE7EDBA6189E65DB0E08C7A92E867C49F1A98171BCD803CF879975286655D96D16A9445304CEFD7D2E1B28C74912D42DD671FB32DCF406C9123F49D10AA94F510CFEF76A528C941A5E43C086E66B50721A5956F4ACFF2D6A4599A9DE1FF5B774E3F1357BDA690F417FE000F1014324D5D64687487CBD2F013486B6D7882859B9FA7DDE2090A101A343F425358646A8A9EAEBEDBE1EEFA081641505C6E818BA1C7CBD6EDFC0000000000000000000000000000000000000000000E1A2D3B";
size_t pk_len = 0;
uint8_t *pk = decode_hex(pk_hex, &pk_len);
if (pk_len != pqcrystals_dilithium2_PUBLICKEYBYTES)
{
printf("%s - pk=%zu vs pqcrystals_dilithium2_PUBLICKEYBYTES=%zu\n", "got unexpected length of public key", pk_len, pqcrystals_dilithium2_PUBLICKEYBYTES);
return 1;
}
size_t msg_len = 0;
uint8_t *msg = decode_hex(msg_hex, &msg_len);
size_t sig_len = 0;
uint8_t *sig = decode_hex(sig_hex, &sig_len);
if (sig_len != pqcrystals_dilithium2_BYTES)
{
printf("%s - sig=%zu vs pqcrystals_dilithium2_BYTES=%zu\n", "got unexpected length of signature", sig_len, pqcrystals_dilithium2_BYTES);
return 1;
}
// MESSAGE REVERSAL
uint8_t *swapped = swapped_msg(msg, msg_len);
if (crypto_sign_verify(sig, sig_len, swapped, msg_len, pk) != 0)
{
printf("%s", "got error verifying signature\n");
return 1;
}
}
uint8_t *
decode_hex(const char *hex, size_t *size)
{
size_t chars = strlen(hex);
size_t length = chars/2;
uint8_t *ret = calloc(length, sizeof(uint8_t));
for (int i = 0; i < chars; i += 2)
{
uint8_t value = 0;
char ch = hex[i];
if ( (ch >= '0') && (ch <= '9') )
value |= ch - '0';
else if ( (ch >= 'A') && (ch <= 'F') )
value |= ch - 'A' + 10;
else if ( (ch >= 'a') && (ch <= 'f') )
value |= ch - 'a' + 10;
else // shouldn't ever get here
value |= 0;
value <<= 4;
ch = hex[i+1];
if ( (ch >= '0') && (ch <= '9') )
value |= ch - '0';
else if ( (ch >= 'A') && (ch <= 'F') )
value |= ch - 'A' + 10;
else if ( (ch >= 'a') && (ch <= 'f') )
value |= ch - 'a' + 10;
else // shouldn't ever get here
value |= 0;
ret[i/2] = value;
}
*size = length;
return ret;
}
uint8_t *
swapped_msg(uint8_t *msg, size_t msg_len)
{
uint8_t *ret = calloc(msg_len, sizeof(uint8_t));
for (size_t i = 0; i < msg_len; i++) {
ret[msg_len - i - 1] = msg[i];
}
return ret;
} I use the the second vector of the first test case from MW's above -- and with MW's reversal noted -- it passes:
with the message byte order swap above (
(this is built against /~https://github.com/pq-crystals/dilithium/tree/standard/ as of However, without swapping the byte order of the message itself, it fails verification against the algorithm author's standard reference implementation... AFAICT -- and again, I might be wrong -- if Section 8.1's reversal algorithms is meant to be applied to the input message M, this isn't called out as a difference either in the NIST ML-DSA IPD draft over upstream (Section 1.3 doesn't mention this), and isn't made clear in the Algorithm 2 definition... Thanks! |
Our I'll see if I can put a fix for this in quickly. |
Perfect, thank you @celic! |
This will also impact FIPS 203, ML-KEM. |
Also to clarify, do you notice this on the signatures, or key values output from the server? Do you need to reverse the public and private key when communicating back to the server to get the correct verdict? |
I'll put it in points so we can refer to it more easily. ML-DSA:
I have not needed to reverse the outputs, pk,sk or signature, I did not dig too far into SigGen failures at this point because of this issue. I have not attempted to implement any testing for ML-KEM beyond fetching vectors. Probably off topic, with KeyGen, we had an error report on one set of vectors about a PK and SK not matching on one test but it is intermittent, I have held of looking into that as well. (I have these vectors saved) Please let me know if you need any more information? MW |
Try siggen where you reverse the resulting signature before sending it to
the server.
…On Tue, Apr 9, 2024, 6:53 PM MW ***@***.***> wrote:
Also to clarify, do you notice this on the signatures, or key values
output from the server? Do you need to reverse the public and private key
when communicating back to the server to get the correct verdict?
I'll put it in points so we can refer to it more easily.
ML-DSA:
1. SigGen -- Total fail at the moment both AFT and GDT, reversing or
not reversing the message.
2. SigVer -- I can obtain passes if I reverse the message.
3. KeyGen -- I can obtain passes if I reverse the seed.
I have not needed to reverse the outputs, pk,sk or signature, I did not
dig too far into SigGen failures at this point because of this issue. I
have not attempted to implement any testing for ML-KEM beyond fetching
vectors.
Probably off topic, with KeyGen, we had an error report on one set of
vectors about a PK and SK not being related but it is intermittent, I have
held of looking into that as well. (I have these vectors saved)
Please let me know if you need any more information?
MW
—
Reply to this email directly, view it on GitHub
<#320 (comment)>,
or unsubscribe
</~https://github.com/notifications/unsubscribe-auth/AATQXEJBEP7FOSJY2NSDRTDY4RWQNAVCNFSM6AAAAABF3Z6DO6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDANBWGE3DMNZRHA>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
I got 100% failure, AFT, GDT SigGen with:
Not tried: With GDP we are "non deterministic" and we are generating a key pair using a random entropy source. |
Allow me to add my observations: ML-DSA:
ML-KEM:
|
I see. This is concerning the |
The fix for this issue is on Demo as of this afternoon's v1.1.0.34 hotfix deployment. |
environment
Demo
testSessionId
501055 -- sigVer all passing with reversal of message
501053 -- keyGen all passing with reversal of seed
vsId
2261682 -- sigVer
2261680 -- keyGen
Algorithm registration
Endpoint in which the error is experienced
demo
I was able to get ML-DSA sigVer vectors to pass if I reversed the byte order of the message being supplied to our verifier.
Looking at the spec, and I am not super familiar with Dilithium, it appears that the message M is passed into H as is without any modification during the verification operation.
Our test harness passes hex encoded byte arrays from left to right, so "ABCDEF" => [0xAB, 0xCD, ... etc]
With respect to keyGen I was able to get a successful pass if I reversed the byte order of seed supplied to our implementation as well.
Without the byte order reversal it is 100% failure in for the modes tested so far.
Reversal in this case is: [0,1,2,3] => [3,2,1,0]
Let me know if you need any more information?
I have attached vector sets, our responses etc
Thanks,
MW
[ml-dsa_keygen_pass.zip](/~https://github.com/us
ml-dsa_sigVer_pass.zip
nistgov/ACVP-Server/files/14899860/ml-dsa_keygen_pass.zip)
The text was updated successfully, but these errors were encountered: